Skip to content

Commit 286d0b9

Browse files
authored
fix(ci): bound hosted gate run pagination (#100332)
1 parent 535ad8a commit 286d0b9

2 files changed

Lines changed: 46 additions & 11 deletions

File tree

scripts/verify-pr-hosted-gates.mjs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ const ARTIFACT_FALLBACK_REQUIRED_WORKFLOWS = [
1717
"Blacksmith ARM Testbox",
1818
"Workflow Sanity",
1919
];
20+
const WORKFLOW_RUNS_PAGE_SIZE = 100;
21+
const MAX_WORKFLOW_RUN_SEARCH_RESULTS = 1_000;
2022

2123
function readOptionValue(argv, index, optionName) {
2224
const value = argv[index + 1];
@@ -168,8 +170,19 @@ function stripAnsi(raw) {
168170
return raw.replace(new RegExp(`${escape}\\[[0-?]*[ -/]*[@-~]`, "gu"), "");
169171
}
170172

171-
export function parseWorkflowRunPages(raw) {
172-
return JSON.parse(stripAnsi(raw)).flatMap((page) => page.workflow_runs ?? []);
173+
export function parseWorkflowRunPage(raw) {
174+
const page = JSON.parse(stripAnsi(raw));
175+
return {
176+
totalCount: page.total_count ?? 0,
177+
workflowRuns: page.workflow_runs ?? [],
178+
};
179+
}
180+
181+
export function workflowRunPageCount(totalCount) {
182+
return Math.min(
183+
Math.ceil(totalCount / WORKFLOW_RUNS_PAGE_SIZE),
184+
MAX_WORKFLOW_RUN_SEARCH_RESULTS / WORKFLOW_RUNS_PAGE_SIZE,
185+
);
173186
}
174187

175188
export function collectHostedGateEvidence({ sha, workflowRuns, changelogOnly = false }) {
@@ -220,11 +233,24 @@ export function collectHostedGateEvidence({ sha, workflowRuns, changelogOnly = f
220233
}
221234

222235
function loadWorkflowRuns(repo, sha) {
223-
const raw = execPlainGh(
224-
["api", `repos/${repo}/actions/runs?head_sha=${sha}&per_page=100`, "--paginate", "--slurp"],
225-
{ encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] },
226-
);
227-
return parseWorkflowRunPages(raw);
236+
const loadPage = (page) =>
237+
parseWorkflowRunPage(
238+
execPlainGh(
239+
[
240+
"api",
241+
`repos/${repo}/actions/runs?head_sha=${sha}&per_page=${WORKFLOW_RUNS_PAGE_SIZE}&page=${page}`,
242+
],
243+
{ encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] },
244+
),
245+
);
246+
247+
// Keep every request pinned to the head SHA and bound it to GitHub's documented search window.
248+
const firstPage = loadPage(1);
249+
const workflowRuns = [...firstPage.workflowRuns];
250+
for (let page = 2; page <= workflowRunPageCount(firstPage.totalCount); page += 1) {
251+
workflowRuns.push(...loadPage(page).workflowRuns);
252+
}
253+
return workflowRuns;
228254
}
229255

230256
export function main(argv = process.argv.slice(2)) {

test/scripts/verify-pr-hosted-gates.test.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import { describe, expect, it } from "vitest";
22
import {
33
collectHostedGateEvidence,
44
parseArgs,
5-
parseWorkflowRunPages,
5+
parseWorkflowRunPage,
66
SCHEDULED_HOSTED_WORKFLOWS,
7+
workflowRunPageCount,
78
} from "../../scripts/verify-pr-hosted-gates.mjs";
89

910
const sha = "773ffd87a1e1e34451ad6e38fda37380c2569a50";
@@ -394,9 +395,17 @@ describe("verify-pr-hosted-gates", () => {
394395
}
395396
});
396397

397-
it("accepts JSON emitted through a colorizing GitHub CLI shim", () => {
398+
it("accepts one workflow-runs page emitted through a colorizing GitHub CLI shim", () => {
398399
expect(
399-
parseWorkflowRunPages('\u001B[1;37m[{"workflow_runs":[{"id":1,"name":"CI"}]}]\u001B[0m'),
400-
).toEqual([{ id: 1, name: "CI" }]);
400+
parseWorkflowRunPage(
401+
'\u001B[1;37m{"total_count":101,"workflow_runs":[{"id":1,"name":"CI"}]}\u001B[0m',
402+
),
403+
).toEqual({ totalCount: 101, workflowRuns: [{ id: 1, name: "CI" }] });
404+
});
405+
406+
it("bounds workflow-run pagination to GitHub's search result limit", () => {
407+
expect(workflowRunPageCount(0)).toBe(0);
408+
expect(workflowRunPageCount(101)).toBe(2);
409+
expect(workflowRunPageCount(10_000)).toBe(10);
401410
});
402411
});

0 commit comments

Comments
 (0)