Skip to content

feat(pacquet/cli): apply --filter selection in recursive run and exec#12712

Merged
zkochan merged 8 commits into
mainfrom
claude/pacquet-filter-recursive-path-ng3tt2
Jun 29, 2026
Merged

feat(pacquet/cli): apply --filter selection in recursive run and exec#12712
zkochan merged 8 commits into
mainfrom
claude/pacquet-filter-recursive-path-ng3tt2

Conversation

@KSXGitHub

@KSXGitHub KSXGitHub commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Wires pnpm's --filter / --filter-prod workspace selection into pacquet's recursive command path — the primary (titular) blocker from the issue. The recursive run / exec / pack runners used to operate on every workspace project; the selectors were parsed into Config::filter / Config::filter_prod but never narrowed the set.

A shared helper, cli_args::recursive::select_recursive_projects, builds the workspace graph over all projects and restricts it to the selection — include selectors unioned, !-prefixed excludes (e.g. !pnpm) subtracted — mirroring the selectedProjectsGraph pnpm hands its recursive handlers in main.ts. run -r, exec -r, and pack -r all route through it, so --filter is one cross-cutting selection path for every recursive command. With no selectors every project is selected, so unfiltered behavior is unchanged. The selectors resolve against the same graph options used for the topological sort, so the selected set and run order agree on edges. Recursive run's no-script error now distinguishes "None of the packages" from "None of the selected packages", keyed on whether the filter narrowed the set. When --filter narrows a non-empty workspace to no projects, recursive run / exec exit 0 (no-op) instead of erroring on --resume-from or writing an empty --report-summary, matching pnpm's main-dispatch exit-0 for an empty selection.

The two smaller publish-only prerequisites from the issue (the reusable already-published check and the pnpm-publish-summary.json writer) are not yet in this PR: they have no consumer in the current tree (recursive publish lives in the separate assembly PR) and would be dead code under the workspace's -D warnings, so they land best alongside the publish command that calls them.

Resolves #12711.

Squash Commit Body

The recursive `run` / `exec` / `pack` command path operated on every
workspace project; the `--filter` / `--filter-prod` selectors were parsed
into `Config::filter` / `Config::filter_prod` but never narrowed the set.

Add `select_recursive_projects`, a shared helper that builds the workspace
graph over all projects and restricts it to the selectors' selection
(include selectors unioned, `!`-prefixed excludes subtracted), mirroring
the `selectedProjectsGraph` pnpm hands its recursive handlers in main.ts.
`run -r`, `exec -r`, and `pack -r` all route through it. The selectors
resolve against the same graph options used for the sort, so the selected
set and the topological order agree. With no selectors every project is
selected, so unfiltered behavior is unchanged.

The recursive `run` no-script error now distinguishes "None of the
packages" from "None of the selected packages", keyed on whether the
filter narrowed the set. An empty selection over a non-empty workspace is
a no-op (exit 0) rather than erroring on `--resume-from` or writing an
empty `--report-summary`, matching pnpm's main-dispatch exit-0.

Checklist

  • The change is implemented in both the TypeScript CLI and the Rust pacquet/ port: this is the pacquet port of behavior the TypeScript CLI already has (--filter in recursive run / exec / pack).
  • Added or updated tests: integration tests for include-selection, !-exclude selection, the --filter-prod production-only dependency walk (a dev-only edge is dropped by the ... selector, so --filter-prod cannot collapse to --filter), the "None of the selected packages" error, and the empty-selection no-op on run / exec, plus a pack -r --filter selection test.

Summary by CodeRabbit

  • New Features

    • Recursive run, exec, and pack now narrow execution to --filter / --filter-prod-selected workspace projects (topological order, sequential).
    • If the recursive --filter matches no projects, the command succeeds without running anything.
  • Bug Fixes

    • Improved handling and messaging for “no script” cases, distinguishing between “none in selected projects” vs “none in any package.”
    • Prevents exec summary output when nothing is selected/executed.
  • Tests

    • Added integration coverage for filtered recursive run, exec, and pack behaviors (including --filter-prod and failure modes).
  • Documentation

    • Updated recursive command documentation and filtering guidance.

The recursive `run` / `exec` command path operated on every workspace
project; the `--filter` / `--filter-prod` selectors were parsed into
`Config::filter` / `Config::filter_prod` but never narrowed the set.

