import { AuthService } from '../auth/auth.service'; import { AppError } from '../common/errors/app-error'; import { GiteaClient } from '../integrations/gitea/gitea.client'; import { ProjectRepository } from './project.repository'; import { ProjectSummary } from './project.types'; import { ProjectsService } from './projects.service'; describe('ProjectsService', () => { const project: ProjectSummary = { id: 'project_access_manage', key: 'access-manage', name: 'access-manage', repositoryUrl: 'https://gitea.ops.mrzhan.top/my-project/access-manage.git', defaultBranch: 'develop', status: 'active', environments: [], }; function createService(options?: { giteaConfigured?: boolean; branches?: Array<{ name: string; commitSha: string }>; tags?: Array<{ name: string; commitSha: string }>; commits?: Record; pullRequests?: Record< string, { number: number; title: string; state: string; merged: boolean; } >; }) { const repository = { findMany: jest.fn(() => Promise.resolve([project])), findByKey: jest.fn((key: string) => Promise.resolve(key === project.key ? project : null), ), } satisfies Pick; const gitea = { healthSummary: jest.fn(() => options?.giteaConfigured ? { status: 'ok' as const } : { status: 'not_configured' as const }, ), listBranches: jest.fn(() => Promise.resolve(options?.branches ?? [{ name: 'develop', commitSha: 'abc' }]), ), listTags: jest.fn(() => Promise.resolve(options?.tags ?? [{ name: 'v1.0.0', commitSha: 'def' }]), ), getCommit: jest.fn((owner: string, repo: string, sha: string) => Promise.resolve( options?.commits?.[sha] ?? { sha, message: `commit ${sha}`, }, ), ), getCommitPullRequest: jest.fn((owner: string, repo: string, sha: string) => Promise.resolve(options?.pullRequests?.[sha]), ), } satisfies Pick< GiteaClient, | 'healthSummary' | 'listBranches' | 'listTags' | 'getCommit' | 'getCommitPullRequest' >; const auth = { listAllowedProjectKeys: jest.fn(() => Promise.resolve([project.key])), requireProjectPermission: jest.fn(() => Promise.resolve()), } satisfies Pick< AuthService, 'listAllowedProjectKeys' | 'requireProjectPermission' >; return { auth, gitea, repository, service: new ProjectsService( repository as unknown as ProjectRepository, gitea as unknown as GiteaClient, auth as unknown as AuthService, ), }; } it('returns fallback refs when Gitea is not configured', async () => { const { gitea, service } = createService({ giteaConfigured: false }); const refs = await service.listProjectRefs(project.key); expect(refs.source).toBe('fallback'); expect(refs.branches).toContainEqual({ name: 'develop' }); expect(refs.tags).toContainEqual({ name: 'v2026.06.05-envsplit.7' }); expect(gitea.listBranches).not.toHaveBeenCalled(); }); it('returns Gitea refs when Gitea is configured', async () => { const { gitea, service } = createService({ giteaConfigured: true, branches: [{ name: 'feature/devops-platform', commitSha: 'abc123' }], tags: [{ name: 'v2026.06.11.1', commitSha: 'def456' }], commits: { abc123: { sha: 'abc123', message: 'feat: add platform refs' }, def456: { sha: 'def456', message: 'chore: tag release' }, }, pullRequests: { abc123: { number: 2, title: 'feat: add platform refs', state: 'closed', merged: true, }, }, }); const refs = await service.listProjectRefs(project.key); expect(refs).toEqual({ source: 'gitea', branches: [ { name: 'feature/devops-platform', commitSha: 'abc123', commit: { sha: 'abc123', message: 'feat: add platform refs' }, pullRequest: { number: 2, title: 'feat: add platform refs', state: 'closed', merged: true, url: 'https://gitea.ops.mrzhan.top/my-project/access-manage/pulls/2', }, }, ], tags: [ { name: 'v2026.06.11.1', commitSha: 'def456', commit: { sha: 'def456', message: 'chore: tag release' }, }, ], }); expect(gitea.listBranches).toHaveBeenCalledWith('my-project', 'access-manage'); expect(gitea.getCommit).toHaveBeenCalledWith( 'my-project', 'access-manage', 'abc123', ); }); it('raises a not found error for unknown projects', async () => { const { service } = createService(); await expect(service.listProjectRefs('unknown')).rejects.toBeInstanceOf(AppError); }); });