diff --git a/tests/release-pipeline.test.ts b/tests/release-pipeline.test.ts index 9022051..89991db 100644 --- a/tests/release-pipeline.test.ts +++ b/tests/release-pipeline.test.ts @@ -36,13 +36,15 @@ describe('candidate state from the ci.yml jobs', () => { const t = (name: string, status: string, run = 5, sha = SHA, wf = 'ci.yml'): Task => ({ id: 1, name, run_number: run, workflow_id: wf, head_sha: sha, status }); const url = (n: number) => `run/${n}`; test('none, pending, red; the newest run counts', () => { - expect(taskState([t('ci', 'success', 5, 'b'.repeat(40))], SHA, url)).toEqual({ state: 'none' }); + expect(taskState([t('linux', 'success', 5, 'b'.repeat(40))], SHA, url)).toEqual({ state: 'none' }); expect(taskState([t('ci', 'success'), t('windows', 'running')], SHA, url)).toEqual({ state: 'pending', run: 'run/5', running: ['windows (running)'] }); - expect(taskState([t('ci', 'success'), t('acceptance (bun)', 'failure')], SHA, url)).toEqual({ state: 'red', run: 'run/5', failed: ['acceptance (bun)'], cancelledOnly: false }); + expect(taskState([t('linux', 'success'), t('windows', 'failure')], SHA, url)).toEqual({ state: 'red', run: 'run/5', failed: ['windows'], cancelledOnly: false }); // a cancelled run (old-tag runs freed, superseded) is not a failure: a version-only child runs everything expect(taskState([t('ci', 'success'), t('linux', 'cancelled')], SHA, url)).toEqual({ state: 'red', run: 'run/5', failed: ['linux'], cancelledOnly: true }); - expect(taskState([t('ci', 'failure', 4), t('ci', 'running', 6)], SHA, url).state).toBe('pending'); + expect(taskState([t('linux', 'failure', 4), t('linux', 'running', 6)], SHA, url).state).toBe('pending'); expect(taskState([t('promote', 'failure', 9, SHA, 'release.yml')], SHA, url)).toEqual({ state: 'none' }); + // background tests never gate: a red ci / acceptance job leaves the candidate pending on its installers + expect(taskState([t('ci', 'failure'), t('acceptance (bun)', 'failure'), t('linux', 'success'), t('windows', 'running')], SHA, url)).toEqual({ state: 'pending', run: 'run/5', running: ['windows (running)'] }); }); test('tags and prereleases', () => { expect(tagVersion('v0.8.5')).toBe('0.8.5'); diff --git a/tools/release-candidate.ts b/tools/release-candidate.ts index 414c181..bb0ff92 100644 --- a/tools/release-candidate.ts +++ b/tools/release-candidate.ts @@ -94,7 +94,9 @@ export interface Task { id: number; name: string; run_number: number; workflow_i /** The state of a commit from its ci.yml jobs (the newest run of that commit) and whether its record exists. Pure. */ export function taskState(tasks: Task[], sha: string, runUrl: (n: number) => string): Exclude { - const mine = tasks.filter(t => t.head_sha === sha && t.workflow_id === 'ci.yml'); + // the background test jobs (ci, acceptance) never gate a release (the owner's decision 2026-10-16): only the + // installer builds and the record count; tools/ci-status.ts reports the tests + const mine = tasks.filter(t => t.head_sha === sha && t.workflow_id === 'ci.yml' && !/^(ci|acceptance\b)/.test(t.name)); if (!mine.length) return { state: 'none' }; const latest = Math.max(...mine.map(t => t.run_number)); const jobs = mine.filter(t => t.run_number === latest);