From 44a3ba59e6d0d442b71e43445792edccd145a637 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Wed, 26 Aug 2026 04:36:28 -0700 Subject: [PATCH] test(git): isolate worktree-shared-directories git config portably (#16582) `os.devNull` is `\\.\nul` on win32. Git normalizes it to `//./nul` and rejects it as a config path, so every `git` call in this suite threw in `beforeEach` and 15 of 19 tests failed on Windows. POSIX resolves the same constant to /dev/null, which Git accepts, so CI never saw it. Point GIT_CONFIG_GLOBAL at a real empty file in a private mkdtemp directory, matching how skill-git-tree-identity and skill-windows-workspace already isolate, and use GIT_CONFIG_NOSYSTEM instead of GIT_CONFIG_SYSTEM. Set both on `process.env` rather than only on the suite's `git()` helper. `resolveWorktreeSharedDirectories` runs its own `git check-ignore` through the production runner, and `GitRuntimeOptions` carries no env, so the runner inherits `process.env`. The per-call override never reached the code under test: a host `core.excludesFile` could make a fixture that is not gitignored come back as ignored. Fixes #15409 --- .../git/worktree-shared-directories.test.ts | 56 +++++++++++++++---- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/src/main/git/worktree-shared-directories.test.ts b/src/main/git/worktree-shared-directories.test.ts index 97671c88fa6..7bd33987fba 100644 --- a/src/main/git/worktree-shared-directories.test.ts +++ b/src/main/git/worktree-shared-directories.test.ts @@ -1,8 +1,8 @@ import { execFileSync } from 'node:child_process' import { lstatSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' -import { devNull, tmpdir } from 'node:os' +import { tmpdir } from 'node:os' import { join } from 'node:path' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest' import { clearConfiguredWorktreeSharedDirectoriesCacheForTests, getConfiguredWorktreeSharedDirectories, @@ -16,16 +16,50 @@ import { import { assertWorktreeCleanForRemoval } from './worktree' import { getStatus } from './status' +// Why an empty file and not `os.devNull`: that constant is `\\.\nul` on win32, which +// Git normalizes to `//./nul` and rejects — `fatal: unable to access '//./nul': Invalid +// argument`. Every git call in this file then threw. POSIX resolves it to /dev/null, +// which Git accepts, so CI never saw it. An empty file works on every platform and +// matches how skill-git-tree-identity and skill-windows-workspace already isolate. +// +// Why process.env and not just this helper's env: resolveWorktreeSharedDirectories +// runs its own `git check-ignore` through the production runner, which inherits +// process.env. Overriding only the setup helper left the code under test reading the +// host's real config, so a developer with core.excludesFile set saw a fixture that is +// not gitignored come back as ignored. +let gitConfigRoot: string +let previousGitConfigGlobal: string | undefined +let previousGitConfigNosystem: string | undefined + +beforeAll(() => { + gitConfigRoot = mkdtempSync(join(tmpdir(), 'orca-shared-dirs-gitconfig-')) + const emptyGlobalGitConfig = join(gitConfigRoot, 'global.gitconfig') + writeFileSync(emptyGlobalGitConfig, '') + previousGitConfigGlobal = process.env.GIT_CONFIG_GLOBAL + previousGitConfigNosystem = process.env.GIT_CONFIG_NOSYSTEM + process.env.GIT_CONFIG_GLOBAL = emptyGlobalGitConfig + process.env.GIT_CONFIG_NOSYSTEM = '1' +}) + +afterAll(() => { + restoreGitEnv('GIT_CONFIG_GLOBAL', previousGitConfigGlobal) + restoreGitEnv('GIT_CONFIG_NOSYSTEM', previousGitConfigNosystem) + rmSync(gitConfigRoot, { recursive: true, force: true }) +}) + +function restoreGitEnv( + name: 'GIT_CONFIG_GLOBAL' | 'GIT_CONFIG_NOSYSTEM', + value: string | undefined +): void { + if (value === undefined) { + delete process.env[name] + return + } + process.env[name] = value +} + const git = (args: string[], cwd: string): void => { - execFileSync('git', args, { - cwd, - stdio: 'ignore', - env: { - ...process.env, - GIT_CONFIG_GLOBAL: devNull, - GIT_CONFIG_SYSTEM: devNull - } - }) + execFileSync('git', args, { cwd, stdio: 'ignore' }) } describe('resolveWorktreeSharedDirectories', () => {