Skip to content

fix(task): exclude inherited tasks from wildcard pattern matching#7850

Closed
jdx wants to merge 2 commits into
mainfrom
fix/wildcard-inherited-tasks
Closed

fix(task): exclude inherited tasks from wildcard pattern matching#7850
jdx wants to merge 2 commits into
mainfrom
fix/wildcard-inherited-tasks

Conversation

@jdx

@jdx jdx commented Jan 27, 2026

Copy link
Copy Markdown
Owner

Summary

  • Wildcard patterns like //...:task now only match tasks explicitly defined at that path, not tasks inherited from parent configs
  • Adds inherited field to Task struct to track task origin
  • Fixes circular dependency when root defines depends = ['//...:test'] and subdirs inherit that task
  • Fixes unexpected execution when running //packages/...:build on packages that don't define their own build task
  • Explicit paths like //packages/app:build still work for inherited tasks (explicit intent)

Test plan

  • Added e2e test test_task_monorepo_wildcard_inherited covering:
    • Wildcards only match explicitly defined tasks
    • Explicit paths still work for inherited tasks
    • Inherited tasks still visible in task list
    • No circular dependency with wildcard depends
  • Existing monorepo tests pass (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.

  • Add Task.inherited (non-serialized) and set it during subdir task load to track task origin
  • Filter wildcard matches (...) to exclude inherited tasks in both dependency resolution and task lookup
  • Keep explicit paths (e.g., //pkg:task) working for inherited tasks; root tasks still match //:task
  • New e2e test_task_monorepo_wildcard_inherited covering wildcard behavior, explicit paths, task listing, and circular dependency regression

Written by Cursor Bugbot for commit cda978f. This will update automatically on new commits. Configure here.

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>
Copilot AI review requested due to automatic review settings January 27, 2026 12:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 inherited boolean field to the Task struct to track whether a task comes from a parent config
  • Modified wildcard pattern matching to filter out inherited tasks in both get_task_lists and match_tasks_with_context
  • Added logic to mark tasks as inherited when their config_root differs 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.

Comment thread src/task/task_list.rs
// 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)

Copilot AI Jan 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment thread src/task/mod.rs
) -> 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("...");

Copilot AI Jan 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment thread src/config/mod.rs
Comment on lines +1732 to +1733
if let Some(ref config_root) = task.config_root {
task.inherited = config_root != &subdir;

Copilot AI Jan 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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;
}

Copilot uses AI. Check for mistakes.
@github-actions

github-actions Bot commented Jan 27, 2026

Copy link
Copy Markdown

Hyperfine Performance

mise x -- echo

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%

@jdx

jdx commented Jan 27, 2026

Copy link
Copy Markdown
Owner Author

Closing in favor of #7851 which reverts task inheritance entirely.

@jdx jdx closed this Jan 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants