fix(pacquet): support recursive project listing#12848
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe list CLI now supports recursive workspace listing, forwards the recursive flag through dispatch, and updates local output rendering and parsing behavior. A separate switch-version mapping now recognizes the ChangesRecursive list command flow
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Suggested labels: ✨ 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 |
PR Summary by QodoPacquet CLI: allow
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
Code Review by Qodo
Context used✅ Compliance rules (platform):
51 rules 1.
|
PR Code Suggestions ✨Latest suggestions up to bcfff0a Warning
Previous suggestionsSuggestions up to commit bb40324
Suggestions
|
||||||||||||||||||||||||||||||
Micro-Benchmark ResultsLinux |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #12848 +/- ##
==========================================
- Coverage 85.84% 85.62% -0.22%
==========================================
Files 448 449 +1
Lines 69558 69986 +428
==========================================
+ Hits 59709 59925 +216
- Misses 9849 10061 +212 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.152881940039999,
"stddev": 0.13421702250105774,
"median": 4.19242159164,
"user": 3.81019826,
"system": 3.4823563199999996,
"min": 3.94854923364,
"max": 4.33028517864,
"times": [
4.23157881764,
4.007818954639999,
4.33028517864,
4.17178343064,
3.94854923364,
4.28139507264,
4.06074956164,
4.2130597526399995,
4.26915624964,
4.01444314864
]
},
{
"command": "pacquet@main",
"mean": 4.07744507964,
"stddev": 0.1332408875761204,
"median": 4.01595162964,
"user": 3.8104067600000002,
"system": 3.44589752,
"min": 3.9416688046400004,
"max": 4.26450676164,
"times": [
3.97348734964,
3.97643180264,
3.97377213764,
4.055471456639999,
4.26450676164,
3.9416688046400004,
4.1244356696399995,
4.2437778676399995,
3.96543941364,
4.25545953264
]
},
{
"command": "pnpr@HEAD",
"mean": 2.05567175164,
"stddev": 0.07075487630152924,
"median": 2.05987321364,
"user": 2.64070026,
"system": 2.99751602,
"min": 1.94386012164,
"max": 2.13900419664,
"times": [
2.13634876464,
1.94386012164,
1.98899685964,
2.02031614164,
2.13900419664,
2.00447454664,
2.0029037676400003,
2.09943028564,
2.11463125664,
2.10675157564
]
},
{
"command": "pnpr@main",
"mean": 2.0861243814400003,
"stddev": 0.13702878160160592,
"median": 2.01759180064,
"user": 2.6472023600000005,
"system": 2.96351172,
"min": 1.94091217064,
"max": 2.34539882764,
"times": [
2.34539882764,
1.99202856964,
2.22930558464,
2.16614550264,
2.0030648396400004,
1.9786796226399999,
1.94091217064,
2.03211876164,
2.1953378846400002,
1.9782520506399999
]
}
]
}Scenario: Isolated linker: fresh restore, hot cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 0.64001491106,
"stddev": 0.011812198994178538,
"median": 0.63951689976,
"user": 0.37351614,
"system": 1.321026,
"min": 0.61913096376,
"max": 0.65691702976,
"times": [
0.61913096376,
0.64412978876,
0.63278749276,
0.6409922837600001,
0.65604717376,
0.63556951876,
0.63804151576,
0.64767428976,
0.6288590537600001,
0.65691702976
]
},
{
"command": "pacquet@main",
"mean": 0.65372895486,
"stddev": 0.07806841294697547,
"median": 0.63101982826,
"user": 0.36972594000000003,
"system": 1.3231692,
"min": 0.6136461507600001,
"max": 0.87442577276,
"times": [
0.64610656576,
0.6315359137600001,
0.63238467676,
0.63445272176,
0.61654292976,
0.63050374276,
0.62892962976,
0.6287614447600001,
0.6136461507600001,
0.87442577276
]
},
{
"command": "pnpr@HEAD",
"mean": 0.6971113189600001,
"stddev": 0.01394880198707752,
"median": 0.69537546276,
"user": 0.39836224,
"system": 1.3530887999999999,
"min": 0.6774956117600001,
"max": 0.72008328676,
"times": [
0.69171484876,
0.67920663376,
0.69395407876,
0.7047858837600001,
0.6968929997600001,
0.69679684676,
0.69299698576,
0.71718601376,
0.72008328676,
0.6774956117600001
]
},
{
"command": "pnpr@main",
"mean": 0.68977328656,
"stddev": 0.026310953004549782,
"median": 0.68915545126,
"user": 0.39202803999999997,
"system": 1.3410170999999997,
"min": 0.66180918776,
"max": 0.75487018576,
"times": [
0.66731069876,
0.6986604657600001,
0.6994531537600001,
0.69011537376,
0.68972904276,
0.67148551676,
0.68858185976,
0.75487018576,
0.66180918776,
0.67571738076
]
}
]
}Scenario: Isolated linker: fresh install, cold cache + cold store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 4.22419483874,
"stddev": 0.02727807993099961,
"median": 4.220838247340001,
"user": 3.7242448999999995,
"system": 3.3378434599999993,
"min": 4.190685745840001,
"max": 4.2715248828400005,
"times": [
4.190685745840001,
4.192019627840001,
4.22223560084,
4.219440893840001,
4.20158647384,
4.21580839784,
4.25818411784,
4.223152043840001,
4.247310602840001,
4.2715248828400005
]
},
{
"command": "pacquet@main",
"mean": 4.226148386740001,
"stddev": 0.04130619056456617,
"median": 4.220863896340001,
"user": 3.7181679,
"system": 3.3447957599999993,
"min": 4.17002972384,
"max": 4.28725437984,
"times": [
4.28725437984,
4.2447901988400005,
4.232114198840001,
4.20961359384,
4.18794215784,
4.26667536184,
4.17002972384,
4.182229196840001,
4.20593713784,
4.274897917840001
]
},
{
"command": "pnpr@HEAD",
"mean": 2.1829362899399998,
"stddev": 0.09681637851647654,
"median": 2.16709389784,
"user": 2.4835495,
"system": 2.89103956,
"min": 2.07789108684,
"max": 2.34546071184,
"times": [
2.14303711184,
2.20235666184,
2.34546071184,
2.09033907084,
2.1403007018399998,
2.07789108684,
2.09423249484,
2.19115068384,
2.34525027084,
2.1993441048399998
]
},
{
"command": "pnpr@main",
"mean": 2.13815998514,
"stddev": 0.07417790524325311,
"median": 2.14911346534,
"user": 2.4737620999999996,
"system": 2.8836227599999993,
"min": 2.03297788684,
"max": 2.27557740084,
"times": [
2.15310771084,
2.05673649384,
2.14928301884,
2.14894391184,
2.16557599784,
2.03297788684,
2.27557740084,
2.06399130984,
2.12035866484,
2.2150474558399997
]
}
]
}Scenario: Isolated linker: fresh install, hot cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 1.35484943534,
"stddev": 0.015942483654712254,
"median": 1.35098547614,
"user": 1.30789244,
"system": 1.69271914,
"min": 1.33496924814,
"max": 1.38663572114,
"times": [
1.35909195414,
1.38663572114,
1.3650181861400001,
1.37120454814,
1.34320541814,
1.34305726214,
1.34334106314,
1.35627894414,
1.33496924814,
1.3456920081400001
]
},
{
"command": "pacquet@main",
"mean": 1.37763532644,
"stddev": 0.03712632468680655,
"median": 1.36629350864,
"user": 1.31765104,
"system": 1.6949237400000001,
"min": 1.35318146014,
"max": 1.4787352711400001,
"times": [
1.35318146014,
1.3639066181400001,
1.36868039914,
1.4787352711400001,
1.37266569014,
1.39207604114,
1.35937896814,
1.3575517241400001,
1.36913185514,
1.3610452371400001
]
},
{
"command": "pnpr@HEAD",
"mean": 0.6616755592400001,
"stddev": 0.030920394918131772,
"median": 0.6555687611400001,
"user": 0.34152883999999994,
"system": 1.2832577400000003,
"min": 0.6388008101400001,
"max": 0.74678448214,
"times": [
0.65254199014,
0.6464679321400001,
0.64381471814,
0.74678448214,
0.6585955321400001,
0.65936798214,
0.6602476211400001,
0.6621369571400001,
0.6388008101400001,
0.6479975671400001
]
},
{
"command": "pnpr@main",
"mean": 0.65132565894,
"stddev": 0.008423488567772818,
"median": 0.6515928091400001,
"user": 0.34105394,
"system": 1.27172874,
"min": 0.6334627691400001,
"max": 0.6613157771400001,
"times": [
0.6608442471400001,
0.65214282314,
0.6613157771400001,
0.6334627691400001,
0.65959068214,
0.6510427951400001,
0.6530304691400001,
0.64497796514,
0.64833353914,
0.6485155221400001
]
}
]
}Scenario: Isolated linker: fresh install, cold cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 3.02112379162,
"stddev": 0.023020787216307608,
"median": 3.0138283869199998,
"user": 1.77585302,
"system": 1.94397652,
"min": 2.99360767942,
"max": 3.0662644064199998,
"times": [
3.03405283042,
3.00640395742,
3.01032499042,
3.0108149744199997,
3.02037564942,
2.99360767942,
3.01684179942,
3.0662644064199998,
3.00081901742,
3.05173261142
]
},
{
"command": "pacquet@main",
"mean": 3.03618421752,
"stddev": 0.07512892373559935,
"median": 3.0181541669199996,
"user": 1.7687727199999999,
"system": 1.9571121200000001,
"min": 2.99358411442,
"max": 3.24562400842,
"times": [
3.01900398642,
3.0173043474199996,
3.00362143942,
2.99358411442,
3.04423805242,
3.02128463742,
2.99365652042,
3.24562400842,
3.00404393642,
3.0194811324199997
]
},
{
"command": "pnpr@HEAD",
"mean": 0.67504738432,
"stddev": 0.008853246670759844,
"median": 0.67631966042,
"user": 0.34524772,
"system": 1.30926452,
"min": 0.65462059842,
"max": 0.68745472642,
"times": [
0.68280728642,
0.68745472642,
0.65462059842,
0.67323269042,
0.67125230142,
0.67569352942,
0.67993804742,
0.67794860242,
0.67058026942,
0.67694579142
]
},
{
"command": "pnpr@main",
"mean": 0.67752480262,
"stddev": 0.06854580979831519,
"median": 0.6571892429199999,
"user": 0.34385101999999995,
"system": 1.2796234199999998,
"min": 0.64978875742,
"max": 0.87224882942,
"times": [
0.65944320042,
0.64978875742,
0.66261958542,
0.65057942542,
0.65222736142,
0.65712438042,
0.65436055742,
0.65960182342,
0.65725410542,
0.87224882942
]
}
]
}Scenario: Isolated linker: fresh resolve, hot cache, offline
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 0.65425210524,
"stddev": 0.013572890268959527,
"median": 0.65674990454,
"user": 0.62016344,
"system": 0.15208536,
"min": 0.63812289254,
"max": 0.6743359935400001,
"times": [
0.65812371454,
0.64235511854,
0.65537609454,
0.63950893454,
0.63812289254,
0.63944220054,
0.66335304854,
0.67061149454,
0.6743359935400001,
0.66129156054
]
},
{
"command": "pacquet@main",
"mean": 0.64692366854,
"stddev": 0.011812110630754458,
"median": 0.64406136404,
"user": 0.6104749399999999,
"system": 0.15317245999999998,
"min": 0.62715140454,
"max": 0.67401603454,
"times": [
0.64041653454,
0.65160894054,
0.62715140454,
0.64331091754,
0.65136236254,
0.64433802754,
0.67401603454,
0.64954175354,
0.64370600954,
0.64378470054
]
},
{
"command": "pnpr@HEAD",
"mean": 0.10787726670000003,
"stddev": 0.0007511433544329648,
"median": 0.10802762554,
"user": 0.028440600000000003,
"system": 0.017433960000000002,
"min": 0.10494263554000001,
"max": 0.10915797654,
"times": [
0.10737653654000001,
0.10814809454,
0.10818401154000001,
0.10787919354,
0.10814132754000001,
0.10774764454,
0.10825412454000001,
0.10766771354,
0.10819933854000001,
0.10769969354,
0.10494263554000001,
0.10792821954000001,
0.10789610954000001,
0.10827689954000001,
0.10810425654000001,
0.10832466754,
0.10744014954,
0.10802762554,
0.10851208654000001,
0.10732845554,
0.10915797654,
0.10714227854000001,
0.10776021554000001,
0.10853456954,
0.10825784354000001
]
},
{
"command": "pnpr@main",
"mean": 0.10801660694000001,
"stddev": 0.00041878026300983017,
"median": 0.10802907754,
"user": 0.02655584,
"system": 0.019212439999999997,
"min": 0.10701094954000001,
"max": 0.10889877754,
"times": [
0.10735641854000001,
0.10822735554,
0.10701094954000001,
0.10837454154000001,
0.10785135154,
0.10851945554,
0.10803469254,
0.10806855554,
0.10767735254000001,
0.10833549754,
0.10802289554000001,
0.10802907754,
0.10754739954,
0.10784600654000001,
0.10867038154000001,
0.10752022954000001,
0.10889877754,
0.10783754154000001,
0.10802023054000001,
0.10806520354,
0.10793095554000001,
0.10816849654,
0.10775112954,
0.10814942054000001,
0.10850125754
]
}
]
}Scenario: Isolated linker: fresh restore, cold cache + cold store + cold pnpr
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 6.85774151936,
"stddev": 0.14399848890315398,
"median": 6.81025513226,
"user": 4.017508059999999,
"system": 3.7526394000000005,
"min": 6.71210739626,
"max": 7.13567015826,
"times": [
7.13567015826,
6.78171504326,
6.79621291426,
7.0522639402600005,
6.82429735026,
6.95670565426,
6.71210739626,
6.73456137026,
6.84678787526,
6.7370934912600005
]
},
{
"command": "pacquet@main",
"mean": 6.858461168260002,
"stddev": 0.13130365002339717,
"median": 6.84339541576,
"user": 4.02402766,
"system": 3.7795646999999994,
"min": 6.695562922260001,
"max": 7.11478670626,
"times": [
6.88972754026,
7.02720848926,
7.11478670626,
6.81844408226,
6.695562922260001,
6.8683467492600005,
6.79493761326,
6.76627276426,
6.72264922826,
6.88667558726
]
},
{
"command": "pnpr@HEAD",
"mean": 4.90645633906,
"stddev": 0.05414392359835954,
"median": 4.91565017326,
"user": 2.73993386,
"system": 3.2245492,
"min": 4.81166332026,
"max": 4.98095403726,
"times": [
4.97872079726,
4.87131082826,
4.92348760726,
4.92512263526,
4.9201140292600005,
4.98095403726,
4.91118631726,
4.8391454752600005,
4.81166332026,
4.90285834326
]
},
{
"command": "pnpr@main",
"mean": 4.965768923360001,
"stddev": 0.13657339564812823,
"median": 4.97319805876,
"user": 2.7552669599999997,
"system": 3.2158420999999997,
"min": 4.79084252826,
"max": 5.23495814126,
"times": [
5.03367784426,
5.01285234226,
4.79084252826,
5.07569490626,
5.23495814126,
4.87648101626,
4.81684285426,
5.02361319226,
4.93354377526,
4.85918263326
]
}
]
} |
|
| Branch | pr/12848 |
| 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,182.94 ms |
| isolated-linker.fresh-install.cold-cache.hot-store | 📈 view plot | 675.05 ms |
| isolated-linker.fresh-install.hot-cache.hot-store | 📈 view plot | 661.68 ms |
| isolated-linker.fresh-resolve.hot-cache.offline | 📈 view plot | 107.88 ms |
| isolated-linker.fresh-restore.cold-cache.cold-store | 📈 view plot | 2,055.67 ms |
| isolated-linker.fresh-restore.cold-cache.cold-store.cold-pnpr | 📈 view plot | 4,906.46 ms |
| isolated-linker.fresh-restore.hot-cache.hot-store | 📈 view plot | 697.11 ms |
|
Code review by qodo was updated up to the latest commit 9e7bff2 |
PR Code Suggestions ✨Warning
|
||||||||||||
9e7bff2 to
abbcf29
Compare
|
Code review by qodo was updated up to the latest commit abbcf29 |
PR Code Suggestions ✨Warning
|
||||||||||||
|
Code review by qodo was updated up to the latest commit bb40324 |
|
Code review by qodo was updated up to the latest commit bcfff0a |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
pacquet/crates/cli/tests/list.rs (1)
42-44: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winSet-based comparison can hide duplicate entries.
Collecting into a
BTreeSet<String>de-duplicates names, so a regression that emits the same project twice (e.g. root counted alongside a workspace package) would not be caught by the current assertions. Consider also assertingpackages.len()matches the expected count (or returning aVecand checking both length and set membership) to make the regression test more meaningful.♻️ Suggested strengthening
-fn recursive_project_names(pacquet: Command, extra_args: &[&str]) -> BTreeSet<String> { +fn recursive_project_names(pacquet: Command, extra_args: &[&str]) -> (BTreeSet<String>, usize) { let output = pacquet .with_arg("-r") .with_arg("list") .with_args(extra_args) .with_arg("--depth") .with_arg("-1") .with_arg("--json") .output() .expect("spawn pacquet list"); assert!( output.status.success(), "recursive list should succeed:\n{}", String::from_utf8_lossy(&output.stderr), ); let packages: Vec<Value> = serde_json::from_slice(&output.stdout).expect("parse list JSON"); - packages.iter().map(|pkg| pkg["name"].as_str().expect("package name").to_string()).collect() + let names: BTreeSet<String> = + packages.iter().map(|pkg| pkg["name"].as_str().expect("package name").to_string()).collect(); + (names, packages.len()) }Then assert
names.len() == packages.len()at each call site alongside the set equality check.As per path instructions, "add regression tests that fail without the fix ... with meaningful assertions on returned project sets and JSON shape; don't accept vacuous assertions."
🤖 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/list.rs` around lines 42 - 44, The list tests in the `packages` helper are only checking set membership, which can mask duplicate project entries. Update the `packages` parsing/assertion flow in `list.rs` so the helper returns a `Vec<String>` (or otherwise preserves duplicates) and add explicit length checks at each call site, alongside the existing `BTreeSet` equality assertions. Use the existing `packages`/`names` test helpers and JSON parsing logic to verify both the expected project set and the exact count, so duplicate emissions fail the regression tests.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.
Nitpick comments:
In `@pacquet/crates/cli/tests/list.rs`:
- Around line 42-44: The list tests in the `packages` helper are only checking
set membership, which can mask duplicate project entries. Update the `packages`
parsing/assertion flow in `list.rs` so the helper returns a `Vec<String>` (or
otherwise preserves duplicates) and add explicit length checks at each call
site, alongside the existing `BTreeSet` equality assertions. Use the existing
`packages`/`names` test helpers and JSON parsing logic to verify both the
expected project set and the exact count, so duplicate emissions fail the
regression tests.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: da0d0dfc-2180-45cc-96bc-e9008f7e9933
📒 Files selected for processing (1)
pacquet/crates/cli/tests/list.rs
Brings in the pkg command (#12795), recursive project listing (#12848), the Pkg command_name match fix (#12850), and the github-actions dependency bump (#12785). No conflicts. main's changes are the pkg/list CLI commands and CI workflows, disjoint from the login/auth-commands work; the shared command-registry files (cli_args, cli_command, dispatch, dispatch_query, switch_cli_version) merged cleanly with both the login and the pkg/list entries.
Summary
Pacquet now handles the recursive list shape used by the pnpm repo TS CI chunker:
pn -r list --depth -1 --json.The fix has four parts:
list --depth -1accepts-1as a separate value, matching TypeScript pnpm.list/llhonor recursive dispatch and enumerate the selected workspace projects instead of listing only the current directory.nameAtVersion()helper still prints raw names and can be aligned separately if maintainers want that broader parity change.pkgcommand from currentmainis included in the version-switch command-name mapping, fixing the PR merge-commit Dylint failure.This fixes the pnpm v12 CI path in #12811 where switching the script to
--depth=-1avoided the parser error but made Windows chunks select0 of 0tests.Squash Commit Body
Checklist
pacquet/port, or the description notes what still needs porting.Written by an agent (Codex, GPT-5).
Summary by CodeRabbit
pacquet list/llrecursive mode so it’s properly applied to listing runs.--depthparsing for negative values (including--depth -1), including with--json.pkgwhen applying switch-skipping logic.--depthparsing to accept hyphenated values.--json, negative depth behavior, and ANSI-safe rendering.