patch.moi/apps/patch/test/patch-workspace.test.ts
matamune 5639829747
All checks were successful
check / check (push) Successful in 39s
Add local patch workspace commands
2026-05-18 18:58:36 +00:00

158 lines
4.4 KiB
TypeScript

import { mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { describe, expect, test } from "bun:test";
import { runCli } from "../src/cli";
const workspaceRoot = join(import.meta.dir, "../../..");
describe("patch workspace CLI", () => {
test("captures a feature branch as patch/* and rebuilds main from upstream", async () => {
const repo = await createPatchRepo();
const beforeDoctor = await invoke([
"patch",
"doctor",
"--repo",
repo,
"--json",
]);
expect(beforeDoctor.code).toBe(1);
expect(JSON.parse(beforeDoctor.stdout)).toMatchObject({
mainExists: true,
upstreamExists: true,
patchBranches: [],
ready: false,
});
const capture = await invoke([
"patch",
"capture",
"patch/010-feature",
"--repo",
repo,
"--from",
"feature",
"--base",
"main",
"--message",
"patch: feature",
"--json",
]);
expect(capture.code).toBe(0);
expect(JSON.parse(capture.stdout)).toMatchObject({
status: "changed",
patchBranch: "patch/010-feature",
from: "feature",
base: "main",
message: "patch: feature",
});
expect((await git(repo, ["rev-list", "--count", "main..patch/010-feature"])).stdout.trim()).toBe("1");
const list = await invoke([
"patch",
"list",
"--repo",
repo,
"--json",
]);
expect(list.code).toBe(0);
expect(JSON.parse(list.stdout).patchBranches).toMatchObject([
{ name: "patch/010-feature", subject: "patch: feature" },
]);
await git(repo, ["switch", "upstream"]);
await writeFile(join(repo, "upstream.txt"), "base\nupstream movement\n", "utf8");
await git(repo, ["add", "upstream.txt"]);
await git(repo, ["commit", "-m", "upstream movement"]);
const rebuild = await invoke([
"patch",
"rebuild",
"--repo",
repo,
"--base",
"upstream",
"--to",
"main",
"--json",
]);
expect(rebuild.code).toBe(0);
expect(JSON.parse(rebuild.stdout)).toMatchObject({
status: "changed",
targetBranch: "main",
applied: [{ name: "patch/010-feature" }],
});
expect((await git(repo, ["branch", "--show-current"])).stdout.trim()).toBe("main");
expect(await readFile(join(repo, "upstream.txt"), "utf8")).toBe("base\nupstream movement\n");
expect(await readFile(join(repo, "feature.txt"), "utf8")).toBe("feature\n");
const afterDoctor = await invoke([
"patch",
"doctor",
"--repo",
repo,
"--json",
]);
expect(afterDoctor.code).toBe(0);
expect(JSON.parse(afterDoctor.stdout)).toMatchObject({
clean: true,
ready: true,
patchBranches: [{ name: "patch/010-feature" }],
});
});
});
async function createPatchRepo(): Promise<string> {
const repo = await mkdtemp(join(tmpdir(), "patch-workspace-"));
await mkdir(repo, { recursive: true });
await git(repo, ["init", "-b", "upstream"]);
await git(repo, ["config", "user.name", "Patch Moi Test"]);
await git(repo, ["config", "user.email", "patch@example.test"]);
await writeFile(join(repo, "upstream.txt"), "base\n", "utf8");
await git(repo, ["add", "upstream.txt"]);
await git(repo, ["commit", "-m", "upstream base"]);
await git(repo, ["switch", "-c", "main"]);
await git(repo, ["switch", "-c", "feature"]);
await writeFile(join(repo, "feature.txt"), "feature\n", "utf8");
await git(repo, ["add", "feature.txt"]);
await git(repo, ["commit", "-m", "feature work"]);
await git(repo, ["switch", "main"]);
return repo;
}
async function invoke(
args: string[],
): Promise<{ code: number; stdout: string; stderr: string }> {
let stdout = "";
let stderr = "";
const code = await runCli(args, {
cwd: workspaceRoot,
env: {},
stdout: (text) => {
stdout += text;
},
stderr: (text) => {
stderr += text;
},
});
return { code, stdout, stderr };
}
async function git(cwd: string, args: string[]): Promise<{ stdout: string; stderr: string }> {
const proc = Bun.spawn({
cmd: ["git", ...args],
cwd,
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, code] = await Promise.all([
new Response(proc.stdout).text(),
new Response(proc.stderr).text(),
proc.exited,
]);
if (code !== 0) {
throw new Error(`git ${args.join(" ")} failed: ${stderr || stdout}`);
}
return { stdout, stderr };
}