diff --git a/.changeset/fix-config-globalconfig.md b/.changeset/fix-config-globalconfig.md new file mode 100644 index 0000000000..79582d2769 --- /dev/null +++ b/.changeset/fix-config-globalconfig.md @@ -0,0 +1,7 @@ +--- +"@pnpm/config.commands": patch +"@pnpm/config.reader": patch +"pnpm": patch +--- + +Fixed `pnpm config get globalconfig` to return the global `config.yaml` path again [pnpm/pnpm#11962](https://github.com/pnpm/pnpm/issues/11962). diff --git a/config/commands/src/configGet.ts b/config/commands/src/configGet.ts index a0e927b303..4522324518 100644 --- a/config/commands/src/configGet.ts +++ b/config/commands/src/configGet.ts @@ -1,4 +1,4 @@ -import { isIniConfigKey, types } from '@pnpm/config.reader' +import { getGlobalConfigPath, isIniConfigKey, types } from '@pnpm/config.reader' import { getObjectValueByPropertyPath } from '@pnpm/object.property-path' import { isCamelCase } from '@pnpm/text.naming-cases' import camelcase from 'camelcase' @@ -35,6 +35,9 @@ function lookupConfig (opts: ConfigCommandOptions, key: string, isScopedKey: boo } return { value: opts.authConfig[key] } } + if (key === 'globalconfig') { + return { value: getGlobalConfigPath(opts.configDir) } + } const kebabKey = isCamelCase(key) ? kebabCase(key) : key // Resolve typed keys from Config — check explicitly set values first, // then fall back to authConfig (for keys like registry set in .npmrc) diff --git a/config/commands/test/configGet.test.ts b/config/commands/test/configGet.test.ts index edebf26c37..89bc535105 100644 --- a/config/commands/test/configGet.test.ts +++ b/config/commands/test/configGet.test.ts @@ -1,3 +1,5 @@ +import path from 'node:path' + import { describe, expect, test } from '@jest/globals' import { config } from '@pnpm/config.commands' @@ -267,7 +269,18 @@ test('config get with scoped registry key that does not exist', async () => { expect(getOutputString(getResult)).toBe('undefined') }) -// globalconfig and npm-globalconfig tests removed — pnpm no longer exposes these npm-compat properties +test('config get globalconfig returns the global config.yaml path', async () => { + const configDir = path.join(process.cwd(), 'global-config') + const getResult = await config.handler(createConfigCommandOpts({ + dir: process.cwd(), + cliOptions: {}, + configDir, + global: true, + authConfig: {}, + }), ['get', 'globalconfig']) + + expect(getOutputString(getResult)).toBe(path.join(configDir, 'config.yaml')) +}) describe('does not traverse the prototype chain (#10296)', () => { test.each([ diff --git a/config/reader/src/dirs.ts b/config/reader/src/dirs.ts index a1fdcc24a7..5a8cd78ee9 100644 --- a/config/reader/src/dirs.ts +++ b/config/reader/src/dirs.ts @@ -1,6 +1,12 @@ import os from 'node:os' import path from 'node:path' +import { GLOBAL_CONFIG_YAML_FILENAME } from '@pnpm/constants' + +export function getGlobalConfigPath (configDir: string): string { + return path.join(configDir, GLOBAL_CONFIG_YAML_FILENAME) +} + export function getCacheDir ( opts: { env: NodeJS.ProcessEnv diff --git a/config/reader/src/index.ts b/config/reader/src/index.ts index dc3372b6cb..baade0fc61 100644 --- a/config/reader/src/index.ts +++ b/config/reader/src/index.ts @@ -36,7 +36,7 @@ import type { } from './Config.js' import { isConfigFileKey } from './configFileKey.js' import { extractAndRemoveDependencyBuildOptions, hasDependencyBuildOptions } from './dependencyBuildOptions.js' -import { getCacheDir, getConfigDir, getDataDir, getStateDir } from './dirs.js' +import { getCacheDir, getConfigDir, getDataDir, getGlobalConfigPath, getStateDir } from './dirs.js' import { parseEnvVars } from './env.js' import { getNetworkConfigs } from './getNetworkConfigs.js' import { getOptionsFromPnpmSettings } from './getOptionsFromRootManifest.js' @@ -52,6 +52,7 @@ import { types } from './types.js' export { types } export { getDefaultWorkspaceConcurrency, getWorkspaceConcurrency } from './concurrency.js' +export { getGlobalConfigPath } from './dirs.js' export { getDefaultCreds, getNetworkConfigs, type NetworkConfigs } from './getNetworkConfigs.js' export { getOptionsFromPnpmSettings, type OptionsFromRootManifest } from './getOptionsFromRootManifest.js' export type { Creds } from './parseCreds.js' @@ -305,7 +306,7 @@ export async function getConfig (opts: { } } if (ignoredKeys.length > 0) { - const globalYamlConfigPath = path.join(configDir, GLOBAL_CONFIG_YAML_FILENAME) + const globalYamlConfigPath = getGlobalConfigPath(configDir) 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, { diff --git a/pnpm/test/config/get.ts b/pnpm/test/config/get.ts index 56a47f5fd6..cc47564e6c 100644 --- a/pnpm/test/config/get.ts +++ b/pnpm/test/config/get.ts @@ -276,6 +276,7 @@ test('pnpm config get shows settings from global config.yaml', () => { expect(configGet('dangerously-allow-all-builds')).toBe('true') expect(configGet('dlxCacheMaxAge')).toBe('1234') expect(configGet('dlx-cache-max-age')).toBe('1234') + expect(configGet('globalconfig')).toBe(path.join(configDir, 'config.yaml')) // doesn't list CLI options expect(configGet('dev')).toBe('undefined') @@ -289,3 +290,18 @@ test('pnpm config get shows settings from global config.yaml', () => { expect(configGet('packageExtensions')).toBe('undefined') expect(configGet('package-extensions')).toBe('undefined') }) + +test('the path from "config get globalconfig" is the file that pnpm actually reads global settings from', () => { + prepare() + + const XDG_CONFIG_HOME = path.resolve('.config') + const env = { XDG_CONFIG_HOME } + const configGet = (key: string) => + execPnpmSync(['config', 'get', key], { expectSuccess: true, env }).stdout.toString().trim() + + const globalConfigPath = configGet('globalconfig') + fs.mkdirSync(path.dirname(globalConfigPath), { recursive: true }) + fs.writeFileSync(globalConfigPath, 'dlxCacheMaxAge: 4321\n') + + expect(configGet('dlx-cache-max-age')).toBe('4321') +})