diff --git a/src/workflow.ts b/src/workflow.ts index 13ea9b02..0fd0f34e 100644 --- a/src/workflow.ts +++ b/src/workflow.ts @@ -131,6 +131,12 @@ async function processIssue( startedAt: new Date().toISOString(), updatedAt: new Date().toISOString(), } satisfies RunState); + issueLogger.info( + buildIssueJobLogFields(runState, runState.stage, { + resumed: existing !== null, + }), + "Taking issue job", + ); try { await executeIssue(config, linear, runState); @@ -179,6 +185,30 @@ export async function sleep(ms: number): Promise { await new Promise((resolve) => setTimeout(resolve, ms)); } +export interface IssueJobLogFields { + projectId: string; + issueKey: string; + issueId: string; + issueTitle: string; + stage: string; + resumed?: true; +} + +export function buildIssueJobLogFields( + state: RunState, + stage: string, + options?: { resumed?: boolean }, +): IssueJobLogFields { + return { + projectId: state.projectId, + issueKey: state.issue.key, + issueId: state.issue.id, + issueTitle: state.issue.title, + stage, + ...(options?.resumed ? { resumed: true as const } : {}), + }; +} + async function executeIssue( config: ResolvedProjectConfig, linear: LinearClient, @@ -196,6 +226,7 @@ async function executeIssue( } if (state.stage === "planning") { + logger.info(buildIssueJobLogFields(state, "planning"), "Planning issue"); const prompt = await buildPlanPrompt(config.skills.plan, state.issue); const result = await runPlanSession(config, prompt); state.codexSessionId = result.sessionId ?? state.codexSessionId; @@ -207,12 +238,17 @@ async function executeIssue( state.issue.id, buildPlanComment(state.issue.key, state.planSummary), ); + logger.info(buildIssueJobLogFields(state, "planning"), "Plan completed"); } if (state.stage === "implementing") { if (!state.codexSessionId) { throw new Error("Missing codex session id for implement step"); } + logger.info( + buildIssueJobLogFields(state, "implementing"), + "Implementing issue", + ); const prompt = await buildImplementPrompt( config.skills.implement, state.issue, @@ -243,6 +279,10 @@ async function executeIssue( state.issue.id, `Implementation completed. Draft PR: ${state.pullRequest.url ?? "(created)"}`, ); + logger.info( + buildIssueJobLogFields(state, "implementing"), + "Implementation completed", + ); } if (state.stage === "pr_created") { @@ -253,6 +293,7 @@ async function executeIssue( } if (state.stage === "reviewing" || state.stage === "testing") { + logger.info(buildIssueJobLogFields(state, "testing"), "Testing issue"); await linear.markStage(state.issue.id, "testing"); await linear.applyStageLabel(state.issue.id, "testing"); Object.assign(state, transitionStage(state, "testing")); @@ -319,6 +360,10 @@ async function executeIssue( await saveRunState(config.workspacePath, state); await linear.markStage(state.issue.id, "done"); await linear.comment(state.issue.id, "Review/testing passed. Marked done."); + logger.info( + buildIssueJobLogFields(state, "testing"), + "Review/testing completed", + ); } } diff --git a/tests/workflow.test.ts b/tests/workflow.test.ts index 34697c33..74332805 100644 --- a/tests/workflow.test.ts +++ b/tests/workflow.test.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from "bun:test"; import type { ResolvedProjectConfig } from "../src/types"; import { + buildIssueJobLogFields, buildPlanComment, parseReviewOutcome, resolvePollingSettings, @@ -120,3 +121,77 @@ describe("resolvePollingSettings", () => { }); }); }); + +describe("buildIssueJobLogFields", () => { + it("returns consistent issue job fields", () => { + const now = new Date().toISOString(); + const fields = buildIssueJobLogFields( + { + projectId: "default", + projectName: "Default", + workspacePath: "/tmp/work", + repository: { + owner: "acme", + name: "repo", + baseBranch: "main", + }, + issue: { + id: "lin_123", + key: "ENG-1", + title: "Improve logging", + url: "https://linear.app/acme/issue/ENG-1/improve-logging", + }, + stage: "planning", + bugs: [], + startedAt: now, + updatedAt: now, + }, + "planning", + ); + + expect(fields).toEqual({ + projectId: "default", + issueKey: "ENG-1", + issueId: "lin_123", + issueTitle: "Improve logging", + stage: "planning", + }); + }); + + it("includes resumed flag when issue run is resumed", () => { + const now = new Date().toISOString(); + const fields = buildIssueJobLogFields( + { + projectId: "default", + projectName: "Default", + workspacePath: "/tmp/work", + repository: { + owner: "acme", + name: "repo", + baseBranch: "main", + }, + issue: { + id: "lin_123", + key: "ENG-1", + title: "Improve logging", + url: "https://linear.app/acme/issue/ENG-1/improve-logging", + }, + stage: "implementing", + bugs: [], + startedAt: now, + updatedAt: now, + }, + "implementing", + { resumed: true }, + ); + + expect(fields).toEqual({ + projectId: "default", + issueKey: "ENG-1", + issueId: "lin_123", + issueTitle: "Improve logging", + stage: "implementing", + resumed: true, + }); + }); +});