fix(release): require beta smoke run url

This commit is contained in:
Vincent Koc 2026-06-16 02:52:31 +02:00
parent 6326395c0a
commit b7d53800d6
No known key found for this signature in database
2 changed files with 14 additions and 103 deletions

View file

@ -264,74 +264,17 @@ export function parseWorkflowRunIdFromOutput(output: string): string | undefined
return /\/actions\/runs\/(\d+)/u.exec(output)?.[1];
}
type WorkflowRunListEntry = {
createdAt?: string;
created_at?: string;
databaseId?: number | string;
id?: number | string;
};
function normalizeRunId(value: unknown): string | undefined {
if (typeof value === "number" && Number.isFinite(value)) {
return String(value);
export function requireWorkflowRunIdFromOutput(output: string, workflow: string): string {
const runId = parseWorkflowRunIdFromOutput(output);
if (!runId) {
throw new Error(
`gh workflow run ${workflow} did not return an Actions run URL; refusing to guess from recent workflow_dispatch runs`,
);
}
if (typeof value === "string" && value.trim()) {
return value.trim();
}
return undefined;
}
export function selectNewestDispatchedRunId(params: {
beforeIds: ReadonlySet<string>;
runs: readonly WorkflowRunListEntry[];
}): string | undefined {
return params.runs
.filter((entry) => {
const id = normalizeRunId(entry.databaseId ?? entry.id);
return id !== undefined && !params.beforeIds.has(id);
})
.toSorted((a, b) =>
(b.createdAt ?? b.created_at ?? "").localeCompare(a.createdAt ?? a.created_at ?? ""),
)
.map((entry) => normalizeRunId(entry.databaseId ?? entry.id))
.find((id): id is string => id !== undefined);
}
function listWorkflowDispatchRuns(repo: string, workflow: string): WorkflowRunListEntry[] {
const encodedWorkflow = encodeURIComponent(workflow);
const response = ghJson(
repo,
`actions/workflows/${encodedWorkflow}/runs?event=workflow_dispatch&per_page=50`,
) as { workflow_runs?: WorkflowRunListEntry[] };
return response.workflow_runs ?? [];
}
async function findDispatchedWorkflowRunId(params: {
beforeIds: ReadonlySet<string>;
repo: string;
workflow: string;
}): Promise<string> {
for (let attempt = 0; attempt < 60; attempt++) {
const runId = selectNewestDispatchedRunId({
beforeIds: params.beforeIds,
runs: listWorkflowDispatchRuns(params.repo, params.workflow),
});
if (runId) {
return runId;
}
await new Promise((resolve) => {
setTimeout(resolve, 5_000);
});
}
throw new Error(`could not find dispatched run for ${params.workflow}`);
return runId;
}
async function dispatchTelegram(options: Options, packageSpec: string): Promise<string> {
const beforeIds = new Set(
listWorkflowDispatchRuns(options.repo, TELEGRAM_BETA_WORKFLOW_FILE)
.map((entry) => normalizeRunId(entry.databaseId ?? entry.id))
.filter((id): id is string => id !== undefined),
);
const output = run(
"gh",
[
@ -351,15 +294,7 @@ async function dispatchTelegram(options: Options, packageSpec: string): Promise<
],
{ capture: true },
);
const runId = parseWorkflowRunIdFromOutput(output);
if (runId) {
return runId;
}
return await findDispatchedWorkflowRunId({
beforeIds,
repo: options.repo,
workflow: TELEGRAM_BETA_WORKFLOW_FILE,
});
return requireWorkflowRunIdFromOutput(output, TELEGRAM_BETA_WORKFLOW_FILE);
}
export async function pollRun(
@ -508,7 +443,7 @@ async function main(): Promise<void> {
}
if (!options.skipParallels) {
runParallels(options.beta, options.model);
runParallels(version, options.model);
}
if (telegramRunId) {

View file

@ -6,8 +6,8 @@ import {
parseWorkflowRunIdFromOutput,
pollRun,
readPositiveInt,
requireWorkflowRunIdFromOutput,
run,
selectNewestDispatchedRunId,
} from "../../scripts/release-beta-smoke.ts";
describe("release-beta-smoke", () => {
@ -54,34 +54,10 @@ describe("release-beta-smoke", () => {
).toBe("1234567890");
});
it("selects the newest workflow_dispatch run not present before dispatch", () => {
const beforeIds = new Set(["100", "101"]);
expect(
selectNewestDispatchedRunId({
beforeIds,
runs: [
{ databaseId: 100, createdAt: "2026-05-04T10:00:00Z" },
{ databaseId: 102, createdAt: "2026-05-04T10:01:00Z" },
{ databaseId: 103, createdAt: "2026-05-04T10:02:00Z" },
],
}),
).toBe("103");
});
it("selects runs returned by the actions workflow runs API", () => {
const beforeIds = new Set(["200"]);
expect(
selectNewestDispatchedRunId({
beforeIds,
runs: [
{ id: 200, created_at: "2026-05-04T10:00:00Z" },
{ id: 201, created_at: "2026-05-04T10:02:00Z" },
{ id: 202, created_at: "2026-05-04T10:01:00Z" },
],
}),
).toBe("201");
it("fails closed when gh dispatch output does not include the run url", () => {
expect(() =>
requireWorkflowRunIdFromOutput("✓ Created workflow_dispatch event", "npm-telegram.yml"),
).toThrow("refusing to guess from recent workflow_dispatch runs");
});
it("replaces stale Telegram proof placeholders", () => {