Add `select_recursive_projects`, a shared helper that builds the
workspace graph over all projects and restricts it to the selectors'
selection — include selectors unioned, `!`-prefixed excludes subtracted —
mirroring the `selectedProjectsGraph` pnpm hands its recursive handlers in
main.ts. With no selectors every project is selected, so the unfiltered
behavior is unchanged. The recursive `run` no-script error now
distinguishes "None of the packages" from "None of the selected packages"
the way pnpm does, keyed on whether the filter narrowed the set.

Refs #12711

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgEs4dECzHdR3aj19DLxiD
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 91edd68f-08d6-4b9c-a065-f64f8f1276ed

📥 Commits

Reviewing files that changed from the base of the PR and between 9e7721b and 7916c2e.

📒 Files selected for processing (1)
  • pacquet/crates/cli/tests/run_recursive.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • pacquet/crates/cli/tests/run_recursive.rs

📝 Walkthrough

Walkthrough

Shared helpers for workspace discovery and recursive project selection are added, and recursive run, exec, and pack now use them for --filter/--filter-prod narrowing. Recursive run adds a selected-set script error variant, and new integration tests cover filtered selection, exclusion, no-match, and production-only traversal.

Changes

--filter support for recursive run/exec/pack

Layer / File(s) Summary
Shared workspace discovery and filter-selection helpers
pacquet/crates/cli/src/cli_args/recursive.rs
Adds discover_workspace_projects and select_recursive_projects, expands imports for workspace manifest reading, filtering, and graph construction, updates module docs, and adds Clone/Copy to GraphPkg.
Recursive run: shared helpers and NoSelectedScript
pacquet/crates/cli/src/cli_args/run.rs, pacquet/crates/cli/src/cli_args/run/recursive.rs
Replaces inline workspace discovery and graph construction with the shared helpers, adds RecursiveRunError::NoSelectedScript, and refines the empty-selection and no-command error paths.
Recursive exec and pack use shared helpers
pacquet/crates/cli/src/cli_args/exec.rs, pacquet/crates/cli/src/cli_args/exec/recursive.rs, pacquet/crates/cli/src/cli_args/pack.rs
Switches recursive exec and pack to discover_workspace_projects / select_recursive_projects, and updates the recursive-mode doc comments.
Recursive filter tests and porting notes
pacquet/crates/cli/tests/run_recursive.rs, pacquet/crates/cli/tests/exec_recursive.rs, pacquet/crates/cli/tests/pack_recursive.rs, pacquet/plans/TEST_PORTING.md
Adds recursive run/exec/pack integration tests for filtered selection, exclusion, no-match success, selected-set script failures, and production-only traversal, and updates the porting notes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

  • pnpm/pnpm#12093: Modifies the same recursive run machinery that this PR refactors for filtered selection and empty-selection behavior.
  • pnpm/pnpm#12133: Also affects workspace enumeration for recursive commands and is closely related to how filtered project sets are derived.

Suggested labels

product: pacquet

Suggested reviewers

  • zkochan
✨ 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 claude/pacquet-filter-recursive-path-ng3tt2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Micro-Benchmark Results

Linux

group                          main                                   pr
-----                          ----                                   --
tarball/download_dependency    1.00      6.6±0.39ms   653.3 KB/sec    1.00      6.6±0.22ms   656.0 KB/sec

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
pacquet/crates/cli/tests/run_recursive.rs (1)

132-135: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prefer // comments here, or let the test names speak for themselves.

These /// blocks describe the test scenarios rather than a rustdoc-visible API contract, and they mostly restate what the test names/assertions already say. As per path instructions, "Use doc comments for rustdoc-visible API contracts, and use regular // comments only for non-obvious implementation rationale" and "Do not duplicate tests in prose: if a behavior is already covered by a test, keep the doc comment focused on the contract rather than re-narrating the test case."

Also applies to: 171-173, 205-209

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pacquet/crates/cli/tests/run_recursive.rs` around lines 132 - 135, The
`run_recursive` tests are using rustdoc-style `///` comments for scenario
narration instead of API contracts. Replace the `///` blocks in the affected
test cases with regular `//` comments, or remove them if the test names and
assertions already make the behavior clear. Keep any remaining comments focused
on non-obvious rationale, and avoid restating what the test itself verifies in
prose.

