From 8c9fc0690754fbaa12f1ae9b994428538892a057 Mon Sep 17 00:00:00 2001 From: default <216188+jdx@users.noreply.github.com> Date: Wed, 12 Aug 2026 10:35:20 +0000 Subject: [PATCH 1/3] feat(task): add --all to run picker --- docs/cli/run.md | 4 ++++ docs/cli/tasks/run.md | 4 ++++ e2e/tasks/test_task_run_all_picker | 30 ++++++++++++++++++++++++++++++ mise.usage.kdl | 2 ++ src/cli/bootstrap.rs | 1 + src/cli/mod.rs | 1 + src/cli/run.rs | 12 +++++++++--- src/cli/watch.rs | 3 ++- src/task/task_list.rs | 9 +++++---- 9 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 e2e/tasks/test_task_run_all_picker diff --git a/docs/cli/run.md b/docs/cli/run.md index 8cefbc91893..5d238535614 100644 --- a/docs/cli/run.md +++ b/docs/cli/run.md @@ -37,6 +37,10 @@ $ mise run build ## Flags +### `--all` + +Load all tasks from the entire monorepo in the interactive selector + ### `--affected` Run matching tasks only for projects affected by Git changes diff --git a/docs/cli/tasks/run.md b/docs/cli/tasks/run.md index b9f9298d743..b1714d256b8 100644 --- a/docs/cli/tasks/run.md +++ b/docs/cli/tasks/run.md @@ -51,6 +51,10 @@ Arguments to pass to the tasks. Use ":::" to separate tasks ## Flags +### `--all` + +Load all tasks from the entire monorepo in the interactive selector + ### `--affected` Run matching tasks only for projects affected by Git changes diff --git a/e2e/tasks/test_task_run_all_picker b/e2e/tasks/test_task_run_all_picker new file mode 100644 index 00000000000..67a7b126028 --- /dev/null +++ b/e2e/tasks/test_task_run_all_picker @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +export MISE_EXPERIMENTAL=1 + +cat <<'EOF' >mise.toml +monorepo_root = true + +[monorepo] +config_roots = ["projects/frontend"] + +[tasks.root] +run = 'echo "root task ran"' +EOF + +mkdir -p projects/frontend +cat <<'EOF' >projects/frontend/mise.toml +[tasks.child] +run = 'echo "child task ran"' +EOF + +# The root task is selected first, so move down once to select the child task. +if [[ $(uname) == Darwin ]]; then + output=$(printf '\033[B\r' | script -q /dev/null mise run --all) +else + output=$(printf '\033[B\r' | script -qec 'mise run --all' /dev/null) +fi +if [[ $output != *"child task ran"* ]]; then + echo "interactive selector did not run the child task" + exit 1 +fi diff --git a/mise.usage.kdl b/mise.usage.kdl index 4df10a02235..171e34fe7c3 100644 --- a/mise.usage.kdl +++ b/mise.usage.kdl @@ -3215,6 +3215,7 @@ Examples: $ mise run cmd1 arg1 arg2 ::: cmd2 arg1 arg2 """# + flag --all help="Load all tasks from the entire monorepo in the interactive selector" flag --affected help="Run matching tasks only for projects affected by Git changes" flag --affected-base help=#""" Git base revision for --affected @@ -4070,6 +4071,7 @@ Examples: $ mise run cmd1 arg1 arg2 ::: cmd2 arg1 arg2 """# + flag --all help="Load all tasks from the entire monorepo in the interactive selector" flag --affected help="Run matching tasks only for projects affected by Git changes" flag --affected-base help=#""" Git base revision for --affected diff --git a/src/cli/bootstrap.rs b/src/cli/bootstrap.rs index a779c699149..eb45803b8ec 100644 --- a/src/cli/bootstrap.rs +++ b/src/cli/bootstrap.rs @@ -1622,6 +1622,7 @@ impl Bootstrap { task: task.into(), args: vec![], args_last: vec![], + all: false, affected: false, affected_base: None, affected_head: None, diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 86682cc3df5..60b83b66f8f 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -784,6 +784,7 @@ impl Cli { task, args: self.task_args.unwrap_or_default(), args_last: self.task_args_last, + all: false, affected: false, affected_base: None, affected_head: None, diff --git a/src/cli/run.rs b/src/cli/run.rs index fd02a00ab2a..0b97bdaee2a 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -76,6 +76,10 @@ pub struct Run { #[clap(allow_hyphen_values = true, hide = true, last = true)] pub args_last: Vec, + /// Load all tasks from the entire monorepo in the interactive selector + #[clap(long, verbatim_doc_comment)] + pub all: bool, + /// Run matching tasks only for projects affected by Git changes #[clap(long, verbatim_doc_comment)] pub affected: bool, @@ -331,6 +335,7 @@ async fn get_affected_task_list( head: Option<&str>, explain: bool, json: bool, + all: bool, ) -> Result> { Settings::get().ensure_experimental("affected tasks")?; let workspace_root = config @@ -395,7 +400,7 @@ async fn get_affected_task_list( .collect::>(); let args = affected_task_args(args); - let mut tasks = get_task_lists(config, &args, true, only).await?; + let mut tasks = get_task_lists(config, &args, true, only, all).await?; // Restrict only the task-pattern matches. `Run::run` calls `resolve_depends` // after this returns, so prerequisites from unaffected projects remain intact. tasks.retain(|task| { @@ -598,7 +603,7 @@ impl Run { ) .collect_vec(); - let task_list = get_task_lists(&config, &args, false, false).await?; + let task_list = get_task_lists(&config, &args, false, false, false).await?; if let Some(task) = task_list.first() { // raw_args tasks act as proxies for tools that handle their @@ -646,10 +651,11 @@ impl Run { self.affected_head.as_deref(), self.affected_explain, self.affected_json, + self.all, ) .await? } else { - get_task_lists(&config, &args, true, self.skip_deps).await? + get_task_lists(&config, &args, true, self.skip_deps, self.all).await? }; if self.affected_json { return Ok(()); diff --git a/src/cli/watch.rs b/src/cli/watch.rs index e5de2f269bb..144e19cb133 100644 --- a/src/cli/watch.rs +++ b/src/cli/watch.rs @@ -85,7 +85,8 @@ impl Watch { if args.is_empty() { args.push("default".to_string()); } - let tasks = crate::task::task_list::get_task_lists(&config, &args, false, false).await?; + let tasks = + crate::task::task_list::get_task_lists(&config, &args, false, false, false).await?; let watched_tasks = if self.skip_deps { tasks.to_vec() } else { diff --git a/src/task/task_list.rs b/src/task/task_list.rs index 2488ca38fab..f9fbef2bed5 100644 --- a/src/task/task_list.rs +++ b/src/task/task_list.rs @@ -367,9 +367,9 @@ async fn err_no_task( } /// Prompt the user to select a task interactively -async fn prompt_for_task() -> Result { - let config = Config::get().await?; - let tasks = config.tasks().await?; +async fn prompt_for_task(config: &Arc, all: bool) -> Result { + let ctx = all.then(TaskLoadContext::all); + let tasks = config.tasks_with_context(ctx.as_ref()).await?; ensure!( !tasks.is_empty(), "no tasks defined. see {url}", @@ -410,6 +410,7 @@ pub async fn get_task_lists( args: &[String], prompt: bool, only: bool, + all: bool, ) -> Result> { let args = args .iter() @@ -546,7 +547,7 @@ pub async fn get_task_lists( tasks.push(task.with_args(args)); continue; } - tasks.push(prompt_for_task().await?); + tasks.push(prompt_for_task(config, all).await?); } else { cur_tasks .into_iter() From 4cf8a8e95fa6c88ce28dfd311de7f0eccbe8bc24 Mon Sep 17 00:00:00 2001 From: default <216188+jdx@users.noreply.github.com> Date: Wed, 12 Aug 2026 10:47:12 +0000 Subject: [PATCH 2/3] fix(task): constrain --all to picker --- docs/cli/run.md | 2 +- docs/cli/tasks/run.md | 5 ++--- e2e/tasks/test_task_run_all_picker | 11 +++++++--- mise.usage.kdl | 7 ++++--- src/cli/bootstrap.rs | 2 +- src/cli/mod.rs | 2 +- src/cli/run.rs | 33 +++++++++++++++--------------- src/task/task_list.rs | 18 ++++++++++++---- 8 files changed, 47 insertions(+), 33 deletions(-) diff --git a/docs/cli/run.md b/docs/cli/run.md index 5d238535614..bcc80c3b242 100644 --- a/docs/cli/run.md +++ b/docs/cli/run.md @@ -39,7 +39,7 @@ $ mise run build ### `--all` -Load all tasks from the entire monorepo in the interactive selector +Open the interactive selector with all tasks from the entire monorepo ### `--affected` diff --git a/docs/cli/tasks/run.md b/docs/cli/tasks/run.md index b1714d256b8..3d30fdf9cc4 100644 --- a/docs/cli/tasks/run.md +++ b/docs/cli/tasks/run.md @@ -42,8 +42,7 @@ $ mise run build Tasks to run Can specify multiple tasks by separating with `:::` e.g.: mise run task1 arg1 arg2 ::: task2 arg1 arg2 - -**Default:** `default` +Defaults to `default` when omitted ### `[ARGS]…` @@ -53,7 +52,7 @@ Arguments to pass to the tasks. Use ":::" to separate tasks ### `--all` -Load all tasks from the entire monorepo in the interactive selector +Open the interactive selector with all tasks from the entire monorepo ### `--affected` diff --git a/e2e/tasks/test_task_run_all_picker b/e2e/tasks/test_task_run_all_picker index 67a7b126028..f1ca0644b07 100644 --- a/e2e/tasks/test_task_run_all_picker +++ b/e2e/tasks/test_task_run_all_picker @@ -8,8 +8,8 @@ monorepo_root = true [monorepo] config_roots = ["projects/frontend"] -[tasks.root] -run = 'echo "root task ran"' +[tasks.default] +run = 'echo "default task ran"' EOF mkdir -p projects/frontend @@ -18,7 +18,9 @@ cat <<'EOF' >projects/frontend/mise.toml run = 'echo "child task ran"' EOF -# The root task is selected first, so move down once to select the child task. +assert "mise run" "default task ran" + +# The default task is selected first, so move down once to select the child task. if [[ $(uname) == Darwin ]]; then output=$(printf '\033[B\r' | script -q /dev/null mise run --all) else @@ -28,3 +30,6 @@ if [[ $output != *"child task ran"* ]]; then echo "interactive selector did not run the child task" exit 1 fi + +assert_fail_contains "mise run --all default" "cannot be used with" +assert_fail_contains "mise run --all --affected" "cannot be used with" diff --git a/mise.usage.kdl b/mise.usage.kdl index 171e34fe7c3..6ed85f33aaf 100644 --- a/mise.usage.kdl +++ b/mise.usage.kdl @@ -3215,7 +3215,7 @@ Examples: $ mise run cmd1 arg1 arg2 ::: cmd2 arg1 arg2 """# - flag --all help="Load all tasks from the entire monorepo in the interactive selector" + flag --all help="Open the interactive selector with all tasks from the entire monorepo" flag --affected help="Run matching tasks only for projects affected by Git changes" flag --affected-base help=#""" Git base revision for --affected @@ -4071,7 +4071,7 @@ Examples: $ mise run cmd1 arg1 arg2 ::: cmd2 arg1 arg2 """# - flag --all help="Load all tasks from the entire monorepo in the interactive selector" + flag --all help="Open the interactive selector with all tasks from the entire monorepo" flag --affected help="Run matching tasks only for projects affected by Git changes" flag --affected-base help=#""" Git base revision for --affected @@ -4208,7 +4208,8 @@ Default to always show with `MISE_TASK_TIMINGS=1` Tasks to run Can specify multiple tasks by separating with `:::` e.g.: mise run task1 arg1 arg2 ::: task2 arg1 arg2 -"""# required=#false default=default +Defaults to `default` when omitted +"""# required=#false arg "[ARGS]…" help="Arguments to pass to the tasks. Use \":::\" to separate tasks" required=#false var=#true arg "[-- ARGS_LAST]…" help="Arguments to pass to the tasks. Use \":::\" to separate tasks" required=#false var=#true hide=#true mount run="mise tasks --usage" diff --git a/src/cli/bootstrap.rs b/src/cli/bootstrap.rs index eb45803b8ec..9edd4c4a20a 100644 --- a/src/cli/bootstrap.rs +++ b/src/cli/bootstrap.rs @@ -1619,7 +1619,7 @@ impl Bootstrap { async fn run_task(&self, task: &str, skip_tools: bool) -> Result<()> { run::Run { - task: task.into(), + task: Some(task.into()), args: vec![], args_last: vec![], all: false, diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 60b83b66f8f..4790c216eab 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -781,7 +781,7 @@ impl Cli { }; if tasks.iter().any(|(_, t)| t.is_match(&task)) { return Ok(Commands::Run(Box::new(run::Run { - task, + task: Some(task), args: self.task_args.unwrap_or_default(), args_last: self.task_args_last, all: false, diff --git a/src/cli/run.rs b/src/cli/run.rs index 0b97bdaee2a..afc1e90c97b 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -61,12 +61,9 @@ pub struct Run { /// Tasks to run /// Can specify multiple tasks by separating with `:::` /// e.g.: mise run task1 arg1 arg2 ::: task2 arg1 arg2 - #[clap( - allow_hyphen_values = true, - verbatim_doc_comment, - default_value = "default" - )] - pub task: String, + /// Defaults to `default` when omitted + #[clap(allow_hyphen_values = true, verbatim_doc_comment)] + pub task: Option, /// Arguments to pass to the tasks. Use ":::" to separate tasks. #[clap(allow_hyphen_values = true)] @@ -76,8 +73,8 @@ pub struct Run { #[clap(allow_hyphen_values = true, hide = true, last = true)] pub args_last: Vec, - /// Load all tasks from the entire monorepo in the interactive selector - #[clap(long, verbatim_doc_comment)] + /// Open the interactive selector with all tasks from the entire monorepo + #[clap(long, conflicts_with_all = ["task", "affected"], verbatim_doc_comment)] pub all: bool, /// Run matching tasks only for projects affected by Git changes @@ -335,7 +332,6 @@ async fn get_affected_task_list( head: Option<&str>, explain: bool, json: bool, - all: bool, ) -> Result> { Settings::get().ensure_experimental("affected tasks")?; let workspace_root = config @@ -400,7 +396,7 @@ async fn get_affected_task_list( .collect::>(); let args = affected_task_args(args); - let mut tasks = get_task_lists(config, &args, true, only, all).await?; + let mut tasks = get_task_lists(config, &args, true, only, false).await?; // Restrict only the task-pattern matches. `Run::run` calls `resolve_depends` // after this returns, so prerequisites from unaffected projects remain intact. tasks.retain(|task| { @@ -563,15 +559,17 @@ fn display_affected_text(text: &str) -> String { impl Run { pub async fn run(mut self) -> Result<()> { // Check help flags before doing any work - if self.task == "-h" { + if self.task.as_deref() == Some("-h") { self.get_clap_command().print_help()?; return Ok(()); } - if self.task == "--help" { + if self.task.as_deref() == Some("--help") { self.get_clap_command().print_long_help()?; return Ok(()); } + let task = self.task.clone().unwrap_or_else(|| "default".to_string()); + Settings::ensure_not_safe("running tasks")?; // Unescape task args early so we can check for help flags @@ -594,7 +592,7 @@ impl Run { // Handle task help early to avoid unnecessary toolset/deps work if has_help_in_task_args { // Build args list to get the task (filter out --help/-h for task lookup) - let args = once(self.task.clone()) + let args = once(task.clone()) .chain( self.args .iter() @@ -638,9 +636,11 @@ impl Run { self.tmpdir = tmpdir.path().to_path_buf(); // Build args list - don't include args_last yet, they'll be added after task resolution - let args = once(self.task.clone()) - .chain(self.args.clone()) - .collect_vec(); + let args = if self.all { + vec![] + } else { + once(task).chain(self.args.clone()).collect_vec() + }; let mut task_list = if self.affected { get_affected_task_list( @@ -651,7 +651,6 @@ impl Run { self.affected_head.as_deref(), self.affected_explain, self.affected_json, - self.all, ) .await? } else { diff --git a/src/task/task_list.rs b/src/task/task_list.rs index f9fbef2bed5..7189595b1f1 100644 --- a/src/task/task_list.rs +++ b/src/task/task_list.rs @@ -367,8 +367,8 @@ async fn err_no_task( } /// Prompt the user to select a task interactively -async fn prompt_for_task(config: &Arc, all: bool) -> Result { - let ctx = all.then(TaskLoadContext::all); +async fn prompt_for_task(config: &Arc, load_all: bool) -> Result { + let ctx = load_all.then(TaskLoadContext::all); let tasks = config.tasks_with_context(ctx.as_ref()).await?; ensure!( !tasks.is_empty(), @@ -410,8 +410,18 @@ pub async fn get_task_lists( args: &[String], prompt: bool, only: bool, - all: bool, + prompt_all: bool, ) -> Result> { + if prompt_all { + let mut task = prompt_for_task(config, true).await?; + if only { + task.depends.clear(); + task.depends_post.clear(); + task.wait_for.clear(); + } + return Ok(vec![task]); + } + let args = args .iter() .map(|s| vec![s.to_string()]) @@ -547,7 +557,7 @@ pub async fn get_task_lists( tasks.push(task.with_args(args)); continue; } - tasks.push(prompt_for_task(config, all).await?); + tasks.push(prompt_for_task(config, false).await?); } else { cur_tasks .into_iter() From 3346361f49b1a12c99c93b984919021f9f59e686 Mon Sep 17 00:00:00 2001 From: default <216188+jdx@users.noreply.github.com> Date: Wed, 12 Aug 2026 11:02:04 +0000 Subject: [PATCH 3/3] chore(ci): fix run flag ordering --- docs/cli/run.md | 8 ++++---- docs/cli/tasks/run.md | 8 ++++---- man/man1/mise.1 | 10 +++++++--- mise.usage.kdl | 4 ++-- src/cli/run.rs | 8 ++++---- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/docs/cli/run.md b/docs/cli/run.md index bcc80c3b242..2a9b681d515 100644 --- a/docs/cli/run.md +++ b/docs/cli/run.md @@ -37,10 +37,6 @@ $ mise run build ## Flags -### `--all` - -Open the interactive selector with all tasks from the entire monorepo - ### `--affected` Run matching tasks only for projects affected by Git changes @@ -63,6 +59,10 @@ Defaults to MISE_AFFECTED_HEAD, CI metadata, or HEAD Output affected projects and tasks as JSON without running tasks +### `--all` + +Open the interactive selector with all tasks from the entire monorepo + ### `-c --continue-on-error` Continue running tasks even if one fails diff --git a/docs/cli/tasks/run.md b/docs/cli/tasks/run.md index 3d30fdf9cc4..d57d739e1d4 100644 --- a/docs/cli/tasks/run.md +++ b/docs/cli/tasks/run.md @@ -50,10 +50,6 @@ Arguments to pass to the tasks. Use ":::" to separate tasks ## Flags -### `--all` - -Open the interactive selector with all tasks from the entire monorepo - ### `--affected` Run matching tasks only for projects affected by Git changes @@ -76,6 +72,10 @@ Defaults to MISE_AFFECTED_HEAD, CI metadata, or HEAD Output affected projects and tasks as JSON without running tasks +### `--all` + +Open the interactive selector with all tasks from the entire monorepo + ### `-c --continue-on-error` Continue running tasks even if one fails diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 45865dcdf7b..4ff5cf6b094 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -3399,6 +3399,9 @@ Defaults to MISE_AFFECTED_HEAD, CI metadata, or HEAD \fB\-\-affected\-json\fR Output affected projects and tasks as JSON without running tasks .TP +\fB\-\-all\fR +Open the interactive selector with all tasks from the entire monorepo +.TP \fB\-c, \-\-continue\-on\-error\fR Continue running tasks even if one fails .TP @@ -4222,6 +4225,9 @@ Defaults to MISE_AFFECTED_HEAD, CI metadata, or HEAD \fB\-\-affected\-json\fR Output affected projects and tasks as JSON without running tasks .TP +\fB\-\-all\fR +Open the interactive selector with all tasks from the entire monorepo +.TP \fB\-c, \-\-continue\-on\-error\fR Continue running tasks even if one fails .TP @@ -4359,9 +4365,7 @@ Default to always show with `MISE_TASK_TIMINGS=1` Tasks to run Can specify multiple tasks by separating with `:::` e.g.: mise run task1 arg1 arg2 ::: task2 arg1 arg2 -.RS -\fIDefault: \fRdefault -.RE +Defaults to `default` when omitted .TP \fB\fR Arguments to pass to the tasks. Use ":::" to separate tasks diff --git a/mise.usage.kdl b/mise.usage.kdl index 6ed85f33aaf..470eb588603 100644 --- a/mise.usage.kdl +++ b/mise.usage.kdl @@ -3215,7 +3215,6 @@ Examples: $ mise run cmd1 arg1 arg2 ::: cmd2 arg1 arg2 """# - flag --all help="Open the interactive selector with all tasks from the entire monorepo" flag --affected help="Run matching tasks only for projects affected by Git changes" flag --affected-base help=#""" Git base revision for --affected @@ -3231,6 +3230,7 @@ Defaults to MISE_AFFECTED_HEAD, CI metadata, or HEAD arg } flag --affected-json help="Output affected projects and tasks as JSON without running tasks" + flag --all help="Open the interactive selector with all tasks from the entire monorepo" flag "-c --continue-on-error" help="Continue running tasks even if one fails" flag "-C --cd" help="Change to this directory before executing the command" { arg @@ -4071,7 +4071,6 @@ Examples: $ mise run cmd1 arg1 arg2 ::: cmd2 arg1 arg2 """# - flag --all help="Open the interactive selector with all tasks from the entire monorepo" flag --affected help="Run matching tasks only for projects affected by Git changes" flag --affected-base help=#""" Git base revision for --affected @@ -4087,6 +4086,7 @@ Defaults to MISE_AFFECTED_HEAD, CI metadata, or HEAD arg } flag --affected-json help="Output affected projects and tasks as JSON without running tasks" + flag --all help="Open the interactive selector with all tasks from the entire monorepo" flag "-c --continue-on-error" help="Continue running tasks even if one fails" flag "-C --cd" help="Change to this directory before executing the command" { arg diff --git a/src/cli/run.rs b/src/cli/run.rs index afc1e90c97b..6b6ca019162 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -73,10 +73,6 @@ pub struct Run { #[clap(allow_hyphen_values = true, hide = true, last = true)] pub args_last: Vec, - /// Open the interactive selector with all tasks from the entire monorepo - #[clap(long, conflicts_with_all = ["task", "affected"], verbatim_doc_comment)] - pub all: bool, - /// Run matching tasks only for projects affected by Git changes #[clap(long, verbatim_doc_comment)] pub affected: bool, @@ -109,6 +105,10 @@ pub struct Run { )] pub affected_json: bool, + /// Open the interactive selector with all tasks from the entire monorepo + #[clap(long, conflicts_with_all = ["task", "affected"], verbatim_doc_comment)] + pub all: bool, + /// Continue running tasks even if one fails #[clap(long, short = 'c', verbatim_doc_comment)] pub continue_on_error: bool,