[PR #332] [MERGED] fix(releases): mirror assets idempotently so missing assets self-heal (#331) #6298

Closed
opened 2026-07-12 09:52:25 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/RayLabsHQ/gitea-mirror/pull/332
Author: @arunavo4
Created: 6/23/2026
Status: Merged
Merged: 6/23/2026
Merged by: @arunavo4

Base: mainHead: fix/release-asset-reconciliation-331


📝 Commits (1)

  • 48a701b fix(releases): mirror assets idempotently so missing assets self-heal (#331)

📊 Changes

2 files changed (+289 additions, -48 deletions)

View changed files

📝 src/lib/gitea-releases.test.ts (+83 -1)
📝 src/lib/gitea.ts (+206 -47)

📄 Description

Fixes #331

The bug

Release assets were uploaded in only one place — the create branch of mirrorGitHubReleasesToGitea() (src/lib/gitea.ts). When a Gitea release already exists, the code takes the update branch, PATCHes the changelog/title, and continues without ever touching assets. There was no idempotent reconciliation.

So any release whose assets weren't fully uploaded on that single create-path run — first sync interrupted, container restart, a transient download/upload failure, large multi-MB assets — stays permanently asset-less, and re-syncing always hits the update branch and can never recover it. Asset failures were also swallowed to console.error + continue, so the job still reported success ("no errors in the logs", per the issue).

Reproduced on a real Forgejo pull-mirror

Using shauninman/MinUI against Forgejo 11 (native mirror: true repo, as gitea-mirror creates):

  • Clean first sync of the real function works — both releases created, all 4 assets (~74 MB each) uploaded.
  • Deleting the assets off v20251127-1 (= interrupted first upload) and re-running the real function logs Updating existing release v20251127-1 and leaves it at 0 assets — exactly the reported symptom (Forgejo's 4.6 MB auto-generated source archive only).

Also ruled out every infra cause: Forgejo accepts release creation + 35 MB+ uploads on mirror repos; its native mirror creates 43 tags but 0 releases; Bun's fetch downloads the GitHub asset fine.

The fix

  • reconcileReleaseAssets() — idempotent reconciler run on both the create and update paths. Compares Gitea's existing attachments to GitHub's by name + size: skips matches, uploads missing ones, replaces size-mismatched copies. Existing broken releases self-heal on the next sync.
  • classifyAssetsForReconciliation() — pure decision function extracted for unit testing (the lack of asset tests is why this slipped past #310).
  • Surfaced failures — asset upload counts in the summary log + a visible ⚠️ warning when any fail, instead of silent swallowing.
  • 5 new unit tests covering the broken state, partial backfill, idempotency, size-mismatch replacement, and the no-assets case.

Verification

  • bun test src/lib/gitea-releases.test.ts15/15 pass.
  • End-to-end against the real mirrorGitHubReleasesToGitea on a Forgejo pull-mirror: v20251127-1 went 0 → 2 assets (Backfilled 2 missing/changed asset(s)), already-present assets skipped (no re-download), second run uploads 0 (fully idempotent).

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/RayLabsHQ/gitea-mirror/pull/332 **Author:** [@arunavo4](https://github.com/arunavo4) **Created:** 6/23/2026 **Status:** ✅ Merged **Merged:** 6/23/2026 **Merged by:** [@arunavo4](https://github.com/arunavo4) **Base:** `main` ← **Head:** `fix/release-asset-reconciliation-331` --- ### 📝 Commits (1) - [`48a701b`](https://github.com/RayLabsHQ/gitea-mirror/commit/48a701b72868b9e1a528467a4a91e5d159652ef4) fix(releases): mirror assets idempotently so missing assets self-heal (#331) ### 📊 Changes **2 files changed** (+289 additions, -48 deletions) <details> <summary>View changed files</summary> 📝 `src/lib/gitea-releases.test.ts` (+83 -1) 📝 `src/lib/gitea.ts` (+206 -47) </details> ### 📄 Description Fixes #331 ## The bug Release assets were uploaded in **only one place** — the *create* branch of `mirrorGitHubReleasesToGitea()` (`src/lib/gitea.ts`). When a Gitea release already exists, the code takes the *update* branch, PATCHes the changelog/title, and `continue`s **without ever touching assets**. There was no idempotent reconciliation. So any release whose assets weren't fully uploaded on that single create-path run — first sync interrupted, container restart, a transient download/upload failure, large multi-MB assets — stays **permanently asset-less**, and re-syncing always hits the update branch and can never recover it. Asset failures were also swallowed to `console.error` + `continue`, so the job still reported success ("no errors in the logs", per the issue). ## Reproduced on a real Forgejo pull-mirror Using `shauninman/MinUI` against Forgejo 11 (native `mirror: true` repo, as gitea-mirror creates): - Clean first sync of the **real** function works — both releases created, all 4 assets (~74 MB each) uploaded. - Deleting the assets off `v20251127-1` (= interrupted first upload) and re-running the real function logs `Updating existing release v20251127-1` and leaves it at **0 assets** — exactly the reported symptom (Forgejo's 4.6 MB auto-generated source archive only). Also ruled out every infra cause: Forgejo accepts release creation + 35 MB+ uploads on mirror repos; its native mirror creates **43 tags but 0 releases**; Bun's `fetch` downloads the GitHub asset fine. ## The fix - **`reconcileReleaseAssets()`** — idempotent reconciler run on **both** the create and update paths. Compares Gitea's existing attachments to GitHub's by **name + size**: skips matches, uploads missing ones, replaces size-mismatched copies. Existing broken releases **self-heal on the next sync**. - **`classifyAssetsForReconciliation()`** — pure decision function extracted for unit testing (the lack of asset tests is why this slipped past #310). - **Surfaced failures** — asset upload counts in the summary log + a visible `⚠️` warning when any fail, instead of silent swallowing. - **5 new unit tests** covering the broken state, partial backfill, idempotency, size-mismatch replacement, and the no-assets case. ## Verification - `bun test src/lib/gitea-releases.test.ts` → **15/15 pass**. - End-to-end against the **real `mirrorGitHubReleasesToGitea`** on a Forgejo pull-mirror: `v20251127-1` went **0 → 2 assets** (`Backfilled 2 missing/changed asset(s)`), already-present assets skipped (no re-download), second run uploads 0 (fully idempotent). --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-07-12 09:52:25 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/gitea-mirror#6298