Skip to content

Commit e437569

Browse files
author
Anton Sergeyev
committed
fix(tools): allow using env vars in tools
When parsing `tools` section, add locally defined environment variables to Tera context, so they are available for templating. Note that this only allows using the variables from the current file. References to other files are not resolved.
1 parent 567ff33 commit e437569

File tree

4 files changed

+89
-3
lines changed

4 files changed

+89
-3
lines changed

docs/dev-tools/index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ It's also compatible
2222
with asdf `.tool-versions` files as well as [idiomatic version files](/configuration#idiomatic-version-files) like `.node-version` and
2323
`.ruby-version`. See [configuration](/configuration) for more details.
2424

25+
When specifying tool versions, you can also refer to environment variables defined in the same file, but note
26+
that environment variables from referenced files are not resolved here.
27+
2528
::: info
2629
mise is inspired by [asdf](https://asdf-vm.com) and can leverage asdf's
2730
vast [plugin ecosystem](https://github.com/mise-plugins/registry)

docs/templates.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@ Here is an example of a `mise.toml` file that uses templates:
2020
```toml
2121
[env]
2222
PROJECT_NAME = "{{ cwd | basename }}"
23+
TERRAFORM_VERSION = "1.0.0"
2324

2425
[tools]
26+
# refers to env variable defined in this file
27+
terraform = "{{ env.TERRAFORM_VERSION }}"
28+
# refers to external env variable
2529
node = "{{ get_env(name='NODE_VERSION', default='20') }}"
2630
```
2731

src/config/config_file/mise_toml.rs

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::config::config_file::{config_root, toml::deserialize_arr};
2222
use crate::config::env_directive::{AgeFormat, EnvDirective, EnvDirectiveOptions, RequiredValue};
2323
use crate::config::settings::SettingsPartial;
2424
use crate::config::{Alias, AliasMap, Config};
25-
use crate::file;
25+
use crate::env_diff::EnvMap;
2626
use crate::file::{create_dir_all, display_path};
2727
use crate::hooks::{Hook, Hooks};
2828
use crate::redactions::Redactions;
@@ -31,6 +31,7 @@ use crate::task::Task;
3131
use crate::tera::{BASE_CONTEXT, get_tera};
3232
use crate::toolset::{ToolRequest, ToolRequestSet, ToolSource, ToolVersionOptions};
3333
use crate::watch_files::WatchFile;
34+
use crate::{env, file};
3435

3536
use super::{ConfigFileType, min_version::MinVersionSpec};
3637

@@ -137,11 +138,13 @@ impl MiseToml {
137138
"config_root",
138139
config_root::config_root(path).to_str().unwrap(),
139140
);
140-
Self {
141+
let mut rf = Self {
141142
path: path.to_path_buf(),
142143
context,
143144
..Default::default()
144-
}
145+
};
146+
rf.update_context_env(env::PRISTINE_ENV.clone());
147+
rf
145148
}
146149

147150
pub fn from_file(path: &Path) -> eyre::Result<Self> {
@@ -166,6 +169,7 @@ impl MiseToml {
166169
rf.context = BASE_CONTEXT.clone();
167170
rf.context
168171
.insert("config_root", path.parent().unwrap().to_str().unwrap());
172+
rf.update_context_env(env::PRISTINE_ENV.clone());
169173
rf.path = path.to_path_buf();
170174
let project_root = rf.project_root().map(|p| p.to_path_buf());
171175
for task in rf.tasks.0.values_mut() {
@@ -356,6 +360,23 @@ impl MiseToml {
356360
Ok(())
357361
}
358362

363+
// Merge base OS env vars with env sections from this file,
364+
// so they are available for templating.
365+
// Note this only merges regular key-value variables; referenced files are not resolved.
366+
fn update_context_env(&mut self, mut base_env: EnvMap) {
367+
let env_vars = self
368+
.env
369+
.0
370+
.iter()
371+
.filter_map(|e| match e {
372+
EnvDirective::Val(key, value, _) => Some((key.clone(), value.clone())),
373+
_ => None,
374+
})
375+
.collect::<IndexMap<_, _>>();
376+
base_env.extend(env_vars);
377+
self.context.insert("env", &base_env);
378+
}
379+
359380
fn parse_template(&self, input: &str) -> eyre::Result<String> {
360381
self.parse_template_with_context(&self.context, input)
361382
}
@@ -1731,6 +1752,30 @@ mod tests {
17311752
});
17321753
}
17331754

1755+
#[tokio::test]
1756+
async fn test_env_var_in_tool() {
1757+
let _config = Config::get().await.unwrap();
1758+
let p = CWD.as_ref().unwrap().join(".test.mise.toml");
1759+
file::write(
1760+
&p,
1761+
r#"
1762+
[env]
1763+
TERRAFORM_VERSION = '1.0.0'
1764+
JQ_PREFIX = '1.6'
1765+
1766+
[tools]
1767+
terraform = "{{env.TERRAFORM_VERSION}}"
1768+
jq = { prefix = "{{ env.JQ_PREFIX }}" }
1769+
"#,
1770+
)
1771+
.unwrap();
1772+
let cf = MiseToml::from_file(&p).unwrap();
1773+
assert_snapshot!(replace_path(&format!(
1774+
"{:#?}",
1775+
cf.to_tool_request_set().unwrap().tools
1776+
)));
1777+
}
1778+
17341779
#[tokio::test]
17351780
async fn test_env_array_valid() {
17361781
let _config = Config::get().await.unwrap();
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
source: src/config/config_file/mise_toml.rs
3+
expression: "replace_path(&format!(\"{:#?}\", cf.to_tool_request_set().unwrap().tools))"
4+
---
5+
{
6+
BackendArg(terraform): [
7+
Version {
8+
backend: BackendArg(terraform),
9+
version: "1.0.0",
10+
options: ToolVersionOptions {
11+
os: None,
12+
install_env: {},
13+
opts: {},
14+
},
15+
source: MiseToml(
16+
"~/cwd/.test.mise.toml",
17+
),
18+
},
19+
],
20+
BackendArg(jq): [
21+
Prefix {
22+
backend: BackendArg(jq),
23+
prefix: "1.6",
24+
options: ToolVersionOptions {
25+
os: None,
26+
install_env: {},
27+
opts: {},
28+
},
29+
source: MiseToml(
30+
"~/cwd/.test.mise.toml",
31+
),
32+
},
33+
],
34+
}

0 commit comments

Comments
 (0)