Extract check rerun error classification with operation context

Create classifyRerunChecksError() to provide operation-specific error
messages when check reruns fail. This replaces generic GitHub error
copy with context appropriate to what the user attempted (rerun
checks). Follows the pattern of classifyListPrsError and improves
error handling by delegating extraction to extractExecError.
This commit is contained in:
Jinjing
2026-08-17 21:18:27 -07:00
parent 36f11c380e
commit de5f29d66b
3 changed files with 26 additions and 10 deletions
@@ -1,11 +1,8 @@
import type { GitHubRerunPRChecksResult } from '../../../../shared/github/check-types'
import {
ghExecFileAsync,
acquire,
release,
classifyGhError,
type LocalGitExecOptions
} from '../../gh-utils'
import { ghExecFileAsync, acquire, release, type LocalGitExecOptions } from '../../gh-utils'
// Why: pure error helpers come from their own modules so tests that mock gh-utils still classify for real.
import { extractExecError } from '../../../git/exec-error'
import { classifyRerunChecksError } from '../../gh-error-classification'
import { resolveGitHubRepoExecution, type GitHubApiRepository } from '../../github-api-repository'
import { getPRChecks } from './get-pr-checks'
import { parseActionsRunId } from './check-detail-field-mapping'
@@ -92,9 +89,8 @@ export async function rerunPRChecks(
}
return { ok: true, count }
} catch (err) {
const message =
err instanceof Error ? err.message : typeof err === 'string' ? err : 'Unknown error'
const classified = classifyGhError(message).message
const { stderr } = extractExecError(err)
const classified = classifyRerunChecksError(stderr).message
// Why: these POSTs are not idempotent — say how many reruns already started so a retry isn't blind.
return {
ok: false,
@@ -81,3 +81,21 @@ export function classifyListPrsError(stderr: string): ClassifiedError {
const c = classifyGhError(stderr)
return { type: c.type, message: `Failed to load pull requests: ${stderr.trim()}` }
}
// Why: classifyGhError's copy names an "issue"; a failed check rerun must name
// the operation the user actually triggered.
export function classifyRerunChecksError(stderr: string): ClassifiedError {
const c = classifyGhError(stderr)
const trimmed = stderr.trim()
const rerunMessages: Record<ClassifiedError['type'], string> = {
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.',
issues_disabled: `Failed to rerun checks: ${trimmed}`,
validation_error: `Could not rerun checks — ${trimmed}`,
rate_limited: c.message,
network_error: c.message,
unknown: `Failed to rerun checks: ${trimmed}`
}
return { type: c.type, message: rerunMessages[c.type] }
}
@@ -601,6 +601,8 @@ describe('updater', () => {
await vi.advanceTimersByTimeAsync(100)
expect(revalidation.invocationCount()).toBe(1)
updater.quitAndInstall()
// Advancing here proves the second request never scheduled its own quit timer.
await vi.advanceTimersByTimeAsync(100)
expect(revalidation.invocationCount()).toBe(1)
revalidation.settle({ ok: true })
await settleQuitAndInstall()