templates: one Jinja language (hive-template) for the notify router's flows, flows document version 2
A todo node's key and text were hand-expanded `{field}` strings. They are now Jinja templates rendered through the new hive-template crate (minijinja, an unknown variable is an error), and the controller's save check reads the variables the template uses. The flows document is version 2; a version 1 document reads as version 2 with each `{field}` converted to `{{ field }}`, and the next save writes it.
This commit is contained in:
parent
11393bc538
commit
8ef3138863
2 changed files with 306 additions and 91 deletions
|
|
@ -175,28 +175,20 @@ fn holds(condition: &Condition, fields: &Fields) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
/// `template` with each `{field}` replaced by that field's value, a list
|
||||
/// joined with `, `. A name that is no field is an error naming it.
|
||||
/// `template`, a Jinja template, rendered over the event's fields; a list field
|
||||
/// reads as its items joined with `, `. A name that is no field is an error.
|
||||
pub fn expand(template: &str, fields: &Fields) -> Result<String, String> {
|
||||
let mut out = String::with_capacity(template.len());
|
||||
let mut rest = template;
|
||||
while let Some(open) = rest.find('{') {
|
||||
out.push_str(&rest[..open]);
|
||||
let after = &rest[open + 1..];
|
||||
let Some(close) = after.find('}') else {
|
||||
out.push_str(&rest[open..]);
|
||||
return Ok(out);
|
||||
};
|
||||
let name = &after[..close];
|
||||
match fields.get(name) {
|
||||
Some(Value::Text(v)) => out.push_str(v),
|
||||
Some(Value::List(items)) => out.push_str(&items.join(", ")),
|
||||
None => return Err(format!("{{{name}}} is no event field")),
|
||||
}
|
||||
rest = &after[close + 1..];
|
||||
}
|
||||
out.push_str(rest);
|
||||
Ok(out)
|
||||
let context: BTreeMap<&str, String> = fields
|
||||
.iter()
|
||||
.map(|(name, value)| {
|
||||
let text = match value {
|
||||
Value::Text(v) => v.clone(),
|
||||
Value::List(items) => items.join(", "),
|
||||
};
|
||||
(*name, text)
|
||||
})
|
||||
.collect();
|
||||
hive_template::render(template, &context)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -387,9 +379,9 @@ mod tests {
|
|||
f.nodes[2].kind = NodeKind::Todo(TodoSink {
|
||||
to: Recipients::Agent("triage".to_owned()),
|
||||
op: Op::Upsert,
|
||||
key: "forge:{repo}#{number}:triage".to_owned(),
|
||||
key: "forge:{{ repo }}#{{ number }}:triage".to_owned(),
|
||||
prefix: false,
|
||||
text: "triage {repo}#{number}".to_owned(),
|
||||
text: "triage {{ repo }}#{{ number }}".to_owned(),
|
||||
});
|
||||
let got = evaluate(
|
||||
&f,
|
||||
|
|
@ -502,13 +494,10 @@ mod tests {
|
|||
fn a_placeholder_expands_to_its_field_and_an_unknown_one_is_an_error() {
|
||||
let fields = event("assigned", &["a", "b"], &[], &[]);
|
||||
assert_eq!(
|
||||
expand("{repo}#{number} {assignees_added} {", &fields),
|
||||
expand("{{ repo }}#{{ number }} {{ assignees_added }} {", &fields),
|
||||
Ok("hyperhive/hyperhive#7 a, b {".to_owned())
|
||||
);
|
||||
assert_eq!(
|
||||
expand("x {nope}", &fields),
|
||||
Err("{nope} is no event field".to_owned())
|
||||
);
|
||||
assert!(expand("x {{ nope }}", &fields).is_err());
|
||||
}
|
||||
|
||||
/// A sink naming a placeholder the event lacks sends nothing, rather
|
||||
|
|
@ -519,7 +508,7 @@ mod tests {
|
|||
f.nodes[2].kind = NodeKind::Todo(TodoSink {
|
||||
to: Recipients::Agent("triage".to_owned()),
|
||||
op: Op::Upsert,
|
||||
key: "forge:{repo}#{numbr}:triage".to_owned(),
|
||||
key: "forge:{{ repo }}#{{ numbr }}:triage".to_owned(),
|
||||
prefix: false,
|
||||
text: "t".to_owned(),
|
||||
});
|
||||
|
|
@ -527,7 +516,7 @@ mod tests {
|
|||
assert!(evaluate(&f, "issue_assign", &fields).is_empty());
|
||||
// Control: spelled right, the same flow emits.
|
||||
if let NodeKind::Todo(s) = &mut f.nodes[2].kind {
|
||||
s.key = "forge:{repo}#{number}:triage".to_owned();
|
||||
s.key = "forge:{{ repo }}#{{ number }}:triage".to_owned();
|
||||
}
|
||||
assert_eq!(evaluate(&f, "issue_assign", &fields).len(), 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ mod tests {
|
|||
);
|
||||
for bad in [
|
||||
junk(2, b"not json"),
|
||||
junk(3, br#"{"version":2,"flows":[]}"#),
|
||||
junk(3, br#"{"version":3,"flows":[]}"#),
|
||||
junk(4, br#"{"flows":[{"id":"x"}]}"#),
|
||||
Read::Failed("timeout".to_owned()),
|
||||
] {
|
||||
|
|
|
|||
Loading…
Reference in a new issue