Source: Path instructions

pacquet/crates/cli/tests/exec_recursive.rs (1)

75-77: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use plain comments here, or drop the prose entirely.

These /// lines re-narrate the test case instead of documenting a rustdoc-visible API contract, and the test name already captures the behavior. As per path instructions, "Use doc comments for rustdoc-visible API contracts, and use regular // comments only for non-obvious implementation rationale" and "Do not duplicate tests in prose: if a behavior is already covered by a test, keep the doc comment focused on the contract rather than re-narrating the test case."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pacquet/crates/cli/tests/exec_recursive.rs` around lines 75 - 77, The
`exec_recursive.rs` comment is test narration rather than a rustdoc-visible API
contract. Replace the `///` prose near the recursive exec test with plain `//`
comments if you need implementation rationale, or remove it entirely since
`test_recursive_exec_filter` already covers the behavior. Keep only
contract-focused rustdoc on public API symbols and avoid duplicating the test
case in doc comments.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pacquet/crates/cli/src/cli_args/exec/recursive.rs`:
- Around line 64-74: Short-circuit the recursive exec flow when the filtered
selection is empty so it behaves like pnpm. In the recursive exec dispatch path
around `discover_workspace_projects`, `select_recursive_projects`, and
`graph.is_empty()`, return early before calling `get_resumed_package_chunks` or
`write_recursive_summary` when no projects match the filter, while still keeping
`RecursiveExecError::NoPackage` for an empty discovered workspace. This keeps
`--resume-from` and `--report-summary` from running on an empty graph and
preserves the no-op contract.

---

Nitpick comments:
In `@pacquet/crates/cli/tests/exec_recursive.rs`:
- Around line 75-77: The `exec_recursive.rs` comment is test narration rather
than a rustdoc-visible API contract. Replace the `///` prose near the recursive
exec test with plain `//` comments if you need implementation rationale, or
remove it entirely since `test_recursive_exec_filter` already covers the
behavior. Keep only contract-focused rustdoc on public API symbols and avoid
duplicating the test case in doc comments.

In `@pacquet/crates/cli/tests/run_recursive.rs`:
- Around line 132-135: The `run_recursive` tests are using rustdoc-style `///`
comments for scenario narration instead of API contracts. Replace the `///`
blocks in the affected test cases with regular `//` comments, or remove them if
the test names and assertions already make the behavior clear. Keep any
remaining comments focused on non-obvious rationale, and avoid restating what
the test itself verifies in prose.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d42ce06c-e7d1-49eb-92a9-12a790330e46

📥 Commits

Reviewing files that changed from the base of the PR and between 517ea5d and 806973a.

📒 Files selected for processing (7)
  • pacquet/crates/cli/src/cli_args/exec.rs
  • pacquet/crates/cli/src/cli_args/exec/recursive.rs
  • pacquet/crates/cli/src/cli_args/recursive.rs
  • pacquet/crates/cli/src/cli_args/run/recursive.rs
  • pacquet/crates/cli/tests/exec_recursive.rs
  • pacquet/crates/cli/tests/run_recursive.rs
  • pacquet/plans/TEST_PORTING.md

Comment thread pacquet/crates/cli/src/cli_args/exec/recursive.rs
@codecov-commenter

codecov-commenter commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.38%. Comparing base (1dd12bd) to head (7916c2e).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #12712      +/-   ##
==========================================
+ Coverage   85.20%   85.38%   +0.17%     
==========================================
  Files         397      397              
  Lines       61268    61304      +36     
==========================================
+ Hits        52206    52342     +136     
+ Misses       9062     8962     -100     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…tion

Address review feedback on the --filter wiring:

- When --filter narrows a non-empty workspace to no projects, recursive
  run/exec now exit 0 instead of erroring on --resume-from or writing an
  empty --report-summary summary, matching pnpm's main-dispatch exit-0 for
  an empty selectedProjectsGraph (main.ts).
- Resolve the selectors against the same graph options used for the
  topological sort, so the selected set and the run order agree on edges
  (upstream reads one linkWorkspacePackages-aware graph for both).

