Overlay one YAML or JSON document on another, or apply a JSON Patch, without losing the file’s comments and layout. A merge patch suits environment overrides; a JSON Patch suits scripted changes with a test guard.
use oneyaml::{Document, MergePatch, Patch, PatchErrorKind}; fn main() -> Result<(), Box<dyn std::error::Error>> { let src = "\ # values.yaml image: repository: registry.example.com/web tag: \"1.4.2\" # set by CI replicas: 2 resources: limits: cpu: 500m memory: 256Mi "; // An environment overlay as a merge patch: objects merge, null deletes. let mut doc = Document::parse(src)?; let overlay = MergePatch::from_json(r#"{"replicas": 5, "resources": {"limits": {"cpu": null, "memory": "1Gi"}}}"#)?; doc.apply_merge_patch(&overlay)?; print!("{doc}"); // A JSON Patch with a guard: `test` must pass or nothing changes. let bump = Patch::from_json( r#"[{"op": "test", "path": "/image/tag", "value": "1.4.2"}, {"op": "replace", "path": "/image/tag", "value": "1.5.0"}]"#, )?; doc.apply_patch(&bump)?; println!("tag now {:?}", doc.get_path("image.tag").and_then(|n| n.as_str())); // Applied again, the test fails, and the document is left as it was. let err = doc.apply_patch(&bump).err().ok_or("expected the test to fail")?; println!("second run: {:?} at op {:?}", err.kind() == PatchErrorKind::Test, err.op_index()); Ok(()) }
# values.yaml image: repository: registry.example.com/web tag: "1.4.2" # set by CI replicas: 5 resources: limits: memory: 1Gi tag now Some("1.5.0") second run: true at op Some(0)
Good to know
- All or nothing. If any operation fails, the document is exactly as it was.
err.kind()says why, anderr.op_index()which operation. - A merge patch merges mappings and replaces everything else.
nulldeletes a key; a list in the patch replaces the whole list. - Only the named values change. The
# set by CIcomment and the quotes around the tag stay. - YAML rules, not JSON rules.
testcompares YAML values (1is not1.0), a pointer token matches a key by its text, and writes below an alias or to a key merged in by<<are refused. Acopyormovewrites the value without its comments. Patch::from_jsonandMergePatch::from_jsonalso read YAML text. For text from outside, read aValuewithLimits::untrusted()first and build the patch withPatch::from_valueorMergePatch::new.
Every difference from RFC 6902 is listed under patches and pointers.
A longer guide: Apply a JSON Patch to a YAML file.