Fix shallow merge overwriting same-section entries in multi-document YAML#2430
Conversation
…YAML Previously, when merging multiple YAML documents, entries under the same top-level section (e.g., two different deployers under `deployers:`) would be lost because the shallow merge simply replaced the entire hash. This implements deep recursive merging so that different entries under the same section are properly combined.
WalkthroughIntroduces a private Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Important Action Needed: IP Allowlist UpdateIf your organization protects your Git platform with IP whitelisting, please add the new CodeRabbit IP address to your allowlist:
Failure to add the new IP will result in interrupted reviews. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@crates/settings/src/yaml/emitter.rs`:
- Around line 558-584: Replace the loose contains-based assertions in
test_emit_deep_merges_hash_sections with an insta snapshot assertion: call
emit_documents(&[get_document(yaml1), get_document(yaml2)]) as before, unwrap
the output string, and use insta::assert_snapshot!(output) (or similar) to
capture the entire merged YAML; if insta isn't already a dev-dependency add it
to Cargo.toml dev-deps and create the expected snapshot file via running tests
to record the correct merged output. Ensure you reference the existing test
function test_emit_deep_merges_hash_sections and the helpers emit_documents and
get_document when making the change.
| #[test] | ||
| fn test_emit_deep_merges_hash_sections() { | ||
| let yaml1 = r#" | ||
| networks: | ||
| mainnet: | ||
| rpcs: | ||
| - https://eth.llamarpc.com | ||
| chain-id: 1 | ||
| deployers: | ||
| deployer1: | ||
| network: mainnet | ||
| address: 0x0000000000000000000000000000000000000001 | ||
| "#; | ||
| let yaml2 = r#" | ||
| deployers: | ||
| deployer2: | ||
| network: mainnet | ||
| address: 0x0000000000000000000000000000000000000002 | ||
| "#; | ||
| let result = emit_documents(&[get_document(yaml1), get_document(yaml2)]); | ||
| assert!(result.is_ok()); | ||
| let output = result.unwrap(); | ||
| assert!(output.contains("deployer1:"), "deployer1 should be present"); | ||
| assert!(output.contains("deployer2:"), "deployer2 should be present"); | ||
| assert!(output.contains("0x0000000000000000000000000000000000000001")); | ||
| assert!(output.contains("0x0000000000000000000000000000000000000002")); | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider an insta snapshot for the merged YAML output.
Using a snapshot would capture structure/ordering regressions more reliably than contains checks.
♻️ Possible refactor (if `insta` is already in dev-deps)
- let output = result.unwrap();
- assert!(output.contains("deployer1:"), "deployer1 should be present");
- assert!(output.contains("deployer2:"), "deployer2 should be present");
- assert!(output.contains("0x0000000000000000000000000000000000000001"));
- assert!(output.contains("0x0000000000000000000000000000000000000002"));
+ let output = result.unwrap();
+ insta::assert_snapshot!(output);As per coding guidelines: Prefer insta snapshots for Rust testing.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #[test] | |
| fn test_emit_deep_merges_hash_sections() { | |
| let yaml1 = r#" | |
| networks: | |
| mainnet: | |
| rpcs: | |
| - https://eth.llamarpc.com | |
| chain-id: 1 | |
| deployers: | |
| deployer1: | |
| network: mainnet | |
| address: 0x0000000000000000000000000000000000000001 | |
| "#; | |
| let yaml2 = r#" | |
| deployers: | |
| deployer2: | |
| network: mainnet | |
| address: 0x0000000000000000000000000000000000000002 | |
| "#; | |
| let result = emit_documents(&[get_document(yaml1), get_document(yaml2)]); | |
| assert!(result.is_ok()); | |
| let output = result.unwrap(); | |
| assert!(output.contains("deployer1:"), "deployer1 should be present"); | |
| assert!(output.contains("deployer2:"), "deployer2 should be present"); | |
| assert!(output.contains("0x0000000000000000000000000000000000000001")); | |
| assert!(output.contains("0x0000000000000000000000000000000000000002")); | |
| } | |
| #[test] | |
| fn test_emit_deep_merges_hash_sections() { | |
| let yaml1 = r#" | |
| networks: | |
| mainnet: | |
| rpcs: | |
| - https://eth.llamarpc.com | |
| chain-id: 1 | |
| deployers: | |
| deployer1: | |
| network: mainnet | |
| address: 0x0000000000000000000000000000000000000001 | |
| "#; | |
| let yaml2 = r#" | |
| deployers: | |
| deployer2: | |
| network: mainnet | |
| address: 0x0000000000000000000000000000000000000002 | |
| "#; | |
| let result = emit_documents(&[get_document(yaml1), get_document(yaml2)]); | |
| assert!(result.is_ok()); | |
| let output = result.unwrap(); | |
| insta::assert_snapshot!(output); | |
| } |
🤖 Prompt for AI Agents
In `@crates/settings/src/yaml/emitter.rs` around lines 558 - 584, Replace the
loose contains-based assertions in test_emit_deep_merges_hash_sections with an
insta snapshot assertion: call emit_documents(&[get_document(yaml1),
get_document(yaml2)]) as before, unwrap the output string, and use
insta::assert_snapshot!(output) (or similar) to capture the entire merged YAML;
if insta isn't already a dev-dependency add it to Cargo.toml dev-deps and create
the expected snapshot file via running tests to record the correct merged
output. Ensure you reference the existing test function
test_emit_deep_merges_hash_sections and the helpers emit_documents and
get_document when making the change.
|
@coderabbitai assess this PR size classification for the totality of the PR with the following criterias and report it in your comment: S/M/L PR Classification Guidelines:This guide helps classify merged pull requests by effort and complexity rather than just line count. The goal is to assess the difficulty and scope of changes after they have been completed. Small (S)Characteristics:
Review Effort: Would have taken 5-10 minutes Examples:
Medium (M)Characteristics:
Review Effort: Would have taken 15-30 minutes Examples:
Large (L)Characteristics:
Review Effort: Would have taken 45+ minutes Examples:
Additional Factors to ConsiderWhen deciding between sizes, also consider:
Notes:
|
|
The author of this PR is on the CodeRabbit Free Plan. In order to use the Chat feature, please upgrade the PR author to CodeRabbit Pro by visiting https://app.coderabbit.ai/login. |
Motivation
When merging multiple YAML documents, entries under the same top-level section were being silently lost. For example, if two documents each defined a different deployer under
deployers:, only the second document's deployer would survive because the shallow merge replaced the entire hash at each top-level key.Solution
Implement recursive deep merging via
deep_merge_hash()function. When both the base and incoming documents have a hash at the same key, the function recursively merges them instead of overwriting. Non-hash values and mixed types still overwrite as before.Key changes:
deep_merge_hash(base, incoming)recursive functionemit_documentswith deep merge calltest_emit_deep_merges_hash_sectionsto verify merge behaviorChecks
By submitting this for review, I'm confirming I've done the following:
Summary by CodeRabbit
New Features
Tests