feat(pacquet/cli): apply --filter selection in recursive run and exec#12712
Conversation
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
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughShared helpers for workspace discovery and recursive project selection are added, and recursive Changes--filter support for recursive run/exec/pack
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Micro-Benchmark ResultsLinux |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
pacquet/crates/cli/tests/run_recursive.rs (1)
132-135: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winPrefer
//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 winUse 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
📒 Files selected for processing (7)
pacquet/crates/cli/src/cli_args/exec.rspacquet/crates/cli/src/cli_args/exec/recursive.rspacquet/crates/cli/src/cli_args/recursive.rspacquet/crates/cli/src/cli_args/run/recursive.rspacquet/crates/cli/tests/exec_recursive.rspacquet/crates/cli/tests/run_recursive.rspacquet/plans/TEST_PORTING.md
Codecov Report✅ All modified and coverable lines are covered by tests. 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. 🚀 New features to boost your workflow:
|
…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
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
left a comment
There was a problem hiding this comment.
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.
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
There was a problem hiding this comment.
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
📒 Files selected for processing (9)
pacquet/crates/cli/src/cli_args/exec.rspacquet/crates/cli/src/cli_args/exec/recursive.rspacquet/crates/cli/src/cli_args/pack.rspacquet/crates/cli/src/cli_args/recursive.rspacquet/crates/cli/src/cli_args/run.rspacquet/crates/cli/src/cli_args/run/recursive.rspacquet/crates/cli/tests/exec_recursive.rspacquet/crates/cli/tests/pack_recursive.rspacquet/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
Integrated-Benchmark Report (Linux)Commit: Each scenario reports direct installs and pnpr installs. Bencher consumes pacquet@HEAD and pnpr@HEAD. Scenario: Isolated linker: fresh restore, cold cache + cold store
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
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
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
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
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
]
}
]
} |
|
| Branch | pr/12712 |
| Testbed | pacquet |
Click to view all benchmark results
| Benchmark | Latency | Benchmark 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%) |
|
| Branch | pr/12712 |
| Testbed | pnpr |
⚠️ 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-thresholdsflag.
Click to view all benchmark results
| Benchmark | Latency | milliseconds (ms) |
|---|---|---|
| isolated-linker.fresh-install.cold-cache.cold-store | 📈 view plot | 2,829.61 ms |
| isolated-linker.fresh-install.cold-cache.hot-store | 📈 view plot | 680.23 ms |
| isolated-linker.fresh-install.hot-cache.hot-store | 📈 view plot | 695.40 ms |
| isolated-linker.fresh-restore.cold-cache.cold-store | 📈 view plot | 2,800.34 ms |
| isolated-linker.fresh-restore.hot-cache.hot-store | 📈 view plot | 712.19 ms |
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`.
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
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
Summary
Wires pnpm's
--filter/--filter-prodworkspace selection into pacquet's recursive command path — the primary (titular) blocker from the issue. The recursiverun/exec/packrunners used to operate on every workspace project; the selectors were parsed intoConfig::filter/Config::filter_prodbut 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 theselectedProjectsGraphpnpm hands its recursive handlers inmain.ts.run -r,exec -r, andpack -rall route through it, so--filteris 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. Recursiverun'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--filternarrows a non-empty workspace to no projects, recursiverun/execexit 0 (no-op) instead of erroring on--resume-fromor 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.jsonwriter) 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
Checklist
pacquet/port: this is the pacquet port of behavior the TypeScript CLI already has (--filterin recursiverun/exec/pack).!-exclude selection, the--filter-prodproduction-only dependency walk (a dev-only edge is dropped by the...selector, so--filter-prodcannot collapse to--filter), the "None of the selected packages" error, and the empty-selection no-op onrun/exec, plus apack -r --filterselection test.Summary by CodeRabbit
New Features
run,exec, andpacknow narrow execution to--filter/--filter-prod-selected workspace projects (topological order, sequential).--filtermatches no projects, the command succeeds without running anything.Bug Fixes
execsummary output when nothing is selected/executed.Tests
run,exec, andpackbehaviors (including--filter-prodand failure modes).Documentation