mirror of
https://github.com/pnpm/pnpm.git
synced 2026-05-13 19:16:21 -04:00
fix: keep workspace-root excluded when --recursive --filter uses only negative filters (#11480)
* fix: include workspace root only when --filter is positive PR #10465 stopped the implicit workspace-root exclusion for `pnpm -r run/exec/test/add` whenever any --filter was provided. That gate was too broad: with a negative-only filter set (e.g. `--filter '!a'`) the workspace root started showing up in the matched projects, contradicting the documented default behavior. Only suppress the implicit root exclusion when the user provided at least one positive (non-`!`) filter that could have been intended to select the root. Negative-only filter sets keep the documented default, and `--include-workspace-root` continues to opt the root in explicitly. Close #11341. * test: fix root-exclusion assertion to match --stream prefix The --stream reporter prefixes output lines with the project's relative directory, so the workspace root appears as `. which$`, not `root which$`. The original assertion would have passed even if the regression were still present. Verified the corrected assertion fails against the buggy code and passes against the fix.
This commit is contained in:
5
.changeset/recursive-filter-root-exclusion.md
Normal file
5
.changeset/recursive-filter-root-exclusion.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
Fix a regression where `pnpm --recursive --filter '!<pkg>' run/exec/test/add` would include the workspace root in the matched projects. The workspace root is now correctly excluded by default when only negative `--filter` arguments are provided, matching the [documented behavior](https://pnpm.io/cli/recursive). To include the root, pass `--include-workspace-root` [#11341](https://github.com/pnpm/pnpm/issues/11341).
|
||||
@@ -249,7 +249,7 @@ export async function main (inputArgv: string[]): Promise<void> {
|
||||
if (config.workspaceRoot) {
|
||||
filters.push({ filter: `{${relativeWSDirPath()}}`, followProdDepsOnly: Boolean(config.filterProd.length) })
|
||||
} else if (
|
||||
filters.length === 0 &&
|
||||
!filters.some(({ filter }) => !filter.startsWith('!')) &&
|
||||
workspaceDir &&
|
||||
config.workspacePackagePatterns &&
|
||||
!isRootOnlyPatterns(config.workspacePackagePatterns) &&
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import fs from 'node:fs'
|
||||
|
||||
import { expect, test } from '@jest/globals'
|
||||
import { prepare } from '@pnpm/prepare'
|
||||
import { prepare, preparePackages } from '@pnpm/prepare'
|
||||
|
||||
import { execPnpmSync } from '../utils/index.js'
|
||||
|
||||
@@ -42,3 +42,115 @@ test('pnpm --filter . add <pkg> should work', async () => {
|
||||
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'))
|
||||
expect(pkg.dependencies['is-positive']).toBeTruthy()
|
||||
})
|
||||
|
||||
// Regression test for https://github.com/pnpm/pnpm/issues/11341
|
||||
test('pnpm --recursive --filter "!<pkg>" run should still exclude the workspace root', async () => {
|
||||
preparePackages([
|
||||
{
|
||||
location: '.',
|
||||
package: {
|
||||
name: 'root',
|
||||
version: '0.0.0',
|
||||
private: true,
|
||||
scripts: {
|
||||
which: "node -e \"console.log('root')\"",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
location: 'a',
|
||||
package: {
|
||||
name: 'a',
|
||||
version: '1.0.0',
|
||||
scripts: {
|
||||
which: "node -e \"console.log('a')\"",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
location: 'b',
|
||||
package: {
|
||||
name: 'b',
|
||||
version: '1.0.0',
|
||||
scripts: {
|
||||
which: "node -e \"console.log('b')\"",
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
fs.writeFileSync('pnpm-workspace.yaml', 'packages:\n - "*"\n')
|
||||
|
||||
const result = execPnpmSync([
|
||||
'--stream',
|
||||
'--config.verify-deps-before-run=false',
|
||||
'--recursive',
|
||||
'--filter',
|
||||
'!a',
|
||||
'run',
|
||||
'which',
|
||||
])
|
||||
expect(result.status).toBe(0)
|
||||
|
||||
const stdout = result.stdout.toString()
|
||||
expect(stdout).toContain('b which$')
|
||||
// The `--stream` reporter prefixes lines with the project's relative directory,
|
||||
// so the workspace root (cwd === wsDir) would appear as `. which$` if included.
|
||||
expect(stdout).not.toContain('. which$')
|
||||
expect(stdout).not.toContain('a which$')
|
||||
})
|
||||
|
||||
test('pnpm --recursive --filter "!<pkg>" --include-workspace-root run should include the workspace root', async () => {
|
||||
preparePackages([
|
||||
{
|
||||
location: '.',
|
||||
package: {
|
||||
name: 'root',
|
||||
version: '0.0.0',
|
||||
private: true,
|
||||
scripts: {
|
||||
which: "node -e \"console.log('root')\"",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
location: 'a',
|
||||
package: {
|
||||
name: 'a',
|
||||
version: '1.0.0',
|
||||
scripts: {
|
||||
which: "node -e \"console.log('a')\"",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
location: 'b',
|
||||
package: {
|
||||
name: 'b',
|
||||
version: '1.0.0',
|
||||
scripts: {
|
||||
which: "node -e \"console.log('b')\"",
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
fs.writeFileSync('pnpm-workspace.yaml', 'packages:\n - "*"\n')
|
||||
|
||||
const result = execPnpmSync([
|
||||
'--stream',
|
||||
'--config.verify-deps-before-run=false',
|
||||
'--recursive',
|
||||
'--include-workspace-root',
|
||||
'--filter',
|
||||
'!a',
|
||||
'run',
|
||||
'which',
|
||||
])
|
||||
expect(result.status).toBe(0)
|
||||
|
||||
const stdout = result.stdout.toString()
|
||||
expect(stdout).toContain('b which$')
|
||||
expect(stdout).toContain('. which$')
|
||||
expect(stdout).not.toContain('a which$')
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user