feat(wfe-yaml): add YAML 1.1 merge key support via yaml-merge-keys

Preprocesses <<: *anchor merge keys before serde_yaml 0.9 deserialization.
serde_yaml implements YAML 1.2 which dropped merge keys; the yaml-merge-keys
crate resolves them as a preprocessing step, giving full anchor + merge
support for DRY pipeline definitions.
This commit is contained in:
2026-03-26 15:59:28 +00:00
parent fe65d2debc
commit 39b3daf57c
3 changed files with 16 additions and 2 deletions

View File

@@ -49,6 +49,7 @@ wfe-containerd = { version = "1.0.0", path = "wfe-containerd" }
# YAML # YAML
serde_yaml = "0.9" serde_yaml = "0.9"
yaml-merge-keys = { version = "0.8", features = ["serde_yaml"] }
regex = "1" regex = "1"
# Deno runtime # Deno runtime

View File

@@ -15,6 +15,7 @@ wfe-core = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
serde_json = { workspace = true } serde_json = { workspace = true }
serde_yaml = { workspace = true } serde_yaml = { workspace = true }
yaml-merge-keys = { workspace = true }
async-trait = { workspace = true } async-trait = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }

View File

@@ -8,6 +8,8 @@ pub mod validation;
use std::collections::HashMap; use std::collections::HashMap;
use serde::de::Error as _;
use crate::compiler::CompiledWorkflow; use crate::compiler::CompiledWorkflow;
use crate::error::YamlWorkflowError; use crate::error::YamlWorkflowError;
@@ -23,6 +25,10 @@ pub fn load_workflow(
/// Load workflows from a YAML string, applying variable interpolation. /// Load workflows from a YAML string, applying variable interpolation.
/// Returns a Vec of compiled workflows (supports multi-workflow files). /// Returns a Vec of compiled workflows (supports multi-workflow files).
///
/// Supports YAML 1.1 merge keys (`<<: *anchor`) via the `yaml-merge-keys`
/// crate. serde_yaml 0.9 implements YAML 1.2 which dropped merge keys;
/// we preprocess the YAML to resolve them before deserialization.
pub fn load_workflow_from_str( pub fn load_workflow_from_str(
yaml: &str, yaml: &str,
config: &HashMap<String, serde_json::Value>, config: &HashMap<String, serde_json::Value>,
@@ -30,8 +36,14 @@ pub fn load_workflow_from_str(
// Interpolate variables. // Interpolate variables.
let interpolated = interpolation::interpolate(yaml, config)?; let interpolated = interpolation::interpolate(yaml, config)?;
// Parse YAML as multi-workflow file. // Parse to a generic YAML value first, then resolve merge keys (<<:).
let file: schema::YamlWorkflowFile = serde_yaml::from_str(&interpolated)?; // This adds YAML 1.1 merge key support on top of serde_yaml 0.9's YAML 1.2 parser.
let raw_value: serde_yaml::Value = serde_yaml::from_str(&interpolated)?;
let merged_value = yaml_merge_keys::merge_keys_serde(raw_value)
.map_err(|e| YamlWorkflowError::Parse(serde_yaml::Error::custom(format!("merge key resolution failed: {e}"))))?;
// Deserialize the merge-resolved value into our schema.
let file: schema::YamlWorkflowFile = serde_yaml::from_value(merged_value)?;
let specs = resolve_workflow_specs(file)?; let specs = resolve_workflow_specs(file)?;