From 42a8f29f41861a33fb69cd7fe0efa0f88f24f52e Mon Sep 17 00:00:00 2001 From: Zoltan Kochan Date: Sun, 3 May 2026 01:13:03 +0200 Subject: [PATCH] fix(config): default minimumReleaseAgeStrict to true when user sets minimumReleaseAge (#11436) * fix(config): default minimumReleaseAgeStrict to true when user sets minimumReleaseAge Without this, a user-set `minimumReleaseAge` would silently fall back to installing an immature version when no mature version satisfied the requested range, making the setting look like it had no effect (#11433). The built-in default of `minimumReleaseAge` (1440) stays non-strict for backward compatibility, and an explicit `minimumReleaseAgeStrict: false` is still respected. * chore(changeset): downgrade to patch * fix(config): apply minimumReleaseAgeStrict default after env var parsing Move the strict-default logic to run after `parseEnvVars` so `pnpm_config_minimum_release_age` is also covered. * test(config): also assert minimumReleaseAge in the strict=false test --- .../strict-min-release-age-when-user-set.md | 6 ++ config/reader/src/index.ts | 14 ++++ config/reader/test/index.ts | 83 +++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 .changeset/strict-min-release-age-when-user-set.md diff --git a/.changeset/strict-min-release-age-when-user-set.md b/.changeset/strict-min-release-age-when-user-set.md new file mode 100644 index 0000000000..9f9050a2c0 --- /dev/null +++ b/.changeset/strict-min-release-age-when-user-set.md @@ -0,0 +1,6 @@ +--- +"@pnpm/config.reader": patch +"pnpm": patch +--- + +`minimumReleaseAgeStrict` now defaults to `true` whenever the user explicitly sets `minimumReleaseAge` (via `pnpm-workspace.yaml`, the global `config.yaml`, the CLI, or `pnpm_config_*` env vars). Previously, an explicitly configured `minimumReleaseAge` could silently fall back to installing an immature version when no mature version satisfied the requested range, making the setting look like it had no effect [#11433](https://github.com/pnpm/pnpm/issues/11433). Set `minimumReleaseAgeStrict: false` to opt back into the silent fallback behavior. The built-in default (1440) remains non-strict, preserving the existing behavior for users who haven't configured the setting. diff --git a/config/reader/src/index.ts b/config/reader/src/index.ts index 1dc278a325..381ffefd5f 100644 --- a/config/reader/src/index.ts +++ b/config/reader/src/index.ts @@ -472,6 +472,20 @@ export async function getConfig (opts: { } } + // When the user explicitly sets `minimumReleaseAge`, treat it as strict by + // default. Without this, a user-set value would silently fall back to + // installing an immature version when no mature version satisfies the + // requested range — making the setting look like it had no effect. + // The built-in default for `minimumReleaseAge` is intentionally non-strict + // for backward compatibility. This must run after env var parsing so + // pnpm_config_minimum_release_age also enables strict mode. + if ( + pnpmConfig.explicitlySetKeys.has('minimumReleaseAge') && + pnpmConfig.minimumReleaseAgeStrict == null + ) { + pnpmConfig.minimumReleaseAgeStrict = true + } + overrideSupportedArchitecturesWithCLI(pnpmConfig, cliOptions) pnpmConfig.useLockfile = (() => { diff --git a/config/reader/test/index.ts b/config/reader/test/index.ts index d62ed115a9..32f542da03 100644 --- a/config/reader/test/index.ts +++ b/config/reader/test/index.ts @@ -316,6 +316,89 @@ test('.npmrc does not load pnpm settings', async () => { expect(config.authConfig.packages).toBeUndefined() }) +describe('minimumReleaseAgeStrict default', () => { + test('defaults to true when minimumReleaseAge is set in pnpm-workspace.yaml', async () => { + prepareEmpty() + + writeYamlFileSync('pnpm-workspace.yaml', { + minimumReleaseAge: 60, + }) + + const { config } = await getConfig({ + cliOptions: {}, + packageManager: { name: 'pnpm', version: '1.0.0' }, + workspaceDir: process.cwd(), + }) + + expect(config.minimumReleaseAge).toBe(60) + expect(config.minimumReleaseAgeStrict).toBe(true) + }) + + test('defaults to true when minimumReleaseAge is set on the CLI', async () => { + prepareEmpty() + + const { config } = await getConfig({ + cliOptions: { + 'minimum-release-age': 60, + }, + packageManager: { name: 'pnpm', version: '1.0.0' }, + workspaceDir: process.cwd(), + }) + + expect(config.minimumReleaseAge).toBe(60) + expect(config.minimumReleaseAgeStrict).toBe(true) + }) + + test('defaults to true when minimumReleaseAge is set via pnpm_config_* env var', async () => { + prepareEmpty() + + const { config } = await getConfig({ + cliOptions: {}, + env: { + pnpm_config_minimum_release_age: '60', + }, + packageManager: { name: 'pnpm', version: '1.0.0' }, + workspaceDir: process.cwd(), + }) + + expect(config.minimumReleaseAge).toBe(60) + expect(config.minimumReleaseAgeStrict).toBe(true) + }) + + test('respects an explicit minimumReleaseAgeStrict=false from pnpm-workspace.yaml', async () => { + prepareEmpty() + + writeYamlFileSync('pnpm-workspace.yaml', { + minimumReleaseAge: 60, + minimumReleaseAgeStrict: false, + }) + + const { config } = await getConfig({ + cliOptions: {}, + packageManager: { name: 'pnpm', version: '1.0.0' }, + workspaceDir: process.cwd(), + }) + + expect(config.minimumReleaseAge).toBe(60) + expect(config.minimumReleaseAgeStrict).toBe(false) + }) + + test('does not become strict when only the built-in default for minimumReleaseAge applies', async () => { + prepareEmpty() + + writeYamlFileSync('pnpm-workspace.yaml', {}) + + const { config } = await getConfig({ + cliOptions: {}, + packageManager: { name: 'pnpm', version: '1.0.0' }, + workspaceDir: process.cwd(), + }) + + expect(config.minimumReleaseAge).toBe(1440) + expect(config.minimumReleaseAgeStrict).toBeUndefined() + }) +}) + test('camelCase settings from pnpm-workspace.yaml are read into typed Config properties', async () => { prepareEmpty()