compare: treat an empty value and an absent key as equal - #72
Merged
Conversation
The importer stopped writing description and homepage_url when the value is empty, so every existing config differs from a fresh import of the same unchanged repository. compare exists to answer whether something changed, and it started answering wrongly for half the fleet. Three features filter through it and all three degraded: import and bulk-import stopped dropping unchanged repositories from their pull requests, and drift-check began reporting repositories that had not drifted. Normalising in compare rather than reverting the importer keeps the cleaner generated output and covers the whole class, so a future serialization change that moves a field between empty and absent stops mattering. The pass is deliberately narrow. Only empty string and null scalars are dropped; false and 0 are meaningful and stay, which the YAML tag distinguishes. Containers left empty are kept, since collapsing them asserts a broader equivalence than this needs.
dev-milos
marked this pull request as ready for review
August 13, 2026 13:17
mladjan-gadzic
previously approved these changes
Aug 13, 2026
The falsey keys in the empty-versus-absent case sat on both sides, so stripping them would have stripped both and the case would still have passed. The new pair has the falsey key on one side only and asserts inequality, which fails if false is ever treated as empty.
mladjan-gadzic
approved these changes
Aug 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes G-Research/gr-oss#1430
The importer stopped writing
descriptionandhomepage_urlwhen the value is empty —nilIfEmpty(), introduced in f6454cb. Every existing config therefore differs from a freshimport of the same unchanged repository, and
compare, whose only job is answeringwhether something changed, started answering wrongly.
Measured against a real config repository during release testing:
homepage_url: ""Three features filter through
compareand all three degraded.importandbulk-importstopped dropping unchanged repositories, which is the exact symptom #51 set out to remove.
drift-checkbegan reporting repositories that had not drifted — awkwardly, since the changearrived in the same pull request that built drift-check on top of
compare.Approach
Normalise in
comparerather than revert the importer.nilIfEmptyproduces cleaner generated config and is worth keeping. More importantly thiscovers the whole class: a future serialization change that moves a field between empty and
absent stops mattering, rather than this one instance being patched.
hashNormalizedYamlFilealready establishes the pattern — it dropsid,branch_policy_idsandtag_policy_idsbefore hashing, then sorts keys. This is one morestep alongside those, reusing the same recursive shape.
Deliberately narrow
falseand0are meaningful values and are kept; the YAML tagdistinguishes them from an empty string.
reviewers: {}it stays.Collapsing empty maps and lists asserts an equivalence this does not need, and
over-normalising would hide real differences.
Only empty is ever collapsed against absent. A config saying
description: "old"against afresh import that omits it still compares as different.
Tests
The existing table had four cases and all of them asserted equality, so an over-aggressive
normaliser would have passed every one silently. Two added:
has_downloads: falsepresent — droppingfalsey values rather than empty ones is the obvious way to get this wrong
Confirmed the first fails without the change and passes with it, so it actually guards the
regression.
Verification
go build,go vet,go test ./pkg/compare/...all pass.Against the real config repository, importing six unchanged repositories:
Then editing two of the fresh files — a description, and
has_issuesfromtruetofalse—returns exactly those two as different. The boolean case matters: it confirms falsey values
survive normalisation.