Skip to content

feat(tasks): change task_config.includes resolution from override to additive#8740

Closed
risu729 wants to merge 3 commits intojdx:mainfrom
risu729:task-includes-additive
Closed

feat(tasks): change task_config.includes resolution from override to additive#8740
risu729 wants to merge 3 commits intojdx:mainfrom
risu729:task-includes-additive

Conversation

@risu729
Copy link
Copy Markdown
Contributor

@risu729 risu729 commented Mar 24, 2026

While I was reading the code of task_config.includes, I found an architectural inconsistency in its resolution depending on whether tasks were global or local.

Before this PR:

  • Global Tasks: load_global_tasks iterated over every single global config file and extended the tasks array by independently evaluating load_file_tasks (and therefore default_task_includes) for each one. This meant global includes stacked together.
  • Local / Monorepo Tasks: task_includes_for_dir utilized a find_map to find the first config with a custom includes array and completely ignored the rest, throwing away default includes if any custom ones were present. Only task_config.includes in the config with the highest precedence (child over parent) was evaluated.

I think it should at least be overridable, but it would be more intuitive and also make the implementation simple if we standardize the behaviour by changing it from overriding to additive everywhere.

This resolves the inconsistency of task loading orders between environments, fixing the test assertions that previously relied on the overriding side-effect.

Reverts #6159
Replaces #6636

@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 focuses on improving the consistency and predictability of task configuration within the mise tool. By changing the task_config.includes resolution to be additive, it ensures that all specified task files and directories are included, regardless of configuration precedence. The PR also includes updates to the tool registry and adds a new test case to validate the changes.

Highlights

  • Task Configuration: The task_config.includes resolution logic was changed from overriding to additive, ensuring that includes from all relevant configuration files are merged.
  • Inconsistency Resolution: Addressed an inconsistency in how task_config.includes was handled between global and local tasks, ensuring uniform behavior.
  • Test Cases: Added a new end-to-end test case to verify the additive and hierarchical behavior of task_config.includes.
  • Tool Registry Updates: Updated multiple tool registry entries to correct the test commands, removing the unnecessary 2>&1 redirection.
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.

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 refactors the task_config.includes mechanism to be additive and hierarchical, allowing multiple configuration files to contribute to the included task files and directories, with corresponding updates to documentation and a new end-to-end test. The test tooling was enhanced to redirect stderr to stdout and strip ANSI escape codes from command output for more robust assertions. Many registry .toml files were updated to simplify their test commands by removing 2>&1 redirection, though a potential issue exists in registry/btop.toml where removing the sed command might cause test failures if btop --version outputs ANSI codes. Additionally, the documentation for task_config.includes could be improved by linking directly to its section and rephrasing its description for better clarity.

Comment thread src/cli/test_tool.rs Outdated
Comment thread src/config/mod.rs
Comment thread src/cli/test_tool.rs Outdated
Comment thread registry/httpie-go.toml Outdated
Comment thread registry/kubent.toml Outdated
Comment thread registry/sampler.toml Outdated
Comment thread registry/sbt.toml Outdated
Comment thread registry/superhtml.toml Outdated
Comment thread registry/trzsz-ssh.toml Outdated
Comment thread registry/zprint.toml Outdated
…additive

Resolves the inconsistency of task loading orders between global tasks and local tasks where 'task_config.includes' overrode default includes instead of adding to them.

Reverts jdx#6159
@risu729 risu729 force-pushed the task-includes-additive branch from a0407ab to 24bc4f4 Compare March 24, 2026 13:22
@risu729
Copy link
Copy Markdown
Contributor Author

risu729 commented Mar 24, 2026

/gemini review

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 modifies the behavior of task_config.includes to be additive instead of overriding, resolving an inconsistency in task loading orders. The changes include documentation updates, a new end-to-end test to verify the additive behavior, and modifications to the code that loads file tasks.

