fix(task): execute monorepo subdirectory prepare steps from root#8291
fix(task): execute monorepo subdirectory prepare steps from root#8291
Conversation
When running `mise run //subdir:task` from the monorepo root, prepare steps defined in the subdirectory config were skipped because prepare ran before task resolution. Move prepare to run after `get_task_lists()` so subdirectory config files discovered during task resolution can be passed to the PrepareEngine. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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 in Highlights
Changelog
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 addresses an issue where prepare steps in monorepo subdirectories were skipped when running tasks from the root. The solution involves moving the prepare execution phase to after task resolution and injecting the configuration files of the resolved tasks into the PrepareEngine. Overall, the changes are well-structured and include a comprehensive end-to-end test. My feedback focuses on minor performance optimizations regarding the deduplication of configuration files and the use of more efficient data structures for tracking disabled providers.
| let subdir_configs: Vec<_> = task_list | ||
| .iter() | ||
| .filter_map(|task| task.cf.clone()) | ||
| .collect(); |
There was a problem hiding this comment.
Resolved tasks in a monorepo often share the same configuration file. Deduplicating subdir_configs before passing them to the PrepareEngine prevents redundant processing of the same prepare configuration.
| let subdir_configs: Vec<_> = task_list | |
| .iter() | |
| .filter_map(|task| task.cf.clone()) | |
| .collect(); | |
| let subdir_configs: Vec<_> = task_list | |
| .iter() .filter_map(|task| task.cf.clone()) | |
| .unique_by(|cf| cf.get_path().to_path_buf()) | |
| .collect(); |
| self.providers.iter().map(|p| p.id().to_string()).collect(); | ||
| let mut disabled: Vec<String> = vec![]; | ||
|
|
||
| for cf in config_files { |
| } | ||
| } | ||
|
|
||
| /// List all discovered providers |
There was a problem hiding this comment.
There was a problem hiding this comment.
Pull request overview
This PR fixes an issue where monorepo subdirectory prepare steps were being skipped when running tasks from the root directory using the //subdir:task syntax. The fix moves prepare step execution to occur after task resolution, allowing the PrepareEngine to discover and include prepare providers from subdirectory config files.
Changes:
- Refactored
PrepareEngineto extract provider building logic into a helper method and addedadd_config_files()for injecting additional config file providers - Moved prepare step execution in
Runcommand to after task resolution so subdirectory configs are available - Added e2e test validating monorepo subdirectory prepare steps execute correctly
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/prepare/engine.rs | Extracts build_provider() helper and adds add_config_files() method to support injecting subdirectory config providers |
| src/cli/run.rs | Moves prepare execution after task resolution and injects subdirectory config files into PrepareEngine |
| e2e/cli/test_prepare | Adds test case for monorepo subdirectory prepare steps when running //subdir:task from root |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let mut seen_ids: HashSet<String> = | ||
| self.providers.iter().map(|p| p.id().to_string()).collect(); |
There was a problem hiding this comment.
The seen_ids HashSet is initialized from existing providers but doesn't check for duplicates within the new config files being added. If the same provider ID appears in multiple config files passed to this method, only the first occurrence will be added. Consider documenting this behavior or adding validation to warn about duplicate provider IDs within the input config files.
| let subdir_configs: Vec<_> = task_list | ||
| .iter() | ||
| .filter_map(|task| task.cf.clone()) | ||
| .collect(); |
There was a problem hiding this comment.
The cloning of task.cf values and collection into subdir_configs could benefit from a comment explaining why we're collecting config files from tasks. While the prepare execution comment above provides context, documenting this specific collection step would clarify why we need these config files and what they represent (subdirectory configs from resolved tasks).
|
bugbot run |
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.17 x -- echo |
21.9 ± 0.3 | 21.4 | 24.3 | 1.00 |
mise x -- echo |
22.8 ± 1.9 | 22.1 | 61.6 | 1.04 ± 0.09 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.17 env |
21.3 ± 0.5 | 20.8 | 31.9 | 1.00 |
mise env |
21.5 ± 0.4 | 20.8 | 27.2 | 1.01 ± 0.03 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.17 hook-env |
22.0 ± 0.5 | 21.4 | 27.9 | 1.00 |
mise hook-env |
22.1 ± 0.2 | 21.6 | 24.1 | 1.01 ± 0.03 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.17 ls |
19.6 ± 0.2 | 19.2 | 21.0 | 1.00 |
mise ls |
19.7 ± 0.4 | 19.2 | 26.8 | 1.00 ± 0.03 |
xtasks/test/perf
| Command | mise-2026.2.17 | mise | Variance |
|---|---|---|---|
| install (cached) | 123ms | 122ms | +0% |
| ls (cached) | 74ms | 74ms | +0% |
| bin-paths (cached) | 79ms | 79ms | +0% |
| task-ls (cached) | 802ms | 796ms | +0% |
### 🚀 Features - **(install)** auto-lock all platforms after tool installation by @jdx in [#8277](#8277) ### 🐛 Bug Fixes - **(config)** respect --yes flag for config trust prompts by @jdx in [#8288](#8288) - **(exec)** strip shims from PATH on Unix to prevent infinite recursion by @jdx in [#8276](#8276) - **(install)** validate --locked before --dry-run short-circuit by @altendky in [#8290](#8290) - **(release)** refresh PATH after mise up in release-plz by @jdx in [#8292](#8292) - **(schema)** replace unevaluatedProperties with additionalProperties by @jdx in [#8285](#8285) - **(task)** avoid duplicated stderr on task failure in replacing mode by @jdx in [#8275](#8275) - **(task)** use process groups to kill child process trees on Unix by @jdx in [#8279](#8279) - **(task)** run depends_post tasks even when parent task fails by @jdx in [#8274](#8274) - **(task)** suggest similar commands when mistyping a CLI subcommand by @jdx in [#8286](#8286) - **(task)** execute monorepo subdirectory prepare steps from root by @jdx in [#8291](#8291) - **(upgrade)** don't force-reinstall already installed versions by @jdx in [#8282](#8282) - **(watch)** restore terminal state after watchexec exits by @jdx in [#8273](#8273) ### 📚 Documentation - clarify that MISE_CEILING_PATHS excludes the ceiling directory itself by @jdx in [#8283](#8283) ### Chore - replace gen-release-notes script with communique by @jdx in [#8289](#8289) ### New Contributors - @altendky made their first contribution in [#8290](#8290) ## 📦 Aqua Registry Updates #### New Packages (4) - [`Skarlso/crd-to-sample-yaml`](https://github.com/Skarlso/crd-to-sample-yaml) - [`kunobi-ninja/kunobi-releases`](https://github.com/kunobi-ninja/kunobi-releases) - [`swanysimon/markdownlint-rs`](https://github.com/swanysimon/markdownlint-rs) - [`tmux/tmux-builds`](https://github.com/tmux/tmux-builds) #### Updated Packages (2) - [`firecow/gitlab-ci-local`](https://github.com/firecow/gitlab-ci-local) - [`k1LoW/runn`](https://github.com/k1LoW/runn)
## [2026.2.18](https://github.com/jdx/mise/compare/v2026.2.17..v2026.2.18) - 2026-02-21 ### 🚀 Features - **(install)** auto-lock all platforms after tool installation by @jdx in [#8277](jdx/mise#8277) ### 🐛 Bug Fixes - **(config)** respect --yes flag for config trust prompts by @jdx in [#8288](jdx/mise#8288) - **(exec)** strip shims from PATH on Unix to prevent infinite recursion by @jdx in [#8276](jdx/mise#8276) - **(install)** validate --locked before --dry-run short-circuit by @altendky in [#8290](jdx/mise#8290) - **(release)** refresh PATH after mise up in release-plz by @jdx in [#8292](jdx/mise#8292) - **(schema)** replace unevaluatedProperties with additionalProperties by @jdx in [#8285](jdx/mise#8285) - **(task)** avoid duplicated stderr on task failure in replacing mode by @jdx in [#8275](jdx/mise#8275) - **(task)** use process groups to kill child process trees on Unix by @jdx in [#8279](jdx/mise#8279) - **(task)** run depends_post tasks even when parent task fails by @jdx in [#8274](jdx/mise#8274) - **(task)** suggest similar commands when mistyping a CLI subcommand by @jdx in [#8286](jdx/mise#8286) - **(task)** execute monorepo subdirectory prepare steps from root by @jdx in [#8291](jdx/mise#8291) - **(upgrade)** don't force-reinstall already installed versions by @jdx in [#8282](jdx/mise#8282) - **(watch)** restore terminal state after watchexec exits by @jdx in [#8273](jdx/mise#8273) ### 📚 Documentation - clarify that MISE_CEILING_PATHS excludes the ceiling directory itself by @jdx in [#8283](jdx/mise#8283) ### Chore - replace gen-release-notes script with communique by @jdx in [#8289](jdx/mise#8289) ### New Contributors - @altendky made their first contribution in [#8290](jdx/mise#8290) ### 📦 Aqua Registry Updates #### New Packages (4) - [`Skarlso/crd-to-sample-yaml`](https://github.com/Skarlso/crd-to-sample-yaml) - [`kunobi-ninja/kunobi-releases`](https://github.com/kunobi-ninja/kunobi-releases) - [`swanysimon/markdownlint-rs`](https://github.com/swanysimon/markdownlint-rs) - [`tmux/tmux-builds`](https://github.com/tmux/tmux-builds) #### Updated Packages (2) - [`firecow/gitlab-ci-local`](https://github.com/firecow/gitlab-ci-local) - [`k1LoW/runn`](https://github.com/k1LoW/runn) ## [2026.2.17](https://github.com/jdx/mise/compare/v2026.2.16..v2026.2.17) - 2026-02-19 ### 🚀 Features - **(prepare)** update mtime of outputs after command is run by @halms in [#8243](jdx/mise#8243) ### 🐛 Bug Fixes - **(install)** use backend bin paths for per-tool postinstall hooks by @jdx in [#8234](jdx/mise#8234) - **(use)** write to config.toml instead of config.local.toml by @jdx in [#8240](jdx/mise#8240) - default legacy .mise.backend installs to non-explicit by @jean-humann in [#8245](jdx/mise#8245) ### 🚜 Refactor - **(config)** consolidate flat task_* settings into nested task.* by @jdx in [#8239](jdx/mise#8239) ### Chore - **(prepare)** refactor common code into ProviderBase by @halms in [#8246](jdx/mise#8246) ### 📦 Aqua Registry Updates #### Updated Packages (1) - [`namespacelabs/foundation/nsc`](https://github.com/namespacelabs/foundation/nsc)
This updates the tests introduced in: jdx#8291 to demonstrate a case where prepare steps are not properly run.
…#8291) ## Summary - **Fixes** monorepo subdirectory prepare steps being skipped when running `mise run //subdir:task` from the root ([discussions/6564#discussioncomment-15853930](jdx#6564 (comment))) - Moves prepare execution to after task resolution so subdirectory config files discovered during `get_task_lists()` are passed to `PrepareEngine` - Extracts `build_provider()` helper in `PrepareEngine` and adds `add_config_files()` method for injecting additional config file providers ## Test plan - [x] `mise run build` compiles successfully - [x] `mise run test:e2e test_prepare` passes (all existing + new test) - [x] New e2e test: sets up monorepo with subdirectory prepare provider, runs `mise run //subapp:check` from root, asserts prepare step executed before task 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes task execution ordering and expands which `prepare` providers can run for a `mise run`, which could affect dependency prep behavior in multi-config/monorepo setups. > > **Overview** > Fixes `mise run //subdir:task` in monorepos so auto-enabled `prepare` steps from the referenced subdirectory config are executed. > > This moves auto-`prepare` execution in `run` to *after* task resolution and injects the resolved tasks’ config files into `PrepareEngine` via a new `add_config_files()` path (with provider construction refactored into `build_provider()`). Adds an e2e regression test that asserts subdirectory `prepare` runs when invoking `//subapp:check` from the repo root. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit f13905e. 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> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### 🚀 Features - **(install)** auto-lock all platforms after tool installation by @jdx in [jdx#8277](jdx#8277) ### 🐛 Bug Fixes - **(config)** respect --yes flag for config trust prompts by @jdx in [jdx#8288](jdx#8288) - **(exec)** strip shims from PATH on Unix to prevent infinite recursion by @jdx in [jdx#8276](jdx#8276) - **(install)** validate --locked before --dry-run short-circuit by @altendky in [jdx#8290](jdx#8290) - **(release)** refresh PATH after mise up in release-plz by @jdx in [jdx#8292](jdx#8292) - **(schema)** replace unevaluatedProperties with additionalProperties by @jdx in [jdx#8285](jdx#8285) - **(task)** avoid duplicated stderr on task failure in replacing mode by @jdx in [jdx#8275](jdx#8275) - **(task)** use process groups to kill child process trees on Unix by @jdx in [jdx#8279](jdx#8279) - **(task)** run depends_post tasks even when parent task fails by @jdx in [jdx#8274](jdx#8274) - **(task)** suggest similar commands when mistyping a CLI subcommand by @jdx in [jdx#8286](jdx#8286) - **(task)** execute monorepo subdirectory prepare steps from root by @jdx in [jdx#8291](jdx#8291) - **(upgrade)** don't force-reinstall already installed versions by @jdx in [jdx#8282](jdx#8282) - **(watch)** restore terminal state after watchexec exits by @jdx in [jdx#8273](jdx#8273) ### 📚 Documentation - clarify that MISE_CEILING_PATHS excludes the ceiling directory itself by @jdx in [jdx#8283](jdx#8283) ### Chore - replace gen-release-notes script with communique by @jdx in [jdx#8289](jdx#8289) ### New Contributors - @altendky made their first contribution in [jdx#8290](jdx#8290) ## 📦 Aqua Registry Updates #### New Packages (4) - [`Skarlso/crd-to-sample-yaml`](https://github.com/Skarlso/crd-to-sample-yaml) - [`kunobi-ninja/kunobi-releases`](https://github.com/kunobi-ninja/kunobi-releases) - [`swanysimon/markdownlint-rs`](https://github.com/swanysimon/markdownlint-rs) - [`tmux/tmux-builds`](https://github.com/tmux/tmux-builds) #### Updated Packages (2) - [`firecow/gitlab-ci-local`](https://github.com/firecow/gitlab-ci-local) - [`k1LoW/runn`](https://github.com/k1LoW/runn)
Summary
mise run //subdir:taskfrom the root (discussions/6564#discussioncomment-15853930)get_task_lists()are passed toPrepareEnginebuild_provider()helper inPrepareEngineand addsadd_config_files()method for injecting additional config file providersTest plan
mise run buildcompiles successfullymise run test:e2e test_preparepasses (all existing + new test)mise run //subapp:checkfrom root, asserts prepare step executed before task🤖 Generated with Claude Code
Note
Medium Risk
Changes task execution ordering and expands which
prepareproviders can run for amise run, which could affect dependency prep behavior in multi-config/monorepo setups.Overview
Fixes
mise run //subdir:taskin monorepos so auto-enabledpreparesteps from the referenced subdirectory config are executed.This moves auto-
prepareexecution inrunto after task resolution and injects the resolved tasks’ config files intoPrepareEnginevia a newadd_config_files()path (with provider construction refactored intobuild_provider()). Adds an e2e regression test that asserts subdirectoryprepareruns when invoking//subapp:checkfrom the repo root.Written by Cursor Bugbot for commit f13905e. This will update automatically on new commits. Configure here.