Fixes#334 and a sibling bug of the same class (a JSON field silently ignored by Gitea's API). Two commits, each independently verified against a live Gitea 1.24.7 and end-to-end against real GitHub data.
Root cause: the release create/update payloads sent the JSON field title:, but Gitea/Forgejo's release API exposes the title through name (Go struct Title string \json:"name"`). The unknown title` key is silently dropped, so every mirrored release got a blank title.
Fix:title: → name: in both release payloads (create POST + update PATCH). Self-healing: the update-detection already compares existingRelease.name, so previously-blank releases get corrected on the next sync.
Verified: raw API (POST with title → name:""; with name → correct); end-to-end on the exact issue repo chenasraf/pantry-flutter (blank v0.19.0 healed + v0.18.0–v0.15.0 created, all titled); regression test gitea-release-name.test.ts.
2. Labels not updated on issue/PR re-sync (sibling)
Root cause: the same silent-ignore class. Gitea's EditIssueOption has no labels field (only CreateIssueOption does), so a labels key in a PATCH .../issues/{index} body is dropped. The issue and PR-as-issue update paths sent labels in the PATCH, so label changes never propagated onto already-mirrored issues, and a deadlock-orphaned issue recovered via PATCH never got its labels.
Fix: new reconcileGiteaIssueLabels helper that replaces the set via PUT .../issues/{index}/labels (idempotent — adds new, removes deleted). Called on the two issue and two PR update paths; the dead labels key is removed from those PATCH bodies. Labels on freshly created issues still come from CreateIssueOption on the POST.
Verified: raw API (PATCH leaves labels unchanged; PUT replaces them); end-to-end (a mirrored issue drifted to no-labels reconciled back to its GitHub label set); regression test gitea-issue-labels.test.ts driving the real mirrorGitRepoIssuesToGitea update path.
Issue/milestone title fields are untouched (that is their correct Gitea API field). Full suite: 360 pass, 0 fail.
🔄 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/335
**Author:** [@arunavo4](https://github.com/arunavo4)
**Created:** 7/1/2026
**Status:** ✅ Merged
**Merged:** 7/1/2026
**Merged by:** [@arunavo4](https://github.com/arunavo4)
**Base:** `main` ← **Head:** `fix/release-title-not-mirrored-334`
---
### 📝 Commits (3)
- [`05d215d`](https://github.com/RayLabsHQ/gitea-mirror/commit/05d215d2142de690f5e0ccaaee56c8413bd58394) fix(releases): send Gitea release title as `name`, not `title` (#334)
- [`d124886`](https://github.com/RayLabsHQ/gitea-mirror/commit/d12488615eb983aa9257bf91cc79e80c3a5b3562) fix(issues): reconcile labels on issue/PR update via the labels sub-resource (#334 sibling)
- [`f4f2789`](https://github.com/RayLabsHQ/gitea-mirror/commit/f4f2789827ee40c543cd7886a49c0899548f4d86) test: make #334 regression tests deterministic via pure payload builders
### 📊 Changes
**3 files changed** (+251 additions, -35 deletions)
<details>
<summary>View changed files</summary>
➕ `src/lib/gitea-issue-labels.test.ts` (+52 -0)
➕ `src/lib/gitea-release-name.test.ts` (+51 -0)
📝 `src/lib/gitea.ts` (+148 -35)
</details>
### 📄 Description
Fixes #334 and a sibling bug of the same class (a JSON field silently ignored by Gitea's API). Two commits, each independently verified against a live Gitea 1.24.7 and end-to-end against real GitHub data.
---
## 1. Release titles blank in Gitea (#334)
**Root cause:** the release create/update payloads sent the JSON field `title:`, but Gitea/Forgejo's release API exposes the title through **`name`** (Go struct `Title string \`json:"name"\``). The unknown `title` key is silently dropped, so every mirrored release got a blank title.
**Fix:** `title:` → `name:` in both release payloads (create `POST` + update `PATCH`). Self-healing: the update-detection already compares `existingRelease.name`, so previously-blank releases get corrected on the next sync.
**Verified:** raw API (POST with `title` → `name:""`; with `name` → correct); end-to-end on the exact issue repo `chenasraf/pantry-flutter` (blank `v0.19.0` healed + `v0.18.0`–`v0.15.0` created, all titled); regression test `gitea-release-name.test.ts`.
## 2. Labels not updated on issue/PR re-sync (sibling)
**Root cause:** the same silent-ignore class. Gitea's `EditIssueOption` has **no `labels` field** (only `CreateIssueOption` does), so a `labels` key in a `PATCH .../issues/{index}` body is dropped. The issue and PR-as-issue **update** paths sent `labels` in the PATCH, so label changes never propagated onto already-mirrored issues, and a deadlock-orphaned issue recovered via PATCH never got its labels.
**Fix:** new `reconcileGiteaIssueLabels` helper that replaces the set via `PUT .../issues/{index}/labels` (idempotent — adds new, removes deleted). Called on the two issue and two PR update paths; the dead `labels` key is removed from those PATCH bodies. Labels on freshly created issues still come from `CreateIssueOption` on the POST.
**Verified:** raw API (PATCH leaves labels unchanged; PUT replaces them); end-to-end (a mirrored issue drifted to no-labels reconciled back to its GitHub label set); regression test `gitea-issue-labels.test.ts` driving the real `mirrorGitRepoIssuesToGitea` update path.
---
Issue/milestone `title` fields are untouched (that *is* their correct Gitea API field). Full suite: **360 pass, 0 fail.**
---
<sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
📋 Pull Request Information
Original PR: https://github.com/RayLabsHQ/gitea-mirror/pull/335
Author: @arunavo4
Created: 7/1/2026
Status: ✅ Merged
Merged: 7/1/2026
Merged by: @arunavo4
Base:
main← Head:fix/release-title-not-mirrored-334📝 Commits (3)
05d215dfix(releases): send Gitea release title asname, nottitle(#334)d124886fix(issues): reconcile labels on issue/PR update via the labels sub-resource (#334 sibling)f4f2789test: make #334 regression tests deterministic via pure payload builders📊 Changes
3 files changed (+251 additions, -35 deletions)
View changed files
➕
src/lib/gitea-issue-labels.test.ts(+52 -0)➕
src/lib/gitea-release-name.test.ts(+51 -0)📝
src/lib/gitea.ts(+148 -35)📄 Description
Fixes #334 and a sibling bug of the same class (a JSON field silently ignored by Gitea's API). Two commits, each independently verified against a live Gitea 1.24.7 and end-to-end against real GitHub data.
1. Release titles blank in Gitea (#334)
Root cause: the release create/update payloads sent the JSON field
title:, but Gitea/Forgejo's release API exposes the title throughname(Go structTitle string \json:"name"`). The unknowntitle` key is silently dropped, so every mirrored release got a blank title.Fix:
title:→name:in both release payloads (createPOST+ updatePATCH). Self-healing: the update-detection already comparesexistingRelease.name, so previously-blank releases get corrected on the next sync.Verified: raw API (POST with
title→name:""; withname→ correct); end-to-end on the exact issue repochenasraf/pantry-flutter(blankv0.19.0healed +v0.18.0–v0.15.0created, all titled); regression testgitea-release-name.test.ts.2. Labels not updated on issue/PR re-sync (sibling)
Root cause: the same silent-ignore class. Gitea's
EditIssueOptionhas nolabelsfield (onlyCreateIssueOptiondoes), so alabelskey in aPATCH .../issues/{index}body is dropped. The issue and PR-as-issue update paths sentlabelsin the PATCH, so label changes never propagated onto already-mirrored issues, and a deadlock-orphaned issue recovered via PATCH never got its labels.Fix: new
reconcileGiteaIssueLabelshelper that replaces the set viaPUT .../issues/{index}/labels(idempotent — adds new, removes deleted). Called on the two issue and two PR update paths; the deadlabelskey is removed from those PATCH bodies. Labels on freshly created issues still come fromCreateIssueOptionon the POST.Verified: raw API (PATCH leaves labels unchanged; PUT replaces them); end-to-end (a mirrored issue drifted to no-labels reconciled back to its GitHub label set); regression test
gitea-issue-labels.test.tsdriving the realmirrorGitRepoIssuesToGiteaupdate path.Issue/milestone
titlefields are untouched (that is their correct Gitea API field). Full suite: 360 pass, 0 fail.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.