fix(task): prevent wildcard glob test:* from matching parent task test#8165
fix(task): prevent wildcard glob test:* from matching parent task test#8165
test:* from matching parent task test#8165Conversation
Summary of ChangesHello @jdx, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses a critical bug where wildcard task patterns, such as Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request correctly fixes a bug where a wildcard task dependency could match its parent task, causing a circular dependency. The fix is straightforward and effective, preventing the wildcard from matching an empty task suffix. The addition of both a unit test and an end-to-end test ensures the fix is well-covered. The changes are solid, and I have one minor suggestion to make the new unit test more concise.
src/task/mod.rs
Outdated
| assert_eq!(matches.len(), 2); | ||
| assert!(matches.contains(&&"test:foo".to_string())); | ||
| assert!(matches.contains(&&"test:bar".to_string())); | ||
| assert!(!matches.contains(&&"test".to_string())); |
There was a problem hiding this comment.
For improved clarity and robustness, you could consolidate these assertions into a single assert_eq! that checks the exact contents and order of the matched tasks. This makes the test more concise and ensures no other unexpected tasks are matched.
Since BTreeMap iterates over keys in sorted order, the order of matches is deterministic.
| assert_eq!(matches.len(), 2); | |
| assert!(matches.contains(&&"test:foo".to_string())); | |
| assert!(matches.contains(&&"test:bar".to_string())); | |
| assert!(!matches.contains(&&"test".to_string())); | |
| assert_eq!( | |
| matches, | |
| vec![&"test:bar".to_string(), &"test:foo".to_string()] | |
| ); |
There was a problem hiding this comment.
Pull request overview
This PR fixes a bug where wildcard glob patterns like test:* incorrectly matched parent tasks without suffixes (e.g., test), causing circular dependency errors. The fix ensures that * wildcards only match tasks with actual colon-separated suffixes.
Changes:
- Modified pattern matching logic to require non-empty task parts when using
*wildcards - Added unit test to verify the corrected pattern matching behavior
- Added e2e test to validate the fix in a real-world scenario
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/task/mod.rs | Updated wildcard matching logic to prevent self-matches and added unit test |
| e2e/tasks/test_task_wildcard_no_self_match | Added e2e test verifying wildcard patterns don't match parent tasks |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.13 x -- echo |
24.1 ± 0.5 | 23.3 | 29.5 | 1.00 |
mise x -- echo |
24.1 ± 0.5 | 23.3 | 29.4 | 1.00 ± 0.03 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.13 env |
23.8 ± 0.8 | 22.9 | 31.3 | 1.01 ± 0.04 |
mise env |
23.6 ± 0.3 | 23.0 | 25.4 | 1.00 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.13 hook-env |
24.2 ± 0.5 | 23.4 | 26.2 | 1.00 |
mise hook-env |
24.4 ± 0.4 | 23.7 | 26.3 | 1.01 ± 0.03 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.13 ls |
22.6 ± 0.7 | 21.8 | 31.4 | 1.00 |
mise ls |
22.9 ± 0.5 | 22.1 | 27.2 | 1.01 ± 0.04 |
xtasks/test/perf
| Command | mise-2026.2.13 | mise | Variance |
|---|---|---|---|
| install (cached) | 128ms | 127ms | +0% |
| ls (cached) | 80ms | 79ms | +1% |
| bin-paths (cached) | 84ms | 83ms | +1% |
| task-ls (cached) | 812ms | 821ms | -1% |
…test`
When a task named "test" has `run = [{ task = "test:*" }]`, the glob
pattern incorrectly matched the task itself because `*` was matching
an empty string for the task part. This caused a circular dependency
error. Now `test:*` requires the matched task to actually have a
colon-separated suffix (e.g. `test:foo`, `test:bar`).
Fixes #8138
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous fix for test:* matching parent task test broke bare task name lookups. Track whether the * glob was explicit (test:*) vs implicit (test) and only require non-empty task suffix for explicit wildcards. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4965f15 to
cfbeeeb
Compare
### 🚀 Features - **(task)** stream keep-order output in real-time per task by @jdx in [#8164](#8164) ### 🐛 Bug Fixes - **(aqua)** resolve lockfile artifacts for target platform (fix discussion #7479) by @mackwic in [#8183](#8183) - **(exec)** strip shims from PATH to prevent recursive shim execution by @jdx in [#8189](#8189) - **(hook-env)** preserve PATH reordering done after activation by @jdx in [#8190](#8190) - **(lockfile)** resolve version aliases before lockfile lookup by @jdx in [#8194](#8194) - **(registry)** set helm-diff archive bin name to diff by @jean-humann in [#8173](#8173) - **(task)** improve source freshness checks with dynamic task dirs by @rooperuu in [#8169](#8169) - **(task)** resolve global tasks when running from monorepo root by @jdx in [#8192](#8192) - **(task)** prevent wildcard glob `test:*` from matching parent task `test` by @jdx in [#8165](#8165) - **(task)** resolve task_config.includes relative to config root by @jdx in [#8193](#8193) - **(upgrade)** skip untrusted tracked configs during upgrade by @jdx in [#8195](#8195) ### 🚜 Refactor - use enum for npm.pacakge_manager by @risu729 in [#8180](#8180) ### 📚 Documentation - **(plugins)** replace node/asdf-nodejs examples with vfox plugins by @jdx in [#8191](#8191) ### ⚡ Performance - call npm view only once by @risu729 in [#8181](#8181) ### New Contributors - @jean-humann made their first contribution in [#8173](#8173) - @mackwic made their first contribution in [#8183](#8183) - @rooperuu made their first contribution in [#8169](#8169) ## 📦 Aqua Registry Updates #### New Packages (2) - [`BetterDiscord/cli`](https://github.com/BetterDiscord/cli) - [`glossia.ai/cli`](https://github.com/glossia.ai/cli)
…test` (jdx#8165) ## Summary - When a task named `test` has `run = [{ task = "test:*" }]`, the `*` wildcard incorrectly matched the task itself (because `*` matched the empty string for the task part after splitting on `:`), causing a circular dependency error - Fixed `get_matching()` to require that `task:*` patterns only match tasks that actually have a colon-separated suffix (e.g. `test:foo`, `test:bar`), not the parent task `test` - Added unit test and e2e test Fixes jdx#8138 ## Test plan - [x] Unit test `test_get_matching_wildcard_does_not_match_parent` verifies the pattern matching logic - [x] E2e test `test_task_wildcard_no_self_match` verifies the full flow with `mise run test` 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Small, targeted change to task-glob matching semantics plus additional tests; low risk aside from potentially impacting edge-case wildcard behavior. > > **Overview** > Fixes `GetMatchingExt::get_matching` so patterns with an explicit `:` task glob (e.g. `test:*`) only match tasks that actually have a colon-separated suffix, preventing the parent task `test` from being selected and creating circular dependencies. > > Adds a focused unit test for the matching behavior and a new e2e task test ensuring `mise run test` runs `test:foo`/`test:bar` without invoking itself. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit cfbeeeb. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
### 🚀 Features - **(task)** stream keep-order output in real-time per task by @jdx in [jdx#8164](jdx#8164) ### 🐛 Bug Fixes - **(aqua)** resolve lockfile artifacts for target platform (fix discussion jdx#7479) by @mackwic in [jdx#8183](jdx#8183) - **(exec)** strip shims from PATH to prevent recursive shim execution by @jdx in [jdx#8189](jdx#8189) - **(hook-env)** preserve PATH reordering done after activation by @jdx in [jdx#8190](jdx#8190) - **(lockfile)** resolve version aliases before lockfile lookup by @jdx in [jdx#8194](jdx#8194) - **(registry)** set helm-diff archive bin name to diff by @jean-humann in [jdx#8173](jdx#8173) - **(task)** improve source freshness checks with dynamic task dirs by @rooperuu in [jdx#8169](jdx#8169) - **(task)** resolve global tasks when running from monorepo root by @jdx in [jdx#8192](jdx#8192) - **(task)** prevent wildcard glob `test:*` from matching parent task `test` by @jdx in [jdx#8165](jdx#8165) - **(task)** resolve task_config.includes relative to config root by @jdx in [jdx#8193](jdx#8193) - **(upgrade)** skip untrusted tracked configs during upgrade by @jdx in [jdx#8195](jdx#8195) ### 🚜 Refactor - use enum for npm.pacakge_manager by @risu729 in [jdx#8180](jdx#8180) ### 📚 Documentation - **(plugins)** replace node/asdf-nodejs examples with vfox plugins by @jdx in [jdx#8191](jdx#8191) ### ⚡ Performance - call npm view only once by @risu729 in [jdx#8181](jdx#8181) ### New Contributors - @jean-humann made their first contribution in [jdx#8173](jdx#8173) - @mackwic made their first contribution in [jdx#8183](jdx#8183) - @rooperuu made their first contribution in [jdx#8169](jdx#8169) ## 📦 Aqua Registry Updates #### New Packages (2) - [`BetterDiscord/cli`](https://github.com/BetterDiscord/cli) - [`glossia.ai/cli`](https://github.com/glossia.ai/cli)
Summary
testhasrun = [{ task = "test:*" }], the*wildcard incorrectly matched the task itself (because*matched the empty string for the task part after splitting on:), causing a circular dependency errorget_matching()to require thattask:*patterns only match tasks that actually have a colon-separated suffix (e.g.test:foo,test:bar), not the parent tasktestFixes #8138
Test plan
test_get_matching_wildcard_does_not_match_parentverifies the pattern matching logictest_task_wildcard_no_self_matchverifies the full flow withmise run test🤖 Generated with Claude Code
Note
Low Risk
Small, targeted change to task-glob matching semantics plus additional tests; low risk aside from potentially impacting edge-case wildcard behavior.
Overview
Fixes
GetMatchingExt::get_matchingso patterns with an explicit:task glob (e.g.test:*) only match tasks that actually have a colon-separated suffix, preventing the parent tasktestfrom being selected and creating circular dependencies.Adds a focused unit test for the matching behavior and a new e2e task test ensuring
mise run testrunstest:foo/test:barwithout invoking itself.Written by Cursor Bugbot for commit cfbeeeb. This will update automatically on new commits. Configure here.