fix: config set --location=project with npm-managed settings (#10074)

close #9884
This commit is contained in:
Ryo Matsukawa
2025-10-13 01:33:23 +09:00
committed by GitHub
parent eaaf8cb965
commit 587424f24f
3 changed files with 68 additions and 9 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/plugin-commands-config": patch
pnpm: patch
---
Fixed `pnpm config set --location=project` incorrectly handling keys with slashes (auth tokens, registry settings) [#9884](https://github.com/pnpm/pnpm/issues/9884).

View File

@@ -1,3 +1,4 @@
import path from 'path'
import util from 'util'
import { types } from '@pnpm/config'
import { PnpmError } from '@pnpm/error'
@@ -23,17 +24,31 @@ export async function configSet (opts: ConfigCommandOptions, key: string, valueP
if (valueParam != null && opts.json) {
value = JSON.parse(valueParam)
}
if (opts.global && settingShouldFallBackToNpm(key)) {
const _runNpm = runNpm.bind(null, opts.npmPath)
if (value == null) {
_runNpm(['config', 'delete', key])
if (shouldFallbackToNpm) {
if (opts.global) {
const _runNpm = runNpm.bind(null, opts.npmPath)
if (value == null) {
_runNpm(['config', 'delete', key])
return
}
if (typeof value === 'string') {
_runNpm(['config', 'set', `${key}=${value}`])
return
}
throw new PnpmError('CONFIG_SET_AUTH_NON_STRING', `Cannot set ${key} to a non-string value (${JSON.stringify(value)})`)
} else {
const configPath = path.join(opts.dir, '.npmrc')
const settings = await safeReadIniFile(configPath)
if (value == null) {
if (settings[key] == null) return
delete settings[key]
} else {
settings[key] = value
}
await writeIniFile(configPath, settings)
return
}
if (typeof value === 'string') {
_runNpm(['config', 'set', `${key}=${value}`])
return
}
throw new PnpmError('CONFIG_SET_AUTH_NON_STRING', `Cannot set ${key} to a non-string value (${JSON.stringify(value)})`)
}
const { configPath, isWorkspaceYaml } = getConfigFilePath(opts)

View File

@@ -291,6 +291,44 @@ test('config set with location=project and json=true', async () => {
})
})
test('config set registry-specific setting with --location=project should create .npmrc', async () => {
const tmp = tempDir()
const configDir = path.join(tmp, 'global-config')
fs.mkdirSync(configDir, { recursive: true })
await config.handler({
dir: process.cwd(),
cliOptions: {},
configDir,
location: 'project',
rawConfig: {},
}, ['set', '//registry.example.com/:_auth', 'test-auth-value'])
expect(readIniFileSync(path.join(tmp, '.npmrc'))).toEqual({
'//registry.example.com/:_auth': 'test-auth-value',
})
expect(fs.existsSync(path.join(tmp, 'pnpm-workspace.yaml'))).toBeFalsy()
})
test('config set scoped registry with --location=project should create .npmrc', async () => {
const tmp = tempDir()
const configDir = path.join(tmp, 'global-config')
fs.mkdirSync(configDir, { recursive: true })
await config.handler({
dir: process.cwd(),
cliOptions: {},
configDir,
location: 'project',
rawConfig: {},
}, ['set', '@myorg:registry', 'https://test-registry.example.com/'])
expect(readIniFileSync(path.join(tmp, '.npmrc'))).toEqual({
'@myorg:registry': 'https://test-registry.example.com/',
})
expect(fs.existsSync(path.join(tmp, 'pnpm-workspace.yaml'))).toBeFalsy()
})
test('config set when both pnpm-workspace.yaml and .npmrc exist, pnpm-workspace.yaml has priority', async () => {
const tmp = tempDir()
const configDir = path.join(tmp, 'global-config')