diff --git a/CHANGELOG.md b/CHANGELOG.md index 8583ea7..c19c379 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.2.5] - 2025-08-09 + +### Fixed +- Fixed critical authentication issue in releases mirroring that was still using encrypted tokens +- Added missing repository existence check for releases mirroring function +- Fixed "user does not exist [uid: 0]" error specifically affecting GitHub releases synchronization + +### Improved +- Enhanced releases mirroring with duplicate detection to avoid errors on re-runs +- Better error handling and logging for release operations with [Releases] prefix +- Added individual release error handling to continue mirroring even if some releases fail + +### Notes +This patch completes the authentication fixes started in v3.2.4, specifically addressing the releases mirroring function that was accidentally missed in the previous update. + ## [3.2.4] - 2025-08-09 ### Fixed diff --git a/package.json b/package.json index 0ce12f1..f67722b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "gitea-mirror", "type": "module", - "version": "3.2.4", + "version": "3.2.5", "engines": { "bun": ">=1.2.9" }, diff --git a/src/lib/gitea.ts b/src/lib/gitea.ts index fe39c9b..e1ccc8a 100644 --- a/src/lib/gitea.ts +++ b/src/lib/gitea.ts @@ -1298,36 +1298,80 @@ export async function mirrorGitHubReleasesToGitea({ throw new Error("Gitea config is incomplete for mirroring releases."); } + // Decrypt config tokens for API usage + const decryptedConfig = decryptConfigTokens(config as Config); + const repoOwner = await getGiteaRepoOwnerAsync({ config, repository, }); - const { url, token } = config.giteaConfig; + // Verify the repository exists in Gitea before attempting to mirror releases + console.log(`[Releases] Verifying repository ${repository.name} exists at ${repoOwner}`); + const repoExists = await isRepoPresentInGitea({ + config, + owner: repoOwner, + repoName: repository.name, + }); + + if (!repoExists) { + console.error(`[Releases] Repository ${repository.name} not found at ${repoOwner}. Cannot mirror releases.`); + throw new Error(`Repository ${repository.name} does not exist in Gitea at ${repoOwner}. Please ensure the repository is mirrored first.`); + } const releases = await octokit.rest.repos.listReleases({ owner: repository.owner, repo: repository.name, }); - for (const release of releases.data) { - await httpPost( - `${url}/api/v1/repos/${repoOwner}/${repository.name}/releases`, - { - tag_name: release.tag_name, - target: release.target_commitish, - title: release.name || release.tag_name, - note: release.body || "", - draft: release.draft, - prerelease: release.prerelease, - }, - { - Authorization: `token ${token}`, - } - ); + console.log(`[Releases] Found ${releases.data.length} releases to mirror for ${repository.fullName}`); + + if (releases.data.length === 0) { + console.log(`[Releases] No releases to mirror for ${repository.fullName}`); + return; } - console.log(`✅ Mirrored ${releases.data.length} GitHub releases to Gitea`); + let mirroredCount = 0; + let skippedCount = 0; + + for (const release of releases.data) { + try { + // Check if release already exists + const existingReleasesResponse = await httpGet( + `${config.giteaConfig.url}/api/v1/repos/${repoOwner}/${repository.name}/releases/tags/${release.tag_name}`, + { + Authorization: `token ${decryptedConfig.giteaConfig.token}`, + } + ).catch(() => null); + + if (existingReleasesResponse) { + console.log(`[Releases] Release ${release.tag_name} already exists, skipping`); + skippedCount++; + continue; + } + + await httpPost( + `${config.giteaConfig.url}/api/v1/repos/${repoOwner}/${repository.name}/releases`, + { + tag_name: release.tag_name, + target: release.target_commitish, + title: release.name || release.tag_name, + note: release.body || "", + draft: release.draft, + prerelease: release.prerelease, + }, + { + Authorization: `token ${decryptedConfig.giteaConfig.token}`, + } + ); + mirroredCount++; + console.log(`[Releases] Successfully mirrored release: ${release.tag_name}`); + } catch (error) { + console.error(`[Releases] Failed to mirror release ${release.tag_name}: ${error instanceof Error ? error.message : String(error)}`); + } + } + + console.log(`✅ Mirrored ${mirroredCount} new releases to Gitea (${skippedCount} already existed)`); } export async function mirrorGitRepoPullRequestsToGitea({