T-22 — sprint-aware branch-resolutie (resolveBranchForJob):
- SPRINT-mode → feat/sprint-<sprint_run_id-suffix> (één branch voor hele run)
- STORY-mode → feat/story-<story_id-suffix> (één per story)
- Legacy (zonder sprint_run_id): bestaand gedrag
Sibling-detection herbruikt branch wanneer een eerdere job in dezelfde
scope al de branch heeft.
T-24 — SPRINT-mode draft-PR + ready-bij-DONE:
- createPullRequest accepteert nu draft + enableAutoMerge flags
- Nieuwe markPullRequestReady-helper voor draft → ready transitie
- maybeCreateAutoPr in SPRINT-mode: opent één draft-PR per SprintRun met
sprint_goal als titel; geen auto-merge; sibling-tasks hergebruiken de
PR
- update-job-status detecteert sprint-DONE via PropagationResult en zet
de draft-PR via markPullRequestReady ready-for-review (mens reviewt en
mergt zelf)
T-23 — STORY-mode dekking: bestaande createPullRequest + auto-merge gedrag
ongewijzigd. Tests uitgebreid met sprint-aware mocks; 6 nieuwe
branch-resolution tests + 2 sprint-mode auto-pr tests + 4 markPullRequest
Ready/draft-PR tests.
Tests: 195/195 groen (180 → 195; 15 nieuwe scenario's voor sprint-aware
branch + SPRINT-mode draft-PR + markPullRequestReady).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
91 lines
3 KiB
TypeScript
91 lines
3 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
|
|
vi.mock('../src/prisma.js', () => ({
|
|
prisma: {
|
|
claudeJob: {
|
|
findUnique: vi.fn(),
|
|
findFirst: vi.fn(),
|
|
},
|
|
},
|
|
}))
|
|
|
|
import { prisma } from '../src/prisma.js'
|
|
import { resolveBranchForJob } from '../src/tools/wait-for-job.js'
|
|
|
|
const mockPrisma = prisma as unknown as {
|
|
claudeJob: {
|
|
findUnique: ReturnType<typeof vi.fn>
|
|
findFirst: ReturnType<typeof vi.fn>
|
|
}
|
|
}
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
describe('resolveBranchForJob — sprint-aware', () => {
|
|
it('SPRINT-mode: kiest feat/sprint-<id-suffix> en marks reused=false bij eerste task', async () => {
|
|
mockPrisma.claudeJob.findUnique.mockResolvedValue({
|
|
sprint_run_id: 'run-cuid-12345678',
|
|
sprint_run: { id: 'run-cuid-12345678', pr_strategy: 'SPRINT' },
|
|
})
|
|
mockPrisma.claudeJob.findFirst.mockResolvedValue(null)
|
|
|
|
const result = await resolveBranchForJob('job-1', 'story-anything')
|
|
|
|
expect(result.branchName).toBe('feat/sprint-12345678')
|
|
expect(result.reused).toBe(false)
|
|
})
|
|
|
|
it('SPRINT-mode: marks reused=true wanneer sibling al de branch gebruikt', async () => {
|
|
mockPrisma.claudeJob.findUnique.mockResolvedValue({
|
|
sprint_run_id: 'run-cuid-12345678',
|
|
sprint_run: { id: 'run-cuid-12345678', pr_strategy: 'SPRINT' },
|
|
})
|
|
mockPrisma.claudeJob.findFirst.mockResolvedValue({ branch: 'feat/sprint-12345678' })
|
|
|
|
const result = await resolveBranchForJob('job-2', 'story-anything')
|
|
|
|
expect(result.branchName).toBe('feat/sprint-12345678')
|
|
expect(result.reused).toBe(true)
|
|
})
|
|
|
|
it('STORY-mode (sprint-flow): valt terug op story-branch via legacy-pad', async () => {
|
|
mockPrisma.claudeJob.findUnique.mockResolvedValue({
|
|
sprint_run_id: 'run-cuid-12345678',
|
|
sprint_run: { id: 'run-cuid-12345678', pr_strategy: 'STORY' },
|
|
})
|
|
mockPrisma.claudeJob.findFirst.mockResolvedValue(null)
|
|
|
|
const result = await resolveBranchForJob('job-1', 'story-cuid-87654321')
|
|
|
|
expect(result.branchName).toBe('feat/story-87654321')
|
|
expect(result.reused).toBe(false)
|
|
})
|
|
|
|
it('Legacy (geen sprint_run): bestaand gedrag — feat/story-<id-suffix>', async () => {
|
|
mockPrisma.claudeJob.findUnique.mockResolvedValue({
|
|
sprint_run_id: null,
|
|
sprint_run: null,
|
|
})
|
|
mockPrisma.claudeJob.findFirst.mockResolvedValue(null)
|
|
|
|
const result = await resolveBranchForJob('job-1', 'story-cuid-87654321')
|
|
|
|
expect(result.branchName).toBe('feat/story-87654321')
|
|
expect(result.reused).toBe(false)
|
|
})
|
|
|
|
it('Legacy: hergebruik branch wanneer sibling-job in dezelfde story al een branch heeft', async () => {
|
|
mockPrisma.claudeJob.findUnique.mockResolvedValue({
|
|
sprint_run_id: null,
|
|
sprint_run: null,
|
|
})
|
|
mockPrisma.claudeJob.findFirst.mockResolvedValue({ branch: 'feat/story-87654321' })
|
|
|
|
const result = await resolveBranchForJob('job-2', 'story-cuid-87654321')
|
|
|
|
expect(result.branchName).toBe('feat/story-87654321')
|
|
expect(result.reused).toBe(true)
|
|
})
|
|
})
|