61 lines
3.9 KiB
TypeScript
61 lines
3.9 KiB
TypeScript
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
import { dirname, resolve } from "node:path";
|
|
import { spawnSync } from "node:child_process";
|
|
|
|
import { readTemporalConfig, renderTemporalGitOpsManifest } from "../../src/platform-infra-temporal";
|
|
|
|
function option(name: string): string | null {
|
|
const index = process.argv.indexOf(name);
|
|
return index >= 0 ? process.argv[index + 1] ?? null : null;
|
|
}
|
|
|
|
function required(value: string | null, name: string): string {
|
|
if (value === null || value.length === 0) throw new Error(`${name} is required`);
|
|
return value;
|
|
}
|
|
|
|
function run(command: string, args: string[], cwd: string, allowFailure = false) {
|
|
const result = spawnSync(command, args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
if (!allowFailure && result.status !== 0) throw new Error(`${command} ${args.join(" ")} failed: ${result.stderr.trim()}`);
|
|
return result;
|
|
}
|
|
|
|
const sourceCommit = required(option("--source-commit"), "--source-commit");
|
|
const worktree = resolve(option("--worktree") ?? "/workspace/temporal-gitops");
|
|
const dryRun = process.argv.includes("--dry-run");
|
|
if (!/^[0-9a-f]{40}$/u.test(sourceCommit)) throw new Error("--source-commit must be a full Git commit SHA");
|
|
const temporal = readTemporalConfig();
|
|
if (!temporal.delivery.enabled) throw new Error("config/platform-infra/temporal.yaml#delivery.enabled must be true");
|
|
const target = temporal.targets.find((item) => item.id === temporal.defaults.targetId && item.enabled);
|
|
if (target === undefined) throw new Error("Temporal default delivery target is not enabled");
|
|
const manifest = renderTemporalGitOpsManifest(temporal, target, sourceCommit);
|
|
if (manifest.includes("kind: Secret")) throw new Error("GitOps manifest must not contain Secret payloads");
|
|
if (!manifest.includes("kind: Deployment") || !manifest.includes("kind: Service")) throw new Error("Temporal GitOps renderer did not produce workloads");
|
|
if (!manifest.includes(`unidesk.ai/source-commit: ${sourceCommit}`)) throw new Error("Temporal GitOps renderer did not preserve exact source identity");
|
|
if (dryRun) {
|
|
console.log(JSON.stringify({ ok: true, mutation: false, mode: "dry-run", sourceCommit, branch: temporal.delivery.gitops.branch, manifestPath: temporal.delivery.gitops.manifestPath, objectCount: manifest.split("\n---\n").length, secretValuesPrinted: false, valuesPrinted: false }));
|
|
process.exit(0);
|
|
}
|
|
|
|
rmSync(worktree, { recursive: true, force: true });
|
|
run("git", ["clone", "--no-checkout", temporal.delivery.gitops.readUrl, worktree], process.cwd());
|
|
const fetched = run("git", ["fetch", "origin", temporal.delivery.gitops.branch], worktree, true).status === 0;
|
|
if (fetched) run("git", ["checkout", "-B", temporal.delivery.gitops.branch, `origin/${temporal.delivery.gitops.branch}`], worktree);
|
|
else {
|
|
run("git", ["checkout", "--orphan", temporal.delivery.gitops.branch], worktree);
|
|
run("git", ["rm", "-rf", "."], worktree, true);
|
|
}
|
|
const manifestPath = resolve(worktree, temporal.delivery.gitops.manifestPath);
|
|
if (!manifestPath.startsWith(`${worktree}/`)) throw new Error("delivery.gitops.manifestPath escaped worktree");
|
|
mkdirSync(dirname(manifestPath), { recursive: true });
|
|
writeFileSync(manifestPath, `${manifest.trim()}\n`, "utf8");
|
|
run("git", ["add", temporal.delivery.gitops.manifestPath], worktree);
|
|
run("git", ["config", "user.name", temporal.delivery.gitops.author.name], worktree);
|
|
run("git", ["config", "user.email", temporal.delivery.gitops.author.email], worktree);
|
|
const changed = run("git", ["diff", "--cached", "--quiet"], worktree, true).status !== 0;
|
|
if (changed) {
|
|
run("git", ["commit", "-m", `chore(temporal): publish ${sourceCommit.slice(0, 12)}`], worktree);
|
|
run("git", ["push", temporal.delivery.gitops.writeUrl, `HEAD:${temporal.delivery.gitops.branch}`], worktree);
|
|
}
|
|
console.log(JSON.stringify({ ok: true, mutation: changed, sourceCommit, branch: temporal.delivery.gitops.branch, manifestPath: temporal.delivery.gitops.manifestPath, secretValuesPrinted: false, valuesPrinted: false }));
|