mirror of
https://github.com/morluto/rea.git
synced 2026-10-19 04:19:54 -05:00
Scope main pushes from a successful ancestor so canceled runs cannot hide changes. Keep the complete portable suite in fast feedback and move coverage plus Intel macOS to hourly, manual, explicit-full, and release qualification. Let qualification finish independently of superseded feedback. Bind publication to full qualification at its exact revision and publish the verified tarball after checking workflow identity, version, and SHA-256. Keep trusted cache writers and reject incomplete merged test inventories. Validation: 151 focused CI tests; typecheck/lint; actionlint 1.7.7; knip; all 1044 files discovered; bounded blob/merge smoke; macOS package verifier with retention and cleanup; npm pack dry run. Native Linux/ARM/Windows and remote workflow execution remain CI verification.
77 lines
2.0 KiB
JavaScript
77 lines
2.0 KiB
JavaScript
import { execFileSync } from "node:child_process";
|
|
import { appendFileSync } from "node:fs";
|
|
|
|
const repository = process.env.CI_REPOSITORY;
|
|
const branch = process.env.CI_DEFAULT_BRANCH;
|
|
const head = process.env.HEAD_SHA;
|
|
const shaPattern = /^[0-9a-f]{40}$/i;
|
|
|
|
function ancestor(base) {
|
|
try {
|
|
execFileSync("git", ["merge-base", "--is-ancestor", base, head], {
|
|
stdio: "ignore",
|
|
});
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function write(base, reason) {
|
|
const output = { base, reason };
|
|
if (process.env.GITHUB_OUTPUT) {
|
|
appendFileSync(
|
|
process.env.GITHUB_OUTPUT,
|
|
`base=${base}\nreason=${reason.replace(/[\r\n]/g, " ")}\n`,
|
|
);
|
|
}
|
|
console.log(JSON.stringify(output));
|
|
}
|
|
|
|
if (!repository || !branch || !head || !shaPattern.test(head)) {
|
|
write("", "Repository, default branch, or checked-out head is invalid");
|
|
} else {
|
|
try {
|
|
const response = execFileSync(
|
|
"gh",
|
|
[
|
|
"api",
|
|
"--method",
|
|
"GET",
|
|
`repos/${repository}/actions/workflows/ci.yml/runs`,
|
|
"-f",
|
|
`branch=${branch}`,
|
|
"-f",
|
|
"event=push",
|
|
"-f",
|
|
"status=success",
|
|
"-F",
|
|
"per_page=100",
|
|
],
|
|
{ encoding: "utf8", timeout: 15_000, maxBuffer: 4 * 1024 * 1024 },
|
|
);
|
|
const runs = JSON.parse(response).workflow_runs;
|
|
if (!Array.isArray(runs))
|
|
throw new Error("GitHub returned no workflow run list");
|
|
const base = runs.find(
|
|
(run) =>
|
|
run?.event === "push" &&
|
|
run?.conclusion === "success" &&
|
|
run?.head_branch === branch &&
|
|
run?.head_repository?.full_name === repository &&
|
|
typeof run?.head_sha === "string" &&
|
|
shaPattern.test(run.head_sha) &&
|
|
run.head_sha.toLowerCase() !== head.toLowerCase() &&
|
|
ancestor(run.head_sha),
|
|
)?.head_sha;
|
|
if (base) write(base, "");
|
|
else
|
|
write(
|
|
"",
|
|
"No trusted successful CI push baseline is an ancestor of this head",
|
|
);
|
|
} catch {
|
|
write("", "Could not read a successful CI push baseline from GitHub");
|
|
}
|
|
}
|