Empty-workspace handling (recursive run -> no-script error, exec ->
NO_PACKAGE) is left as-is; it predates --filter and is orthogonal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgEs4dECzHdR3aj19DLxiD
@github-actions github-actions Bot added the reviewed: coderabbit CodeRabbit submitted an approving review label Jun 29, 2026
claude added 2 commits June 29, 2026 03:24
Route `pack -r`'s workspace sweep through the shared
`select_recursive_projects` helper that `run -r` / `exec -r` use, so
`pack -r --filter` narrows which projects are packed instead of silently
packing every project. Keeps `--filter` a single cross-cutting selection
path across all recursive commands.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgEs4dECzHdR3aj19DLxiD
… run

Add a recursive-run integration test that narrows the workspace with
`--filter-prod`, exercising the `follow_prod_deps_only: true` branch of
`select_recursive_projects` that the `--filter`-only tests never reached
(flagged uncovered by Codecov).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgEs4dECzHdR3aj19DLxiD

@KSXGitHub KSXGitHub left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Code comments should explain the why, not the what.

Code comments should not explain the obvious.

If the code is already self-documenting, the code comments would be unnecessary.

Code comments should be succinct.

Comment thread pacquet/crates/cli/src/cli_args/exec/recursive.rs Outdated
Comment thread pacquet/crates/cli/src/cli_args/run/recursive.rs Outdated
Comment thread pacquet/crates/cli/src/cli_args/exec/recursive.rs Outdated
Comment thread pacquet/crates/cli/src/cli_args/recursive.rs Outdated
claude added 3 commits June 29, 2026 03:45
Per review, make the comments added for `--filter` selection succinct:
keep the non-obvious "why", drop restatement of self-documenting code and
narration of pnpm's behavior.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgEs4dECzHdR3aj19DLxiD
The recursive `run` / `exec` / `pack` function- and module-level doc
comments still said the command runs over "every workspace project"; with
`--filter` wired in they run over the selected subset. Update them to
match the code.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgEs4dECzHdR3aj19DLxiD
…cher docs

