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