Files
workinf_Blender_Wasm/tools/web/check-ci-report.mjs
mes123456 7c16b279ae
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled
Advance M7 workflows and release operations
2026-08-15 17:43:53 -04:00

93 lines
5.9 KiB
JavaScript

import assert from "node:assert/strict";
import crypto from "node:crypto";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
const reportRoot = path.join(repoRoot, "release/ci-reports");
const requested = process.argv.slice(2);
const paths = requested.length > 0
? requested.map((value) => path.isAbsolute(value) ? value : path.resolve(repoRoot, value))
: ["quick", "chromium", "release"].map((lane) => path.join(reportRoot, `${lane}.json`)).filter((file) => fs.existsSync(file));
assert.ok(paths.length > 0, "no CI lane reports were provided or found");
const sha256 = (value) => crypto.createHash("sha256").update(value).digest("hex");
const commonBindings = ["packageJson", "lockfile", "ledger", "engineManifest", "releaseNotes", "knownLimitations", "releaseRecovery", "sbom"];
const releaseBindings = ["binaryArchive", "sourceArchive", "sha256Sums", "rcManifest"];
const expectedRecordIds = {
quick: ["lockfile-install", "typecheck", "lint", "unit", "status", "evidence-schema", "rc-docs"],
chromium: ["lockfile-install", "p0-user-loop", "offline-browser-smoke", "network-interruption", "device-loss", "oom-recovery", "opfs-quota", "malicious-blend", "malicious-archive"],
release: [
"lockfile-install", "full-e2e", "performance-100k-1m", "performance-10m",
"performance-texture-4k", "performance-texture-8k", "performance-simulation",
"performance-long-media", "vdb-native", "vdb-server", "vdb-opfs", "vdb-webgpu",
"vdb-viewport", "vdb-faults", "v1-acceptance", "offline-reproducibility",
"archive-browser", "binary-archive", "source-archive", "deployment-runbook",
"upgrade-runbook", "rollback-runbook", "operations-diagnostics", "operations-rehearsal",
"rc-manifest",
],
};
const reports = [];
for (const reportPath of paths) {
const bytes = fs.readFileSync(reportPath);
const report = JSON.parse(bytes);
assert.equal(report.schemaVersion, 1, `${reportPath} schemaVersion drifted`);
assert.ok(["quick", "chromium", "release"].includes(report.lane), `${reportPath} lane is invalid`);
assert.equal(report.status, "READY", `${reportPath} is not READY`);
assert.match(report.commit, /^[a-f0-9]{40}$/);
assert.ok(!Number.isNaN(Date.parse(report.generatedAt)), `${reportPath} generatedAt is invalid`);
assert.equal(report.retentionDays, report.lane === "quick" ? 7 : report.lane === "chromium" ? 14 : 30);
for (const name of ["os", "node", "npm", "chrome", "blender", "emscripten"]) assert.equal(typeof report.environment[name], "string", `${reportPath} omits environment.${name}`);
for (const name of [...commonBindings, ...releaseBindings]) {
const binding = report.bindings[name];
assert.ok(binding && typeof binding.path === "string", `${reportPath} omits binding ${name}`);
if (binding.sha256 !== null) {
assert.match(binding.sha256, /^[a-f0-9]{64}$/);
const file = path.join(repoRoot, binding.path);
assert.equal(sha256(fs.readFileSync(file)), binding.sha256, `${reportPath} binding drifted: ${name}`);
}
}
if (report.lane === "release") {
for (const name of releaseBindings) assert.match(report.bindings[name].sha256, /^[a-f0-9]{64}$/);
}
else {
for (const name of releaseBindings) assert.equal(report.bindings[name].sha256, null);
}
assert.ok(Array.isArray(report.records) && report.records.length > 0, `${reportPath} has no command records`);
assert.deepEqual(report.records.map((record) => record.id), expectedRecordIds[report.lane], `${reportPath} command coverage drifted`);
for (const record of report.records) {
assert.equal(record.exitCode, 0, `${reportPath} command failed: ${record.id}`);
assert.ok(Number.isSafeInteger(record.durationMs) && record.durationMs >= 0);
assert.match(record.output.sha256, /^[a-f0-9]{64}$/);
const artifact = path.join(repoRoot, record.output.path);
assert.equal(fs.statSync(artifact).size, record.output.bytes, `${record.id} output length drifted`);
assert.equal(sha256(fs.readFileSync(artifact)), record.output.sha256, `${record.id} output hash drifted`);
}
const sidecar = fs.readFileSync(`${reportPath}.sha256`, "utf8").trim().split(/\s+/)[0];
assert.equal(sidecar, sha256(bytes), `${reportPath} sidecar hash drifted`);
reports.push(report);
}
if (reports.length > 1) {
assert.equal(new Set(reports.map((report) => report.commit)).size, 1, "CI lane reports do not bind one commit");
for (const binding of commonBindings) {
assert.equal(new Set(reports.map((report) => report.bindings[binding].sha256)).size, 1, `CI lane ${binding} bindings differ`);
}
}
if (reports.length === 3) {
assert.deepEqual(new Set(reports.map((report) => report.lane)), new Set(["quick", "chromium", "release"]));
const releaseReport = reports.find((report) => report.lane === "release");
const rcManifest = JSON.parse(fs.readFileSync(path.join(repoRoot, releaseReport.bindings.rcManifest.path), "utf8"));
assert.equal(rcManifest.gitCommit, releaseReport.commit, "RC manifest and CI reports bind different commits");
assert.equal(rcManifest.bindings.packageJsonSha256, releaseReport.bindings.packageJson.sha256);
assert.equal(rcManifest.bindings.packageLockSha256, releaseReport.bindings.lockfile.sha256);
assert.equal(rcManifest.bindings.ledgerSha256, releaseReport.bindings.ledger.sha256);
assert.equal(rcManifest.bindings.engineManifestSha256, releaseReport.bindings.engineManifest.sha256);
assert.equal(rcManifest.artifacts.sbom.sha256, releaseReport.bindings.sbom.sha256);
assert.equal(rcManifest.artifacts.binaryArchive.sha256, releaseReport.bindings.binaryArchive.sha256);
assert.equal(rcManifest.artifacts.sourceArchive.sha256, releaseReport.bindings.sourceArchive.sha256);
assert.equal(rcManifest.bindings.sha256SumsSha256, releaseReport.bindings.sha256Sums.sha256);
}
process.stdout.write(`ci-report-ok lanes=${reports.map((report) => report.lane).join(",")} commit=${reports[0].commit}\n`);