1+ import { existsSync , statSync } from "node:fs" ;
2+ import { dirname , join , resolve } from "node:path" ;
13import common from "@agentos-software/common" ;
24import git from "@agentos-software/git" ;
3- import { moduleAccessMounts } from "./helpers/node-modules-mount.js" ;
4- import { resolve } from "node:path" ;
55import { afterEach , beforeEach , describe , expect , test } from "vitest" ;
66import { AgentOs } from "../src/index.js" ;
7- import { requireBuilt } from "./helpers/registry-commands .js" ;
7+ import { moduleAccessMounts } from "./helpers/node-modules-mount .js" ;
88
99type ExecResult = {
1010 stdout : string ;
@@ -19,8 +19,34 @@ const GIT_QUICKSTART_PERMISSIONS = {
1919} as const ;
2020
2121const COMMON_SOFTWARE = common ;
22- const GIT_PACKAGE = requireBuilt ( git , "git" ) ;
22+ const GIT_PACKAGE = requireBuiltPackage ( git , "git" ) ;
2323const 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
2551function 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