fix(scm-github): fetch in-progress failed job logs

This commit is contained in:
i-trytoohard 2026-05-15 05:15:59 +05:30
parent 60b5c91f98
commit 487269aea0
2 changed files with 52 additions and 9 deletions

View File

@ -221,6 +221,29 @@ function extractFailedStep(log: string): string | undefined {
return lastStep;
}
async function getFailedJobLog(
pr: PRInfo,
runReference: { runId: string; jobId?: string },
): Promise<string> {
try {
return await gh([
"run",
"view",
runReference.runId,
"--repo",
repoFlag(pr),
"--log-failed",
...(runReference.jobId ? ["--job", runReference.jobId] : []),
]);
} catch (err) {
if (!runReference.jobId) throw err;
return gh([
"api",
`repos/${pr.owner}/${pr.repo}/actions/jobs/${runReference.jobId}/logs`,
]);
}
}
async function getCIChecksFromStatusRollup(pr: PRInfo): Promise<CICheck[]> {
const raw = await gh([
"pr",
@ -886,15 +909,7 @@ function createGitHubSCM(): SCM {
if (seenRuns.has(seenKey)) continue;
seenRuns.add(seenKey);
const log = await gh([
"run",
"view",
runReference.runId,
"--repo",
repoFlag(pr),
"--log-failed",
...(runReference.jobId ? ["--job", runReference.jobId] : []),
]);
const log = await getFailedJobLog(pr, runReference);
const failedJob: CIFailureSummary["failedJobs"][number] = {
name: check.name,

View File

@ -707,6 +707,34 @@ describe("scm-github plugin", () => {
await expect(scm.getCIFailureSummary?.(pr, checks)).resolves.toBeNull();
});
it("falls back to job logs API when gh run view cannot read logs yet", async () => {
const checks = [
{
name: "lint",
status: "failed" as const,
conclusion: "FAILURE",
url: "https://github.com/acme/repo/actions/runs/123/job/456",
},
];
mockGhError("run 123 is still in progress; logs will be available when it is complete");
mockGhRaw("2026-05-14T23:40:42Z ##[error]Lint failed\nunused variable");
const summary = await scm.getCIFailureSummary?.(pr, checks);
expect(summary?.failedJobs).toEqual([
{
name: "lint",
runUrl: "https://github.com/acme/repo/actions/runs/123/job/456",
logTail: "2026-05-14T23:40:42Z ##[error]Lint failed\nunused variable",
},
]);
expect(ghMock).toHaveBeenLastCalledWith(
expect.stringMatching(/(?:^|[\\/])gh(?:\.(?:exe|cmd|bat))?$/i),
["api", "repos/acme/repo/actions/jobs/456/logs"],
expect.any(Object),
);
});
});
// ---- getCISummary ------------------------------------------------------