Skip to content

fix: keep workspace-root excluded when --recursive --filter uses only negative filters#11480

Merged
zkochan merged 2 commits into
mainfrom
fix/11341
May 5, 2026
Merged

fix: keep workspace-root excluded when --recursive --filter uses only negative filters#11480
zkochan merged 2 commits into
mainfrom
fix/11341

Conversation

@zkochan

@zkochan zkochan commented May 5, 2026

Copy link
Copy Markdown
Member

Summary

Fixes #11341. When pnpm --recursive --filter '!<pkg>' run/exec/test/add was used, the workspace root started appearing in the matched projects in 10.33.0+, contradicting the documented default behavior that root is excluded for these commands unless --include-workspace-root is set.

Root cause

PR #10465 (which fixed #10462--filter <root> not finding the root in single-package workspaces) gated the implicit root-exclusion on filters.length === 0. That gate was too broad: any user filter — including a negative one like --filter '!a' — disabled the implicit exclusion.

Fix

Suppress the implicit root exclusion only 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.

Filter Before After
(none) root excluded ✓ root excluded ✓
--filter '!a' root included root excluded ✓
--filter a root excluded (a selected) ✓ root excluded (a selected) ✓
--filter root-name root selected ✓ (#10462) root selected ✓ (#10462)
--include-workspace-root --filter '!a' root included ✓ root included ✓

The isRootOnlyPatterns guard from #10927 still ensures single-package workspaces (packages: ['.'] or empty pnpm-workspace.yaml) are unaffected.

Test plan


Written by an agent (Claude Code, claude-opus-4-7).

Summary by CodeRabbit

  • Bug Fixes

    • Fixed a regression where the workspace root was incorrectly included when using --recursive with only negative filters; the root is now excluded by default. Use --include-workspace-root to include it.
  • Tests

    • Added regression tests to verify recursive filtering now excludes or includes the workspace root as expected.
  • Documentation

    • Added a patch changeset documenting the regression fix and behavior.

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.
Copilot AI review requested due to automatic review settings May 5, 2026 23:21
@coderabbitai

coderabbitai Bot commented May 5, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: be2146db-8819-4df8-9e90-3057aa691659

📥 Commits

Reviewing files that changed from the base of the PR and between ae13f4d and be68071.

📒 Files selected for processing (1)
  • pnpm/test/recursive/filter.ts

📝 Walkthrough

Walkthrough

This PR fixes a regression in recursive workspace filtering: when all provided filters are negative (e.g., --filter '!<pkg>'), the workspace root was wrongly included. The guard that auto-adds a root exclusion now triggers only when no positive filters exist. Tests and a changeset documenting the patch were added.

Changes

Recursive Filter Root Exclusion

Layer / File(s) Summary
Core Logic
pnpm/src/main.ts
Changed the guard that auto-appends a root-exclusion filter from filters.length === 0 to !filters.some(({ filter }) => !filter.startsWith('!')), so an exclusion is added when there are no positive filters (i.e., all filters are negations).
Tests
pnpm/test/recursive/filter.ts
Added two regression tests (using preparePackages) that assert: (1) --recursive --filter '!a' excludes the workspace root; (2) --recursive --filter '!a' --include-workspace-root includes the workspace root.
Changelog / Release Note
.changeset/recursive-filter-root-exclusion.md
Added a patch-level changeset entry describing the regression fix and noting that --include-workspace-root can be used to include the root.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • #11341 — Reports the regression where pnpm --recursive --filter '!a' included the workspace root; this PR addresses that exact behavior.
  • #10462 — Discusses --filter behavior with workspace root detection; related to workspace-root matching logic.
  • #10485 — Similar root-inclusion filtering bug; the core change in pnpm/src/main.ts appears to address the same class of issue.

Poem

I nibble at filters under moonlight's glow,
Negations trimmed so roots don't roam,
Tests hop in rows to make it so,
Patch written snug — the workspace home. 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main fix: it addresses the specific regression where workspace root was incorrectly included when using --recursive with only negative filters.
Linked Issues check ✅ Passed The PR fully addresses the primary objective in #11341 (fix regression where workspace root is included with negative-only filters) and maintains the fix from #10462 (allowing --filter to match root when appropriate).
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the workspace-root filtering regression: the conditional logic change, regression tests, and changeset entry are all necessary and related to the stated objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/11341

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a regression in recursive command filtering where the workspace root was incorrectly included when users supplied only negative (!) --filter arguments, restoring the documented default behavior (root excluded unless explicitly opted in).

Changes:

  • Adjust implicit workspace-root exclusion logic to remain active when all user-provided filters are negative.
  • Add regression tests for --recursive --filter '!<pkg>' with/without --include-workspace-root.
  • Add a changeset documenting the patch-level fix.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
pnpm/src/main.ts Refines the condition that adds the implicit !{<root>} filter so negative-only filter sets still exclude the root.
pnpm/test/recursive/filter.ts Adds regression coverage for negative-only filter behavior and the --include-workspace-root override.
.changeset/recursive-filter-root-exclusion.md Documents the regression and the corrected default behavior in a patch changeset.
Comments suppressed due to low confidence (1)

pnpm/src/main.ts:256

  • This condition has a double-negation and is hard to parse (!filters.some(...!filter.startsWith('!'))). For readability/maintainability, consider extracting a named boolean (e.g. hasPositiveFilter) or using filters.every(({filter}) => filter.startsWith('!')).
    } else if (
      !filters.some(({ filter }) => !filter.startsWith('!')) &&
      workspaceDir &&
      config.workspacePackagePatterns &&
      !isRootOnlyPatterns(config.workspacePackagePatterns) &&
      !config.includeWorkspaceRoot &&

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pnpm/test/recursive/filter.ts Outdated
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.
@zkochan zkochan merged commit 9018103 into main May 5, 2026
12 of 13 checks passed
@zkochan zkochan deleted the fix/11341 branch May 5, 2026 23:51
zkochan added a commit that referenced this pull request May 6, 2026
… 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.
zkochan added a commit that referenced this pull request May 6, 2026
… 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pnpm --recursive + --filter includes workspace root (regression since 10.33.0) --filter doesn't find root package with pnpm-workspace.yaml

2 participants