diff --git a/docs/cli/index.md b/docs/cli/index.md index 81f6222224..a93b9d66ad 100644 --- a/docs/cli/index.md +++ b/docs/cli/index.md @@ -115,7 +115,7 @@ Can also use `MISE_NO_CONFIG=1` - [`mise run [FLAGS]`](/cli/run.md) - [`mise search [FLAGS] [NAME]`](/cli/search.md) - [`mise self-update [FLAGS] [VERSION]`](/cli/self-update.md) -- [`mise set [--file ] [-g --global] [ENV_VAR]…`](/cli/set.md) +- [`mise set [FLAGS] [ENV_VAR]…`](/cli/set.md) - [`mise settings [FLAGS] [SETTING] [VALUE] `](/cli/settings.md) - [`mise settings add [-l --local] `](/cli/settings/add.md) - [`mise settings get [-l --local] `](/cli/settings/get.md) diff --git a/docs/cli/set.md b/docs/cli/set.md index b58fffe390..76d5538ed7 100644 --- a/docs/cli/set.md +++ b/docs/cli/set.md @@ -1,11 +1,12 @@ # `mise set` -- **Usage**: `mise set [--file ] [-g --global] [ENV_VAR]…` +- **Usage**: `mise set [FLAGS] [ENV_VAR]…` - **Source code**: [`src/cli/set.rs`](https://github.com/jdx/mise/blob/main/src/cli/set.rs) Set environment variables in mise.toml By default, this command modifies `mise.toml` in the current directory. +Use `-E ` to create/modify environment-specific config files like `mise..toml`. ## Arguments @@ -26,6 +27,10 @@ Defaults to MISE_DEFAULT_CONFIG_FILENAME environment variable, or `mise.toml`. Set the environment variable in the global config file +### `-E --env ` + +Create/modify an environment-specific config file like .mise.<env>.toml + Examples: ``` @@ -34,6 +39,9 @@ $ mise set NODE_ENV=production $ mise set NODE_ENV production +$ mise set -E staging NODE_ENV=staging +# creates or modifies mise.staging.toml + $ mise set key value source NODE_ENV production ~/.config/mise/config.toml diff --git a/e2e/cli/test_set b/e2e/cli/test_set index 12e105be2c..a6da732e56 100644 --- a/e2e/cli/test_set +++ b/e2e/cli/test_set @@ -8,3 +8,18 @@ assert_fail "mise set FOO" "Environment variable FOO not found" assert "mise set --file .test.mise.toml FOO=bar" "" assert "mise set --file .test.mise.toml FOO" "bar" + +# Test -E flag for environment-specific config files +assert "mise set -E staging STAGING_VAR=staging_value" "" +assert "mise set -E staging STAGING_VAR" "staging_value" +assert "mise set -E staging" "STAGING_VAR staging_value ~/workdir/mise.staging.toml" + +# Test that -E flag only shows vars from that environment file +assert "mise set -E production PROD_VAR=prod_value" "" +assert "mise set -E production" "PROD_VAR prod_value ~/workdir/mise.production.toml" +# STAGING_VAR should not appear when reading production env +assert_not_contains "mise set -E production" "STAGING_VAR" + +# Test that regular set doesn't show env-specific vars +assert_not_contains "mise set" "STAGING_VAR" +assert_not_contains "mise set" "PROD_VAR" diff --git a/e2e/cli/test_set_env b/e2e/cli/test_set_env new file mode 100755 index 0000000000..038a98358b --- /dev/null +++ b/e2e/cli/test_set_env @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +# Create an initial mise.toml file to reproduce the issue +echo '[tools] +node = "20"' >mise.toml + +# This should create mise.pp.toml (environment-specific) instead of modifying mise.toml +# Currently this fails because the -E flag doesn't exist +if mise set -E pp NODE_ENV=production 2>/dev/null; then + # If the command succeeded, check if it created the environment-specific file + if [[ -f "mise.pp.toml" ]]; then + assert "cat mise.pp.toml" '[env] +NODE_ENV = "production"' + # Ensure original mise.toml wasn't modified + assert "cat mise.toml" '[tools] +node = "20"' + else + echo "ERROR: mise set -E pp should create mise.pp.toml but it doesn't exist" + exit 1 + fi +else + echo "Expected: mise set -E flag should exist and work" + echo "Actual: mise set command doesn't support -E flag" + exit 1 +fi + +# Cleanup +rm -f mise.toml mise.pp.toml diff --git a/mise.usage.kdl b/mise.usage.kdl index f4e7489b6c..33573047bd 100644 --- a/mise.usage.kdl +++ b/mise.usage.kdl @@ -699,14 +699,17 @@ cmd self-update help="Updates mise itself." { } cmd set help="Set environment variables in mise.toml" { alias ev env-vars hide=#true - long_help "Set environment variables in mise.toml\n\nBy default, this command modifies `mise.toml` in the current directory." - after_long_help "Examples:\n\n $ mise set NODE_ENV=production\n\n $ mise set NODE_ENV\n production\n\n $ mise set\n key value source\n NODE_ENV production ~/.config/mise/config.toml\n" + long_help "Set environment variables in mise.toml\n\nBy default, this command modifies `mise.toml` in the current directory.\nUse `-E ` to create/modify environment-specific config files like `mise..toml`." + after_long_help "Examples:\n\n $ mise set NODE_ENV=production\n\n $ mise set NODE_ENV\n production\n\n $ mise set -E staging NODE_ENV=staging\n # creates or modifies mise.staging.toml\n\n $ mise set\n key value source\n NODE_ENV production ~/.config/mise/config.toml\n" flag --file help="The TOML file to update" { long_help "The TOML file to update\n\nDefaults to MISE_DEFAULT_CONFIG_FILENAME environment variable, or `mise.toml`." arg } flag --complete help="Render completions" hide=#true flag "-g --global" help="Set the environment variable in the global config file" + flag "-E --env" help="Create/modify an environment-specific config file like .mise..toml" { + arg + } flag "--remove --rm --unset" help="Remove the environment variable from config file" var=#true hide=#true { long_help "Remove the environment variable from config file\n\nCan be used multiple times." arg diff --git a/src/cli/set.rs b/src/cli/set.rs index 2b39ef832b..f83c5466a5 100644 --- a/src/cli/set.rs +++ b/src/cli/set.rs @@ -16,6 +16,7 @@ use tabled::Tabled; /// Set environment variables in mise.toml /// /// By default, this command modifies `mise.toml` in the current directory. +/// Use `-E ` to create/modify environment-specific config files like `mise..toml`. #[derive(Debug, clap::Args)] #[clap(aliases = ["ev", "env-vars"], verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Set { @@ -30,9 +31,13 @@ pub struct Set { complete: bool, /// Set the environment variable in the global config file - #[clap(short, long, verbatim_doc_comment, overrides_with = "file")] + #[clap(short, long, verbatim_doc_comment, overrides_with_all = &["file", "env"])] global: bool, + /// Create/modify an environment-specific config file like .mise..toml + #[clap(short = 'E', long, overrides_with_all = &["global", "file"])] + env: Option, + /// Remove the environment variable from config file /// /// Can be used multiple times. @@ -60,7 +65,7 @@ impl Set { _ => {} } - let filename = self.filename(); + let filename = self.filename()?; let config = MiseToml::from_file(&filename).unwrap_or_default(); let mut mise_toml = get_mise_toml(&filename)?; @@ -144,6 +149,22 @@ impl Set { _ => None, }) .collect() + } else if self.env.is_some() { + // When -E flag is used, read from the environment-specific file + let filename = self.filename()?; + let config = MiseToml::from_file(&filename).unwrap_or_default(); + config + .env_entries()? + .into_iter() + .filter_map(|ed| match ed { + EnvDirective::Val(key, value, _) => Some(Row { + key, + value, + source: display_path(&filename), + }), + _ => None, + }) + .collect() } else { Config::get() .await? @@ -160,13 +181,21 @@ impl Set { Ok(rows) } - fn filename(&self) -> PathBuf { + fn filename(&self) -> Result { if let Some(file) = &self.file { - file.clone() + Ok(file.clone()) } else if self.global { - config::global_config_path() + Ok(config::global_config_path()) + } else if let Some(env) = &self.env { + let cwd = env::current_dir()?; + let p = cwd.join(format!(".mise.{env}.toml")); + if p.exists() { + Ok(p) + } else { + Ok(cwd.join(format!("mise.{env}.toml"))) + } } else { - config::local_toml_config_path() + Ok(config::local_toml_config_path()) } } } @@ -197,6 +226,9 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( $ mise set NODE_ENV production + $ mise set -E staging NODE_ENV=staging + # creates or modifies mise.staging.toml + $ mise set key value source NODE_ENV production ~/.config/mise/config.toml diff --git a/xtasks/fig/src/mise.ts b/xtasks/fig/src/mise.ts index 5940ac91fb..a3602bc818 100644 --- a/xtasks/fig/src/mise.ts +++ b/xtasks/fig/src/mise.ts @@ -1798,6 +1798,15 @@ esac`), description: "Set the environment variable in the global config file", isRepeatable: false, }, + { + name: ["-E", "--env"], + description: + "Create/modify an environment-specific config file like .mise..toml", + isRepeatable: false, + args: { + name: "env", + }, + }, ], args: { name: "env_var",