feat: add dependsOn package dependency selection#467
Conversation
Co-authored-by: GPT-5 Codex <codex@openai.com>
1e68775 to
6d9d369
Compare
Fold the redundant intermediate set and the duplicated value-loop in add_package_dependency_entry into a single pass, and extract the shared package-to-task lookup into resolve_packages_to_tasks, now reused by map_subgraph_to_tasks. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: GPT-5 Codex <codex@openai.com>
Add a plan-snapshot fixture where a selected package transitively depends on another selected package only through a task-less intermediate. The two build tasks stay unordered, locking in that nearest object-form dependsOn selection does not create transitive ordering edges. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b79c338884
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let pkg_to_task = self.resolve_nearest_packages_to_tasks( | ||
| package_graph | ||
| .edges(origin_package) | ||
| .filter(|edge| entry.dependency_types.contains(edge.weight())) | ||
| .map(|edge| edge.target()), |
There was a problem hiding this comment.
Exclude the source package from dependency walks
When a dependency path cycles back to the package that declared the object dependsOn (for example app -> plugin -> app, with plugin lacking the requested task), this walk can return the origin package as a nearest match. That makes { "task": "build", "from": ... } add app#build from within app (or a self-edge when the source is app#build), even though the new semantics say the source package itself is not selected; seed the walk with origin_package as already seen or filter it out before adding edges.
Useful? React with 👍 / 👎.
This reverts commit 6296ffa. Co-authored-by: GPT-5 Codex <codex@openai.com>
The mechanical reverts of #467 and #469 could not account for changes that landed on main afterwards: - #477 renamed plan task-graph snapshots from `.jsonc` to `.md`, so reverting the `depends_on_package_dependencies` fixture left `snapshots/task_graph.md` behind as an orphan with no package. The plan snapshot harness runs every fixture directory through workspace discovery, so this stale directory would fail the suite — remove it. - `vec1` was used only by the reverted object-form `dependsOn` config, so it is now an unused dependency of `vite_task_graph` that `cargo shear` rejects — drop it. - Reverting #467's `task-query.md` edits would reintroduce the internal `vite-task.json` name into published docs; keep the public `vite.config.*` spelling that main already uses. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QowxsN8vDKKbQdaSMdxL67
## Motivation
Object-form `dependsOn` package selection — `{ "task": "build", "from": "dependencies" }` — was added in #467 and refined in #469, but implemented as **query-time expansion**: the selections were kept on the declaring task and expanded per query instead of being stored in the global task graph. That is the wrong layer. The resulting dependencies never appear as task graph edges, so they are invisible to anything that inspects the graph (graph snapshots, tooling, recursive traversal).
This PR reverts #467 and #469 so the feature can be reintroduced at graph-construction time. The reimplementation is the stacked follow-up **#479**.
## Notes
The first two commits are pure `git revert`s. A third commit completes them for changes that landed on `main` *after* the reverted PRs, which a mechanical revert cannot account for:
- #477 renamed plan task-graph snapshots from `.jsonc` to `.md`, so reverting the `depends_on_package_dependencies` fixture left an orphaned `snapshots/task_graph.md` behind. The plan snapshot harness runs every fixture directory through workspace discovery, so the stale directory would fail the suite.
- `vec1` was used only by the reverted object-form config, so it becomes an unused dependency of `vite_task_graph` that `cargo shear` rejects.
---
**Stack** (via Graphite):
- #478 ← this PR (revert)
- #479 (reimplementation)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01QowxsN8vDKKbQdaSMdxL67
## Motivation Stacked on #478 (the revert of the query-time implementation). Object-form `dependsOn` entries — `{ "task": "build", "from": ["dependencies", "devDependencies"] }` — run a task in the direct workspace packages listed under a package.json dependency field. The previous implementation (#467/#469, reverted in #478) expanded these at query time, so the selections never appeared in the global task graph. This reimplements the feature at **graph-load time**: each object entry is resolved against the package dependency graph and the matching `package#task` selections become ordinary task graph edges (`add_package_dependency_edges`). Because they are now plain edges: - they appear in the global task graph, and - they flow through the existing dependency machinery for free — including `--ignore-depends-on`, which drops them at query time like any other `dependsOn` edge. Only direct dependencies are followed, and an edge is added only when the dependency package actually defines the task. Supported fields are `dependencies`, `devDependencies`, and `peerDependencies`. ## Snapshot coverage Because the edges now live in the global task graph, the fixture asserts edge construction through the rendered `task_graph.md`: every `from` variant, recursive cross-package chains, and the exclusion of peer-only and missing-task dependencies are all visible there. The only behavior the static graph cannot express — `--ignore-depends-on` removing the materialized edges at query time — is kept as the single per-case plan snapshot. The other four per-case snapshots in the original change were redundant re-assertions of edges already shown in `task_graph.md`, so they were dropped. ## Behavior note vs #467/#469 The reverted query-stage impl also preserved ordering *among* the sibling dependency tasks selected by a single object `dependsOn` (e.g. `ui#build → shared#build` when `app#test` selected both and `ui` depends on `shared`), scoped to that one query's execution graph. The graph-stage model intentionally does not: every edge here is global, and a global `ui#build → shared#build` edge would make a plain `vp run ui#build` also build `shared`, contradicting vp's rule that topological ordering applies only with `-r`/`-t`. Ordering among selected dependencies instead comes from each task declaring its own `dependsOn` (the recursive-expansion path documented in `task-query.md`). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01QowxsN8vDKKbQdaSMdxL67

Summary
dependsOnentries with{ task, from }for direct workspace dependency package selection.dependencies,devDependencies, andpeerDependenciesthrough the existing workspace dependency model.Motivation
This provides parity with the common Turbo/Nx
^taskworkflow without special-character task syntax. It reduces migration friction for workspaces that rely on upstream package tasks, such as builds or generated artifacts, before running downstream tasks.