diff --git a/.changeset/runtime-set-default-devengines.md b/.changeset/runtime-set-default-devengines.md new file mode 100644 index 0000000000..0b6958df67 --- /dev/null +++ b/.changeset/runtime-set-default-devengines.md @@ -0,0 +1,6 @@ +--- +"@pnpm/engine.runtime.commands": minor +"pnpm": minor +--- + +`pnpm runtime set ` now saves the runtime to `devEngines.runtime` by default instead of `engines.runtime`. Pass `--save-prod` (or `-P`) to save it to `engines.runtime` instead [#11948](https://github.com/pnpm/pnpm/issues/11948). diff --git a/engine/runtime/commands/src/runtime/runtime.ts b/engine/runtime/commands/src/runtime/runtime.ts index 49ac563434..9f296fe3f7 100644 --- a/engine/runtime/commands/src/runtime/runtime.ts +++ b/engine/runtime/commands/src/runtime/runtime.ts @@ -12,6 +12,8 @@ export type RuntimeCommandOptions = Pick & Partial> export const skipPackageManagerCheck = true @@ -23,6 +25,8 @@ export function rcOptionsTypes (): Record { export function cliOptionsTypes (): Record { return { global: Boolean, + 'save-dev': Boolean, + 'save-prod': Boolean, } } @@ -49,11 +53,22 @@ export function help (): string { name: '--global', shortAlias: '-g', }, + { + description: 'Save the runtime to `devEngines.runtime`. This is the default', + name: '--save-dev', + shortAlias: '-D', + }, + { + description: 'Save the runtime to `engines.runtime`', + name: '--save-prod', + shortAlias: '-P', + }, ], }, ], url: docsUrl('runtime'), usages: [ + 'pnpm runtime set node 22', 'pnpm runtime set node 22 -g', 'pnpm runtime set node lts -g', 'pnpm runtime set node rc/22 -g', @@ -91,6 +106,14 @@ function runtimeSet (opts: RuntimeCommandOptions, params: string[]): void { const versionSpec = params[1]?.trim() const args = ['add', `${runtimeName}@runtime:${versionSpec ?? ''}`] + // Default to `devEngines.runtime`; the manifest writer maps a + // `devDependencies.: runtime:` entry to it. + // `saveDev` wins over `saveProd` to match `getSaveType` precedence. + if (opts.saveDev || !opts.saveProd) { + args.push('--save-dev') + } else { + args.push('--save-prod') + } if (opts.global) { args.push('--global') if (opts.bin) args.push('--global-bin-dir', opts.bin) diff --git a/engine/runtime/commands/test/runtime.test.ts b/engine/runtime/commands/test/runtime.test.ts index 685e47ab61..ae653da21f 100644 --- a/engine/runtime/commands/test/runtime.test.ts +++ b/engine/runtime/commands/test/runtime.test.ts @@ -23,12 +23,12 @@ test('runtime set calls pnpm add with the correct arguments globally', async () }, ['set', 'node', '22']) expect(mockRunPnpmCli).toHaveBeenCalledWith( - ['add', 'node@runtime:22', '--global', '--global-bin-dir', '/usr/local/bin', '--store-dir', '/tmp/store', '--cache-dir', '/tmp/cache'], + ['add', 'node@runtime:22', '--save-dev', '--global', '--global-bin-dir', '/usr/local/bin', '--store-dir', '/tmp/store', '--cache-dir', '/tmp/cache'], { cwd: '/tmp/pnpm-home' } ) }) -test('runtime set uses project dir when not global', async () => { +test('runtime set defaults to --save-dev so the runtime lands in devEngines', async () => { await runtime.handler({ bin: '/usr/local/bin', dir: '/tmp/project', @@ -37,7 +37,53 @@ test('runtime set uses project dir when not global', async () => { }, ['set', 'node', '22']) expect(mockRunPnpmCli).toHaveBeenCalledWith( - ['add', 'node@runtime:22', '--ignore-workspace-root-check'], + ['add', 'node@runtime:22', '--save-dev', '--ignore-workspace-root-check'], + { cwd: '/tmp/project' } + ) +}) + +test('runtime set with --save-prod saves the runtime under engines', async () => { + await runtime.handler({ + bin: '/usr/local/bin', + dir: '/tmp/project', + global: false, + pnpmHomeDir: '/tmp/pnpm-home', + saveProd: true, + }, ['set', 'node', '22']) + + expect(mockRunPnpmCli).toHaveBeenCalledWith( + ['add', 'node@runtime:22', '--save-prod', '--ignore-workspace-root-check'], + { cwd: '/tmp/project' } + ) +}) + +test('runtime set with --save-dev keeps the runtime under devEngines (matches the default)', async () => { + await runtime.handler({ + bin: '/usr/local/bin', + dir: '/tmp/project', + global: false, + pnpmHomeDir: '/tmp/pnpm-home', + saveDev: true, + }, ['set', 'node', '22']) + + expect(mockRunPnpmCli).toHaveBeenCalledWith( + ['add', 'node@runtime:22', '--save-dev', '--ignore-workspace-root-check'], + { cwd: '/tmp/project' } + ) +}) + +test('runtime set with both --save-dev and --save-prod prefers --save-dev (matches getSaveType precedence)', async () => { + await runtime.handler({ + bin: '/usr/local/bin', + dir: '/tmp/project', + global: false, + pnpmHomeDir: '/tmp/pnpm-home', + saveDev: true, + saveProd: true, + }, ['set', 'node', '22']) + + expect(mockRunPnpmCli).toHaveBeenCalledWith( + ['add', 'node@runtime:22', '--save-dev', '--ignore-workspace-root-check'], { cwd: '/tmp/project' } ) }) @@ -51,7 +97,7 @@ test('runtime set without version spec', async () => { }, ['set', 'node']) expect(mockRunPnpmCli).toHaveBeenCalledWith( - ['add', 'node@runtime:', '--global', '--global-bin-dir', '/usr/local/bin'], + ['add', 'node@runtime:', '--save-dev', '--global', '--global-bin-dir', '/usr/local/bin'], { cwd: '/tmp/pnpm-home' } ) }) @@ -65,7 +111,7 @@ test('runtime set works with deno', async () => { }, ['set', 'deno', '2']) expect(mockRunPnpmCli).toHaveBeenCalledWith( - ['add', 'deno@runtime:2', '--global', '--global-bin-dir', '/usr/local/bin'], + ['add', 'deno@runtime:2', '--save-dev', '--global', '--global-bin-dir', '/usr/local/bin'], { cwd: '/tmp/pnpm-home' } ) })