feat: 기능 추가 과정중
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
import { assertCiBuildEnvironment } from "./lib/build-environment.ts";
|
||||
import { supplyChainDigest } from "./lib/supply-chain.ts";
|
||||
|
||||
assertCiBuildEnvironment(process.env);
|
||||
|
||||
async function filesWithin(directory: string): Promise<string[]> {
|
||||
const entries = await readdir(directory, { withFileTypes: true });
|
||||
const nested: 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(): Promise<string> {
|
||||
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: NodeJS.ProcessEnv = 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,
|
||||
buildId: process.env.VITE_BUILD_ID ?? "local-build",
|
||||
commitSha: process.env.VITE_COMMIT_SHA ?? "local",
|
||||
releaseId: process.env.RELEASE_ID ?? "local-release",
|
||||
runnerImage:
|
||||
process.env.CI_RUNNER_IMAGE ?? `${process.platform}-${process.arch}`,
|
||||
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`);
|
||||
Reference in New Issue
Block a user