75 lines
2.9 KiB
JavaScript
75 lines
2.9 KiB
JavaScript
import { spawnSync } from "node:child_process";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
const steps = [
|
|
{ id: "dev-cleanup-safety", command: npmCommand, args: ["run", "dev-cleanup:test"] },
|
|
{ id: "native-helper-safety", command: npmCommand, args: ["run", "helper:test"] },
|
|
{ id: "lint", command: npmCommand, args: ["run", "lint"] },
|
|
{ id: "tests", command: npmCommand, args: ["test"] },
|
|
{ id: "ocr-eval", command: npmCommand, args: ["run", "eval"] },
|
|
{ id: "assessment-self-test", command: npmCommand, args: ["run", "scan:assessment:test"] },
|
|
{ id: "saved-native-validation", command: npmCommand, args: ["run", "scan:native:validate:saved"] },
|
|
{ id: "package-offline-check", command: npmCommand, args: ["run", "package:offline-check"] },
|
|
{ id: "dependency-audit", command: npmCommand, args: ["audit"] },
|
|
{ id: "production-dependency-audit", command: npmCommand, args: ["audit", "--omit=dev"] },
|
|
{ id: "git-diff-check", command: "git", args: ["diff", "--check"] },
|
|
];
|
|
|
|
const startedAt = new Date();
|
|
const results = [];
|
|
for (const step of steps) {
|
|
const stepStartedAt = Date.now();
|
|
console.log(`\n=== Offline acceptance: ${step.id} ===`);
|
|
const invocation = commandInvocation(step);
|
|
const result = spawnSync(invocation.command, invocation.args, {
|
|
cwd: projectRoot,
|
|
encoding: "utf8",
|
|
stdio: "inherit",
|
|
windowsHide: true,
|
|
});
|
|
results.push({
|
|
id: step.id,
|
|
ok: result.status === 0 && !result.error,
|
|
exitCode: result.status,
|
|
signal: result.signal,
|
|
error: result.error?.message ?? null,
|
|
elapsedMs: Date.now() - stepStartedAt,
|
|
});
|
|
}
|
|
|
|
const outputDir = path.join(projectRoot, "outputs", "offline-acceptance");
|
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
const reportPath = path.join(outputDir, "offline-acceptance-report.json");
|
|
const report = {
|
|
version: "offline-acceptance-v2",
|
|
startedAt: startedAt.toISOString(),
|
|
completedAt: new Date().toISOString(),
|
|
ok: results.every((result) => result.ok),
|
|
projectRoot,
|
|
results,
|
|
};
|
|
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2), "utf8");
|
|
|
|
console.log(`\nOffline acceptance: ${report.ok ? "PASS" : "FAIL"}`);
|
|
for (const result of results) {
|
|
console.log(`${result.ok ? "PASS" : "FAIL"} ${result.id} (${result.elapsedMs} ms)`);
|
|
}
|
|
console.log(`Report: ${reportPath}`);
|
|
if (!report.ok) process.exitCode = 1;
|
|
|
|
function commandInvocation(step) {
|
|
if (process.platform !== "win32" || !step.command.endsWith(".cmd")) return step;
|
|
const tokens = [step.command, ...step.args];
|
|
if (tokens.some((token) => !/^[A-Za-z0-9:._=@/-]+$/.test(token))) {
|
|
throw new Error(`Unsafe Windows command token in offline acceptance step ${step.id}.`);
|
|
}
|
|
return {
|
|
command: process.env.ComSpec || "cmd.exe",
|
|
args: ["/d", "/s", "/c", tokens.join(" ")],
|
|
};
|
|
}
|