-
Notifications
You must be signed in to change notification settings - Fork 731
fix: merge case-duplicate github repos and enforce unique lower(url) [CM-1344] #4383
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+138
−0
Merged
Changes from 1 commit
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
c918213
fix: merge case-duplicate github repos and enforce lowercase url uniq…
mbani01 8184f3c
fix: code review
mbani01 e3ab972
fix: code review
mbani01 eff5795
fix: code review
mbani01 ac4dc81
Merge branch 'main' into fix/duplicated_repos
mbani01 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
92 changes: 92 additions & 0 deletions
92
backend/src/osspckgs/migrations/V1784718693__merge_case_duplicate_github_repos.sql
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| -- GitHub paths are case-insensitive, but repos.url is UNIQUE case-sensitively. | ||
| -- Writers that predate URL lowercasing (cargo initial sync on 2026-06-19, maven | ||
| -- enrichment before CM-1305) inserted mixed-case variants of rows that already | ||
| -- existed lowercase: ~40k duplicate groups, ~10k of them serving duplicate | ||
| -- security contacts from both variants. The CM-1305 backfills re-pointed | ||
| -- package links to the lowercase rows but left the stale variants behind. | ||
| -- | ||
| -- Keeper per group: the all-lowercase row when present (links were already | ||
| -- re-pointed to it), else the lowest id. Only package_repos is primary data | ||
| -- and gets re-pointed (repo_docker comes along since it is a free UPDATE); | ||
| -- contacts, snapshots, and scorecard rows on losers are derived and re-fill | ||
| -- via the regular sweeps, so they are dropped with the loser rows. | ||
|
|
||
| CREATE TEMP TABLE repo_merge_members AS | ||
| SELECT id AS repo_id, keeper_id, id = keeper_id AS is_keeper | ||
| FROM ( | ||
| SELECT | ||
| id, | ||
| FIRST_VALUE(id) OVER ( | ||
| PARTITION BY LOWER(url) | ||
| ORDER BY (url = LOWER(url)) DESC, id | ||
| ) AS keeper_id, | ||
| COUNT(*) OVER (PARTITION BY LOWER(url)) AS group_size | ||
| FROM repos | ||
| WHERE host = 'github' | ||
| ) grouped | ||
| WHERE group_size > 1; | ||
|
mbani01 marked this conversation as resolved.
|
||
|
|
||
| CREATE INDEX ON repo_merge_members (repo_id); | ||
| ANALYZE repo_merge_members; | ||
|
|
||
| -- Keep one link per (package, group): the keeper's if it exists, else the most | ||
| -- recently verified. ROW_NUMBER instead of an EXISTS check against the keeper | ||
| -- because 3-variant groups exist: two losers linking the same package would | ||
| -- collide on UNIQUE (package_id, repo_id) after the re-point below. | ||
| DELETE FROM package_repos | ||
| WHERE id IN ( | ||
| SELECT id | ||
| FROM ( | ||
| SELECT pr.id, | ||
| ROW_NUMBER() OVER ( | ||
| PARTITION BY m.keeper_id, pr.package_id | ||
| ORDER BY m.is_keeper DESC, pr.verified_at DESC, pr.id | ||
|
mbani01 marked this conversation as resolved.
Outdated
|
||
| ) AS rn | ||
| FROM package_repos pr | ||
| JOIN repo_merge_members m ON m.repo_id = pr.repo_id | ||
| ) ranked | ||
| WHERE rn > 1 | ||
| ); | ||
|
|
||
| UPDATE package_repos pr | ||
| SET repo_id = m.keeper_id | ||
| FROM repo_merge_members m | ||
| WHERE pr.repo_id = m.repo_id | ||
| AND NOT m.is_keeper; | ||
|
mbani01 marked this conversation as resolved.
Outdated
|
||
|
|
||
| UPDATE repo_docker d | ||
| SET repo_id = m.keeper_id | ||
| FROM repo_merge_members m | ||
| WHERE d.repo_id = m.repo_id | ||
| AND NOT m.is_keeper; | ||
|
|
||
| DELETE FROM repo_scorecard_checks c | ||
| USING repo_merge_members m | ||
| WHERE c.repo_id = m.repo_id | ||
| AND NOT m.is_keeper; | ||
|
|
||
| -- Cascades security_contacts and repo_activity_snapshot on losers. | ||
| DELETE FROM repos r | ||
| USING repo_merge_members m | ||
| WHERE r.id = m.repo_id | ||
| AND NOT m.is_keeper; | ||
|
|
||
| -- Groups that had no lowercase variant: lowercase the surviving row. Safe | ||
| -- against UNIQUE (url) — every row sharing LOWER(url) was in the same group, | ||
| -- and its losers are gone by now. | ||
| UPDATE repos r | ||
| SET url = LOWER(r.url), updated_at = NOW() | ||
| FROM repo_merge_members m | ||
| WHERE r.id = m.repo_id | ||
| AND m.is_keeper | ||
| AND r.url <> LOWER(r.url); | ||
|
mbani01 marked this conversation as resolved.
Outdated
Comment on lines
+109
to
+112
|
||
|
|
||
| -- Recurrence guard; also fails the migration if any duplicate survived the | ||
| -- merge. GitHub-only: it is the only host with both confirmed duplicates and | ||
| -- guaranteed lowercase-on-write today (CASE_INSENSITIVE_HOSTS in | ||
| -- canonicalizeRepoUrl also covers gitlab.com, whose merge is a follow-up). | ||
| -- On other hosts case can be significant and writers do not normalize, so a | ||
| -- wider index could reject legitimately distinct repos. | ||
| CREATE UNIQUE INDEX IF NOT EXISTS repos_github_lower_url_uq | ||
| ON repos (LOWER(url)) | ||
| WHERE host = 'github'; | ||
|
mbani01 marked this conversation as resolved.
Outdated
|
||
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.