diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 5bdfa9e44..acde6710e 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -8,7 +8,6 @@ repos:
- id: end-of-file-fixer
- id: check-yaml
- id: check-toml
- - id: check-added-large-files
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.10.0.1
hooks:
diff --git a/docs/tasks/toml-tasks.md b/docs/tasks/toml-tasks.md
index 6a016b8e1..a841b99fb 100644
--- a/docs/tasks/toml-tasks.md
+++ b/docs/tasks/toml-tasks.md
@@ -18,7 +18,7 @@ alias = 'b' # `mise run b`
[tasks.test]
description = 'Run automated tests'
-run = [ # multiple commands are run in series
+run = [# multiple commands are run in series
'cargo test',
'./scripts/test-e2e.sh',
]
@@ -26,7 +26,7 @@ dir = "{{cwd}}" # run in user's cwd, default is the project's base directory
[tasks.lint]
description = 'Lint with clippy'
-env = {RUST_BACKTRACE = '1'} # env vars for the script
+env = { RUST_BACKTRACE = '1' } # env vars for the script
# specify a shell command to run the script with (default is 'sh -c')
shell = 'bash -c'
# you can specify a multiline script instead of individual commands
@@ -44,6 +44,21 @@ description = 'Cut a new release'
file = 'scripts/release.sh' # execute an external script
```
+## Vars
+
+Vars are variables that can be shared between tasks like environment variables but they are not
+passed
+as environment variables to the scripts. They are defined in the `vars` section of the `mise.toml`
+file.
+
+```toml
+[vars]
+e2e_args = '--headless'
+
+[tasks.test]
+run = './scripts/test-e2e.sh {{vars.e2e_args}}'
+```
+
## Arguments
By default, arguments are passed to the last script in the `run` array. So if a task was defined as:
@@ -53,7 +68,8 @@ By default, arguments are passed to the last script in the `run` array. So if a
run = ['cargo test', './scripts/test-e2e.sh']
```
-Then running `mise run test foo bar` will pass `foo bar` to `./scripts/test-e2e.sh` but not to `cargo test`.
+Then running `mise run test foo bar` will pass `foo bar` to `./scripts/test-e2e.sh` but not to
+`cargo test`.
You can also define arguments using templates:
@@ -65,8 +81,10 @@ run = [
]
```
-Then running `mise run test foo bar` will pass `foo bar` to `cargo test`. `mise run test --e2e-args baz` will pass `baz` to `./scripts/test-e2e.sh`.
-If any arguments are defined with templates then mise will not pass the arguments to the last script in the `run` array.
+Then running `mise run test foo bar` will pass `foo bar` to `cargo test`.
+`mise run test --e2e-args baz` will pass `baz` to `./scripts/test-e2e.sh`.
+If any arguments are defined with templates then mise will not pass the arguments to the last script
+in the `run` array.
:::tip
Using templates to define arguments will make them work with completion and help messages.
@@ -74,7 +92,8 @@ Using templates to define arguments will make them work with completion and help
### Positional Arguments
-These are defined in scripts with `{{arg()}}`. They are used for positional arguments where the order matters.
+These are defined in scripts with `{{arg()}}`. They are used for positional
+arguments where the order matters.
Example:
@@ -85,14 +104,16 @@ run = 'cargo test {{arg(name="file")}}'
# runs: cargo test my-test-file
```
-- `i`: The index of the argument. This can be used to specify the order of arguments. Defaults to the order they're defined in the scripts.
+- `i`: The index of the argument. This can be used to specify the order of arguments. Defaults to
+ the order they're defined in the scripts.
- `name`: The name of the argument. This is used for help/error messages.
- `var`: If `true`, multiple arguments can be passed.
- `default`: The default value if the argument is not provided.
### Options
-These are defined in scripts with `{{option()}}`. They are used for named arguments where the order doesn't matter.
+These are defined in scripts with `{{option()}}`. They are used for named
+arguments where the order doesn't matter.
Example:
@@ -109,7 +130,8 @@ run = 'cargo test {{option(name="file")}}'
### Flags
-Flags are like options except they don't take values. They are defined in scripts with `{{flag()}}`.
+Flags are like options except they don't take values. They are defined in scripts with
+`{{flag()}}`.
Example:
diff --git a/e2e/tasks/test_task_vars b/e2e/tasks/test_task_vars
new file mode 100644
index 000000000..945a5d071
--- /dev/null
+++ b/e2e/tasks/test_task_vars
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+cat <mise.toml
+tasks.a.run = "echo foo: {{vars.foo}}"
+vars.foo = "bar"
+EOF
+
+assert "mise run a" "foo: bar"
diff --git a/schema/mise.json b/schema/mise.json
index d2b7d589d..bd9abfe9f 100644
--- a/schema/mise.json
+++ b/schema/mise.json
@@ -745,6 +745,14 @@
}
]
},
+ "vars": {
+ "description": "variables to set",
+ "type": "object",
+ "additionalProperties": {
+ "description": "value of variable",
+ "type": "string"
+ }
+ },
"task_config": {
"description": "configration for task execution/management",
"type": "object",
diff --git a/schema/mise.json.hbs b/schema/mise.json.hbs
index b08b79540..05dbb31bf 100644
--- a/schema/mise.json.hbs
+++ b/schema/mise.json.hbs
@@ -251,6 +251,14 @@
}
]
},
+ "vars": {
+ "description": "variables to set",
+ "type": "object",
+ "additionalProperties": {
+ "description": "value of variable",
+ "type": "string"
+ }
+ },
"task_config": {
"description": "configration for task execution/management",
"type": "object",
diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs
index 452e8b0e9..a29a9a9f1 100644
--- a/src/config/config_file/mise_toml.rs
+++ b/src/config/config_file/mise_toml.rs
@@ -53,6 +53,8 @@ pub struct MiseToml {
#[serde(default)]
tasks: Tasks,
#[serde(default)]
+ vars: IndexMap,
+ #[serde(default)]
settings: SettingsPartial,
}
@@ -420,6 +422,10 @@ impl ConfigFile for MiseToml {
fn task_config(&self) -> &TaskConfig {
&self.task_config
}
+
+ fn vars(&self) -> eyre::Result<&IndexMap> {
+ Ok(&self.vars)
+ }
}
/// Returns a [`toml_edit::Key`] from the given `key`.
@@ -482,6 +488,7 @@ impl Clone for MiseToml {
tasks: self.tasks.clone(),
task_config: self.task_config.clone(),
settings: self.settings.clone(),
+ vars: self.vars.clone(),
}
}
}
diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs
index 1248f17e9..d7a91c5ac 100644
--- a/src/config/config_file/mod.rs
+++ b/src/config/config_file/mod.rs
@@ -7,6 +7,7 @@ use std::sync::{Mutex, Once};
use eyre::eyre;
use eyre::Result;
+use indexmap::IndexMap;
use legacy_version::LegacyVersionFile;
use once_cell::sync::Lazy;
use serde_derive::Deserialize;
@@ -88,6 +89,10 @@ pub trait ConfigFile: Debug + Send + Sync {
static DEFAULT_TASK_CONFIG: Lazy = Lazy::new(TaskConfig::default);
&DEFAULT_TASK_CONFIG
}
+ fn vars(&self) -> Result<&IndexMap> {
+ static DEFAULT_VARS: Lazy> = Lazy::new(IndexMap::new);
+ Ok(&DEFAULT_VARS)
+ }
}
impl dyn ConfigFile {
diff --git a/src/config/mod.rs b/src/config/mod.rs
index 03916bc87..7da081946 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -44,6 +44,7 @@ pub struct Config {
pub project_root: Option,
pub all_aliases: AliasMap,
pub repo_urls: HashMap,
+ pub vars: IndexMap,
aliases: AliasMap,
env: OnceCell,
env_with_sources: OnceCell,
@@ -97,6 +98,7 @@ impl Config {
aliases: load_aliases(&config_files)?,
project_root: get_project_root(&config_files),
repo_urls: load_plugins(&config_files)?,
+ vars: load_vars(&config_files)?,
config_files,
..Default::default()
};
@@ -806,6 +808,17 @@ fn load_plugins(config_files: &ConfigMap) -> Result> {
Ok(plugins)
}
+fn load_vars(config_files: &ConfigMap) -> Result> {
+ let mut vars = IndexMap::new();
+ for config_file in config_files.values() {
+ for (k, v) in config_file.vars()?.clone() {
+ vars.insert(k, v);
+ }
+ }
+ trace!("load_vars: {}", vars.len());
+ Ok(vars)
+}
+
impl Debug for Config {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let config_files = self
diff --git a/src/task/task_script_parser.rs b/src/task/task_script_parser.rs
index 8e5043ee2..dab8cdc77 100644
--- a/src/task/task_script_parser.rs
+++ b/src/task/task_script_parser.rs
@@ -1,5 +1,7 @@
+use crate::config::CONFIG;
use crate::tera::{get_tera, BASE_CONTEXT};
use eyre::Result;
+use indexmap::IndexMap;
use itertools::Itertools;
use std::collections::HashMap;
use std::path::PathBuf;
@@ -259,6 +261,12 @@ impl TaskScriptParser {
});
let mut ctx = BASE_CONTEXT.clone();
ctx.insert("config_root", config_root);
+ let mut vars = IndexMap::new();
+ ctx.insert("vars", &vars);
+ for (k, v) in &CONFIG.vars {
+ vars.insert(k.clone(), tera.render_str(v, &ctx).unwrap());
+ ctx.insert("vars", &vars);
+ }
let scripts = scripts
.iter()
.map(|s| tera.render_str(s, &ctx).unwrap())