fix(config): respect explicit enableGlobalVirtualStore in CI environments (#10836)

Previously, `ci: true` (auto-detected or configured) unconditionally
set `enableGlobalVirtualStore` to `false`, even when the user had
explicitly enabled it in `pnpm-workspace.yaml` or via CLI. This forced
users to add `ci: false` as a workaround in their workspace config
whenever they wanted GVS in CI-like environments (Nix builds, CI systems
with persistent caches, Docker multistage builds).

Now, the CI override only applies when `enableGlobalVirtualStore` was
not explicitly set (i.e., is `null` or `undefined`). This preserves the
default behavior for ephemeral CI while respecting explicit user
configuration.

Also removes the `ci: false` workarounds from existing tests that
were documenting this limitation.

Co-authored-by: Zoltan Kochan <z@kochan.io>
This commit is contained in:
Victor Sumner
2026-03-02 19:59:57 -05:00
committed by GitHub
parent 14b3a46d0b
commit 9f5c0e391f
5 changed files with 51 additions and 4 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/config": patch
"pnpm": patch
---
CI no longer force-disables `enableGlobalVirtualStore` when it was explicitly set by the user. Previously, `ci: true` (auto-detected or configured) would unconditionally set `enableGlobalVirtualStore` to `false`, even when the user had explicitly enabled it in `pnpm-workspace.yaml` or via CLI. Now, only the default value is overridden in CI — explicit user configuration is respected.

View File

@@ -609,9 +609,11 @@ export async function getConfig (opts: {
pnpmConfig.dev = true
}
if (pnpmConfig.ci) {
if (pnpmConfig.ci && pnpmConfig.enableGlobalVirtualStore == null) {
// Using a global virtual store in CI makes little sense,
// as there is never a warm cache in that environment.
// as there is usually no warm cache in that environment.
// However, if the user explicitly enabled GVS (e.g., for Nix builds
// or CI systems with persistent caches), respect that setting.
pnpmConfig.enableGlobalVirtualStore = false
}

View File

@@ -1504,6 +1504,47 @@ test('pnpm_config_lockfile env var overrides lockfile from pnpm-workspace.yaml i
expect(config.useLockfile).toBe(false)
})
test('ci disables enableGlobalVirtualStore by default', async () => {
prepareEmpty()
writeYamlFile('pnpm-workspace.yaml', {
ci: true,
})
const { config } = await getConfig({
cliOptions: {},
env,
packageManager: {
name: 'pnpm',
version: '1.0.0',
},
workspaceDir: process.cwd(),
})
expect(config.enableGlobalVirtualStore).toBe(false)
})
test('ci respects explicit enableGlobalVirtualStore from config', async () => {
prepareEmpty()
writeYamlFile('pnpm-workspace.yaml', {
ci: true,
enableGlobalVirtualStore: true,
})
const { config } = await getConfig({
cliOptions: {},
env,
packageManager: {
name: 'pnpm',
version: '1.0.0',
},
workspaceDir: process.cwd(),
})
expect(config.enableGlobalVirtualStore).toBe(true)
})
test('pnpm_config_git_branch_lockfile env var overrides git-branch-lockfile from pnpm-workspace.yaml in useGitBranchLockfile', async () => {
prepareEmpty()

View File

@@ -13,7 +13,6 @@ test('using a global virtual store', async () => {
const storeDir = path.resolve('store')
const globalVirtualStoreDir = path.join(storeDir, 'v11/links')
writeYamlFile(path.resolve('pnpm-workspace.yaml'), {
ci: false, // We force CI=false because enableGlobalVirtualStore is always disabled in CI
enableGlobalVirtualStore: true,
storeDir,
privateHoistPattern: '*',

View File

@@ -50,7 +50,6 @@ test('pnpm list returns correct paths with global virtual store', async () => {
},
})
writeYamlFile('pnpm-workspace.yaml', {
ci: false, // enableGlobalVirtualStore is always disabled in CI
enableGlobalVirtualStore: true,
storeDir: path.resolve('store'),
privateHoistPattern: '*',