#!/usr/bin/env bun import { chmod, rm, writeFile } from "node:fs/promises"; import { join, resolve } from "node:path"; const root = resolve(import.meta.dir, ".."); const modules = [ "amezing", "analysis", "astro", "database", "latex", "mdx", "optimize", "prettier-plugin", "shadcn", "tailwind", ]; const api = (process.env.MUDDLE_FORGEJO_URL ?? "https://git.crit.rip").replace( /\/$/, "", ); const owner = process.env.MUDDLE_FORGEJO_OWNER ?? "mdl"; const arguments_ = process.argv.slice(2); const push = arguments_.includes("--push"); const requested = arguments_.filter((argument) => !argument.startsWith("--")); const selected = requested.length > 0 ? requested : modules; const token = process.env.MUDDLE_FORGEJO_TOKEN; if (push && !token) { throw new Error( "Set MUDDLE_FORGEJO_TOKEN before using --push.", ); } for (const name of selected) { if (!modules.includes(name)) { throw new Error(`Unknown integration module ${name}`); } } async function run( command: string[], environment: Record = {}, ): Promise { const child = Bun.spawn(command, { cwd: root, stdout: "pipe", stderr: "pipe", env: { ...process.env, ...environment }, }); const [stdout, stderr, status] = await Promise.all([ new Response(child.stdout).text(), new Response(child.stderr).text(), child.exited, ]); if (status !== 0) { throw new Error(`${command.join(" ")} failed\n${stderr || stdout}`); } return stdout.trim(); } async function changed(path: string): Promise { const tracked = await run(["git", "status", "--porcelain", "--", path]); return tracked.length > 0; } let askPass: string | undefined; try { if (push && token) { askPass = join(import.meta.dir, `.forgejo-askpass-${process.pid}`); await writeFile( askPass, `#!/bin/sh\ncase "$1" in *Username*) printf '%s' token ;; *) printf '%s' "$MUDDLE_FORGEJO_TOKEN" ;; esac\n`, ); await chmod(askPass, 0o700); } for (const name of selected) { const prefix = `modules/${name}`; const hasChanges = await changed(prefix); const message = `chore: update @muddle/${name} integration`; if (!push) { console.log( `would ${hasChanges ? `commit with "${message}" and ` : ""}sync @muddle/${name} to ${api}/${owner}/${name}.git`, ); continue; } if (hasChanges) { await run(["git", "add", "--", prefix]); await run(["git", "commit", "-m", message, "--", prefix]); } const branch = await run([ "git", "subtree", "split", "--prefix", prefix, ]); await run([ "git", "push", `${api}/${owner}/${name}.git`, `${branch}:refs/heads/main`, ], { GIT_ASKPASS: askPass, GIT_TERMINAL_PROMPT: "0", }); console.log(`pushed @muddle/${name}`); } } finally { if (askPass) await rm(askPass, { force: true }); }