patch.moi/apps/patch/test/cli.test.ts
matamune 81ea91e387
Some checks failed
check / check (push) Failing after 3s
Adopt codex-flows 0.3.5 surfaces
2026-05-18 00:07:15 +00:00

218 lines
6.4 KiB
TypeScript

import { mkdir, mkdtemp } 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";
import { EventStore } from "../src/queue";
const workspaceRoot = join(import.meta.dir, "../../..");
describe("patch.moi CLI", () => {
test("dispatches the harness event and records patch.moi state", async () => {
const dataDir = await mkdtemp(join(tmpdir(), "patch-cli-"));
const calls: Array<{ url: string; body: string }> = [];
const result = await invoke([
"run",
"harness",
"--workspace-root",
workspaceRoot,
"--data-dir",
dataDir,
"--json",
], {
env: {
PATCH_WORKSPACE_BACKEND_URL: "https://workspace.example",
},
fetchImpl: async (url, init) => {
calls.push({ url, body: String(init.body ?? "") });
const eventId = JSON.parse(String(init.body ?? "{}")).id;
return Response.json({
status: "accepted",
eventId,
runIds: ["run-harness"],
matched: 1,
}, { status: 202 });
},
});
expect(result.code).toBe(0);
expect(calls).toHaveLength(1);
expect(calls[0]?.url).toBe("https://workspace.example/events");
const payload = JSON.parse(result.stdout);
expect(payload).toMatchObject({
event: { id: "patch:harness:v0.1.3:upstream.release" },
recorded: true,
record: { status: "dispatched", runIds: ["run-harness"], matched: 1 },
attempt: {
status: "started",
eventId: "patch:harness:v0.1.3:upstream.release",
workspaceRunIds: ["run-harness"],
},
});
const store = new EventStore(dataDir);
expect(await store.getFlowEvent("patch:harness:v0.1.3:upstream.release")).toMatchObject({
type: "upstream.release",
});
expect(await store.listMaintenanceAttempts()).toMatchObject([
{ eventId: "patch:harness:v0.1.3:upstream.release", status: "started" },
]);
});
test("dry-runs Codex release matching and blocks accidental local execution", async () => {
const blocked = await invoke([
"run",
"codex-release",
"--tag",
"rust-v0.130.0",
"--workspace-root",
workspaceRoot,
]);
expect(blocked.code).toBe(2);
expect(blocked.stderr).toContain("requires PATCH_WORKSPACE_BACKEND_URL, CODEX_WORKSPACE_MODE=actions, or --allow-local");
const dryRun = await invoke([
"run",
"codex-release",
"--tag",
"rust-v0.130.0",
"--workspace-root",
workspaceRoot,
"--dry-run",
"--json",
]);
expect(dryRun.code).toBe(0);
expect(JSON.parse(dryRun.stdout).matches).toEqual([
{ flow: "openai-codex-bindings", step: "regenerate-bindings", runner: "bun" },
{ flow: "peezy-codex-fork", step: "rebase-patch-stack", runner: "code-mode" },
]);
});
test("syncs a maintenance attempt from workspace run state", async () => {
const dataDir = await mkdtemp(join(tmpdir(), "patch-cli-"));
const store = new EventStore(dataDir);
await store.appendMaintenanceAttempt({
id: "attempt-1",
eventId: "event-1",
eventType: "upstream.release",
operation: "dispatch",
status: "started",
upstreamRepo: "openai/codex",
upstreamTag: "rust-v0.130.0",
workspaceRunIds: ["run-1"],
candidateRefs: [],
createdAt: "2026-05-16T00:00:00.000Z",
updatedAt: "2026-05-16T00:00:00.000Z",
});
const result = await invoke([
"sync",
"attempt-1",
"--data-dir",
dataDir,
"--json",
], {
env: {
PATCH_WORKSPACE_BACKEND_URL: "https://workspace.example",
},
fetchImpl: async () => Response.json({
run: {
id: "run-1",
eventId: "event-1",
status: "completed",
completedAt: "2026-05-16T00:01:00.000Z",
resultJson: JSON.stringify({
status: "changed",
message: "candidate branch ready",
artifacts: {
candidateRefs: [{
kind: "branch",
repo: "peezy-tech/codex",
ref: "refs/heads/candidate",
sha: "abc123",
pushed: false,
}],
},
}),
},
}),
});
expect(result.code).toBe(0);
expect(JSON.parse(result.stdout)).toMatchObject({
attempt: {
id: "attempt-1",
status: "changed",
message: "candidate branch ready",
candidateRefs: [{ ref: "refs/heads/candidate", sha: "abc123" }],
},
});
expect(await store.listMaintenanceAttempts({ status: "changed" })).toMatchObject([
{ id: "attempt-1", status: "changed" },
]);
});
test("sets up the Codex upstream remote when explicitly applied", async () => {
const repo = await mkdtemp(join(tmpdir(), "patch-cli-codex-"));
await mkdir(repo, { recursive: true });
await git(repo, ["init", "-b", "code-mode-exec-hooks"]);
await git(repo, ["remote", "add", "origin", "https://github.com/peezy-tech/codex"]);
const result = await invoke([
"setup",
"codex",
"--repo",
repo,
"--apply",
"--json",
]);
expect(result.code).toBe(0);
expect(JSON.parse(result.stdout)).toMatchObject({
path: repo,
branch: "code-mode-exec-hooks",
upstream: "https://github.com/openai/codex.git",
addedUpstream: true,
clean: true,
ready: true,
});
expect((await git(repo, ["remote", "get-url", "upstream"])).stdout.trim()).toBe("https://github.com/openai/codex.git");
});
});
async function invoke(
args: string[],
options: Parameters<typeof runCli>[1] = {},
): Promise<{ code: number; stdout: string; stderr: string }> {
let stdout = "";
let stderr = "";
const code = await runCli(args, {
cwd: workspaceRoot,
...options,
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 };
}