Files
pikasTech-unidesk/scripts/native/cicd/publish-platform-infra-temporal-gitops.ts
T
2026-07-21 15:59:55 +02:00

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 }));