96 lines
3.2 KiB
JavaScript
Executable File
96 lines
3.2 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
import { createHash } from "node:crypto";
|
|
import { cp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
import { existsSync } from "node:fs";
|
|
import { dirname, join } from "node:path";
|
|
import { spawnSync } from "node:child_process";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const repoRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
const packageJson = JSON.parse(await readFile(join(repoRoot, "package.json"), "utf8"));
|
|
const version = packageJson.version;
|
|
const distDir = parseOutputDir();
|
|
const stageRoot = join(distDir, "stage");
|
|
const appName = `kova-${version}`;
|
|
const appDir = join(stageRoot, appName);
|
|
const archivePath = join(distDir, `${appName}.tar.gz`);
|
|
const checksumPath = `${archivePath}.sha256`;
|
|
const latestArchivePath = join(distDir, "kova.tar.gz");
|
|
const latestChecksumPath = `${latestArchivePath}.sha256`;
|
|
|
|
await rm(stageRoot, { recursive: true, force: true });
|
|
await mkdir(appDir, { recursive: true });
|
|
|
|
for (const path of ["bin", "src", "scenarios", "states", "profiles", "surfaces", "process-roles", "metrics", "support", "fixtures", ".agents/skills/kova-operator", ".agents/skills/ocm-operator"]) {
|
|
await copyRequired(path);
|
|
}
|
|
|
|
for (const path of ["README.md", "LICENSE", "package.json"]) {
|
|
await copyRequired(path);
|
|
}
|
|
|
|
await mkdir(join(appDir, "docs"), { recursive: true });
|
|
for (const path of ["docs/AGENT_USAGE.md", "docs/DIAGNOSTICS_CONTRACT.md", "docs/OCM_OPERATOR_INTEGRATION.md", "docs/REPORT_SCHEMA.md"]) {
|
|
await copyRequired(path);
|
|
}
|
|
|
|
await rm(archivePath, { force: true });
|
|
const tar = spawnSync("tar", ["-czf", archivePath, "-C", stageRoot, appName], {
|
|
cwd: repoRoot,
|
|
encoding: "utf8",
|
|
stdio: ["ignore", "pipe", "pipe"]
|
|
});
|
|
|
|
if (tar.status !== 0) {
|
|
throw new Error(tar.stderr || tar.stdout || "tar failed");
|
|
}
|
|
|
|
const archive = await readFile(archivePath);
|
|
const sha256 = createHash("sha256").update(archive).digest("hex");
|
|
await writeFile(checksumPath, `${sha256} ${appName}.tar.gz\n`, "utf8");
|
|
await cp(archivePath, latestArchivePath);
|
|
await writeFile(latestChecksumPath, `${sha256} kova.tar.gz\n`, "utf8");
|
|
await rm(stageRoot, { recursive: true, force: true });
|
|
|
|
console.log(JSON.stringify({
|
|
schemaVersion: "kova.releaseArtifact.v1",
|
|
version,
|
|
archivePath,
|
|
checksumPath,
|
|
latestArchivePath,
|
|
latestChecksumPath,
|
|
sha256,
|
|
bytes: archive.length
|
|
}, null, 2));
|
|
|
|
async function copyRequired(path) {
|
|
const source = join(repoRoot, path);
|
|
if (!existsSync(source)) {
|
|
throw new Error(`release input missing: ${path}`);
|
|
}
|
|
const destination = join(appDir, path);
|
|
await mkdir(dirname(destination), { recursive: true });
|
|
await cp(source, destination, { recursive: true });
|
|
}
|
|
|
|
function parseOutputDir() {
|
|
let outputDir = "dist";
|
|
const args = process.argv.slice(2);
|
|
for (let index = 0; index < args.length; index += 1) {
|
|
const arg = args[index];
|
|
if (arg === "--output-dir") {
|
|
index += 1;
|
|
if (!args[index]) {
|
|
throw new Error("--output-dir requires a value");
|
|
}
|
|
outputDir = args[index];
|
|
} else if (arg === "--help" || arg === "-h") {
|
|
console.log("Usage: scripts/build-release.mjs [--output-dir <dir>]");
|
|
process.exit(0);
|
|
} else {
|
|
throw new Error(`unknown argument: ${arg}`);
|
|
}
|
|
}
|
|
return join(repoRoot, outputDir);
|
|
}
|