Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ jobs:
- name: Build Frontend Image
uses: docker/build-push-action@v5
with:
context: ./apps/frontend
context: .
file: ./apps/frontend/Dockerfile
push: false
tags: devpulse-frontend:latest
Expand Down
6 changes: 3 additions & 3 deletions apps/backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ FROM node:20-alpine AS builder

WORKDIR /app

COPY apps/backend/package*.json ./
COPY package*.json ./
RUN npm ci

COPY apps/backend/ .
COPY . .
RUN npm run build

FROM node:20-alpine AS runner

WORKDIR /app
ENV NODE_ENV=production

COPY apps/backend/package*.json ./
COPY package*.json ./
RUN npm ci --only=production

COPY --from=builder /app/dist ./dist
Expand Down
7 changes: 7 additions & 0 deletions apps/backend/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ export default tseslint.config(
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-floating-promises': 'warn',
'@typescript-eslint/no-unsafe-argument': 'warn',
'@typescript-eslint/no-unsafe-assignment': 'warn',
'@typescript-eslint/no-unsafe-member-access': 'warn',
'@typescript-eslint/no-unsafe-call': 'warn',
'@typescript-eslint/no-unsafe-return': 'warn',
'@typescript-eslint/no-redundant-type-constituents': 'warn',
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
'no-useless-escape': 'warn',
"prettier/prettier": ["error", { endOfLine: "auto" }],
},
},
Expand Down
2 changes: 1 addition & 1 deletion apps/backend/src/os-finder/ai-query-builder.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable, Logger } from '@nestjs/common';
import { AiService } from '../shared/ai.service';
import { OsFinderFilters, Difficulty, ContributionType, Domain, RepoSize } from '../../packages/shared-types/os-finder.types';
import { OsFinderFilters, Difficulty, ContributionType, Domain } from '../../packages/shared-types/os-finder.types';

@Injectable()
export class AiQueryBuilderService {
Expand Down Expand Up @@ -102,16 +102,16 @@
hasCodeOfConduct: typeof parsed.hasCodeOfConduct === 'boolean' ? parsed.hasCodeOfConduct : false,
licenseTypes: Array.isArray(parsed.licenseTypes) ? parsed.licenseTypes : [],
prMergeRate: 30,
};

Check warning on line 105 in apps/backend/src/os-finder/ai-query-builder.service.ts

View workflow job for this annotation

GitHub Actions / Backend CI

Unsafe assignment of an `any` value

const keywords = Array.isArray(parsed.keywords) ? parsed.keywords : [];

Check warning on line 108 in apps/backend/src/os-finder/ai-query-builder.service.ts

View workflow job for this annotation

GitHub Actions / Backend CI

Unsafe member access .languages on an `any` value

Check warning on line 108 in apps/backend/src/os-finder/ai-query-builder.service.ts

View workflow job for this annotation

GitHub Actions / Backend CI

Unsafe assignment of an `any` value
return {

Check warning on line 109 in apps/backend/src/os-finder/ai-query-builder.service.ts

View workflow job for this annotation

GitHub Actions / Backend CI

Unsafe member access .languages on an `any` value
filters,
keywords,

Check warning on line 111 in apps/backend/src/os-finder/ai-query-builder.service.ts

View workflow job for this annotation

GitHub Actions / Backend CI

Unsafe member access .languageMode on an `any` value

Check warning on line 111 in apps/backend/src/os-finder/ai-query-builder.service.ts

View workflow job for this annotation

GitHub Actions / Backend CI

Unsafe assignment of an `any` value
aiModeUsed: true,

Check warning on line 112 in apps/backend/src/os-finder/ai-query-builder.service.ts

View workflow job for this annotation

GitHub Actions / Backend CI

Unsafe member access .difficulty on an `any` value

Check warning on line 112 in apps/backend/src/os-finder/ai-query-builder.service.ts

View workflow job for this annotation

GitHub Actions / Backend CI

Unsafe assignment of an `any` value
fallbackUsed: false,

Check warning on line 113 in apps/backend/src/os-finder/ai-query-builder.service.ts

View workflow job for this annotation

GitHub Actions / Backend CI

Unsafe member access .contributionTypes on an `any` value
};

Check warning on line 114 in apps/backend/src/os-finder/ai-query-builder.service.ts

View workflow job for this annotation

GitHub Actions / Backend CI

