87 lines
2.3 KiB
JavaScript
87 lines
2.3 KiB
JavaScript
import { spawnSync } from "node:child_process";
|
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
import path from "node:path";
|
|
|
|
const gateId = process.argv
|
|
.slice(2)
|
|
.find((argument) => /^FE-GATE-\d{3}$/.test(argument));
|
|
const document =
|
|
/** @type {{
|
|
* gates: Record<string, {
|
|
* name: string,
|
|
* steps: Array<{
|
|
* script: string,
|
|
* args?: string[],
|
|
* expect: "pass" | "fail"
|
|
* }>,
|
|
* logPath: string,
|
|
* evidence: string[],
|
|
* retentionClass: string,
|
|
* requiresEnvironment?: string[]
|
|
* }>
|
|
* }} */ (JSON.parse(await readFile("config/ci/gates.json", "utf8")));
|
|
const gate = gateId ? document.gates[gateId] : undefined;
|
|
if (!gateId || !gate) {
|
|
process.stderr.write("Usage: ci:gate -- FE-GATE-001..FE-GATE-026\n");
|
|
process.exit(2);
|
|
}
|
|
|
|
const output = [];
|
|
let passed = true;
|
|
for (const variable of gate.requiresEnvironment ?? []) {
|
|
if (!process.env[variable]) {
|
|
output.push(`missing required environment: ${variable}`);
|
|
passed = false;
|
|
}
|
|
}
|
|
|
|
if (passed) {
|
|
for (const step of gate.steps) {
|
|
const result = spawnSync(
|
|
"corepack",
|
|
["pnpm", step.script, ...(step.args ?? [])],
|
|
{ encoding: "utf8", env: process.env },
|
|
);
|
|
output.push(
|
|
`$ corepack pnpm ${step.script} ${(step.args ?? []).join(" ")}`.trim(),
|
|
result.stdout,
|
|
result.stderr,
|
|
);
|
|
const exitedSuccessfully = result.status === 0;
|
|
const expectationMet =
|
|
step.expect === "pass" ? exitedSuccessfully : !exitedSuccessfully;
|
|
if (!expectationMet) {
|
|
output.push(
|
|
`expectation failed: expected ${step.expect}, exit=${result.status}`,
|
|
);
|
|
passed = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
await mkdir(path.dirname(gate.logPath), { recursive: true });
|
|
await writeFile(gate.logPath, `${output.filter(Boolean).join("\n")}\n`);
|
|
|
|
if (passed) {
|
|
for (const evidencePath of gate.evidence) {
|
|
try {
|
|
await access(evidencePath);
|
|
} catch {
|
|
output.push(`missing evidence: ${evidencePath}`);
|
|
passed = false;
|
|
}
|
|
}
|
|
if (!passed) {
|
|
await writeFile(gate.logPath, `${output.filter(Boolean).join("\n")}\n`);
|
|
}
|
|
}
|
|
|
|
if (!passed) {
|
|
process.stderr.write(`${gateId} ${gate.name}: FAIL\n`);
|
|
process.exit(1);
|
|
}
|
|
process.stdout.write(
|
|
`${gateId} ${gate.name}: PASS (${gate.retentionClass})\n`,
|
|
);
|