Comment thread docs/tasks/file-tasks.md
Comment thread docs/tasks/task-configuration.md
Comment thread src/config/mod.rs
Comment thread src/config/mod.rs
@risu729 risu729 marked this pull request as ready for review March 24, 2026 16:37
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 24, 2026

Greptile Summary

This PR changes task_config.includes resolution from an override-style (only the lowest-precedence config's includes were used) to an additive model, where every config layer's includes entries are merged together alongside the default file-task directories. The change is well-motivated, fixes a real inconsistency between global and local task loading, and is backed by a new dedicated e2e test.

Key changes:

  • load_file_tasks: now seeds the include list with default_task_includes() and extends it with the per-config custom includes instead of replacing.
  • task_includes_for_dir: iterates all configs and collects every config's custom includes (resolved relative to each config's root), additive on top of the already-expanded defaults.
  • load_tasks_in_dir (git_includes): not updated — still uses find_map, so git-URL includes remain non-additive and can silently drop git includes from lower-precedence configs when a higher-precedence config also has an includes entry.
  • test_task_monorepo_nested_config: assertions correctly flipped, but the file-header comment and one echo string still describe the old "should NOT appear" behaviour.

Confidence Score: 4/5

  • Safe to merge with one targeted fix: git_includes in load_tasks_in_dir must also be made additive to match the new contract.
  • The core logic change is correct and well-tested for the common (non-git) case. The P1 issue — git_includes still using find_map — is a narrow but real regression for users who mix git-URL and path includes across config layers. The two stale test comments are cosmetic. Once the git_includes loop is updated the PR is ready.
  • src/config/mod.rs (load_tasks_in_dir git_includes block, lines 2380–2387)

Important Files Changed

Filename Overview
src/config/mod.rs Core change: load_file_tasks and task_includes_for_dir now start with default includes and extend with per-config custom includes (additive). However, git_includes in load_tasks_in_dir was not updated and still uses find_map, breaking the additive contract for git-URL includes.
e2e/tasks/test_task_includes_additive New e2e test covering additive includes across root/subdir configs and local overrides. Covers non-git includes thoroughly; no git-URL include scenario tested.
e2e/tasks/test_task_ls Updated to expect do-not-show (from .mise/tasks/) to appear when a custom task_config.includes is also set — correctly reflecting the new additive behaviour.
e2e/tasks/test_task_monorepo_nested_config Monorepo assertions updated to expect default-include tasks to be present. Stale file-header comment and misleading echo string remain from the old behaviour.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[task_includes_for_dir / load_file_tasks] --> B[Start with default_task_includes\ne.g. .mise/tasks, mise-tasks]
    B --> C{For each config\nin precedence order}
    C --> D{Has task_config.includes?}
    D -- Yes --> E[Extend list with\ncustom includes\nresolved from config root]
    D -- No --> F[Skip]
    E --> C
    F --> C
    C -- Done --> G[Deduplicate via .unique]
    G --> H[Resolved include paths]

    subgraph "load_tasks_in_dir — git_includes (NOT YET ADDITIVE)"
        I[configs.iter.rev.find_map] --> J[First config\nwith any includes]
        J --> K[Filter for git:: prefix]
        K --> L[git_includes vec\n⚠ misses git URLs\nfrom other configs]
    end
Loading

