Skip to content

feat(prepare): add dependency ordering to prepare steps#8401

Merged
jdx merged 16 commits intomainfrom
feat/prepare-depends
Mar 2, 2026
Merged

feat(prepare): add dependency ordering to prepare steps#8401
jdx merged 16 commits intomainfrom
feat/prepare-depends

Conversation

@jdx
Copy link
Copy Markdown
Owner

@jdx jdx commented Mar 1, 2026

Summary

  • Add depends field to prepare provider config for declaring inter-provider dependencies
  • Implement Kahn's algorithm scheduler (PrepareDeps) with cycle detection and failure propagation, following the same pattern as tool_deps.rs
  • When no providers have depends, the existing parallel execution path is used unchanged (no regression)
  • When depends are present, a dependency-aware scheduler runs providers as their dependencies complete

Closes #8392 (partial)

TOML syntax

[prepare.uv]
auto = true

[prepare.ansible-galaxy]
auto = true
depends = ["uv"]
run = "ansible-galaxy install -f requirements.yml"
sources = ["requirements.yml"]
outputs = [".galaxy-installed"]

Behavior

  • No depends → same as today (all independent providers run in parallel)
  • depends = ["uv"] → waits for "uv" to complete before starting
  • Cycle detection → blocked providers get Skipped result with warning
  • Unknown dep reference → warning, treated as satisfied (non-blocking)
  • Fresh/skipped dependencies → treated as already satisfied

Test plan

  • Unit: 7 tests in prepare_deps.rs — empty graph, no deps, linear ordering, failure blocking, cycle detection, unknown dep error, diamond deps
  • E2E: test_prepare_depends — linear dependency ordering, independent parallel execution, dry-run
  • E2E: existing test_prepare passes (no regression)
  • Lint and build pass

🤖 Generated with Claude Code


Note

Medium Risk
Adds a new dependency-aware scheduler to mise prepare and refactors tool installation dependency logic onto shared graph code, which could affect execution ordering and failure handling under concurrency. Backwards-compatible behavior is preserved when depends is not used, lowering regression risk.

Overview
Adds a depends field to prepare provider config (docs + JSON schema) so mise prepare can enforce ordering between providers while still running independent providers concurrently.

Updates the prepare engine to switch between the existing parallel execution path and a new dependency-aware scheduler that detects cycles, blocks/skips dependents on failure, and reports a new Failed step result (with aggregated errors). Extracts the Kahn-style scheduler into a reusable DepsGraph and refactors ToolDeps to use it, and adds an e2e test covering dependency ordering and dry-run output.

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

Add `depends` field to prepare provider config, allowing providers to
declare dependencies on other providers. Uses Kahn's algorithm (same
pattern as tool_deps.rs) to schedule providers in topological order
with cycle detection and failure propagation.

When no providers have depends, the existing parallel execution path
is used unchanged. When depends are present, a dependency-aware
scheduler runs providers as their dependencies complete.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 significantly enhances the prepare command by introducing a robust dependency management system. It allows prepare steps to be explicitly ordered, ensuring that complex setup processes can be executed reliably and predictably. This change improves the overall stability and flexibility of the mise environment preparation, making it more suitable for projects with intricate build or setup requirements.

Highlights

  • Dependency Ordering for Prepare Steps: Introduced a new depends field in the prepare provider configuration, allowing users to declare inter-provider dependencies.
  • Kahn's Algorithm Scheduler: Implemented a dependency-aware scheduler using Kahn's algorithm to ensure prepare steps run in the correct order, complete with cycle detection and failure propagation.
  • Backward Compatibility: Maintained the existing parallel execution path for prepare providers that do not specify any dependencies, ensuring no regression in current behavior.
  • Robust Error Handling: Added mechanisms to handle dependency cycles (blocking affected providers) and unknown dependency references (issuing warnings but not blocking execution).
