import { execSync } from "node:child_process"; import { mkdtempSync, rmSync, cpSync, readdirSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; const SITE_BRANCH = process.env.SITE_BRANCH || "site"; if (!process.env.APP_URL) { console.error("APP_URL is required (e.g. https://cuducos.tngl.io/std-pub)"); process.exit(1); } const run = (cmd, opts = {}) => execSync(cmd, { stdio: "inherit", ...opts }); const capture = (cmd, opts = {}) => execSync(cmd, { stdio: ["ignore", "pipe", "inherit"], ...opts }) .toString() .trim(); if (capture("git status --porcelain")) { console.error("Working tree has uncommitted changes. Commit or stash first."); process.exit(1); } let REMOTE; try { const upstream = capture("git rev-parse --abbrev-ref @{upstream}"); REMOTE = upstream.split("/")[0]; } catch { console.error( "Current branch has no upstream. Set one with `git push -u ` first.", ); process.exit(1); } run("npm run build"); const workdir = mkdtempSync(join(tmpdir(), "standard-publication-deploy-")); let worktreeAdded = false; try { const remoteHas = capture(`git ls-remote --heads ${REMOTE} ${SITE_BRANCH}`) !== ""; if (remoteHas) { run(`git fetch ${REMOTE} ${SITE_BRANCH}`); run(`git worktree add --force ${workdir} ${REMOTE}/${SITE_BRANCH}`); run(`git -C ${workdir} checkout -B ${SITE_BRANCH}`); } else { run(`git worktree add --force --orphan -B ${SITE_BRANCH} ${workdir}`); } worktreeAdded = true; for (const entry of readdirSync(workdir)) { if (entry === ".git") continue; rmSync(join(workdir, entry), { recursive: true, force: true }); } for (const entry of readdirSync("public")) { cpSync(join("public", entry), join(workdir, entry), { recursive: true }); } run(`git -C ${workdir} add -A`); const hasChanges = capture(`git -C ${workdir} status --porcelain`) !== ""; const sourceSha = capture("git rev-parse --short HEAD"); if (!hasChanges && remoteHas) { console.log( `No changes to deploy on ${SITE_BRANCH} (source at ${sourceSha}).`, ); } else { run(`git -C ${workdir} commit -m "Deploy ${sourceSha}" --allow-empty`, { env: { ...process.env, GIT_COMMITTER_NAME: process.env.GIT_COMMITTER_NAME || "deploy", GIT_COMMITTER_EMAIL: process.env.GIT_COMMITTER_EMAIL || "deploy@local", }, }); run(`git -C ${workdir} push ${REMOTE} ${SITE_BRANCH}`); } } finally { if (worktreeAdded) { try { run(`git worktree remove --force ${workdir}`); } catch { rmSync(workdir, { recursive: true, force: true }); } } else { rmSync(workdir, { recursive: true, force: true }); } }