Skip to content

Commit 28b8bb4

Browse files
committed
test(git): prove quickstart log and diff e2e
1 parent 1cc4ff4 commit 28b8bb4

2 files changed

Lines changed: 110 additions & 66 deletions

File tree

docs-internal/registry-parity-worklist.md

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -527,14 +527,19 @@ For each: replace `describe.skip` with `describeIf(binaryPresent)` **and** write
527527
real e2e tests that prove Linux-parity behavior — not smoke tests.
528528

529529
### 11. Disabled suites — git, duckdb, codex
530-
- **Broken:** tests exist but are `describe.skip`, so nothing runs even when the
531-
binary is present.
532-
- **Objective (per command, Linux parity):**
533-
- **git** — clone/commit/log/diff/branch against a real repo & remote.
534-
- **duckdb** — real analytical SQL, CSV read/write, file-backed DBs (the bar
535-
example: real duckdb, not a WASI-stripped `SELECT 1`).
536-
- **codex** — real run (after #9).
537-
- **Proof:** each un-skipped suite passes with real behavior.
530+
- **Broken:** tests exist but are skipped or excluded from the default run, so
531+
coverage can disappear even when the binary is present.
532+
- **Status:**
533+
- **git — DONE.** The core quickstart e2e now exercises real upstream Git in a
534+
VM for local origin creation, commit, branch, clone, checkout, `log`, and a
535+
working-tree `diff`. It validates only the git package it uses instead of
536+
eagerly requiring every registry package to be built. Proof:
537+
`2026-07-08T13-13-00-0700-item11-git-quickstart-final.log`.
538+
Rev: `svltqsmx`.
539+
- **duckdb — TODO.** Needs real analytical SQL, CSV read/write, and file-backed
540+
DB e2e kept runnable when the DuckDB package artifacts are present.
541+
- **codex — TODO.** Needs the remaining real full-turn coverage un-skipped after
542+
#9.
538543
- **rev:** one per command, e.g. `test(duckdb): real analytical-SQL e2e; un-skip`
539544

540545
### 12. No tests at all — 9 software + 5 agents
Lines changed: 97 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
import { existsSync, statSync } from "node:fs";
2+
import { dirname, join, resolve } from "node:path";
13
import common from "@agentos-software/common";
24
import git from "@agentos-software/git";
3-
import { moduleAccessMounts } from "./helpers/node-modules-mount.js";
4-
import { resolve } from "node:path";
55
import { afterEach, beforeEach, describe, expect, test } from "vitest";
66
import { AgentOs } from "../src/index.js";
7-
import { requireBuilt } from "./helpers/registry-commands.js";
7+
import { moduleAccessMounts } from "./helpers/node-modules-mount.js";
88

99
type ExecResult = {
1010
stdout: string;
@@ -19,8 +19,34 @@ const GIT_QUICKSTART_PERMISSIONS = {
1919
} as const;
2020

2121
const COMMON_SOFTWARE = common;
22-
const GIT_PACKAGE = requireBuilt(git, "git");
22+
const GIT_PACKAGE = requireBuiltPackage(git, "git");
2323
const MODULE_ACCESS_CWD = resolve(import.meta.dirname, "..");
24+
const GIT_CONFIG = [
25+
"-c safe.directory=*",
26+
"-c init.defaultBranch=main",
27+
"-c user.name=agentos",
28+
"-c user.email=agentos@example.invalid",
29+
].join(" ");
30+
31+
function requireBuiltPackage<T extends { packagePath: string }>(
32+
pkg: T,
33+
name: string,
34+
): T {
35+
const packageDir = pkg.packagePath.endsWith(".aospkg")
36+
? join(dirname(pkg.packagePath), "package")
37+
: pkg.packagePath;
38+
const built =
39+
existsSync(pkg.packagePath) &&
40+
statSync(pkg.packagePath).size > 16 &&
41+
existsSync(join(packageDir, "agentos-package.json")) &&
42+
existsSync(join(packageDir, "bin", name));
43+
if (!built) {
44+
throw new Error(
45+
`software package ${name} is NOT BUILT (no valid ${pkg.packagePath}).`,
46+
);
47+
}
48+
return pkg;
49+
}
2450

2551
function parseCurrentBranch(output: string): string {
2652
const branch = output
@@ -45,65 +71,78 @@ function parseHeadRef(content: string): string {
4571
return headRef;
4672
}
4773

48-
describe("git quickstart integration", () => {
74+
function gitCommand(args: string): string {
75+
return `git ${GIT_CONFIG} ${args}`;
76+
}
4977

50-
let vm: AgentOs;
78+
describe("git quickstart integration", () => {
79+
let vm: AgentOs;
5180

52-
beforeEach(async () => {
53-
vm = await AgentOs.create({
54-
mounts: moduleAccessMounts(MODULE_ACCESS_CWD),
55-
permissions: GIT_QUICKSTART_PERMISSIONS,
56-
software: [COMMON_SOFTWARE, GIT_PACKAGE],
57-
});
81+
beforeEach(async () => {
82+
vm = await AgentOs.create({
83+
mounts: moduleAccessMounts(MODULE_ACCESS_CWD),
84+
permissions: GIT_QUICKSTART_PERMISSIONS,
85+
software: [COMMON_SOFTWARE, GIT_PACKAGE],
5886
});
87+
});
88+
89+
afterEach(async () => {
90+
await vm?.dispose();
91+
});
92+
93+
async function run(command: string): Promise<ExecResult> {
94+
const result = await vm.exec(command);
95+
if (result.exitCode !== 0) {
96+
throw new Error(
97+
`command failed: ${command}\n${result.stderr || result.stdout}`,
98+
);
99+
}
100+
return result;
101+
}
59102

60-
afterEach(async () => {
61-
await vm.dispose();
62-
});
103+
test("covers the quickstart local origin -> clone -> checkout flow", async () => {
104+
await run(gitCommand("init /tmp/origin"));
105+
await vm.writeFile("/tmp/origin/README.md", "# demo repo\n");
106+
await run(gitCommand("-C /tmp/origin add README.md"));
107+
await run(gitCommand("-C /tmp/origin commit -m 'initial commit'"));
63108

64-
async function run(command: string): Promise<ExecResult> {
65-
const result = await vm.exec(command);
66-
if (result.exitCode !== 0) {
67-
throw new Error(
68-
`command failed: ${command}\n${result.stderr || result.stdout}`,
69-
);
70-
}
71-
return result;
72-
}
109+
const defaultBranch = parseCurrentBranch(
110+
(await run(gitCommand("-C /tmp/origin branch"))).stdout,
111+
);
112+
113+
await run(gitCommand("-C /tmp/origin checkout -b feature"));
114+
await vm.writeFile("/tmp/origin/feature.txt", "checked out from feature\n");
115+
await run(gitCommand("-C /tmp/origin add feature.txt"));
116+
await run(gitCommand("-C /tmp/origin commit -m 'add feature file'"));
117+
118+
await run(gitCommand("clone /tmp/origin /tmp/clone"));
119+
120+
const cloneHead = new TextDecoder().decode(
121+
await vm.readFile("/tmp/clone/.git/HEAD"),
122+
);
123+
expect(parseHeadRef(cloneHead)).toBe("feature");
124+
expect(defaultBranch).not.toBe("feature");
73125

74-
test(
75-
"covers the quickstart local origin -> clone -> checkout flow",
76-
async () => {
77-
await run("git init /tmp/origin");
78-
await vm.writeFile("/tmp/origin/README.md", "# demo repo\n");
79-
await run("git -C /tmp/origin add README.md");
80-
await run("git -C /tmp/origin commit -m 'initial commit'");
81-
82-
const defaultBranch = parseCurrentBranch(
83-
(await run("git -C /tmp/origin branch")).stdout,
84-
);
85-
86-
await run("git -C /tmp/origin checkout -b feature");
87-
await vm.writeFile("/tmp/origin/feature.txt", "checked out from feature\n");
88-
await run("git -C /tmp/origin add feature.txt");
89-
await run("git -C /tmp/origin commit -m 'add feature file'");
90-
91-
await run("git clone /tmp/origin /tmp/clone");
92-
93-
const cloneHead = new TextDecoder().decode(
94-
await vm.readFile("/tmp/clone/.git/HEAD"),
95-
);
96-
expect(parseHeadRef(cloneHead)).toBe("feature");
97-
expect(defaultBranch).not.toBe("feature");
98-
99-
const featureFile = await vm.readFile("/tmp/clone/feature.txt");
100-
expect(new TextDecoder().decode(featureFile)).toBe(
101-
"checked out from feature\n",
102-
);
103-
104-
const readme = await vm.readFile("/tmp/clone/README.md");
105-
expect(new TextDecoder().decode(readme)).toBe("# demo repo\n");
106-
},
107-
120_000,
126+
const featureFile = await vm.readFile("/tmp/clone/feature.txt");
127+
expect(new TextDecoder().decode(featureFile)).toBe(
128+
"checked out from feature\n",
108129
);
130+
131+
const readme = await vm.readFile("/tmp/clone/README.md");
132+
expect(new TextDecoder().decode(readme)).toBe("# demo repo\n");
133+
134+
const currentBranch = (
135+
await run(gitCommand("-C /tmp/clone branch --show-current"))
136+
).stdout.trim();
137+
expect(currentBranch).toBe("feature");
138+
139+
const log = await run(gitCommand("-C /tmp/clone log --oneline --all"));
140+
expect(log.stdout).toContain("add feature file");
141+
expect(log.stdout).toContain("initial commit");
142+
143+
await vm.writeFile("/tmp/clone/README.md", "# changed demo repo\n");
144+
const diff = await run(gitCommand("-C /tmp/clone diff -- README.md"));
145+
expect(diff.stdout).toContain("-# demo repo");
146+
expect(diff.stdout).toContain("+# changed demo repo");
147+
}, 120_000);
109148
});

0 commit comments

Comments
 (0)