fix(task): exclude inherited tasks from wildcard pattern matching#7850
fix(task): exclude inherited tasks from wildcard pattern matching#7850jdx wants to merge 2 commits into
Conversation
Wildcard patterns like `//...:task` now only match tasks that are explicitly defined at that path, not tasks inherited from parent configs. This prevents several issues: 1. Circular dependencies when root defines `depends = ['//...:test']` and subdirs inherit that task 2. Unexpected execution when running `//packages/...:build` on packages that don't define their own build task The fix adds an `inherited` field to the Task struct that tracks whether a task came from a parent config. When matching wildcards (patterns containing "..."), inherited tasks are filtered out. Explicit paths like `//packages/app:build` still work for inherited tasks since that represents explicit intent. Fixes: #6564 (comment) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes a bug where wildcard patterns like //...:task were incorrectly matching tasks inherited from parent configs, leading to circular dependencies and unexpected task execution. The fix adds an inherited field to track task origin and filters inherited tasks when wildcard patterns are used, while still allowing explicit paths to access inherited tasks.
Changes:
- Added
inheritedboolean field to theTaskstruct to track whether a task comes from a parent config - Modified wildcard pattern matching to filter out inherited tasks in both
get_task_listsandmatch_tasks_with_context - Added logic to mark tasks as inherited when their
config_rootdiffers from the subdirectory being loaded
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/task/mod.rs | Added inherited field to Task struct and filtering logic for wildcard patterns |
| src/task/task_list.rs | Added filtering of inherited tasks when wildcard patterns are detected |
| src/config/mod.rs | Added logic to mark tasks as inherited based on config_root comparison |
| e2e/tasks/test_task_monorepo_wildcard_inherited | Added comprehensive e2e test covering wildcard behavior with inherited tasks |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // to avoid matching tasks that exist only due to inheritance from parent configs. | ||
| // This prevents issues like circular dependencies when root defines | ||
| // `test = { depends = ['//...:test'] }` and subdirs inherit that task. | ||
| .filter(|task| !t.contains("...") || !task.inherited) |
There was a problem hiding this comment.
The pattern detection logic t.contains(\"...\") is duplicated across multiple locations (here and in match_tasks_with_context). Consider extracting this into a helper function like is_wildcard_pattern to improve maintainability and ensure consistency if the wildcard detection logic needs to change.
| ) -> Result<Vec<Task>> { | ||
| let resolved_pattern = resolve_task_pattern(&td.task, parent_task); | ||
| // When using wildcard patterns (containing "..."), filter out inherited tasks | ||
| let filter_inherited = resolved_pattern.contains("..."); |
There was a problem hiding this comment.
The wildcard pattern detection logic is duplicated here and in task_list.rs. Consider extracting this into a shared helper function to maintain consistency and reduce duplication.
| if let Some(ref config_root) = task.config_root { | ||
| task.inherited = config_root != &subdir; |
There was a problem hiding this comment.
Tasks without a config_root (when task.config_root is None) will have inherited remain as false by default. If tasks can legitimately have None as their config_root and should be considered inherited in certain scenarios, this logic may incorrectly classify them. Consider whether tasks with None config_root should have explicit handling.
| if let Some(ref config_root) = task.config_root { | |
| task.inherited = config_root != &subdir; | |
| match task.config_root { | |
| Some(ref config_root) => { | |
| task.inherited = config_root != &subdir; | |
| } | |
| None => { | |
| task.inherited = false; | |
| } |
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.8 x -- echo |
20.8 ± 0.5 | 19.4 | 22.9 | 1.00 |
mise x -- echo |
21.7 ± 0.8 | 20.3 | 28.3 | 1.05 ± 0.05 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.8 env |
20.1 ± 0.5 | 18.9 | 23.1 | 1.00 |
mise env |
21.2 ± 0.7 | 19.9 | 24.3 | 1.06 ± 0.04 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.8 hook-env |
20.6 ± 0.5 | 19.5 | 23.2 | 1.00 |
mise hook-env |
21.9 ± 0.7 | 20.0 | 24.5 | 1.06 ± 0.04 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.8 ls |
18.1 ± 0.4 | 17.1 | 19.9 | 1.00 |
mise ls |
19.2 ± 0.6 | 17.6 | 21.4 | 1.06 ± 0.04 |
xtasks/test/perf
| Command | mise-2026.1.8 | mise | Variance |
|---|---|---|---|
| install (cached) | 113ms | 114ms | +0% |
| ls (cached) | 69ms | 69ms | +0% |
| bin-paths (cached) | 73ms | 74ms | -1% |
| task-ls (cached) | 290ms | 302ms | -3% |
|
Closing in favor of #7851 which reverts task inheritance entirely. |
Summary
//...:tasknow only match tasks explicitly defined at that path, not tasks inherited from parent configsinheritedfield to Task struct to track task origindepends = ['//...:test']and subdirs inherit that task//packages/...:buildon packages that don't define their own build task//packages/app:buildstill work for inherited tasks (explicit intent)Test plan
test_task_monorepo_wildcard_inheritedcovering:test_task_monorepo_task_inheritance,test_task_monorepo_syntax,test_task_monorepo_optional_colon,test_task_monorepo_name_conflicts)Fixes: #6564 (comment)
🤖 Generated with Claude Code
Note
Prevents wildcard patterns from matching inherited monorepo tasks and adds safeguards against cycles.
Task.inherited(non-serialized) and set it during subdir task load to track task origin...) to exclude inherited tasks in both dependency resolution and task lookup//pkg:task) working for inherited tasks; root tasks still match//:tasktest_task_monorepo_wildcard_inheritedcovering wildcard behavior, explicit paths, task listing, and circular dependency regressionWritten by Cursor Bugbot for commit cda978f. This will update automatically on new commits. Configure here.