Changelog
  • e2e/cli/test_prepare_depends
    • Added a new E2E test to verify the correct execution order of prepare providers with defined dependencies, including parallel execution of independent steps and dry-run behavior.
  • schema/mise.json
    • Updated the JSON schema to include the new depends array property within the prepare provider configuration, allowing for dependency declarations.
  • src/prepare/engine.rs
    • Modified the PrepareEngine to incorporate dependency-aware execution logic.
    • Introduced a depends field to the PrepareJob struct to store provider dependencies.
    • Refactored the run method to conditionally use either a simple parallel execution or a new dependency-aware execution (run_with_deps) based on the presence of dependencies.
    • Implemented run_parallel for providers without dependencies and run_with_deps utilizing Kahn's algorithm for ordered execution.
  • src/prepare/mod.rs
    • Added a new public module prepare_deps for dependency management.
    • Extended the PrepareProvider trait with a depends method to retrieve declared dependencies from provider configurations.
  • src/prepare/prepare_deps.rs
    • Created a new module prepare_deps containing the PrepareDeps struct.
    • Implemented PrepareDeps to manage a dependency graph using petgraph, enabling Kahn's algorithm for scheduling.
    • Added functionality for cycle detection, blocking providers involved in cycles, and propagating failures to dependent providers.
    • Included comprehensive unit tests for various dependency scenarios, including empty graphs, no dependencies, linear ordering, failure blocking, cycle detection, unknown dependencies, and diamond dependencies.
  • src/prepare/rule.rs
    • Added a depends field to the PrepareProviderConfig struct, allowing prepare providers to specify their dependencies.
Activity
  • The pull request introduces a new feature for dependency ordering in prepare steps.
  • The author provided a detailed summary of the changes, including the new depends field, Kahn's algorithm implementation, and behavior notes.
  • A comprehensive test plan was outlined, covering unit tests for prepare_deps.rs and E2E tests for various dependency scenarios, ensuring robustness and preventing regressions.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces dependency management for prepare steps, which is a significant and well-implemented feature. The changes include adding a depends field to the configuration, implementing a dependency scheduler using Kahn's algorithm with cycle detection, and preserving the existing parallel execution for projects without dependencies. The new logic is well-tested with both unit and end-to-end tests. My only suggestion is to improve the error handling in one spot to make the code more robust against potential panics.

Comment thread src/prepare/engine.rs Outdated
}

Ok(PrepareResult { steps: results })
Ok(Arc::try_unwrap(results).unwrap().into_inner().unwrap())
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.

medium

Using unwrap() here can lead to a panic if the Arc has more than one strong reference or if the Mutex is poisoned. While this might be unlikely in the current control flow, it's safer to handle these potential errors gracefully by propagating a Result instead of panicking.

        Arc::try_unwrap(results)
            .map_err(|_| eyre!("Failed to unwrap Arc for prepare results"))?
            .into_inner()
            .map_err(|p| eyre!("Prepare results mutex was poisoned: {p:?}"))

@jdx
Copy link
Copy Markdown
Owner Author

jdx commented Mar 1, 2026

bugbot run

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 1, 2026

Greptile Summary

Added dependency ordering support to prepare providers using Kahn's algorithm scheduler with cycle detection and failure propagation.

Key changes:

  • New depends field in prepare provider config allows declaring inter-provider dependencies
  • PrepareDeps scheduler mirrors the proven pattern from tool_deps.rs - same algorithm, same structure
  • Smart execution path selection: no dependencies = original parallel path (zero regression risk), with dependencies = scheduler
  • Comprehensive cycle detection blocks problematic providers with clear warnings
  • Unknown/fresh/skipped dependencies treated as satisfied (non-blocking)
  • Failure propagation ensures dependent providers skip when dependencies fail

Testing:

  • 7 unit tests in prepare_deps.rs covering empty graph, linear ordering, failure blocking, cycles, diamond dependencies
  • E2E tests verify real-world behavior with linear dependencies and mixed independent/dependent providers
  • Existing test_prepare passes confirming no regression

