fix(run): fail when no packages have script in filtered recursive run (#10437)

* fix(run): fail when no packages have script in filtered recursive run

Previously, `pnpm run -r <script>` and `pnpm run --filter <filter> <script>`
would silently succeed with exit code 0 when no packages had the specified
script, as long as a filter was used. This was inconsistent with the
documentation which states "If none of the packages have the command, the
command fails."

This change makes the command fail with ERR_PNPM_RECURSIVE_RUN_NO_SCRIPT in
all cases where no packages have the script, regardless of whether a filter
is used. The `--if-present` flag can be used to suppress this error.

close #6844
This commit is contained in:
Oleg Pustovit
2026-01-16 01:49:24 +01:00
committed by Zoltan Kochan
parent 6ca07ffbe6
commit 85416ea581
3 changed files with 22 additions and 6 deletions

View File

@@ -0,0 +1,6 @@
---
"pnpm": patch
"@pnpm/plugin-commands-script-runners": patch
---
`pnpm run -r` and `pnpm run --filter` now fail with a non-zero exit code when no packages have the specified script. Previously, this only failed when all packages were selected. Use `--if-present` to suppress this error [#6844](https://github.com/pnpm/pnpm/issues/6844).

View File

@@ -9,7 +9,6 @@ import {
makeNodeRequireOption,
type RunLifecycleHookOptions,
} from '@pnpm/lifecycle'
import { logger } from '@pnpm/logger'
import { groupStart } from '@pnpm/log.group'
import { sortPackages } from '@pnpm/sort-packages'
import pLimit from 'p-limit'
@@ -192,10 +191,7 @@ export async function runRecursive (
if (allPackagesAreSelected) {
throw new PnpmError('RECURSIVE_RUN_NO_SCRIPT', `None of the packages has a "${scriptName}" script`)
} else {
logger.info({
message: `None of the selected packages has a "${scriptName}" script`,
prefix: opts.workspaceDir,
})
throw new PnpmError('RECURSIVE_RUN_NO_SCRIPT', `None of the selected packages has a "${scriptName}" script`)
}
}
opts.reportSummary && await writeRecursiveSummary({

View File

@@ -380,7 +380,7 @@ test('`pnpm recursive run` fails when run with a filter that includes all packag
expect(err.code).toBe('ERR_PNPM_RECURSIVE_RUN_NO_SCRIPT')
})
test('`pnpm recursive run` succeeds when run against a subset of packages and no package has the desired command', async () => {
test('`pnpm recursive run` fails when run against a subset of packages and no package has the desired command, unless if-present is set', async () => {
preparePackages([
{
name: 'project-1',
@@ -422,14 +422,28 @@ test('`pnpm recursive run` succeeds when run against a subset of packages and no
[{ namePattern: 'project-1' }],
{ workspaceDir: process.cwd() }
)
// Recursive run does not fail when if-present is true
await run.handler({
...DEFAULT_OPTS,
allProjects,
dir: process.cwd(),
ifPresent: true,
recursive: true,
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, ['this-command-does-not-exist'])
await expect(
run.handler({
...DEFAULT_OPTS,
allProjects,
dir: process.cwd(),
recursive: true,
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, ['this-command-does-not-exist'])
).rejects.toThrow(/None of the selected packages has a/)
})
test('"pnpm run --filter <pkg>" without specifying the script name', async () => {