diff --git a/.changeset/warn-ignored-global-settings.md b/.changeset/warn-ignored-global-settings.md new file mode 100644 index 0000000000..0c54c5a538 --- /dev/null +++ b/.changeset/warn-ignored-global-settings.md @@ -0,0 +1,6 @@ +--- +"@pnpm/config.reader": patch +"pnpm": patch +--- + +Print a warning when settings that are not allowed in the global config file (e.g. `nodeLinker`, `hoistPattern`) are present in `config.yaml` and silently ignored. Previously these settings were dropped without any feedback, leaving users unsure why their global configuration had no effect. The warning suggests moving those settings to a project-level `pnpm-workspace.yaml`, or sharing them across projects via [config dependencies](https://pnpm.io/11.x/config-dependencies). diff --git a/config/reader/src/index.ts b/config/reader/src/index.ts index 99dc431c78..ea0f486c09 100644 --- a/config/reader/src/index.ts +++ b/config/reader/src/index.ts @@ -290,11 +290,17 @@ export async function getConfig (opts: { // Reuse the global config.yaml already read for npmrcAuthFile const globalYamlConfig = globalYamlConfigForNpmrcAuthFile if (globalYamlConfig) { + const ignoredKeys: string[] = [] for (const key in globalYamlConfig) { if (!isConfigFileKey(kebabCase(key))) { + ignoredKeys.push(key) delete globalYamlConfig[key as keyof typeof globalYamlConfig] } } + if (ignoredKeys.length > 0) { + const globalYamlConfigPath = path.join(configDir, GLOBAL_CONFIG_YAML_FILENAME) + warnings.push(`The following settings cannot be set in the global config file ("${globalYamlConfigPath}") and were ignored: ${ignoredKeys.map(k => `"${k}"`).join(', ')}. Move them to a project-level pnpm-workspace.yaml. To share these settings across projects, use config dependencies: https://pnpm.io/11.x/config-dependencies`) + } addSettingsFromWorkspaceManifestToConfig(pnpmConfig, { configFromCliOpts, projectManifest: undefined, diff --git a/config/reader/test/index.ts b/config/reader/test/index.ts index ce76763996..b405f13ff1 100644 --- a/config/reader/test/index.ts +++ b/config/reader/test/index.ts @@ -1687,6 +1687,44 @@ describe('global config.yaml', () => { expect(config.dangerouslyAllowAllBuilds).toBeDefined() }) + test('warns when global config.yaml contains settings that are not allowed in the global config', async () => { + prepareEmpty() + + fs.mkdirSync('.config/pnpm', { recursive: true }) + writeYamlFileSync('.config/pnpm/config.yaml', { + dangerouslyAllowAllBuilds: true, + nodeLinker: 'hoisted', + hoistPattern: ['*eslint*'], + }) + + process.env.XDG_CONFIG_HOME = path.resolve('.config') + + const { config, warnings } = await getConfig({ + cliOptions: {}, + packageManager: { + name: 'pnpm', + version: '1.0.0', + }, + workspaceDir: process.cwd(), + }) + + // Allowed setting is still applied. + expect(config.dangerouslyAllowAllBuilds).toBe(true) + // Ignored settings do not leak into the config. + expect(config.nodeLinker).not.toBe('hoisted') + expect(config.hoistPattern).toEqual(['*']) + + const warning = warnings.find((w) => w.includes('global config file')) + expect(warning).toBeDefined() + expect(warning).toContain('"nodeLinker"') + expect(warning).toContain('"hoistPattern"') + expect(warning).not.toContain('"dangerouslyAllowAllBuilds"') + expect(warning).toContain(path.join(process.env.XDG_CONFIG_HOME!, 'pnpm', 'config.yaml')) + expect(warning).toContain('pnpm-workspace.yaml') + expect(warning).toContain('https://pnpm.io/11.x/config-dependencies') + expect(warning).not.toContain('.npmrc') + }) + test('reads proxy settings from global config.yaml', async () => { prepareEmpty()