Confidence Score: 5/5

  • This PR is safe to merge - well-tested, follows established patterns, and has zero regression risk for existing workflows.
  • Score reflects excellent implementation quality: mirrors proven tool_deps.rs pattern, comprehensive test coverage (7 unit + E2E tests), smart conditional execution prevents any regression, proper async/await with semaphore-based concurrency control, and thorough cycle detection with clear error messages.
  • No files require special attention - all implementations follow established patterns and include proper testing

Important Files Changed

Filename Overview
src/prepare/prepare_deps.rs New dependency scheduler implementing Kahn's algorithm with cycle detection and failure propagation - comprehensive tests included, follows established pattern from tool_deps.rs
src/prepare/engine.rs Refactored to support both parallel and dependency-aware execution paths - clean separation with no regression risk for non-dependent providers
e2e/cli/test_prepare_depends Comprehensive E2E tests covering linear dependencies, mixed independent/dependent providers, and dry-run mode

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[PrepareEngine.run] --> B{Check if any<br/>providers have depends}
    B -->|No deps| C[run_parallel<br/>Simple parallel execution]
    B -->|Has deps| D[run_with_deps<br/>Dependency-aware execution]
    
    D --> E[Filter deps:<br/>Remove satisfied/unknown]
    E --> F[PrepareDeps.new<br/>Build dependency graph]
    F --> G[Detect cycles]
    G --> H[Block cyclic providers]
    
    H --> I[PrepareDeps.subscribe<br/>Get receiver channel]
    I --> J[emit_leaves<br/>Find ready providers]
    
    J --> K{tokio::select loop}
    K -->|Task completes| L{Success or failure?}
    L -->|Success| M[complete_success<br/>Remove from graph]
    L -->|Failure| N[complete_failure<br/>Block dependents]
    
    M --> J
    N --> J
    
    K -->|Receive ready provider| O[Spawn task with semaphore]
    O --> K
    
    K -->|Receive None| P[All done - exit loop]
    P --> Q[Wait for in-flight tasks]
    Q --> R[Return results]
    
    C --> R
Loading

Last reviewed commit: 6d4177d

autofix-ci Bot and others added 4 commits March 1, 2026 23:47
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace unwrap() on Arc::try_unwrap and Mutex::into_inner with proper
error propagation to avoid potential panics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment thread src/prepare/engine.rs
When using depends, failed providers were logged but silently swallowed,
causing exit code 0. Now failures are recorded as Failed results and
the function returns an error, matching run_parallel behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment thread src/prepare/engine.rs Outdated
jdx and others added 2 commits March 2, 2026 00:19
Add type aliases for complex tuple and Result types used in the
dependency-aware execution path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wrap task execution in catch_unwind so panics are caught and routed
through the normal Ok(Err(...)) path, which calls complete_failure on
the dependency graph. Previously a JoinError from a panic would leave
the node in the graph, preventing is_all_done from ever returning true
and causing the select loop to block forever.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment thread src/prepare/engine.rs
Comment thread src/prepare/prepare_deps.rs
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 2, 2026

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.24 x -- echo 28.2 ± 0.8 27.2 33.3 1.20 ± 0.05
mise x -- echo 23.4 ± 0.7 22.4 29.8 1.00
✅ Performance improvement for x -- echo is 20%

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.24 env 27.9 ± 1.0 26.4 34.4 1.22 ± 0.05
mise env 22.9 ± 0.4 22.0 24.7 1.00
✅ Performance improvement for env is 22%

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.24 hook-env 29.0 ± 0.7 27.8 33.4 1.21 ± 0.03
mise hook-env 23.9 ± 0.4 23.0 25.4 1.00
✅ Performance improvement for hook-env is 21%

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.24 ls 23.3 ± 0.6 22.1 26.5 1.09 ± 0.04
mise ls 21.3 ± 0.6 20.6 28.8 1.00

xtasks/test/perf