Comments Outside Diff (3)

  1. src/config/mod.rs, line 2380-2387 (link)

    P1 git_includes not made additive

    git_includes still uses find_map — it stops at the first config that has any includes entry and only extracts git URLs from that config. This directly conflicts with the additive behaviour introduced in task_includes_for_dir for non-git paths.

    Concrete failure scenario: if mise.local.toml contains includes = ["./local-tasks/"] (no git entry) and mise.toml contains includes = ["git::https://example.com/tasks.git", "./tasks/"], then find_map returns mise.local.toml's list first (.rev() walks from highest-precedence downward), the git:: filter produces an empty vec, and the git include from mise.toml is silently dropped.

    The fix mirrors what was done in task_includes_for_dir:

    let git_includes: Vec<String> = configs
        .iter()
        .rev()
        .filter_map(|cf| cf.task_config().includes.as_ref())
        .flatten()
        .filter(|p| p.starts_with("git::"))
        .cloned()
        .collect();
  2. e2e/tasks/test_task_monorepo_nested_config, line 1-8 (link)

    P2 Stale file-header comment contradicts new behaviour

    The file-level description (lines 5–8) still says default includes "should NOT be loaded" and references the fallback behaviour that was deliberately removed by this PR. This will mislead future readers.

  3. e2e/tasks/test_task_monorepo_nested_config, line 50-52 (link)

    P2 Misleading echo message in test script

    The task's echo output still says "task from default includes - should NOT appear", but Test 3 (line 65) now asserts the task IS listed. Anyone running this task directly will see a confusing message.

Reviews (1): Last reviewed commit: "fix(tasks): fix e2e tests due to additiv..." | Re-trigger Greptile

@jdx
Copy link
Copy Markdown
Owner

jdx commented Mar 24, 2026

I think this should probably go the other way — make global tasks use override semantics to match local, rather than making local additive to match global.

The ability to set task_config.includes and have it replace the defaults is a useful escape hatch. If a project has tasks in .mise/tasks/ that a subdirectory config doesn't want loaded, purely additive semantics make that impossible. There's no opt-out mechanism.

The do-not-show task in the existing test suite was deliberately placed to verify it wouldn't appear when custom includes were set — that was an intentional design choice from #6159, not a bug.

If the inconsistency between global and local is the issue, I'd prefer fixing global to be consistently override, or alternatively adding something like task_config.includes_mode or task_config.excludes to give users control.

This comment was generated by Claude Code.

@risu729
Copy link
Copy Markdown
Contributor Author

risu729 commented Mar 26, 2026

I see, thanks. I think it might be enough to update the documentation to reflect the current behaviour, what do you think?

@jdx
Copy link
Copy Markdown
Owner

jdx commented Apr 4, 2026

yeah probably

@jdx jdx marked this pull request as draft April 4, 2026 16:14
@risu729 risu729 closed this Apr 4, 2026
@risu729 risu729 deleted the task-includes-additive branch April 4, 2026 18:03
jdx added a commit that referenced this pull request Apr 4, 2026
## Summary

Follow-up to #8740.

That PR proposed changing `task_config.includes` semantics, but the
conclusion in the discussion was to document the current behavior
instead of making a breaking change.

This updates the task docs to reflect how `task_config.includes` works
today:

- explicit `task_config.includes` replaces the default file-task
directories for that config scope
- if users want the defaults plus custom paths, they must list the
defaults explicitly
- for local/monorepo task discovery, the nearest config with
`task_config.includes` wins
- global config files are loaded independently, so each global config
file uses its own `includes` or the defaults

It also updates the file-tasks page so the default directories are
clearly described as defaults rather than always-on search paths.

## Verification

- `git diff --check`
- `mise run docs:build`

---------

Co-authored-by: jdx <216188+jdx@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
richardthe3rd pushed a commit to richardthe3rd/mise that referenced this pull request Apr 4, 2026
## Summary

Follow-up to jdx#8740.

That PR proposed changing `task_config.includes` semantics, but the
conclusion in the discussion was to document the current behavior
instead of making a breaking change.

This updates the task docs to reflect how `task_config.includes` works
today:

- explicit `task_config.includes` replaces the default file-task
directories for that config scope
- if users want the defaults plus custom paths, they must list the
defaults explicitly
- for local/monorepo task discovery, the nearest config with
`task_config.includes` wins
- global config files are loaded independently, so each global config
file uses its own `includes` or the defaults

It also updates the file-tasks page so the default directories are
clearly described as defaults rather than always-on search paths.

## Verification

- `git diff --check`
- `mise run docs:build`

---------

Co-authored-by: jdx <216188+jdx@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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