75 lines
5.0 KiB
JavaScript
75 lines
5.0 KiB
JavaScript
import crypto from "node:crypto";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { execFileSync } from "node:child_process";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
const abs = (file) => path.join(root, file);
|
|
const json = (file) => JSON.parse(fs.readFileSync(abs(file), "utf8"));
|
|
const write = (file, value) => fs.writeFileSync(abs(file), `${JSON.stringify(value, null, 2)}\n`);
|
|
const sha = (file) => crypto.createHash("sha256").update(fs.readFileSync(abs(file))).digest("hex");
|
|
const argIndex = process.argv.indexOf("--task");
|
|
const task = argIndex >= 0 ? process.argv[argIndex + 1] : null;
|
|
if (!task) throw new Error("usage: node tools/web/finalize-wbv2-module-batch.mjs --task <task-id>");
|
|
const fullInventoryAudit = process.argv.includes("--full-inventory") || process.env.WBV2_FULL_SOURCE_AUDIT === "1";
|
|
const manifestPath = `tests/golden/${task}/manifest.json`;
|
|
const manifest = json(manifestPath);
|
|
const receiptPath = manifest.artifacts.moduleReceipt.path;
|
|
const statusPath = manifest.artifacts.status.path;
|
|
const taskPlan = json(manifest.artifacts.plan.path);
|
|
const taskRecord = taskPlan.tasks.find((candidate) => candidate.id === task);
|
|
const bindingDelta = taskRecord?.module?.coverageBindings?.length ?? 0;
|
|
execFileSync(process.execPath, [abs("tools/web/bind-wbv2-module-coverage.mjs"), "--task", task], { cwd: root, stdio: "inherit" });
|
|
const inventory = json("tests/golden/WBV2/dynamic-inventory.json");
|
|
const verifiedUnits = inventory.coverage.verifiedUnits;
|
|
const unverifiedUnits = inventory.coverage.unverifiedUnits;
|
|
const receipt = json(receiptPath);
|
|
if (receipt.inventory?.dynamic) {
|
|
receipt.inventory.dynamic.verifiedUnits = verifiedUnits;
|
|
receipt.inventory.dynamic.unverifiedUnits = unverifiedUnits;
|
|
receipt.inventory.dynamic.sha256 = sha("tests/golden/WBV2/dynamic-inventory.json");
|
|
}
|
|
write(receiptPath, receipt);
|
|
let status = fs.readFileSync(abs(statusPath), "utf8");
|
|
status = status.replace(/verified `\d+`/g, `verified \`${verifiedUnits}\``).replace(/unverified `\d+`/g, `unverified \`${unverifiedUnits}\``);
|
|
if (!status.includes("this-segment binding delta:")) status = status.replace(/(dynamic source inventory:[^\n]*)/, `$1; this-segment binding delta: \`${bindingDelta}\``);
|
|
fs.writeFileSync(abs(statusPath), status);
|
|
for (const artifact of Object.values(manifest.artifacts ?? {})) {
|
|
if (artifact?.path && fs.existsSync(abs(artifact.path))) artifact.sha256 = sha(artifact.path);
|
|
}
|
|
manifest.assertions.dynamicVerifiedUnits = verifiedUnits;
|
|
manifest.assertions.dynamicUnverifiedUnits = unverifiedUnits;
|
|
write(manifestPath, manifest);
|
|
if (fullInventoryAudit) {
|
|
execFileSync(process.execPath, [abs("tools/web/generate-source-dynamic-inventory.mjs"), "--output", abs("tests/golden/WBV2/dynamic-inventory.json")], { cwd: root, stdio: "inherit" });
|
|
}
|
|
const inventoryPath = "tests/golden/WBV2/dynamic-inventory.json";
|
|
const checkReportPath = "tests/golden/WBV2/dynamic-inventory-check-report.json";
|
|
const inventoryManifestPath = "tests/golden/WBV2/dynamic-inventory-manifest.json";
|
|
const coverageManifestPath = "tests/golden/WBV2/dynamic-coverage-manifest.json";
|
|
const bindingsPath = "tests/golden/WBV2/dynamic-coverage-bindings.json";
|
|
const auditPath = "tests/golden/WBV2/dynamic-coverage-audit.json";
|
|
// The checker validates manifest hashes before it rewrites its compact report.
|
|
// Bind the newly generated inventory and the previous report first, then run
|
|
// the checker once, and finally bind the report it produced.
|
|
const inventoryManifest = json(inventoryManifestPath);
|
|
inventoryManifest.artifacts.checker.sha256 = sha("tools/web/check-source-dynamic-inventory.mjs");
|
|
inventoryManifest.artifacts.inventory.sha256 = sha(inventoryPath);
|
|
inventoryManifest.artifacts.report.sha256 = sha(checkReportPath);
|
|
write(inventoryManifestPath, inventoryManifest);
|
|
const inventoryCheckArgs = fullInventoryAudit ? [] : ["--task", task];
|
|
execFileSync(process.execPath, [abs("tools/web/check-source-dynamic-inventory.mjs"), ...inventoryCheckArgs], { cwd: root, stdio: "inherit" });
|
|
const refreshedInventoryManifest = json(inventoryManifestPath);
|
|
refreshedInventoryManifest.artifacts.inventory.sha256 = sha(inventoryPath);
|
|
refreshedInventoryManifest.artifacts.report.sha256 = sha(checkReportPath);
|
|
write(inventoryManifestPath, refreshedInventoryManifest);
|
|
const coverageManifest = json(coverageManifestPath);
|
|
coverageManifest.artifacts.inventory.sha256 = sha(inventoryPath);
|
|
coverageManifest.artifacts.inventoryManifest.sha256 = sha(inventoryManifestPath);
|
|
coverageManifest.artifacts.bindings.sha256 = sha(bindingsPath);
|
|
coverageManifest.artifacts.report.sha256 = sha(auditPath);
|
|
coverageManifest.coverage = { ...coverageManifest.coverage, unitCount: inventory.summary.unitCount, verifiedUnits, unverifiedUnits, sourceTreeSha256: inventory.authority.sourceTreeSha256 };
|
|
write(coverageManifestPath, coverageManifest);
|
|
process.stdout.write(`wbv2-module-batch-finalized task=${task} verified=${verifiedUnits} unverified=${unverifiedUnits} inventoryAudit=${fullInventoryAudit ? "full" : "batch"}\n`);
|