Skip to content

Commit 3823719

Browse files
committed
feat: allow yaml tera loader to work with GitLab !references
1 parent 223d208 commit 3823719

File tree

2 files changed

+71
-2
lines changed

2 files changed

+71
-2
lines changed

src/config.rs

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
use crate::errors::FlokiError;
33
use crate::image;
44
use serde::{Deserialize, Serialize};
5+
use serde_yaml::{Mapping as YamlMapping, Value as YamlValue};
56
use tera::from_value;
67
use tera::Context;
78
use tera::Tera;
@@ -128,6 +129,30 @@ enum LoaderType {
128129
Toml,
129130
}
130131

132+
fn strip_yaml_tags(value: &YamlValue) -> YamlValue {
133+
match value {
134+
// For tagged values, we just return the inner value.
135+
YamlValue::Tagged(tagged) => strip_yaml_tags(&tagged.value),
136+
137+
// For sequences and mappings, we need to recursively strip tags.
138+
YamlValue::Sequence(items) => {
139+
let mut stripped = Vec::with_capacity(items.len());
140+
for item in items {
141+
stripped.push(strip_yaml_tags(item));
142+
}
143+
YamlValue::Sequence(stripped)
144+
}
145+
YamlValue::Mapping(map) => {
146+
let mut stripped = YamlMapping::with_capacity(map.len());
147+
for (key, value) in map {
148+
stripped.insert(strip_yaml_tags(key), strip_yaml_tags(value));
149+
}
150+
YamlValue::Mapping(stripped)
151+
}
152+
_ => value.clone(),
153+
}
154+
}
155+
131156
fn makeloader(path: &Path, loader: LoaderType) -> impl tera::Function {
132157
// Get the dirname of the Path given (if a file), or just the directory.
133158
let directory = if path.is_file() {
@@ -145,8 +170,15 @@ fn makeloader(path: &Path, loader: LoaderType) -> impl tera::Function {
145170
.and_then(|full_path| std::fs::read_to_string(full_path).map_err(Into::into))
146171
// Parse the file using the relevant parser
147172
.and_then(|contents| match loader {
148-
LoaderType::Yaml => serde_yaml::from_str(&contents)
149-
.map_err(|err| format!("Failed to parse file as YAML: {err}").into()),
173+
LoaderType::Yaml => {
174+
let raw: YamlValue = serde_yaml::from_str(&contents).map_err(|err| {
175+
tera::Error::msg(format!("Failed to parse file as YAML: {err}"))
176+
})?;
177+
let stripped = strip_yaml_tags(&raw);
178+
serde_yaml::from_value::<tera::Value>(stripped).map_err(|err| {
179+
tera::Error::msg(format!("Failed to convert YAML value: {err}"))
180+
})
181+
}
150182
LoaderType::Json => serde_json::from_str(&contents)
151183
.map_err(|err| format!("Failed to parse file as JSON: {err}").into()),
152184
LoaderType::Toml => toml::from_str(&contents)
@@ -372,4 +404,36 @@ mod test {
372404
assert_eq!(config, "floki: floki");
373405
Ok(())
374406
}
407+
408+
#[test]
409+
fn test_strip_yaml_tags_drops_reference_tag() {
410+
let yaml = "value: !reference [template, script]";
411+
let raw: YamlValue = serde_yaml::from_str(yaml).unwrap();
412+
let stripped = strip_yaml_tags(&raw);
413+
414+
let map = match stripped {
415+
YamlValue::Mapping(map) => map,
416+
other => panic!("expected mapping, got {:?}", other),
417+
};
418+
419+
let key = YamlValue::String("value".into());
420+
let field = map.get(&key).expect("missing value key");
421+
422+
match field {
423+
YamlValue::Sequence(items) => {
424+
assert_eq!(items.len(), 2);
425+
assert_eq!(items[0], YamlValue::String("template".into()));
426+
assert_eq!(items[1], YamlValue::String("script".into()));
427+
}
428+
other => panic!("expected sequence, got {:?}", other),
429+
}
430+
}
431+
432+
#[test]
433+
fn test_tera_yamlload_with_gitlab_reference() -> Result<(), Box<dyn std::error::Error>> {
434+
let template = r#"{% set values = yaml(file="test_resources/gitlab_reference.yaml") %}script0: {{ values.job.script[0] }} script1: {{ values.job.script[1] }}"#;
435+
let rendered = render_template(template, Path::new("floki.yaml"))?;
436+
assert_eq!(rendered, "script0: .shared_template script1: script");
437+
Ok(())
438+
}
375439
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.shared_template:
2+
script:
3+
- echo template
4+
job:
5+
script: !reference [.shared_template, script]

0 commit comments

Comments
 (0)