Follow-up: the `RunArgs::run_recursive` / `ExecArgs::run_recursive`
dispatcher docs and the `PackArgs::run` summary still said the recursive
command runs over "every project"; with `--filter` wired in they run over
the selected subset. The global `--recursive` flag help is left as-is — it
describes `-r`'s workspace-wide-vs-single behavior, and `--filter`
narrowing is a separate flag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgEs4dECzHdR3aj19DLxiD
@KSXGitHub KSXGitHub marked this pull request as ready for review June 29, 2026 04:09
@KSXGitHub KSXGitHub requested a review from zkochan as a code owner June 29, 2026 04:09

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pacquet/crates/cli/tests/run_recursive.rs`:
- Around line 243-279: The recursive run test currently uses a flat workspace
where `--filter-prod` behaves the same as `--filter`, so it does not prove the
`follow_prod_deps_only` path. Update
`recursive_run_filter_prod_selects_only_matching_project` to build a dependency
graph in `write_workspace` and use an ellipsis-style selector in the `pacquet`
command so a dev-only edge is skipped by prod-only traversal. Make the
assertions in `run_recursive.rs` verify that the selected project runs while the
dev-only dependent does not, ensuring the test fails if `--filter-prod` is
ignored.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0ba754fa-a6a0-46ce-b209-2b37e0eed991

📥 Commits

Reviewing files that changed from the base of the PR and between 806973a and 9e7721b.

📒 Files selected for processing (9)
  • pacquet/crates/cli/src/cli_args/exec.rs
  • pacquet/crates/cli/src/cli_args/exec/recursive.rs
  • pacquet/crates/cli/src/cli_args/pack.rs
  • pacquet/crates/cli/src/cli_args/recursive.rs
  • pacquet/crates/cli/src/cli_args/run.rs
  • pacquet/crates/cli/src/cli_args/run/recursive.rs
  • pacquet/crates/cli/tests/exec_recursive.rs
  • pacquet/crates/cli/tests/pack_recursive.rs
  • pacquet/crates/cli/tests/run_recursive.rs
✅ Files skipped from review due to trivial changes (2)
  • pacquet/crates/cli/src/cli_args/run.rs
  • pacquet/crates/cli/src/cli_args/exec.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • pacquet/crates/cli/src/cli_args/exec/recursive.rs
  • pacquet/crates/cli/src/cli_args/recursive.rs

Comment thread pacquet/crates/cli/tests/run_recursive.rs Outdated
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Integrated-Benchmark Report (Linux)

Commit: 7916c2e8c9d4

Each scenario reports direct installs and pnpr installs. Bencher consumes pacquet@HEAD and pnpr@HEAD.

Scenario: Isolated linker: fresh restore, cold cache + cold store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 4.487 ± 0.193 4.304 4.907 1.60 ± 0.09
pacquet@main 4.491 ± 0.157 4.227 4.712 1.60 ± 0.09
pnpr@HEAD 2.800 ± 0.112 2.710 3.107 1.00
pnpr@main 2.933 ± 0.149 2.716 3.115 1.05 ± 0.07
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 4.48653084012,
      "stddev": 0.19295210362209303,
      "median": 4.4265304720200005,
      "user": 3.638274719999999,
      "system": 3.4292433599999996,
      "min": 4.30368774102,
      "max": 4.90681767602,
      "times": [
        4.3395571230200005,
        4.67665396702,
        4.30368774102,
        4.90681767602,
        4.46199045202,
        4.58841308702,
        4.331179076020001,
        4.391070492020001,
        4.339998431020001,
        4.52594035602
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 4.490783734320001,
      "stddev": 0.15729770147557282,
      "median": 4.5219354665200004,
      "user": 3.6861129200000002,
      "system": 3.4039325600000003,
      "min": 4.226940245020001,
      "max": 4.71204139702,
      "times": [
        4.3480436430200005,
        4.640615518020001,
        4.35545138402,
        4.226940245020001,
        4.64548279502,
        4.556273998020001,
        4.50880875002,
        4.53506218302,
        4.71204139702,
        4.37911743002
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 2.80034115922,
      "stddev": 0.11213457964401026,
      "median": 2.76671254102,
      "user": 2.7166617200000003,
      "system": 3.00985056,
      "min": 2.70974412202,
      "max": 3.10689478402,
      "times": [
        2.76632056102,
        3.10689478402,
        2.75889873402,
        2.81059402102,
        2.81510126602,
        2.76710452102,
        2.70974412202,
        2.73710514502,
        2.77807909502,
        2.75356934302
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 2.9332105469200003,
      "stddev": 0.14918110737710258,
      "median": 2.9658077375199996,
      "user": 2.7481996200000003,
      "system": 2.9998306599999998,
      "min": 2.71615672302,
      "max": 3.11548399902,
      "times": [
        3.11526527402,
        2.9637660380199997,
        2.96784943702,
        2.79508214802,
        3.11548399902,
        3.04629320402,
        2.71615672302,
        2.81054016502,
        2.76728645502,
        3.03438202602
      ]
    }
  ]
}

Scenario: Isolated linker: fresh restore, hot cache + hot store

Command Mean [ms] Min [ms] Max [ms] Relative
pacquet@HEAD 641.5 ± 6.3 631.7 652.5 1.00
pacquet@main 648.8 ± 22.9 633.3 708.5 1.01 ± 0.04
pnpr@HEAD 712.2 ± 85.5 666.8 952.8 1.11 ± 0.13
pnpr@main 714.8 ± 66.9 661.4 893.4 1.11 ± 0.10
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 0.6414991372000001,
      "stddev": 0.006296980245139435,
      "median": 0.6396077336,
      "user": 0.38669926,
      "system": 1.32146678,
      "min": 0.6316751726000001,
      "max": 0.6524629946,
      "times": [
        0.6452912726000001,
        0.6385423586,
        0.6371066886,
        0.6384151826000001,
        0.6524629946,
        0.6406731086,
        0.6375840426,
        0.6497636476,
        0.6434769036,
        0.6316751726000001
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 0.6487974767999999,
      "stddev": 0.022883328726511255,
      "median": 0.6407335561,
      "user": 0.38451576000000004,
      "system": 1.3261082800000001,
      "min": 0.6332925506,
      "max": 0.7085021596000001,
      "times": [
        0.6396564606,
        0.6598811186,
        0.6418106516000001,
        0.6353425456,
        0.6332925506,
        0.6567510846,
        0.7085021596000001,
        0.6420561446,
        0.6347687686,
        0.6359132836
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 0.7121894315,
      "stddev": 0.08550312885388064,
      "median": 0.6888514286,
      "user": 0.39725235999999997,
      "system": 1.3625840799999998,
      "min": 0.6667821226,
      "max": 0.9527850786000001,
      "times": [
        0.6667821226,
        0.6877311086,
        0.7087916386,
        0.6958540656000001,
        0.6785248006,
        0.6692750446,
        0.6944968506,
        0.6776818566,
        0.6899717486,
        0.9527850786000001
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 0.714843863,
      "stddev": 0.06685560087233182,
      "median": 0.7006133486,
      "user": 0.39429265999999996,
      "system": 1.35310868,
      "min": 0.6613618926,
      "max": 0.8934338826,
      "times": [
        0.7078926256,
        0.6613618926,
        0.6740636086,
        0.6861371666,
        0.7076932816,
        0.6994542356,
        0.7017724616000001,
        0.8934338826,
        0.7429038316000001,
        0.6737256436
      ]
    }
  ]
}

Scenario: Isolated linker: fresh install, cold cache + cold store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 4.639 ± 0.029 4.596 4.684 1.64 ± 0.09
pacquet@main 4.673 ± 0.031 4.627 4.720 1.65 ± 0.09
pnpr@HEAD 2.830 ± 0.051 2.747 2.937 1.00 ± 0.06
pnpr@main 2.827 ± 0.149 2.691 3.107 1.00
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 4.638779452780001,
      "stddev": 0.029221709329276438,
      "median": 4.63622759548,
      "user": 3.77169818,
      "system": 3.3613968,
      "min": 4.596222801980001,
      "max": 4.68350731998,
      "times": [
        4.67636901098,
        4.64180086098,
        4.68350731998,
        4.62304783198,
        4.663674432980001,
        4.62514626098,
        4.64462217598,
        4.6306543299800005,
        4.596222801980001,
        4.60274950198
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 4.672536613779999,
      "stddev": 0.03058227077085526,
      "median": 4.67416270398,
      "user": 3.8268929799999993,
      "system": 3.4017838999999994,
      "min": 4.62732041998,
      "max": 4.7200153699800005,
      "times": [
        4.68585136898,
        4.67271249498,
        4.68833890398,
        4.62732041998,
        4.70814039298,
        4.63781395098,
        4.63777463498,
        4.67561291298,
        4.67178568798,
        4.7200153699800005
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 2.8296072422800003,
      "stddev": 0.050654347753167635,
      "median": 2.83871381298,
      "user": 2.5398891800000003,
      "system": 2.9591541999999995,
      "min": 2.74658689398,
      "max": 2.93721164898,
      "times": [
        2.8531418749800004,
        2.8369297059800003,
        2.74658689398,
        2.93721164898,
        2.7887375109800003,
        2.80041212998,
        2.80073228998,
        2.84784560298,
        2.8404979199800002,
        2.8439768449800003
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 2.82699047428,
      "stddev": 0.14894220324635546,
      "median": 2.7735073759800004,
      "user": 2.61169528,
      "system": 2.9461730000000004,
      "min": 2.6905184009800003,
      "max": 3.10707874198,
      "times": [
        2.80011688998,
        2.78684981398,
        2.7286767109800003,
        2.6905184009800003,
        2.75744518798,
        3.10707874198,
        3.09983133798,
        2.7761100449800002,
        2.7523729069800003,
        2.77090470698
      ]
    }
  ]
}

Scenario: Isolated linker: fresh install, hot cache + hot store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 1.354 ± 0.020 1.309 1.381 2.04 ± 0.04
pacquet@main 1.356 ± 0.013 1.343 1.375 2.04 ± 0.03
pnpr@HEAD 0.695 ± 0.069 0.658 0.888 1.05 ± 0.10
pnpr@main 0.664 ± 0.008 0.655 0.679 1.00
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 1.3538463124,
      "stddev": 0.019825555835418316,
      "median": 1.3541255104,
      "user": 1.3748597599999999,
      "system": 1.6883564800000002,
      "min": 1.3093299394,
      "max": 1.3812235354,
      "times": [
        1.3519583534000001,
        1.3391216654,
        1.3751512004,
        1.3812235354,
        1.3632357894,
        1.3533237864,
        1.3595258274,
        1.3506657924,
        1.3549272344,
        1.3093299394
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 1.3564176363,
      "stddev": 0.01287492186127889,
      "median": 1.3507535024,
      "user": 1.3526240599999997,
      "system": 1.7042762799999998,
      "min": 1.3430140044,
      "max": 1.3751327794,
      "times": [
        1.3449943244,
        1.3450876184,
        1.3711631614,
        1.3511099804,
        1.3430140044,
        1.3473478164000001,
        1.3751327794,
        1.3619518874,
        1.3503970244,
        1.3739777664
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 0.6953963577,
      "stddev": 0.0688564718908115,
      "median": 0.6713930449000001,
      "user": 0.35984395999999996,
      "system": 1.31404388,
      "min": 0.6582961724,
      "max": 0.8881333054,
      "times": [
        0.6582961724,
        0.6829171984,
        0.6623281064000001,
        0.6712636044,
        0.8881333054,
        0.7036565404,
        0.6715224854,
        0.6700126864,
        0.6695887814,
        0.6762446964000001
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 0.6641545377,
      "stddev": 0.007653190105480283,
      "median": 0.6622168158999999,
      "user": 0.34687426,
      "system": 1.2893423800000001,
      "min": 0.6548126534,
      "max": 0.6794254904,
      "times": [
        0.6590616144,
        0.6582780974,
        0.6612627214,
        0.6660755964,
        0.6794254904,
        0.6637856654000001,
        0.6751140554,
        0.6605585724,
        0.6548126534,
        0.6631709104
      ]
    }
  ]
}

Scenario: Isolated linker: fresh install, cold cache + hot store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 3.011 ± 0.025 2.983 3.055 4.53 ± 0.09
pacquet@main 3.035 ± 0.020 2.993 3.065 4.56 ± 0.09
pnpr@HEAD 0.680 ± 0.008 0.670 0.691 1.02 ± 0.02
pnpr@main 0.665 ± 0.012 0.650 0.692 1.00
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 3.01110583484,
      "stddev": 0.024799241229634474,
      "median": 3.00185970114,
      "user": 1.8219819799999997,
      "system": 1.9764901599999998,
      "min": 2.98343945314,
      "max": 3.05464364714,
      "times": [
        2.99042118814,
        2.98933740614,
        3.00069450814,
        2.98343945314,
        3.00222816414,
        3.04980101114,
        3.02471687114,
        3.05464364714,
        3.0142848611399997,
        3.00149123814
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 3.0348876979400004,
      "stddev": 0.019665292992957255,
      "median": 3.03572863414,
      "user": 1.8164741800000002,
      "system": 1.9756236599999997,
      "min": 2.99334059514,
      "max": 3.06492587114,
      "times": [
        3.02756918014,
        3.03688620214,
        3.05910646914,
        3.03752721914,
        3.03457106614,
        3.02227926014,
        3.04067859314,
        3.06492587114,
        3.03199252314,
        2.99334059514
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 0.6802280244400001,
      "stddev": 0.008179439470023702,
      "median": 0.68012045014,
      "user": 0.36245348,
      "system": 1.3217714600000001,
      "min": 0.66954828314,
      "max": 0.6908646381400001,
      "times": [
        0.6719712951400001,
        0.68232395914,
        0.67484345514,
        0.67211760614,
        0.66954828314,
        0.6908646381400001,
        0.69033749014,
        0.6779708951400001,
        0.68227000514,
        0.6900326171400001
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 0.6649204340400001,
      "stddev": 0.011724692687738401,
      "median": 0.66361970014,
      "user": 0.35843878,
      "system": 1.28015296,
      "min": 0.64950446214,
      "max": 0.69199124414,
      "times": [
        0.66198422814,
        0.6569522171400001,
        0.6655111491400001,
        0.64950446214,
        0.6652551721400001,
        0.6584795681400001,
        0.66798642214,
        0.6573487841400001,
        0.67419109314,
        0.69199124414
      ]
    }
  ]
}

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchpr/12712
Testbedpacquet
Click to view all benchmark results
BenchmarkLatencyBenchmark Result
milliseconds (ms)
(Result Δ%)
Upper Boundary
milliseconds (ms)
(Limit %)
isolated-linker.fresh-install.cold-cache.cold-store📈 view plot
🚷 view threshold
4,638.78 ms
(-2.40%)Baseline: 4,752.65 ms
5,703.18 ms
(81.34%)
isolated-linker.fresh-install.cold-cache.hot-store📈 view plot
🚷 view threshold
3,011.11 ms
(-1.23%)Baseline: 3,048.69 ms
3,658.43 ms
(82.31%)
isolated-linker.fresh-install.hot-cache.hot-store📈 view plot
🚷 view threshold
1,353.85 ms
(-0.24%)Baseline: 1,357.15 ms
1,628.58 ms
(83.13%)
isolated-linker.fresh-restore.cold-cache.cold-store📈 view plot
🚷 view threshold
4,486.53 ms
(-7.21%)Baseline: 4,835.12 ms
5,802.15 ms
(77.33%)
isolated-linker.fresh-restore.hot-cache.hot-store📈 view plot
🚷 view threshold
641.50 ms
(-1.11%)Baseline: 648.70 ms
778.44 ms
(82.41%)
🐰 View full continuous benchmarking report in Bencher

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchpr/12712
Testbedpnpr

⚠️ WARNING: No Threshold found!

Without a Threshold, no Alerts will ever be generated.

Click here to create a new Threshold
For more information, see the Threshold documentation.
To only post results if a Threshold exists, set the --ci-only-thresholds flag.

Click to view all benchmark results
BenchmarkLatencymilliseconds (ms)
isolated-linker.fresh-install.cold-cache.cold-store📈 view plot
⚠️ NO THRESHOLD
2,829.61 ms
isolated-linker.fresh-install.cold-cache.hot-store📈 view plot
⚠️ NO THRESHOLD
680.23 ms
isolated-linker.fresh-install.hot-cache.hot-store📈 view plot
⚠️ NO THRESHOLD
695.40 ms
isolated-linker.fresh-restore.cold-cache.cold-store📈 view plot
⚠️ NO THRESHOLD
2,800.34 ms
isolated-linker.fresh-restore.hot-cache.hot-store📈 view plot
⚠️ NO THRESHOLD
712.19 ms
🐰 View full continuous benchmarking report in Bencher

The flat-workspace fixture passed even if `follow_prod_deps_only` were
ignored: with no dependency edges, `--filter-prod app` and `--filter app`
select the same set, so the test could not tell them apart.

Replace it with a dev-only edge (`app` devDependencies `lib`) and the
`app...` ellipsis selector, so `--filter-prod`'s production-only
dependency walk must drop the dev edge. The test runs `app` and asserts
`lib` is skipped, failing if `--filter-prod` collapses to `--filter`.
@zkochan zkochan added this pull request to the merge queue Jun 29, 2026
Merged via the queue into main with commit 4cd45a3 Jun 29, 2026
36 checks passed
@zkochan zkochan deleted the claude/pacquet-filter-recursive-path-ng3tt2 branch June 29, 2026 06:25
KSXGitHub pushed a commit that referenced this pull request Jun 29, 2026
Bring in the latest main: #12712 wires `--filter` selection into
the recursive `run` / `exec` dispatch via the shared
`select_recursive_projects` helper (the prerequisite for recursive
publishing), and #12713 lands the same precompile-benchmark-revisions
timeout bump already carried on this branch. Clean auto-merge, no conflicts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KtBQzmLLDU3RcGzzCMopPB
KSXGitHub pushed a commit that referenced this pull request Jun 29, 2026
Implement `pacquet publish --recursive`, mirroring pnpm's `recursivePublish`.
With the `--filter` selection now wired into the recursive dispatch
(#12712), `publish -r` selects the workspace projects the selectors
pick, drops the private / unnamed / already-published ones (unless `--force`),
and publishes the rest one dependency-ordered chunk at a time — publishing
serially because an OTP challenge is interactive and per-process. Each
per-package publish reuses the single-package path with git checks already
done once for the workspace, matching upstream's `gitChecks: false` per
sub-publish. `--report-summary` writes `pnpm-publish-summary.json` with the
`{ publishedPackages }` shape.

The already-published check resolves `name@version` against the package's
registry via the npm resolver's metadata fetch; any failure (a 404 for a
new package, a transient network error) is treated as "not published", as
in pnpm's `isAlreadyPublished` catch-all.

`--batch` (a single batched request to a pnpr-style registry) remains
unported and now fails fast with an explicit message instead of the generic
recursive-unsupported error.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KtBQzmLLDU3RcGzzCMopPB
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

product: pacquet reviewed: coderabbit CodeRabbit submitted an approving review state: automerge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pacquet: wire --filter workspace selection into the recursive command path (prerequisite for recursive publish)

4 participants