feat: GitClient shell-out with temp clone + integration test

Co-Authored-By: Claude
This commit is contained in:
2026-06-19 02:00:21 +00:00
parent d41cbc467e
commit 32263df062
2 changed files with 127 additions and 0 deletions

52
src/git.test.ts Normal file
View File

@@ -0,0 +1,52 @@
import { afterAll, beforeAll, expect, test } from "vitest";
import { execFileSync } from "node:child_process";
import { mkdtempSync, mkdirSync, rmSync, readFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { ChildProcessGitClient } from "./git";
let root: string, bare: string, base: string;
beforeAll(() => {
root = mkdtempSync(join(tmpdir(), "jp-git-"));
bare = join(root, "remote.git");
base = join(root, "work");
mkdirSync(bare); mkdirSync(base);
execFileSync("git", ["init", "--bare", "-b", "main", bare]);
// seed an initial commit so the branch exists
const seed = join(root, "seed");
mkdirSync(seed);
execFileSync("git", ["init", "-b", "main", seed]);
execFileSync("git", ["-C", seed, "config", "user.email", "t@t"]);
execFileSync("git", ["-C", seed, "config", "user.name", "t"]);
execFileSync("git", ["-C", seed, "commit", "--allow-empty", "-m", "init"]);
execFileSync("git", ["-C", seed, "remote", "add", "origin", bare]);
execFileSync("git", ["-C", seed, "push", "origin", "main"]);
});
afterAll(() => rmSync(root, { recursive: true, force: true }));
test("clone, write, commit, push lands files in the remote", async () => {
const client = new ChildProcessGitClient({ baseDir: base });
await client.syncClone({ url: bare, branch: "main" });
await client.writeFiles([
{ repoPath: "_posts/2026-06-19-hi.md", data: "---\nlayout: post\n---\n\nHi\n" },
{ repoPath: "assets/img/hi.png", data: Buffer.from([1, 2, 3]) },
]);
await client.commitAndPush({ message: "Publish: Hi", branch: "main", authorName: "t", authorEmail: "t@t" });
const verify = join(root, "verify");
execFileSync("git", ["clone", bare, verify]);
expect(readFileSync(join(verify, "_posts/2026-06-19-hi.md"), "utf8")).toContain("Hi");
expect(Array.from(readFileSync(join(verify, "assets/img/hi.png")))).toEqual([1, 2, 3]);
});
test("second sync resets cleanly (fetch+reset path)", async () => {
const client = new ChildProcessGitClient({ baseDir: base });
await client.syncClone({ url: bare, branch: "main" });
await client.writeFiles([{ repoPath: "_posts/second.md", data: "x" }]);
await client.commitAndPush({ message: "second", branch: "main" });
const verify = join(root, "verify2");
execFileSync("git", ["clone", bare, verify]);
expect(readFileSync(join(verify, "_posts/second.md"), "utf8")).toBe("x");
});