diff --git a/packages/server/src/server/workspace-runtime/git-observation/internal/integration.test.ts b/packages/server/src/server/workspace-runtime/git-observation/internal/integration.test.ts index 2450b975bf..a59ad7568a 100644 --- a/packages/server/src/server/workspace-runtime/git-observation/internal/integration.test.ts +++ b/packages/server/src/server/workspace-runtime/git-observation/internal/integration.test.ts @@ -17,15 +17,17 @@ function createDeferred() { test("selected runtime Git observation prunes paths ignored by that runtime checkout", async () => { let subscriptionInput: Parameters[0] | null = null; + const run = vi.fn(async () => ({ + stdin: new PassThrough(), + stdout: Readable.from(["node_modules/\0packages/server/dist/\0"]), + stderr: Readable.from([]), + exited: Promise.resolve({ code: 0, signal: null }), + kill: () => undefined, + })); + const resolveCommand = vi.fn(async () => "C:\\runtime\\git.exe"); const runtime = { - run: async () => ({ - stdin: new PassThrough(), - stdout: Readable.from(["node_modules/\0packages/server/dist/\0"]), - stderr: Readable.from([]), - exited: Promise.resolve({ code: 0, signal: null }), - kill: () => undefined, - }), - resolveCommand: async () => null, + run, + resolveCommand, scriptTerminal: { kind: "direct-command", command: "/bin/sh", argsPrefix: ["-lc"] }, files: { subscribe: async (input) => { @@ -44,6 +46,43 @@ test("selected runtime Git observation prunes paths ignored by that runtime chec recursive: true, ignoredPaths: ["node_modules", "packages/server/dist"], }); + expect(resolveCommand).toHaveBeenCalledWith("git"); + expect(run).toHaveBeenCalledWith({ + argv: [ + "C:\\runtime\\git.exe", + "ls-files", + "--others", + "--ignored", + "--exclude-standard", + "--directory", + "-z", + ], + env: { GIT_OPTIONAL_LOCKS: "0" }, + purpose: { kind: "git" }, + }); + await subscription.unsubscribe(); +}); + +test("selected runtime Git observation stays available when Git is unavailable", async () => { + let subscriptionInput: Parameters[0] | null = null; + const runtime = { + run: vi.fn(), + resolveCommand: vi.fn(async () => null), + scriptTerminal: { kind: "direct-command", command: "/bin/sh", argsPrefix: ["-lc"] }, + files: { + subscribe: async (input) => { + subscriptionInput = input; + return { unsubscribe: async () => undefined }; + }, + }, + } as unknown as BoundWorkspaceRuntime; + const coordinator = createGitCommonObservationCoordinator(); + coordinator.bind(runtime, "workspace-1", {} as WorkspaceRuntimeDriver); + + const subscription = await observeWorkspaceGit(runtime, () => undefined); + + expect(subscriptionInput).toEqual({ paths: ["."], recursive: true, ignoredPaths: [] }); + expect(runtime.run).not.toHaveBeenCalled(); await subscription.unsubscribe(); }); diff --git a/packages/server/src/server/workspace-runtime/git-observation/internal/integration.ts b/packages/server/src/server/workspace-runtime/git-observation/internal/integration.ts index 3e8b2c2c83..45f9e43be0 100644 --- a/packages/server/src/server/workspace-runtime/git-observation/internal/integration.ts +++ b/packages/server/src/server/workspace-runtime/git-observation/internal/integration.ts @@ -173,9 +173,11 @@ export function createGitCommonObservationCoordinator(): GitCommonObservationCoo } async function readGitIgnoredPaths(runtime: BoundWorkspaceRuntime): Promise { + const git = await runtime.resolveCommand("git"); + if (!git) return []; const process = await runtime.run({ - argv: ["git", "ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "-z"], - env: { GIT_OPTIONAL_LOCKS: "0", PATH: "/usr/local/bin:/usr/bin:/bin" }, + argv: [git, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "-z"], + env: { GIT_OPTIONAL_LOCKS: "0" }, purpose: { kind: "git" }, }); process.stdin.end();