Command mise-2026.2.24 mise Variance
install (cached) 162ms 150ms +8%
ls (cached) 89ms ✅ 80ms +11%
bin-paths (cached) 97ms ✅ 85ms +14%
task-ls (cached) 829ms 822ms +0%

✅ Performance improvement: ls cached is 11%
✅ Performance improvement: bin-paths cached is 14%

… in failures

Extract common Kahn's algorithm scheduling logic from PrepareDeps and
ToolDeps into a generic DepsGraph<K, N> struct, eliminating code
duplication between the two modules (~435 lines removed).

Also fix error details being lost in run_with_deps: previously the
returned error only listed failed provider names, now it includes the
original error messages for each failure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment thread src/prepare/engine.rs Outdated
jdx and others added 3 commits March 2, 2026 01:32
Add a built-in prepare provider for git submodules that detects
.gitmodules and runs `git submodule update --init --recursive`
when submodule directories are stale.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d is_empty

- Replace Arc<Mutex<Vec>> with plain Vec for results/errors in run_with_deps
  since they are only accessed from the main tokio::select! loop
- Track inflight task IDs via HashMap<tokio::task::Id, String> to recover
  provider identity on JoinError (panic/cancellation) and call complete_failure
- Remove unused is_empty() methods from PrepareDeps and ToolDeps
- Remove duplicate test_is_all_done_empty test from ToolDeps

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jdx
Copy link
Copy Markdown
Owner Author

jdx commented Mar 2, 2026

bugbot run

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Comment thread src/prepare/engine.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jdx jdx merged commit 6607a23 into main Mar 2, 2026
36 checks passed
@jdx jdx deleted the feat/prepare-depends branch March 2, 2026 03:01
jdx pushed a commit that referenced this pull request Mar 2, 2026
### 🚀 Features

- **(hooks)** add task references to hooks and watch_files by @jdx in
[#8400](#8400)
- **(prepare)** add git-submodule built-in provider by @jdx in
[#8407](#8407)
- **(prepare)** add human-readable stale reasons to prepare output by
@jdx in [#8408](#8408)
- **(prepare)** add dependency ordering to prepare steps by @jdx in
[#8401](#8401)
- **(prepare)** add --explain flag for provider diagnostics by @jdx in
[#8409](#8409)
- **(prepare)** add per-provider timeout support by @jdx in
[#8405](#8405)
- **(prepare)** add blake3 content-hash freshness checking by @jdx in
[#8404](#8404)
- **(tasks)** monorepo vars and per-task vars by @halms in
[#8248](#8248)

### 🐛 Bug Fixes

- **(aqua)** restore bin_paths disk cache with fresh_file invalidation
by @jdx in [#8398](#8398)
- **(idiomatic)** use generic parser for idiomatic files by @risu729 in
[#8171](#8171)
- **(install)** apply precompiled options to all platforms in lockfile
by @jdx in [#8396](#8396)
- **(install)** normalize "v" prefix when matching lockfile versions by
@jdx in [#8413](#8413)
- **(prepare)** improve git submodule parser and fix check_staleness
error handling by @jdx in [#8412](#8412)
- **(python)** respect precompiled settings in lock file generation by
@jdx in [#8399](#8399)
- **(python)** clarify uv_venv_auto docs + prevent uv shim recursion in
venv creation by @halms in
[#8402](#8402)
- **(task)** remove deprecated `# mise` task header syntax by @jdx in
[#8403](#8403)
- **(vfox)** avoid eager metadata loading during config file detection
by @jdx in [#8397](#8397)
- clarify GitHub attestations to be artifact ones by @scop in
[#8394](#8394)
- ignore comments in idiomatic version files by @iloveitaly in
[#7682](#7682)

### 🚜 Refactor

- unify archive detection by @risu729 in
[#8137](#8137)

### 📚 Documentation

- remove duplicated docs for npm.package_manager by @risu729 in
[#8414](#8414)
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.

1 participant