Unsafe member access .contributionTypes on an `any` value
} catch (parseError) {
this.logger.error(`Failed to parse AI JSON response: ${parseError instanceof Error ? parseError.message : String(parseError)}. Content was: ${aiResponse}`);
return {
Expand Down
47 changes: 25 additions & 22 deletions apps/backend/src/os-finder/ncf-scorer.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { OsFinderCacheService } from './os-finder-cache.service';

describe('NcfScorerService', () => {
let service: NcfScorerService;
let cacheService: OsFinderCacheService;
let _cacheService: OsFinderCacheService;

const mockCacheService = {
getRepoIssues: jest.fn(),
Expand All @@ -22,13 +22,14 @@ describe('NcfScorerService', () => {
}).compile();

service = module.get<NcfScorerService>(NcfScorerService);
cacheService = module.get<OsFinderCacheService>(OsFinderCacheService);
_cacheService = module.get<OsFinderCacheService>(OsFinderCacheService);
});

afterEach(() => {
jest.clearAllMocks();
if ((global.fetch as any).mockRestore) {
(global.fetch as any).mockRestore();
const fetchMock = global.fetch as jest.MockedFunction<typeof fetch>;
if (fetchMock.mockRestore) {
fetchMock.mockRestore();
}
});

Expand All @@ -44,29 +45,30 @@ describe('NcfScorerService', () => {
freshDate.setDate(freshDate.getDate() - 5);

// Mock global fetch
const fetchSpy = jest.spyOn(global, 'fetch').mockImplementation((url: any) => {
let data: any = {};
if (url.includes('/issues?labels=good first issue')) {
jest.spyOn(global, 'fetch').mockImplementation((url: RequestInfo | URL) => {
const urlStr = typeof url === 'string' ? url : url instanceof URL ? url.href : url.url;
let data: unknown = {};
if (urlStr.includes('/issues?labels=good first issue')) {
data = [{ id: 1, updated_at: freshDate.toISOString() }];
} else if (url.includes('/issues?labels=help wanted')) {
} else if (urlStr.includes('/issues?labels=help wanted')) {
data = [{ id: 2 }];
} else if (url.includes('/community/profile')) {
} else if (urlStr.includes('/community/profile')) {
data = {
files: {
contributing: { html_url: 'contrib' },
code_of_conduct: { html_url: 'coc' },
},
};
} else if (url.includes('/readme')) {
} else if (urlStr.includes('/readme')) {
data = { size: 5000 };
} else if (url.includes('/pulls')) {
} else if (urlStr.includes('/pulls')) {
data = [
{
merged_at: freshDate.toISOString(),
author_association: 'FIRST_TIME_CONTRIBUTOR',
},
];
} else if (url.includes('/issues?state=closed')) {
} else if (urlStr.includes('/issues?state=closed')) {
data = [
{
created_at: freshDate.toISOString(),
Expand All @@ -83,7 +85,7 @@ describe('NcfScorerService', () => {
['X-RateLimit-Reset', '1234567'],
]),
json: () => Promise.resolve(data),
} as any);
} as unknown as Response);
});

const breakdown = await service.computeNCFScore('owner', 'repo', 'token', {});
Expand All @@ -106,24 +108,25 @@ describe('NcfScorerService', () => {
const oldDate = new Date();
oldDate.setDate(oldDate.getDate() - 100);

const fetchSpy = jest.spyOn(global, 'fetch').mockImplementation((url: any) => {
let data: any = {};
if (url.includes('/issues?labels=good first issue')) {
jest.spyOn(global, 'fetch').mockImplementation((url: RequestInfo | URL) => {
const urlStr = typeof url === 'string' ? url : url instanceof URL ? url.href : url.url;
let data: unknown = {};
if (urlStr.includes('/issues?labels=good first issue')) {
data = [];
} else if (url.includes('/issues?labels=help wanted')) {
} else if (urlStr.includes('/issues?labels=help wanted')) {
data = [];
} else if (url.includes('/community/profile')) {
} else if (urlStr.includes('/community/profile')) {
data = {
files: {
contributing: null,
code_of_conduct: null,
},
};
} else if (url.includes('/readme')) {
} else if (urlStr.includes('/readme')) {
data = { size: 100 };
} else if (url.includes('/pulls')) {
} else if (urlStr.includes('/pulls')) {
data = [];
} else if (url.includes('/issues?state=closed')) {
} else if (urlStr.includes('/issues?state=closed')) {
// slow close time: 40 days
const start = new Date();
start.setDate(start.getDate() - 50);
Expand All @@ -145,7 +148,7 @@ describe('NcfScorerService', () => {
['X-RateLimit-Reset', '1234567'],
]),
json: () => Promise.resolve(data),
} as any);
} as unknown as Response);
});

const breakdown = await service.computeNCFScore('owner', 'repo', 'token', {});
Expand Down
2 changes: 1 addition & 1 deletion apps/backend/src/os-finder/ncf-scorer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class NcfScorerService {
owner: string,
repo: string,
token: string,
repoDetails: any
_repoDetails: any
): Promise<NCFScoreBreakdown> {
const breakdown: NCFScoreBreakdown = {
total: 1.0, // base score
Expand Down
1 change: 0 additions & 1 deletion apps/backend/src/os-finder/os-finder.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
} from '@nestjs/common';
import { JwtAuthGuard } from '../common/guards/jwt.guard';
import { CurrentUser } from '../common/decorators/current-user.decorator';
import { User } from '../users/entities/user.entity';
import { OsFinderService } from './os-finder.service';
import { SearchQueryDto } from './dto/search-query.dto';
import { SaveRepoDto } from './dto/save-repo.dto';
Expand Down
4 changes: 0 additions & 4 deletions apps/backend/src/os-finder/os-finder.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ import {
OsFinderFilters,
OsFinderRepoResult,
OsFinderSearchResponse,
NCFScoreBreakdown,
RepoHealthFlags,
SavedRepoStatus
} from '../../packages/shared-types/os-finder.types';
import { SearchQueryDto } from './dto/search-query.dto';
import { SaveRepoDto } from './dto/save-repo.dto';
Expand Down Expand Up @@ -376,7 +373,6 @@ export class OsFinderService {
let activeFilters = { ...filters };
let githubQuery = GitHubQueryBuilder.build(activeFilters, userCtx, keywords);
let rawResults: any = null;
let filtersRelaxed: Partial<OsFinderFilters> | null = null;
let relaxationNote: string | null = fallbackUsed ? "AI query builder unavailable. Using keyword matching instead." : null;

try {
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ services:

backend:
build:
context: .
dockerfile: apps/backend/Dockerfile
context: ./apps/backend
dockerfile: Dockerfile
ports:
- "3000:3000"
depends_on:
Expand Down
Loading