Files
AgentCompany/scripts/release/lib/snapshot.mjs
T

78 lines
2.2 KiB
JavaScript

import { mkdtemp } from "node:fs/promises";
import os from "node:os";
import { join } from "node:path";
export function createSnapshotHelpers(run, getGitHubHttpAuthHeader) {
async function createSnapshotBranch({
repo,
branchName,
rootDir,
syncExcludes,
commitMessage,
afterRsync,
}) {
const tempDir = await mkdtemp(join(os.tmpdir(), "agentcompany-release-"));
const auth = await getGitHubHttpAuthHeader();
await run("git", [
"-c",
`http.https://github.com/.extraheader=AUTHORIZATION: basic ${auth}`,
"fetch",
`https://github.com/${repo.nameWithOwner}.git`,
repo.defaultBranch,
]);
await run("git", ["worktree", "add", "--detach", tempDir, "FETCH_HEAD"]);
await run("git", ["-C", tempDir, "checkout", "-b", branchName]);
const rsyncArgs = ["-a", "--delete"];
for (const pattern of syncExcludes) {
rsyncArgs.push("--exclude", pattern);
}
rsyncArgs.push(`${rootDir}/`, `${tempDir}/`);
await run("rsync", rsyncArgs);
await run("git", ["-C", tempDir, "add", "-A"]);
if (afterRsync) {
await afterRsync(tempDir);
}
const diffStatus = await run("git", ["-C", tempDir, "diff", "--cached", "--quiet"], { capture: true })
.then(() => false)
.catch(() => true);
if (!diffStatus) {
throw new Error("Snapshot branch has no staged changes after syncing the workspace.");
}
await run("git", ["-C", tempDir, "commit", "-m", commitMessage]);
await run(
"git",
[
"-C",
tempDir,
"-c",
`http.https://github.com/.extraheader=AUTHORIZATION: basic ${auth}`,
"push",
`https://github.com/${repo.nameWithOwner}.git`,
branchName,
],
);
return tempDir;
}
async function cleanupRemoteBranch(repo, branchName) {
await run("gh", ["api", "-X", "DELETE", `repos/${repo.nameWithOwner}/git/refs/heads/${branchName}`]);
}
async function cleanupLocalWorktree(tempDir) {
await run("git", ["worktree", "remove", "--force", tempDir]);
await run("git", ["worktree", "prune"]);
}
return {
createSnapshotBranch,
cleanupRemoteBranch,
cleanupLocalWorktree,
};
}