This commit is contained in:
Hellings 2026-10-23 09:10:23 -04:00
parent 3cde94c222
commit f18a8fd409
3 changed files with 125 additions and 1 deletions

View file

@ -27,3 +27,15 @@ Preview without network writes.
```sh ```sh
bun scripts/forgejo-modules.ts --dry-run bun scripts/forgejo-modules.ts --dry-run
``` ```
To commit changed integration module directories with generic `chore: update @muddle/<name> integration` messages and push their subtree history, preview the operation first. Unchanged modules are also synced so newly created Forgejo repositories receive their initial branch.
```sh
bun scripts/forgejo-push.ts
```
Push only after review. This requires the same token and creates local commits.
```sh
MUDDLE_FORGEJO_TOKEN=token bun scripts/forgejo-push.ts --push
```

View file

@ -14,7 +14,8 @@
"lint": "bunx eslint . --ignore-pattern node_modules --ignore-pattern ametrine --ignore-pattern .opencode --ignore-pattern dist --ignore-pattern .git --ignore-pattern .cache --ignore-pattern .next --ignore-pattern .turbo --ignore-pattern .vercel --ignore-pattern .vscode --ignore-pattern .idea", "lint": "bunx eslint . --ignore-pattern node_modules --ignore-pattern ametrine --ignore-pattern .opencode --ignore-pattern dist --ignore-pattern .git --ignore-pattern .cache --ignore-pattern .next --ignore-pattern .turbo --ignore-pattern .vercel --ignore-pattern .vscode --ignore-pattern .idea",
"format": "bun run cli.ts fmt .", "format": "bun run cli.ts fmt .",
"muddle": "bun run cli.ts", "muddle": "bun run cli.ts",
"forgejo:modules": "bun scripts/forgejo-modules.ts --dry-run" "forgejo:modules": "bun scripts/forgejo-modules.ts --dry-run",
"forgejo:push": "bun scripts/forgejo-push.ts"
}, },
"bin": { "bin": {
"muddle": "./cli.ts" "muddle": "./cli.ts"

111
scripts/forgejo-push.ts Normal file
View file

@ -0,0 +1,111 @@
#!/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<string, string | undefined> = {},
): Promise<string> {
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<boolean> {
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 });
}