From 4a7cad7fac9a8caec5304da394c7550cf4ad14eb Mon Sep 17 00:00:00 2001 From: n4n5 Date: Fri, 19 Sep 2025 20:03:03 -0600 Subject: [PATCH 1/9] feat: add env propagation --- e2e/tasks/test_task_env_propagation | 15 +++++++++++++++ src/cli/run.rs | 26 ++++++++++++++++++++------ src/task/mod.rs | 12 ++++++++---- 3 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 e2e/tasks/test_task_env_propagation diff --git a/e2e/tasks/test_task_env_propagation b/e2e/tasks/test_task_env_propagation new file mode 100644 index 0000000000..33485fd91f --- /dev/null +++ b/e2e/tasks/test_task_env_propagation @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +cat <mise.toml +[tasks.echo] +env = { "SUB_TASK" = "sub_task_env" } +run = "echo \$SUB_TASK \$MY_VAR" + + +[tasks.propagation] +run = [{ task = "echo" }] +env = { "MY_VAR" = "my_variable" } +EOF +# this should fail not sure how it works. +assert_contains "mise run echo" "sub_task_env" +assert_contains "mise run propagation" "sub_task_env my_variable" \ No newline at end of file diff --git a/src/cli/run.rs b/src/cli/run.rs index 1c63bec41f..a56acb4cbb 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -13,7 +13,7 @@ use std::time::{Duration, SystemTime}; use super::args::ToolArg; use crate::cli::Cli; use crate::cmd::CmdLineRunner; -use crate::config::{Config, Settings}; +use crate::config::{Config, Settings, env_directive::EnvDirective}; use crate::env_diff::EnvMap; use crate::file::display_path; use crate::task::task_file_providers::TaskFileProvidersBuilder; @@ -687,7 +687,7 @@ impl Run { ts_build_start.elapsed().as_millis() ); let env_render_start = std::time::Instant::now(); - let mut env = task.render_env(config, &ts).await?; + let (mut env, task_env) = task.render_env(config, &ts).await?; trace!( "task {} render_env took {}ms", task.name, @@ -740,8 +740,16 @@ impl Run { .await?; let exec_start = std::time::Instant::now(); - self.exec_task_run_entries(config, task, &env, &prefix, rendered_run_scripts, sched_tx) - .await?; + self.exec_task_run_entries( + config, + task, + &env, + &task_env, + &prefix, + rendered_run_scripts, + sched_tx, + ) + .await?; trace!( "task {} exec_task_run_entries took {}ms (total {}ms)", task.name, @@ -770,6 +778,7 @@ impl Run { config: &Arc, task: &Task, env: &BTreeMap, + task_env: &[(String, String)], prefix: &str, rendered_scripts: Vec<(String, Vec)>, sched_tx: Arc>)>>, @@ -784,11 +793,11 @@ impl Run { } } RunEntry::SingleTask { task: spec } => { - self.inject_and_wait(config, &[spec.to_string()], sched_tx.clone()) + self.inject_and_wait(config, &[spec.to_string()], task_env, sched_tx.clone()) .await?; } RunEntry::TaskGroup { tasks } => { - self.inject_and_wait(config, tasks, sched_tx.clone()) + self.inject_and_wait(config, tasks, task_env, sched_tx.clone()) .await?; } } @@ -800,6 +809,7 @@ impl Run { &self, config: &Arc, specs: &[String], + task_env: &[(String, String)], sched_tx: Arc>)>>, ) -> Result<()> { trace!("inject start: {}", specs.join(", ")); @@ -832,6 +842,10 @@ impl Run { match rx.try_recv() { Ok(Some(task)) => { any = true; + let mut task = task.clone(); + let env_directives: Vec = + task_env.iter().cloned().map(Into::into).collect(); + task.env.0.extend_from_slice(&env_directives); trace!("inject initial leaf: {} {}", task.name, task.args.join(" ")); let _ = sched_tx.send((task, sub_deps_clone.clone())); } diff --git a/src/task/mod.rs b/src/task/mod.rs index 81636015c9..d46f04f333 100644 --- a/src/task/mod.rs +++ b/src/task/mod.rs @@ -563,7 +563,11 @@ impl Task { self.name.replace(':', path::MAIN_SEPARATOR_STR).into() } - pub async fn render_env(&self, config: &Arc, ts: &Toolset) -> Result { + pub async fn render_env( + &self, + config: &Arc, + ts: &Toolset, + ) -> Result<(EnvMap, Vec<(String, String)>)> { let mut tera_ctx = ts.tera_ctx(config).await?.clone(); let mut env = ts.full_env(config).await?; if let Some(root) = &config.project_root { @@ -591,9 +595,9 @@ impl Task { }, ) .await?; - + let task_env = env_results.env.into_iter().map(|(k, (v, _))| (k, v)); // Apply the resolved environment variables - env.extend(env_results.env.into_iter().map(|(k, (v, _))| (k, v))); + env.extend(task_env.clone()); // Remove environment variables that were explicitly unset for key in &env_results.env_remove { @@ -611,7 +615,7 @@ impl Task { env.insert(env::PATH_KEY.to_string(), path_env.to_string()); } - Ok(env) + Ok((env, task_env.collect())) } } From 425e77d471d2256a8746a651f2085ead43980a35 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 20 Sep 2025 02:11:19 +0000 Subject: [PATCH 2/9] [autofix.ci] apply automated fixes --- e2e/tasks/test_task_env_propagation | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/tasks/test_task_env_propagation b/e2e/tasks/test_task_env_propagation index 33485fd91f..1e302a86bc 100644 --- a/e2e/tasks/test_task_env_propagation +++ b/e2e/tasks/test_task_env_propagation @@ -12,4 +12,4 @@ env = { "MY_VAR" = "my_variable" } EOF # this should fail not sure how it works. assert_contains "mise run echo" "sub_task_env" -assert_contains "mise run propagation" "sub_task_env my_variable" \ No newline at end of file +assert_contains "mise run propagation" "sub_task_env my_variable" From 64270768057ca7e091bd3ea77f98f2f96662a817 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Fri, 19 Sep 2025 21:30:39 -0600 Subject: [PATCH 3/9] fix: too much arguments --- src/cli/run.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index a56acb4cbb..cf6cd5d81a 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -743,8 +743,7 @@ impl Run { self.exec_task_run_entries( config, task, - &env, - &task_env, + (&env, &task_env), &prefix, rendered_run_scripts, sched_tx, @@ -777,12 +776,12 @@ impl Run { &self, config: &Arc, task: &Task, - env: &BTreeMap, - task_env: &[(String, String)], + full_env: (&BTreeMap, &[(String, String)]), prefix: &str, rendered_scripts: Vec<(String, Vec)>, sched_tx: Arc>)>>, ) -> Result<()> { + let (env, task_env) = full_env; use crate::task::RunEntry; let mut script_iter = rendered_scripts.into_iter(); for entry in task.run() { From 5f70e1a57587d99dd71ea85b1314b8a025e020ab Mon Sep 17 00:00:00 2001 From: n4n5 Date: Sat, 20 Sep 2025 13:08:14 -0600 Subject: [PATCH 4/9] fix: add to async --- src/cli/run.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index cf6cd5d81a..0fc3bdd4b3 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -830,6 +830,8 @@ impl Run { // Pump subgraph into scheduler and signal completion via oneshot when done let (done_tx, done_rx) = oneshot::channel::<()>(); + let task_env_directives: Vec = + task_env.iter().cloned().map(Into::into).collect(); { let sub_deps_clone = sub_deps.clone(); let sched_tx = sched_tx.clone(); @@ -842,9 +844,7 @@ impl Run { Ok(Some(task)) => { any = true; let mut task = task.clone(); - let env_directives: Vec = - task_env.iter().cloned().map(Into::into).collect(); - task.env.0.extend_from_slice(&env_directives); + task.env.0.extend_from_slice(&task_env_directives.clone()); trace!("inject initial leaf: {} {}", task.name, task.args.join(" ")); let _ = sched_tx.send((task, sub_deps_clone.clone())); } @@ -875,6 +875,8 @@ impl Run { task.name, task.args.join(" ") ); + let mut task = task.clone(); + task.env.0.extend_from_slice(&task_env_directives); let _ = sched_tx.send((task, sub_deps_clone.clone())); } None => { From 054fb49f433356b8fe4ed91f98da6d137d859899 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Sat, 20 Sep 2025 13:08:38 -0600 Subject: [PATCH 5/9] fix test file --- e2e/tasks/test_task_env_propagation | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/tasks/test_task_env_propagation b/e2e/tasks/test_task_env_propagation index 1e302a86bc..6b180d5363 100644 --- a/e2e/tasks/test_task_env_propagation +++ b/e2e/tasks/test_task_env_propagation @@ -10,6 +10,6 @@ run = "echo \$SUB_TASK \$MY_VAR" run = [{ task = "echo" }] env = { "MY_VAR" = "my_variable" } EOF -# this should fail not sure how it works. + assert_contains "mise run echo" "sub_task_env" assert_contains "mise run propagation" "sub_task_env my_variable" From fc52255f5b48934b4cf6bdf31d70d7d239700484 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Sat, 20 Sep 2025 13:13:50 -0600 Subject: [PATCH 6/9] little better code (sweep under the carpet) --- src/cli/run.rs | 6 ++---- src/task/mod.rs | 8 +++++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index 0fc3bdd4b3..95fc512d60 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -843,8 +843,7 @@ impl Run { match rx.try_recv() { Ok(Some(task)) => { any = true; - let mut task = task.clone(); - task.env.0.extend_from_slice(&task_env_directives.clone()); + let task = task.derive_env(&task_env_directives.clone()); trace!("inject initial leaf: {} {}", task.name, task.args.join(" ")); let _ = sched_tx.send((task, sub_deps_clone.clone())); } @@ -875,8 +874,7 @@ impl Run { task.name, task.args.join(" ") ); - let mut task = task.clone(); - task.env.0.extend_from_slice(&task_env_directives); + let task = task.derive_env(&task_env_directives); let _ = sched_tx.send((task, sub_deps_clone.clone())); } None => { diff --git a/src/task/mod.rs b/src/task/mod.rs index d46f04f333..cb4034d0fb 100644 --- a/src/task/mod.rs +++ b/src/task/mod.rs @@ -1,7 +1,7 @@ use crate::cli::version::VERSION; use crate::config::config_file::mise_toml::EnvList; use crate::config::config_file::toml::{TomlParser, deserialize_arr}; -use crate::config::env_directive::{EnvResolveOptions, EnvResults, ToolsFilter}; +use crate::config::env_directive::{EnvDirective, EnvResolveOptions, EnvResults, ToolsFilter}; use crate::config::{self, Config}; use crate::path_env::PathEnv; use crate::task::task_script_parser::{TaskScriptParser, has_any_args_defined}; @@ -232,6 +232,12 @@ impl Task { Ok(task) } + pub fn derive_env(&self, env_directives: &[EnvDirective]) -> Self { + let mut new_task = self.clone(); + new_task.env.0.extend_from_slice(env_directives); + new_task + } + /// prints the task name without an extension pub fn display_name(&self, all_tasks: &BTreeMap) -> String { let display_name = self From 08dc7c0df21f06bbec10922411d8200892bbe757 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Sat, 20 Sep 2025 15:27:00 -0600 Subject: [PATCH 7/9] rm usless clone --- src/cli/run.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index 95fc512d60..b33fa65b8e 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -843,7 +843,7 @@ impl Run { match rx.try_recv() { Ok(Some(task)) => { any = true; - let task = task.derive_env(&task_env_directives.clone()); + let task = task.derive_env(&task_env_directives); trace!("inject initial leaf: {} {}", task.name, task.args.join(" ")); let _ = sched_tx.send((task, sub_deps_clone.clone())); } From 5e42dda9fc9ab7bbe33dba89a9bd0c854959361d Mon Sep 17 00:00:00 2001 From: n4n5 Date: Sat, 20 Sep 2025 17:06:22 -0600 Subject: [PATCH 8/9] add comment --- e2e/tasks/test_task_env_propagation | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/tasks/test_task_env_propagation b/e2e/tasks/test_task_env_propagation index 6b180d5363..c072a714ef 100644 --- a/e2e/tasks/test_task_env_propagation +++ b/e2e/tasks/test_task_env_propagation @@ -3,7 +3,7 @@ cat <mise.toml [tasks.echo] env = { "SUB_TASK" = "sub_task_env" } -run = "echo \$SUB_TASK \$MY_VAR" +run = 'echo "\$SUB_TASK \$MY_VAR"' [tasks.propagation] @@ -11,5 +11,5 @@ run = [{ task = "echo" }] env = { "MY_VAR" = "my_variable" } EOF -assert_contains "mise run echo" "sub_task_env" +assert_contains "mise run echo" "sub_task_env " # with trailing space assert_contains "mise run propagation" "sub_task_env my_variable" From 7e93002a2a8fbbf8cd6fba8accc398f391278ffe Mon Sep 17 00:00:00 2001 From: n4n5 Date: Sat, 20 Sep 2025 17:10:04 -0600 Subject: [PATCH 9/9] fix dummy typo --- docs/environments/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/environments/index.md b/docs/environments/index.md index 0a32a52ce8..715b9c051c 100644 --- a/docs/environments/index.md +++ b/docs/environments/index.md @@ -97,7 +97,7 @@ mise en ## Environment in tasks -Its also possible to define environment inside a task +It is also possible to define environment inside a task ```toml [mise.toml] [tasks.print]