import { spawnSync } from "node:child_process"; import { mkdir, readFile, readdir, writeFile } from "node:fs/promises"; import path from "node:path"; import { supplyChainDigest } from "./lib/supply-chain.mjs"; /** @param {string} directory @returns {Promise} */ async function filesWithin(directory) { const entries = await readdir(directory, { withFileTypes: true }); const nested = /** @type {string[][]} */ (await Promise.all( entries.map((entry) => { const target = path.join(directory, entry.name); return entry.isDirectory() ? filesWithin(target) : [target]; }), )); return nested.flat().sort(); } async function distDigest() { const rows = await Promise.all( (await filesWithin("dist")).map(async (file) => ({ path: path.relative("dist", file).replaceAll("\\", "/"), bytes: (await readFile(file)).byteLength, content: supplyChainDigest(await readFile(file)), })), ); return supplyChainDigest(rows); } function build(environment = process.env) { return spawnSync("corepack", ["pnpm", "build"], { env: environment, encoding: "utf8", maxBuffer: 16 * 1024 * 1024, }); } const deterministicEnvironment = { ...process.env, SOURCE_DATE_EPOCH: "946684800", }; const firstBuild = build(deterministicEnvironment); const firstDigest = firstBuild.status === 0 ? await distDigest() : "BUILD_FAILED"; const secondBuild = build(deterministicEnvironment); const secondDigest = secondBuild.status === 0 ? await distDigest() : "BUILD_FAILED"; const restoreBuild = build(); const passed = firstBuild.status === 0 && secondBuild.status === 0 && restoreBuild.status === 0 && firstDigest === secondDigest; await mkdir("artifacts/release", { recursive: true }); await writeFile( "artifacts/release/reproducible-build.json", `${JSON.stringify( { schemaVersion: 1, sourceDateEpoch: deterministicEnvironment.SOURCE_DATE_EPOCH, firstDigest, secondDigest, restored: restoreBuild.status === 0, status: passed ? "PASS" : "FAIL", }, null, 2, )}\n`, ); if (!passed) { process.stderr.write( `Reproducible build failed: first=${firstDigest} second=${secondDigest}\n`, ); process.exit(1); } process.stdout.write(`Reproducible build: PASS (${firstDigest})\n`);