Files
workinf_Blender_Wasm/tools/web/run-v1-acceptance.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

104 lines
3.8 KiB
JavaScript

import fs from "node:fs";
import { spawnSync } from "node:child_process";
import {
evidencePath,
expectedEvidenceIdentity,
root,
sha256,
} from "./v1-acceptance-lib.mjs";
const { ledgerSha256, packageSha256, plan, toolSourceSha256 } = expectedEvidenceIdentity();
const basePort = Number.parseInt(process.env.WEB_ACCEPTANCE_PORT ?? "5400", 10);
if (!Number.isInteger(basePort) || basePort < 1024 || basePort > 65000 - plan.entries.length) {
throw new Error(`WEB_ACCEPTANCE_PORT must leave ${plan.entries.length} sequential ports available`);
}
function capture(command, args) {
const result = spawnSync(command, args, {
cwd: root,
encoding: "utf8",
env: { ...process.env, FORCE_COLOR: "0", NO_COLOR: "1" },
maxBuffer: 16 * 1024 * 1024,
});
return `${result.stdout ?? ""}\n${result.stderr ?? ""}`.trim();
}
const blenderBin = process.env.BLENDER_BIN ?? "build_blender_5.2.0/bin/blender";
const blenderArchiveSha256 = process.env.BLENDER_ARCHIVE_SHA256 ?? "";
if (blenderArchiveSha256 && !/^[a-f0-9]{64}$/.test(blenderArchiveSha256)) {
throw new Error("BLENDER_ARCHIVE_SHA256 must be a lowercase SHA-256");
}
const environment = {
node: process.version,
npm: capture("npm", ["--version"]).split(/\r?\n/)[0],
chromium: capture(process.env.CHROME_PATH ?? "google-chrome", ["--version"]).split(/\r?\n/)[0],
blenderBin: process.env.BLENDER_BIN ? "BLENDER_BIN" : blenderBin,
blenderExecutableSha256: fs.existsSync(blenderBin) ? sha256(fs.readFileSync(blenderBin)) : "unavailable",
blenderArchiveSha256: blenderArchiveSha256 || "unavailable",
blender: capture(blenderBin, [
"--background",
"--factory-startup",
"--python-expr",
"import bpy; print('ACCEPTANCE_BLENDER=' + bpy.app.version_string + ';USD=' + str(bpy.app.build_options.usd))",
]).split(/\r?\n/).filter((line) => line.includes("ACCEPTANCE_BLENDER=")).at(-1) ?? "unavailable",
};
const results = [];
for (const [index, entry] of plan.entries.entries()) {
const started = Date.now();
process.stdout.write(`[${index + 1}/${plan.entries.length}] ${entry.token}\n`);
const result = spawnSync("npm", ["--prefix", "web", "run", entry.script, ...entry.args], {
cwd: root,
encoding: "utf8",
env: {
...process.env,
FORCE_COLOR: "0",
NO_COLOR: "1",
WEB_TEST_PORT: String(basePort + index),
},
maxBuffer: 32 * 1024 * 1024,
});
const output = `${result.stdout ?? ""}\n${result.stderr ?? ""}`.trim();
const storedOutput = output.slice(-4096) || `${entry.token} produced no output`;
const exitCode = result.status ?? 1;
results.push({
token: entry.token,
familyIds: entry.familyIds,
command: entry.command,
exitCode,
durationMs: Date.now() - started,
outputSha256: sha256(storedOutput),
output: storedOutput,
});
process.stdout.write(` exit=${exitCode} durationMs=${results.at(-1).durationMs}\n`);
}
const manifest = {
schemaVersion: 1,
source: "docs/status/parity-ledger.json",
sourceSha256: ledgerSha256,
package: "web/package.json",
packageSha256,
toolSourceSha256,
generatedAt: new Date().toISOString(),
environment,
summary: {
families: plan.familyCount,
declarations: plan.declarationCount,
unique: plan.uniqueCount,
passed: results.filter((result) => result.exitCode === 0).length,
failed: results.filter((result) => result.exitCode !== 0).length,
},
results,
};
fs.writeFileSync(evidencePath, `${JSON.stringify(manifest, null, 2)}\n`);
const failed = results.filter((result) => result.exitCode !== 0);
process.stdout.write(
`v1-acceptance-run-complete passed=${manifest.summary.passed} failed=${manifest.summary.failed} evidence=${evidencePath}\n`,
);
if (failed.length > 0) {
process.stderr.write(`failed acceptance: ${failed.map((result) => result.token).join(", ")}\n`);
process.exitCode = 1;
}