fix: respect transitive dependencies when sorting filtered projects#12688
Conversation
|
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 (7)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (6)
📝 WalkthroughWalkthroughThis PR fixes topological ordering for ChangesWorkspace ordering fix
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant CLI as pnpm run --filter
participant Filter as filterProjectsBySelectorObjects
participant Context as ConfigContext
participant Recursive as runRecursive
participant Sorter as sortFilteredProjects
CLI->>Filter: apply --filter / --filter-prod selectors
Filter-->>Context: selectedProjectsGraph, allProjectsGraph, prodAllProjectsGraph, prodOnlySelectedProjectDirs
Context-->>Recursive: opts with graph fields
Recursive->>Sorter: sortFilteredProjects(opts)
Sorter->>Sorter: tunnel through unselected/prod-pruned graph
Sorter-->>Recursive: ordered chunks respecting transitive deps
Recursive-->>CLI: execute chunks in dependency order
Assessment against linked issues
Possibly related PRs
Suggested labels: Suggested reviewers: ✨ Finishing Touches🧪 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 QodoFix recursive filtered project ordering across transitive workspace deps Description
Diagram
High-Level Assessment
Files changed (19)
|
Code Review by Qodo
1. NODE_OPTIONS breaks Windows
|
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 `@pnpm11/workspace/projects-sorter/src/index.ts`:
- Around line 15-25: The graph traversal in sequenceGraph is reintroducing
dependencies that selectedProjectsGraph has already pruned. Update the
sequencing logic so traversal begins from each selected node’s own dependencies
array, and only falls back to fullProjectsGraph/ProjectsGraph when descending
into an unselected node via sortedDependencies. Keep the fix localized around
sequenceGraph and sortedDependencies, and add a regression test for the
prod-pruned graph shape to ensure dev-only edges are not pulled back into the
order.
🪄 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: 926591f8-6574-40eb-afbb-7123086a71c7
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml,!pnpm-lock.yaml
📒 Files selected for processing (12)
.changeset/sort-filtered-transitive-deps.mdpnpm11/building/commands/src/build/rebuild.tspnpm11/building/commands/src/build/recursive.tspnpm11/exec/commands/src/exec.tspnpm11/exec/commands/src/runRecursive.tspnpm11/exec/commands/test/runRecursive.tspnpm11/releasing/commands/src/publish/pack.tspnpm11/releasing/commands/src/publish/recursivePublish.tspnpm11/workspace/projects-sorter/package.jsonpnpm11/workspace/projects-sorter/src/index.tspnpm11/workspace/projects-sorter/test/index.tspnpm11/workspace/projects-sorter/test/tsconfig.json
|
Code review by qodo was updated up to the latest commit 486d13a |
|
Code review by qodo was updated up to the latest commit 0ae5a7d |
1 similar comment
|
Code review by qodo was updated up to the latest commit 0ae5a7d |
|
Code review by qodo was updated up to the latest commit 210fccd |
1 similar comment
|
Code review by qodo was updated up to the latest commit 210fccd |
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": 3.833785202599999,
"stddev": 0.15336252551829532,
"median": 3.7928080488999996,
"user": 3.59345436,
"system": 3.475130299999999,
"min": 3.6429956838999997,
"max": 4.1008534789,
"times": [
3.8213014819,
3.7548715538999997,
4.0161950009,
3.6429956838999997,
3.9835233878999996,
3.7643146158999996,
3.8511273558999997,
3.7301725669,
4.1008534789,
3.6724968999
]
},
{
"command": "pacquet@main",
"mean": 3.8164683631999994,
"stddev": 0.15705815384546318,
"median": 3.7716645309,
"user": 3.6149122599999997,
"system": 3.4277737999999998,
"min": 3.6134131368999998,
"max": 4.0434065459,
"times": [
3.6670132168999996,
3.6134131368999998,
3.7165001359,
3.7554275639,
3.7879014978999996,
3.6865470379,
4.042664207900001,
4.0434065459,
3.9117004228999996,
3.9401098659
]
},
{
"command": "pnpr@HEAD",
"mean": 2.2064497176,
"stddev": 0.12314806673189574,
"median": 2.1824225743999994,
"user": 2.6730495600000004,
"system": 3.0792602,
"min": 2.0583899668999996,
"max": 2.4728960718999997,
"times": [
2.3247470759,
2.4728960718999997,
2.1525069299,
2.0583899668999996,
2.2184782649,
2.0709012948999996,
2.1793378558999996,
2.1420634559,
2.1855072928999997,
2.2596689669
]
},
{
"command": "pnpr@main",
"mean": 2.1406454684,
"stddev": 0.09699068921237741,
"median": 2.1214143894,
"user": 2.66800326,
"system": 3.0446864999999996,
"min": 2.0393865328999996,
"max": 2.3911926019,
"times": [
2.1342023318999996,
2.1070162479,
2.0592016179,
2.0994007178999996,
2.0393865328999996,
2.1086264469,
2.1430791859,
2.1714669209,
2.1528820799,
2.3911926019
]
}
]
}Scenario: Isolated linker: fresh restore, hot cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 0.65277479728,
"stddev": 0.010035724908680814,
"median": 0.6528855290800001,
"user": 0.3890287,
"system": 1.3351796999999999,
"min": 0.63657481258,
"max": 0.6696339745800001,
"times": [
0.6475405755800001,
0.63657481258,
0.6554923755800001,
0.64464169658,
0.65799508658,
0.64349128058,
0.6621046825800001,
0.6599948055800001,
0.6502786825800001,
0.6696339745800001
]
},
{
"command": "pacquet@main",
"mean": 0.66904267928,
"stddev": 0.041186870859110616,
"median": 0.6504122495800001,
"user": 0.3991192,
"system": 1.3428187,
"min": 0.6422206165800001,
"max": 0.7790069355800001,
"times": [
0.6489153085800001,
0.6823474345800001,
0.66400106958,
0.6499424665800001,
0.6422206165800001,
0.6450720505800001,
0.6508820325800001,
0.6477646745800001,
0.6802742035800001,
0.7790069355800001
]
},
{
"command": "pnpr@HEAD",
"mean": 0.7197881837800002,
"stddev": 0.01895610708569031,
"median": 0.7161338370800001,
"user": 0.3963076,
"system": 1.3790139,
"min": 0.68409460858,
"max": 0.7502761195800001,
"times": [
0.7067203865800001,
0.7502761195800001,
0.7370674995800001,
0.7143696655800001,
0.7139694475800001,
0.68409460858,
0.7196419905800001,
0.7178980085800001,
0.7409313725800001,
0.71291273858
]
},
{
"command": "pnpr@main",
"mean": 0.7279137053800001,
"stddev": 0.021357600969765227,
"median": 0.7195573500800001,
"user": 0.3997613,
"system": 1.3836737,
"min": 0.7034056675800001,
"max": 0.7700592955800001,
"times": [
0.7393842195800001,
0.7545192835800001,
0.7335956275800001,
0.7176117685800001,
0.7179761695800001,
0.7034056675800001,
0.7211385305800001,
0.7700592955800001,
0.70799338058,
0.71345311058
]
}
]
}Scenario: Isolated linker: fresh install, cold cache + cold store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 4.297268311500001,
"stddev": 0.06580595533371197,
"median": 4.2844000576,
"user": 3.77372732,
"system": 3.43198218,
"min": 4.2356838321,
"max": 4.4577713481000005,
"times": [
4.2356838321,
4.2696241371,
4.2592508881,
4.3017993651,
4.2476039631,
4.3153802941,
4.2465142261,
4.2991759781,
4.4577713481000005,
4.3398790831000005
]
},
{
"command": "pacquet@main",
"mean": 4.2800351724,
"stddev": 0.03307671273406055,
"median": 4.2699534156,
"user": 3.7615581199999992,
"system": 3.4142474799999993,
"min": 4.2485324251,
"max": 4.3692386821,
"times": [
4.3692386821,
4.2664876251,
4.2640661301,
4.2806156101,
4.2651742111,
4.2724817581000005,
4.2840420441000004,
4.2822881651,
4.2674250731,
4.2485324251
]
},
{
"command": "pnpr@HEAD",
"mean": 2.1919842029,
"stddev": 0.11718136280720254,
"median": 2.1962357506,
"user": 2.48076442,
"system": 2.9613381799999994,
"min": 2.0199174851,
"max": 2.3949898561,
"times": [
2.2606584641,
2.1129751741000002,
2.3063709081,
2.1191452411,
2.2120736071000002,
2.0199174851,
2.2576088921,
2.1803978941,
2.3949898561,
2.0557045071
]
},
{
"command": "pnpr@main",
"mean": 2.2152257851000003,
"stddev": 0.1613794133521661,
"median": 2.1684407855999996,
"user": 2.5291655200000003,
"system": 2.95335268,
"min": 2.0504413721,
"max": 2.4150853031,
"times": [
2.0548797851000002,
2.3593359081000003,
2.1003735531,
2.3983797661,
2.0504413721,
2.0559610861,
2.4150853031,
2.2365080181,
2.3938890111,
2.0874040481000002
]
}
]
}Scenario: Isolated linker: fresh install, hot cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 1.36401573176,
"stddev": 0.021177715626198978,
"median": 1.3579823205600001,
"user": 1.33032598,
"system": 1.7130967,
"min": 1.33793260706,
"max": 1.4076150520600001,
"times": [
1.4076150520600001,
1.38484651006,
1.3466256030600001,
1.33793260706,
1.35446361106,
1.37228211506,
1.3615010300600001,
1.34601270606,
1.35374966406,
1.3751284190600002
]
},
{
"command": "pacquet@main",
"mean": 1.35368285156,
"stddev": 0.02041848983838078,
"median": 1.35510552656,
"user": 1.32829728,
"system": 1.707379,
"min": 1.32429010606,
"max": 1.40140614706,
"times": [
1.36007552006,
1.35540751506,
1.35879533006,
1.33844734706,
1.32429010606,
1.3506033880600001,
1.40140614706,
1.33663177606,
1.35480353806,
1.35636784806
]
},
{
"command": "pnpr@HEAD",
"mean": 0.6893910274599999,
"stddev": 0.04410123826821697,
"median": 0.67788733656,
"user": 0.33463378,
"system": 1.3180801999999998,
"min": 0.6631561960600001,
"max": 0.81269267706,
"times": [
0.6670305700600001,
0.6715213840600001,
0.6631561960600001,
0.81269267706,
0.68272140806,
0.6767504950600001,
0.67902417806,
0.6798957050600001,
0.6914096500600001,
0.6697080110600001
]
},
{
"command": "pnpr@main",
"mean": 0.68533327656,
"stddev": 0.005338854928215828,
"median": 0.6854411770600001,
"user": 0.35575708,
"system": 1.3051229,
"min": 0.67738713206,
"max": 0.69209701306,
"times": [
0.68601036406,
0.69025173906,
0.6914436540600001,
0.67764138606,
0.6818117380600001,
0.67738713206,
0.68333858806,
0.6884791610600001,
0.6848719900600001,
0.69209701306
]
}
]
}Scenario: Isolated linker: fresh install, cold cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 3.04622938404,
"stddev": 0.04066335456548295,
"median": 3.0396884143399996,
"user": 1.7854619,
"system": 2.0075180599999998,
"min": 3.00694979784,
"max": 3.13827748484,
"times": [
3.07727701884,
3.00771952784,
3.01111000684,
3.00694979784,
3.03533689384,
3.02243460684,
3.04403993484,
3.06793183784,
3.13827748484,
3.05121673084
]
},
{
"command": "pacquet@main",
"mean": 3.08147207944,
"stddev": 0.047496047531306686,
"median": 3.0805297833400003,
"user": 1.8224636999999997,
"system": 2.0088787599999995,
"min": 3.02047117484,
"max": 3.16256444984,
"times": [
3.10098283584,
3.12274334284,
3.03369369184,
3.04371473384,
3.02047117484,
3.06332488284,
3.12716121584,
3.16256444984,
3.09773468384,
3.04232978284
]
},
{
"command": "pnpr@HEAD",
"mean": 0.69556389444,
"stddev": 0.016246353110490903,
"median": 0.69426291634,
"user": 0.33688179999999995,
"system": 1.3520729599999999,
"min": 0.67267040784,
"max": 0.7245183848400001,
"times": [
0.6843842358400001,
0.69306685284,
0.68316408984,
0.71772410684,
0.67267040784,
0.68317201084,
0.6968786638400001,
0.7245183848400001,
0.69545897984,
0.70460121184
]
},
{
"command": "pnpr@main",
"mean": 0.6822304904400001,
"stddev": 0.017311952187210586,
"median": 0.67933081884,
"user": 0.3588369,
"system": 1.2941326599999996,
"min": 0.64980060784,
"max": 0.7136003578400001,
"times": [
0.67720798884,
0.67968174684,
0.6748007848400001,
0.67897989084,
0.69591151484,
0.64980060784,
0.66875400484,
0.7136003578400001,
0.6943092228400001,
0.68925878484
]
}
]
}Scenario: Isolated linker: fresh restore, cold cache + cold store + cold pnpr
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 7.263752312700001,
"stddev": 0.10061113008600972,
"median": 7.2585692414,
"user": 3.87677342,
"system": 3.7708254400000003,
"min": 7.1371803189,
"max": 7.4011984679,
"times": [
7.2061849338999995,
7.2692348418999995,
7.3279484569,
7.4011984679,
7.3718187689,
7.1371803189,
7.1531808069,
7.1506213959,
7.3722514948999995,
7.2479036409
]
},
{
"command": "pacquet@main",
"mean": 7.339791829899999,
"stddev": 0.12991448062615543,
"median": 7.3534186739,
"user": 3.92092502,
"system": 3.75671324,
"min": 7.0900948119,
"max": 7.5129996139,
"times": [
7.2924375079,
7.5129996139,
7.2412266678999995,
7.260405405899999,
7.4143998399,
7.0900948119,
7.2675893739,
7.4313037808999995,
7.4600116649,
7.4274496319
]
},
{
"command": "pnpr@HEAD",
"mean": 5.6495864597,
"stddev": 0.1031863498137556,
"median": 5.6540028834,
"user": 2.825710419999999,
"system": 3.35203204,
"min": 5.4925726058999995,
"max": 5.8625686328999995,
"times": [
5.6757849199,
5.5862063659,
5.6018493379,
5.5475381959,
5.8625686328999995,
5.7131595769,
5.4925726058999995,
5.7081791949,
5.6327624419,
5.675243324899999
]
},
{
"command": "pnpr@main",
"mean": 5.6388930785,
"stddev": 0.0759856651270492,
"median": 5.6123279774,
"user": 2.82053942,
"system": 3.3312157399999998,
"min": 5.5560278918999995,
"max": 5.758304745899999,
"times": [
5.5803553329,
5.5777223379,
5.5560278918999995,
5.5700233559,
5.6196653559,
5.7425226979,
5.6049905989,
5.6621414769,
5.7171769909,
5.758304745899999
]
}
]
} |
|
| Branch | pr/12688 |
| 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,191.98 ms |
| isolated-linker.fresh-install.cold-cache.hot-store | 📈 view plot | 695.56 ms |
| isolated-linker.fresh-install.hot-cache.hot-store | 📈 view plot | 689.39 ms |
| isolated-linker.fresh-restore.cold-cache.cold-store | 📈 view plot | 2,206.45 ms |
| isolated-linker.fresh-restore.cold-cache.cold-store.cold-pnpr | 📈 view plot | 5,649.59 ms |
| isolated-linker.fresh-restore.hot-cache.hot-store | 📈 view plot | 719.79 ms |
|
@qodo-free-for-open-source-projects the remaining open items don't need code changes. Going through them: 1. Not sorting full workspace graph (requirement gap). The relative order among selected projects already matches a full-graph topological sort: each selected project is sequenced after every selected project it transitively depends on, resolved through the full graph. Ordering the whole graph and then filtering its chunks would also serialize selected projects that have no dependency between them, because their unselected connectors fall into earlier chunks. That is the parallelism loss the original report asks to avoid, so the chunks are computed over the selected set on purpose. 3. Windows-unsafe test command. 4. Repeated graph traversal (performance). Item 2 (prod-only filter pulling dev edges) is fixed in 0ae5a7d with a regression test. |
Thanks — that rationale is solid, and I agree the remaining items don’t need code changes.
Also, item 2 is already fixed in So from my side, this looks good to go without further changes. |
|
Code review by qodo was updated up to the latest commit 1d5430d |
1 similar comment
|
Code review by qodo was updated up to the latest commit 1d5430d |
|
Code review by qodo was updated up to the latest commit 9d30115 |
1 similar comment
|
Code review by qodo was updated up to the latest commit 9d30115 |
|
@qodo-free-for-open-source-projects the new items don't need a change either. 4 and 7 are the Windows 1. NODE_OPTIONS breaks Windows. This is the standard 5. Extra prod graph retention. 6. Spread push crash risk. |
Makes sense — I agree those don’t look like blockers here.
And if 4 and 7 are unchanged from the earlier discussion, then I don’t see a new issue in those paths either. The new tests also cover the transitive and mixed |
|
Code review by qodo was updated up to the latest commit 9feb545 |
|
Code review by qodo was updated up to the latest commit bace374 |
|
Code review by qodo was updated up to the latest commit bace374 |
can you please add it back? |
|
Now this has merge conflicts again. I'll resolve them. |
When a recursive command (run, exec, publish, pack, rebuild) is filtered to a subset of projects, the topological sort ran on the selected subgraph alone and dropped edges that pass through unselected projects. Two selected projects related only transitively could then run concurrently or in the wrong order. The sort now resolves edges through the full workspace graph, so a project runs after the selected projects it transitively depends on, while projects without a real dependency relationship still run concurrently. pnpm#8335
The sort seeded its traversal from the full workspace graph, so a prod-only filter (followProdDepsOnly), which drops dev edges, had those edges reintroduced into the order and serialized commands by dependencies the selection removed. Seed each sorted project's own edges from the selected graph and consult the full graph only to tunnel through unselected projects.
…r test The new ordering test declared its inter-package deps with a plain version range, which pnpm resolves from the registry when link-workspace-packages is false (the default), so install -r failed with a 404 on CI. Use the workspace: protocol so the packages link locally, matching the other install-based e2e tests.
…rt order The transitive ordering of --filtered recursive commands tunneled through the full workspace graph, which keeps dev dependencies. For a prod-only filter (--filter-prod), whose selected graph has dev edges pruned, that reintroduced the dropped edges and could serialize commands by dependencies the filter removed; with --bail, a failing dependency would then block its dependent. Resolve order among the selected projects only when a prod-only filter is in effect, which restores the previous behavior for that mode while keeping the transitive fix for regular filters.
…graph The filtered sort dropped the full workspace graph whenever a `--filter-prod` was present. That regressed two cases: - A regular `--filter` combined with any `--filter-prod` lost the transitive ordering for the regularly filtered projects, so `a -> b -> c` with only `a` and `c` selected could run in the same chunk. - A pure `--filter-prod` selection dropped real transitive prod edges, so a prod dependency could run after its dependent. The sort now resolves each selected project through the graph that matches how it was selected: prod-only selected projects through the prod-pruned graph, and regularly selected projects through the full graph. Keeping prod-only projects on the full graph would let a dev-only reverse edge form a cycle and collapse a real prod dependency and its dependent into one chunk, so the graph is picked per project.
A regular filter reaching a selected project through a prod-only intermediate was an untested combination. Lock in that a dev edge pruned by the prod-only selection severs the path (the dependent stays concurrent), while a prod edge kept in the prod graph still chains the full order through.
The producer couples prodAllProjectsGraph and prodOnlySelectedProjectDirs: both are gated on prodProjectSelectors.length > 0, so a prod graph never arrives without a (possibly empty) prodOnlySelectedProjectDirs array. The branch handling 'prod graph set, dirs null' was therefore unreachable and uncovered. Removed it and let the per-project branch handle the empty set, where every project resolves through the full graph. Also hoisted the repeated allProjectsGraph ?? selectedProjectsGraph fallback into one local.
Port pnpm's sortFilteredProjects fix to the pacquet recursive run / exec /
pack runners.
The runners sorted the --filter-selected projects, but the sorter dropped
edges to projects outside the selection. Two selected projects related only
transitively (a -> b -> c with a and c selected, b filtered out) could then
land in the same chunk and run out of order. The sorter now resolves order
through the full workspace graph: each selected project walks its
dependencies, tunnels past unselected projects, and stops at selected ones,
so a transitive relationship becomes a direct edge. Projects with no real
dependency stay in one chunk, preserving concurrency.
A --filter-prod selection prunes dev edges. Its projects sort through the
prod-pruned graph and seed their own edges from it, so the dropped dev edges
are not pulled back into the order. select_recursive_projects returns the
full and prod-pruned graphs and the prod-only-selected dirs alongside the
selection, filters against those prebuilt graphs so no graph is rebuilt per
filter call, and lists a mixed --filter / --filter-prod selection prod-first
to match pnpm's { ...prodFilteredGraph, ...filteredGraph } merge — the
recursive runners execute and print a chunk's projects in insertion order.
The graphs honor the configured link-workspace-packages, so a bare-semver
range naming a sibling drives neither selection nor order under the default
policy, matching pnpm. An unfiltered run keeps a single graph without
cloning, and a regular --filter run skips the prod-only bookkeeping.
Fixes pnpm#8335.
sequenceGraph and sortProjects had grown an optional second graph argument that no production code passed; only tests and sortFilteredProjects's no-prod branch used it. Both are single-argument again, and sortFilteredProjects drives the private sequenceGraphByProject engine directly, so full/prod-pruned-graph resolution lives in one place and the package exposes only single-graph sorting plus sortFilteredProjects. No behavior change: single-argument sequenceGraph and sortProjects order projects by their own edges as before, and sortFilteredProjects yields the same chunks. Tests exercise single-graph sorting through sequenceGraph/sortProjects and all tunneling behavior through sortFilteredProjects.
sequenceGraph and sortProjects sort a single graph (recursive install/update and cycle-warning checks), where every edge is already among the sorted projects and no tunneling is needed. Routing them through sequenceGraphByProject allocated two Sets and a stack per project for nothing, and changed the chunk order on cyclic graphs. Restored the direct dependency filter on sequenceGraph and left the tunneling engine to sortFilteredProjects. The full-graph sort sheds the per-project allocations and matches the pre-change ordering again, including for cycles.
The "`all` is `None` on an unfiltered run because `selected` is already the full graph" invariant was re-derived on the `RecursiveSelection.all` field, the `full_graph` accessor, and `select_recursive_projects`. Keep it on the field and have the accessor and producer reference it instead.
…n test
The mixed-filter ordering test cited the TypeScript
`{ ...prodFilteredGraph, ...filteredGraph }` spread; describe the ordering as
pacquet's own behavior, consistent with the parity paradigm (pnpm#12737)
and the already-de-cited twin in recursive.rs.
bace374 to
6333553
Compare
|
@zkochan rebased onto I also noticed the zizmor check is failing, but it is pre-existing on |
|
Congrats on merging your first pull request! 🎉🎉🎉 |
Resolve the dispatch_query.rs import conflict (keep both the new prefix command and this branch's publish command, alphabetically ordered) and adapt publish's recursive handler to the recursive-selection API change from #12688: select_recursive_projects now returns a RecursiveSelection, and ordering goes through sort_filtered_projects (selected + full/prod graphs) instead of sort_projects.

Summary
When a recursive command (
run,exec,publish,pack,rebuild) is filtered to a subset of projects, the topological sort ran on the selected subgraph only and dropped edges that pass through unselected projects. Two selected projects related only transitively could then run concurrently or in the wrong order, so a dependency's script could start after its dependent's.The sort now resolves edges through the full workspace graph: a project runs after the selected projects it transitively depends on, while projects with no real dependency relationship still run concurrently.
Prod-only filters (
--filter-prod) prune dev dependencies from the graph they select against. The prod-only selected projects resolve order through that prod-pruned graph, so transitive prod dependencies are respected without pulling the dropped dev edges back. A selection that mixes--filterwith--filter-prodresolves each project through the graph that matches how it was selected: regularly filtered projects through the full graph, prod-only ones through the prod-pruned graph. That keeps a regular filter's transitive ordering intact when a prod-only filter is also present, and stops a dev-only reverse edge from forming a cycle that would collapse a real prod dependency and its dependent into one chunk.Note: the cyclic-workspace-dependency warning still inspects the selected subgraph only, so a cycle that runs through unselected projects affects ordering but is not warned about. Left as is to keep this change focused.
Fixes #8335
Squash Commit Body
Checklist
(comment):
commit
dce50a7applies the samesort_filtered_projectsfix — resolvingtransitive order through the full / prod-pruned workspace graph — to pacquet's
recursive
run,exec, andpackrunners, with matching tests. pacquet hasno recursive
publish/rebuildordering, so nothing else needs porting.Summary by CodeRabbit
New Features
Bug Fixes
--filter-prodand combined--filter+--filter-produse cases.