diff --git a/src/main/github/client-pr-checks.test.ts b/src/main/github/client-pr-checks.test.ts index 72ca0f77cff..43be8ba642e 100644 --- a/src/main/github/client-pr-checks.test.ts +++ b/src/main/github/client-pr-checks.test.ts @@ -568,6 +568,74 @@ describe('getPRChecks', () => { } ) }) + it('reports a resource-neutral not-found error when a workflow-run rerun 404s', async () => { + getOwnerRepoMock.mockResolvedValue({ owner: 'acme', repo: 'widgets' }) + ghExecFileAsyncMock + .mockResolvedValueOnce( + graphQLChecksResponse({ + contexts: [ + graphQLCheckRun({ + name: 'lint', + conclusion: 'FAILURE', + detailsUrl: 'https://github.com/acme/widgets/actions/runs/77/job/88', + workflowRunId: 77 + }) + ] + }) + ) + .mockRejectedValueOnce( + Object.assign(new Error('Command failed: gh api'), { + stderr: 'gh: HTTP 404 Not Found (repos/acme/widgets/actions/runs/77/rerun-failed-jobs)', + stdout: '' + }) + ) + + const result = await rerunPRChecks('/repo-root', 42, { failedOnly: true }) + + expect(result).toEqual({ + ok: false, + error: 'GitHub resource to rerun was not found — it may have expired or been deleted.' + }) + }) + + it('reports a resource-neutral not-found error when a standalone check-run rerequest 404s', async () => { + getOwnerRepoMock.mockResolvedValue({ owner: 'acme', repo: 'widgets' }) + ghExecFileAsyncMock + .mockResolvedValueOnce( + graphQLChecksResponse({ + contexts: [ + { + __typename: 'CheckRun', + databaseId: 88, + name: 'external-ci', + status: 'COMPLETED', + conclusion: 'FAILURE', + detailsUrl: 'https://ci.example.com/builds/88', + url: 'https://ci.example.com/builds/88', + checkSuite: { databaseId: 1000, workflowRun: null } + } + ] + }) + ) + .mockRejectedValueOnce( + Object.assign(new Error('Command failed: gh api'), { + stderr: 'gh: HTTP 404 Not Found (repos/acme/widgets/check-runs/88/rerequest)', + stdout: '' + }) + ) + + const result = await rerunPRChecks('/repo-root', 42, { failedOnly: true }) + + expect(ghExecFileAsyncMock).toHaveBeenNthCalledWith( + 2, + ['api', '-X', 'POST', 'repos/acme/widgets/check-runs/88/rerequest'], + expect.objectContaining({ cwd: '/repo-root' }) + ) + expect(result).toEqual({ + ok: false, + error: 'GitHub resource to rerun was not found — it may have expired or been deleted.' + }) + }) it('routes local WSL check retrieval and reruns through the selected distro', async () => { const localGitOptions = { wslDistro: 'Ubuntu' } diff --git a/src/main/github/gh-error-classification.ts b/src/main/github/gh-error-classification.ts index 1093b88dc68..bb333bf06d0 100644 --- a/src/main/github/gh-error-classification.ts +++ b/src/main/github/gh-error-classification.ts @@ -90,7 +90,7 @@ export function classifyRerunChecksError(stderr: string): ClassifiedError { const rerunMessages: Record = { permission_denied: "You don't have permission to rerun checks on this repository. Check your GitHub token scopes.", - not_found: 'Check run not found — it may have expired or been deleted.', + not_found: 'GitHub resource to rerun was not found — it may have expired or been deleted.', issues_disabled: `Failed to rerun checks: ${trimmed}`, validation_error: `Could not rerun checks — ${trimmed}`, rate_limited: c.message,