From aacfead17e694c5503d111e9501063bcf0b49dff Mon Sep 17 00:00:00 2001 From: kuba-mazurkiewicz Date: Mon, 2 Dec 2024 14:51:39 +0100 Subject: [PATCH 1/4] Fix duplicate detection issue: merge_list_item produced incorrect data by failing to retain duplicate elements after merging --- iac_validate/yaml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iac_validate/yaml.py b/iac_validate/yaml.py index 3e3c2cc..1c9bbb6 100644 --- a/iac_validate/yaml.py +++ b/iac_validate/yaml.py @@ -145,7 +145,7 @@ def merge_dict( merge_dict(value, node, merge_list_items) elif isinstance(value, list): if key not in destination: - destination[key] = [] + destination[key] = value[:] if isinstance(destination[key], list): for i in value: merge_list_item(i, destination[key], merge_list_items) From aee12273316fa1a773e6bdf1ed10c7a10bc886f4 Mon Sep 17 00:00:00 2001 From: kuba-mazurkiewicz Date: Mon, 2 Dec 2024 15:51:39 +0100 Subject: [PATCH 2/4] Update the logic to check whether an item is already present in destination[key] before running merge_list_item --- iac_validate/yaml.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iac_validate/yaml.py b/iac_validate/yaml.py index 1c9bbb6..82553de 100644 --- a/iac_validate/yaml.py +++ b/iac_validate/yaml.py @@ -148,7 +148,8 @@ def merge_dict( destination[key] = value[:] if isinstance(destination[key], list): for i in value: - merge_list_item(i, destination[key], merge_list_items) + if i not in destination[key]: + merge_list_item(i, destination[key], merge_list_items) else: destination[key] = value return destination From 9f411b9ba4d3348e5b1c6a0516488dd8b3bc5fd7 Mon Sep 17 00:00:00 2001 From: kuba-mazurkiewicz Date: Tue, 3 Dec 2024 09:58:13 +0100 Subject: [PATCH 3/4] add unit test to make sure merge_dict will not remove duplicate entries --- tests/unit/test_yaml.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/unit/test_yaml.py b/tests/unit/test_yaml.py index 2df034f..cd6a86f 100644 --- a/tests/unit/test_yaml.py +++ b/tests/unit/test_yaml.py @@ -32,6 +32,11 @@ def test_merge_dict(): destination = {} yaml.merge_dict(source, destination) assert destination == source + # make sure that merge_dict will not remove duplicate entries + source = {"root": {"duplicates": [{"name": "abc"}, {"name": "abc"}]}} + destination = {} + yaml.merge_dict(source, destination) + assert destination == source def test_merge_list_item(): From a45aa48729270153cc158db71888ebe9c708e4c0 Mon Sep 17 00:00:00 2001 From: kuba-mazurkiewicz Date: Tue, 3 Dec 2024 20:53:00 +0100 Subject: [PATCH 4/4] merge matching dict list items with extra dst and src primitive attribute --- iac_validate/yaml.py | 6 +----- tests/unit/test_yaml.py | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/iac_validate/yaml.py b/iac_validate/yaml.py index 82553de..6d73355 100644 --- a/iac_validate/yaml.py +++ b/iac_validate/yaml.py @@ -97,8 +97,6 @@ def merge_list_item( for dest_item in destination: match = True comparison = False - unique_source = False - unique_dest = False for k, v in source_item.items(): if isinstance(v, dict) or isinstance(v, list): continue @@ -106,7 +104,6 @@ def merge_list_item( comparison = True continue if k not in dest_item: - unique_source = True continue comparison = True match = False @@ -117,11 +114,10 @@ def merge_list_item( comparison = True continue if k not in source_item: - unique_dest = True continue comparison = True match = False - if comparison and match and not (unique_source and unique_dest): + if comparison and match: merge_dict(source_item, dest_item, merge_list_items) return elif source_item in destination: diff --git a/tests/unit/test_yaml.py b/tests/unit/test_yaml.py index cd6a86f..2444c05 100644 --- a/tests/unit/test_yaml.py +++ b/tests/unit/test_yaml.py @@ -110,9 +110,9 @@ def test_merge_list_item(): ] yaml.merge_list_item(source_item, destination) assert destination == result - # not merge matching dict list items with extra dst and src primitive attribute + # merge matching dict list items with extra dst and src primitive attribute destination = [{"name": "abc", "name2": "def"}] source_item = {"name": "abc", "name3": "ghi"} - result = [{"name": "abc", "name2": "def"}, {"name": "abc", "name3": "ghi"}] + result = [{"name": "abc", "name2": "def", "name3": "ghi"}] yaml.merge_list_item(source_item, destination) assert destination == result