mirror of
https://github.com/RayLabsHQ/gitea-mirror.git
synced 2026-10-26 00:01:25 +00:00
Starred (and other) repos duplicated on every re-mirror (starred/Repo,
Repo-owner, Repo-owner-1, ...) because the existence check only asked
"does a repo with this name exist?" and never "is the existing repo a
mirror of THIS same source?". The repo's own prior mirror counted as a
collision, so generateUniqueRepoName bumped to the next suffix each run,
repointing mirroredLocation at the newest copy. Under a single re-call,
3 concurrent/retried jobs each computed a DIFFERENT suffixed name, so the
location-based in-flight guard never matched and the race produced extra
copies.
Fix (source-identity aware):
- New shared helper src/lib/utils/mirror-source-match.ts:
- normalizeCloneUrl / cloneUrlsMatch: credential-, .git-, slash- and
host-case-insensitive clone URL comparison.
- isMirrorOfSource: a Gitea repo is "ours" only if it is a mirror AND
its original_url matches this repo's source.
- findExistingMirror: resolves an existing same-source mirror via the
recorded mirroredLocation first (survives strategy changes — #309),
then the base candidate name.
- classifyCandidateName: pure available/reusable/taken decision.
- gitea-enhanced: export GiteaRepoInfo and add original_url (Gitea's
recorded migration source) for source matching.
- Both create paths (mirrorGithubRepoToGitea, mirrorGitHubRepoToGiteaOrg):
run findExistingMirror BEFORE name generation; on a hit, reuse that
location and route into the existing "already mirrored" handling rather
than calling generateUniqueRepoName. Names now converge under
concurrency so the in-flight guard becomes effective.
- generateUniqueRepoName is now source-aware: an occupied name held by a
mirror of the SAME source is reused (no suffix); suffixing only happens
on a genuine different-source collision, preserving #95/#236 behavior.
The per-user DB claim check is retained so two users mirroring the same
source into a shared org stay separated.
- Phantom-fork guard (#309): the existingRepoInfo.mirror branches now
verify same-source before marking "mirrored"; on mismatch they fall
through to unique-name generation and create a separate mirror.
- Scheduler: a `failed` repo whose mirroredLocation still resolves to a
live same-source mirror is routed to syncGiteaRepo instead of re-create,
breaking the failed-metadata re-create loop cheaply.
- Remove dead src/lib/starred-repos-handler.ts (zero importers across all
git history); its correct base-name/.mirror reuse logic now lives in the
shared helper.
Tests: src/lib/utils/mirror-source-match.test.ts (30 cases) covers URL
normalization, reuse at base name, reuse via mirroredLocation across a
strategy change, genuine different-source collision (suffix), phantom
fork, stale mirroredLocation fallback, per-user DB-claim separation, and
the suffix-vs-reuse classification. Full suite: 319 pass, 0 fail.