From 05d0e227a1c52627bb52a31b5109773d6bcf2cd3 Mon Sep 17 00:00:00 2001 From: CRT Date: Mon, 26 Oct 2026 11:05:08 +0700 Subject: [PATCH] release: the dev-channel job never gates a release; desktop-dev retries the live dev latest.json on 5xx --- tools/desktop-dev.ts | 12 ++++++++---- tools/release-candidate.ts | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/tools/desktop-dev.ts b/tools/desktop-dev.ts index 29f8a30..fd089f6 100644 --- a/tools/desktop-dev.ts +++ b/tools/desktop-dev.ts @@ -62,10 +62,14 @@ export function pruneDev(releases: T[], keep = K } async function liveDev(): Promise { - const r = await fetch(`${DEV_URL}?t=${Date.now()}`, { signal: AbortSignal.timeout(20_000) }).catch(() => null); - if (!r || r.status === 404) return null; - if (!r.ok) throw new Error(`${DEV_URL}: HTTP ${r.status}`); - return ((await r.json()) as { version?: string }).version ?? null; + // a 5xx from the CDN / origin is often a blip: try a few times before giving up + for (let i = 0; ; i++) { + const r = await fetch(`${DEV_URL}?t=${Date.now()}`, { signal: AbortSignal.timeout(20_000) }).catch(() => null); + if (r?.status === 404) return null; + if (r?.ok) return ((await r.json()) as { version?: string }).version ?? null; + if (i >= 4) throw new Error(`${DEV_URL}: ${r ? `HTTP ${r.status}` : 'no answer'} after ${i + 1} tries`); + await new Promise(res => setTimeout(res, 5_000 * (i + 1))); + } } function commitDate(): Date { diff --git a/tools/release-candidate.ts b/tools/release-candidate.ts index bb0ff92..bb4e8b3 100644 --- a/tools/release-candidate.ts +++ b/tools/release-candidate.ts @@ -95,8 +95,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 { // 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)); + // installer builds and the record count; tools/ci-status.ts reports the tests. The dev job (the owner's dev update + // channel) never gates a release either: a hiccup publishing a dev build must not hold back npm. + const mine = tasks.filter(t => t.head_sha === sha && t.workflow_id === 'ci.yml' && !/^(ci|acceptance\b|dev$)/.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);