diff --git a/feature/github-repo-importer/pkg/compare/compare.go b/feature/github-repo-importer/pkg/compare/compare.go index aa97254..92679c2 100644 --- a/feature/github-repo-importer/pkg/compare/compare.go +++ b/feature/github-repo-importer/pkg/compare/compare.go @@ -102,6 +102,7 @@ func hashNormalizedYamlFile(path string) (string, error) { removeKey(root, "id") removeKey(root, "branch_policy_ids") removeKey(root, "tag_policy_ids") + removeEmptyValues(root) sortMappingNode(root) } @@ -136,6 +137,34 @@ func removeKey(node *yaml.Node, target string) { } } +func removeEmptyValues(node *yaml.Node) { + switch node.Kind { + case yaml.MappingNode: + newContent := make([]*yaml.Node, 0, len(node.Content)) + for i := 0; i < len(node.Content); i += 2 { + k := node.Content[i] + v := node.Content[i+1] + if isEmptyScalar(v) { + continue + } + removeEmptyValues(v) + newContent = append(newContent, k, v) + } + node.Content = newContent + case yaml.SequenceNode: + for _, elem := range node.Content { + removeEmptyValues(elem) + } + } +} + +func isEmptyScalar(node *yaml.Node) bool { + if node.Kind != yaml.ScalarNode { + return false + } + return node.Tag == "!!null" || (node.Tag == "!!str" && node.Value == "") +} + func sortMappingNode(node *yaml.Node) { if node.Kind != yaml.MappingNode { return diff --git a/feature/github-repo-importer/pkg/compare/compare_test.go b/feature/github-repo-importer/pkg/compare/compare_test.go index 077c922..af2bc48 100644 --- a/feature/github-repo-importer/pkg/compare/compare_test.go +++ b/feature/github-repo-importer/pkg/compare/compare_test.go @@ -37,6 +37,24 @@ func TestHashingYamlFiles(t *testing.T) { pathOfFresh: "testdata/existing/existing4.yaml", wantEqual: true, }, + { + name: "empty and null values are equivalent to the key being absent", + pathOfImported: "testdata/imported/imported5.yaml", + pathOfFresh: "testdata/existing/existing5.yaml", + wantEqual: true, + }, + { + name: "a real difference is still detected alongside an empty value", + pathOfImported: "testdata/imported/imported6.yaml", + pathOfFresh: "testdata/existing/existing6.yaml", + wantEqual: false, + }, + { + name: "a false value on one side only is a difference, not an empty value", + pathOfImported: "testdata/imported/imported7.yaml", + pathOfFresh: "testdata/existing/existing7.yaml", + wantEqual: false, + }, } for _, tt := range tests { diff --git a/feature/github-repo-importer/pkg/compare/testdata/existing/existing5.yaml b/feature/github-repo-importer/pkg/compare/testdata/existing/existing5.yaml new file mode 100644 index 0000000..044bdfc --- /dev/null +++ b/feature/github-repo-importer/pkg/compare/testdata/existing/existing5.yaml @@ -0,0 +1,21 @@ +description: "" +homepage_url: "" +visibility: public +default_branch: main +has_issues: true +has_downloads: false +allow_auto_merge: false +archived: false +license_template: +rulesets: + - enforcement: active + name: test + rules: + deletion: true + non_fast_forward: true + target: branch + conditions: + ref_name: + include: + - ~DEFAULT_BRANCH +vulnerability_alerts_enabled: true diff --git a/feature/github-repo-importer/pkg/compare/testdata/existing/existing6.yaml b/feature/github-repo-importer/pkg/compare/testdata/existing/existing6.yaml new file mode 100644 index 0000000..457bc6c --- /dev/null +++ b/feature/github-repo-importer/pkg/compare/testdata/existing/existing6.yaml @@ -0,0 +1,8 @@ +description: Managed by Terraform +homepage_url: "" +visibility: public +default_branch: main +has_issues: true +has_downloads: false +archived: false +vulnerability_alerts_enabled: true diff --git a/feature/github-repo-importer/pkg/compare/testdata/existing/existing7.yaml b/feature/github-repo-importer/pkg/compare/testdata/existing/existing7.yaml new file mode 100644 index 0000000..4be3d6d --- /dev/null +++ b/feature/github-repo-importer/pkg/compare/testdata/existing/existing7.yaml @@ -0,0 +1,6 @@ +visibility: public +default_branch: main +has_issues: true +has_downloads: false +archived: false +vulnerability_alerts_enabled: true diff --git a/feature/github-repo-importer/pkg/compare/testdata/imported/imported5.yaml b/feature/github-repo-importer/pkg/compare/testdata/imported/imported5.yaml new file mode 100644 index 0000000..7192bad --- /dev/null +++ b/feature/github-repo-importer/pkg/compare/testdata/imported/imported5.yaml @@ -0,0 +1,18 @@ +visibility: public +default_branch: main +has_issues: true +has_downloads: false +allow_auto_merge: false +archived: false +rulesets: + - enforcement: active + name: test + rules: + deletion: true + non_fast_forward: true + target: branch + conditions: + ref_name: + include: + - ~DEFAULT_BRANCH +vulnerability_alerts_enabled: true diff --git a/feature/github-repo-importer/pkg/compare/testdata/imported/imported6.yaml b/feature/github-repo-importer/pkg/compare/testdata/imported/imported6.yaml new file mode 100644 index 0000000..05186fb --- /dev/null +++ b/feature/github-repo-importer/pkg/compare/testdata/imported/imported6.yaml @@ -0,0 +1,7 @@ +description: Edited by hand outside the tool +visibility: public +default_branch: main +has_issues: true +has_downloads: false +archived: false +vulnerability_alerts_enabled: true diff --git a/feature/github-repo-importer/pkg/compare/testdata/imported/imported7.yaml b/feature/github-repo-importer/pkg/compare/testdata/imported/imported7.yaml new file mode 100644 index 0000000..d66001b --- /dev/null +++ b/feature/github-repo-importer/pkg/compare/testdata/imported/imported7.yaml @@ -0,0 +1,5 @@ +visibility: public +default_branch: main +has_issues: true +archived: false +vulnerability_alerts_enabled: true