feat: task vars (#3130)

* feat: task vars

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
jdx 2024-11-21 20:49:57 -06:00 committed by GitHub
parent 47e3f24aa9
commit dea5bc66a3
9 changed files with 88 additions and 10 deletions

View File

@ -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:

View File

@ -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 <span v-pre>`{{arg()}}`</span>. They are used for positional arguments where the order matters.
These are defined in scripts with <span v-pre>`{{arg()}}`</span>. 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 <span v-pre>`{{option()}}`</span>. They are used for named arguments where the order doesn't matter.
These are defined in scripts with <span v-pre>`{{option()}}`</span>. 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 <span v-pre>`{{flag()}}`</span>.
Flags are like options except they don't take values. They are defined in scripts with <span v-pre>
`{{flag()}}`</span>.
Example:

8
e2e/tasks/test_task_vars Normal file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
cat <<EOF >mise.toml
tasks.a.run = "echo foo: {{vars.foo}}"
vars.foo = "bar"
EOF
assert "mise run a" "foo: bar"

View File

@ -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",

View File

@ -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",

View File

@ -53,6 +53,8 @@ pub struct MiseToml {
#[serde(default)]
tasks: Tasks,
#[serde(default)]
vars: IndexMap<String, String>,
#[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<String, String>> {
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(),
}
}
}

View File

@ -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<TaskConfig> = Lazy::new(TaskConfig::default);
&DEFAULT_TASK_CONFIG
}
fn vars(&self) -> Result<&IndexMap<String, String>> {
static DEFAULT_VARS: Lazy<IndexMap<String, String>> = Lazy::new(IndexMap::new);
Ok(&DEFAULT_VARS)
}
}
impl dyn ConfigFile {

View File

@ -44,6 +44,7 @@ pub struct Config {
pub project_root: Option<PathBuf>,
pub all_aliases: AliasMap,
pub repo_urls: HashMap<String, String>,
pub vars: IndexMap<String, String>,
aliases: AliasMap,
env: OnceCell<EnvResults>,
env_with_sources: OnceCell<EnvWithSources>,
@ -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<HashMap<String, String>> {
Ok(plugins)
}
fn load_vars(config_files: &ConfigMap) -> Result<IndexMap<String, String>> {
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

View File

@ -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())