PBI-8 (vervolg): Sprint-aware branch + SPRINT-mode draft-PR

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>
This commit is contained in:
Madhura68 2026-05-06 17:15:04 +02:00
parent 7b135e12dd
commit 454d96ee04
7 changed files with 359 additions and 24 deletions

View file

@ -111,6 +111,35 @@ export async function resolveBranchForJob(
jobId: string,
storyId: string,
): Promise<{ branchName: string; reused: boolean }> {
// Sprint-flow (PBI-46): als deze job aan een SprintRun hangt, kies de branch
// op basis van Product.pr_strategy:
// SPRINT → feat/sprint-<sprint_run_id-suffix> (één branch voor hele run)
// STORY → feat/story-<story_id-suffix> (één branch per story; sibling-tasks delen 'm)
// Voor legacy task-jobs zonder sprint_run_id valt de logica terug op het
// bestaande feat/story-<storyId>-pad.
const job = await prisma.claudeJob.findUnique({
where: { id: jobId },
select: {
sprint_run_id: true,
sprint_run: { select: { id: true, pr_strategy: true } },
},
})
if (job?.sprint_run && job.sprint_run.pr_strategy === 'SPRINT') {
const branchName = `feat/sprint-${job.sprint_run.id.slice(-8)}`
const sibling = await prisma.claudeJob.findFirst({
where: {
sprint_run_id: job.sprint_run_id,
branch: branchName,
id: { not: jobId },
},
orderBy: { created_at: 'asc' },
select: { branch: true },
})
return { branchName, reused: sibling !== null }
}
// STORY-mode (default) of legacy: branch per story
const sibling = await prisma.claudeJob.findFirst({
where: {
task: { story_id: storyId },