From e437cf2e3db6cbb65c09938ff997568852bc620a Mon Sep 17 00:00:00 2001 From: Myasnikov Daniil Date: Thu, 28 May 2026 12:00:54 +0500 Subject: [PATCH] ci(release): repair orphaned draft tag_name on retag When the git tag was deleted and re-created between draft creation and merge, GitHub orphaned the draft release: tag_name became "untagged-" while `name` was preserved. The finalize step looked up the draft by tag_name and threw `Draft release for not found`, blocking the release. Fall back to matching by `name` only when the candidate is the GitHub-orphaned form (tag_name matches /^untagged-/), repair the draft's tag_name via updateRelease, then publish. Hard-fail is preserved when neither lookup matches. Same failure recurred on the v1.4.1 finalize run; this commit prevents recurrence but does not auto-recover the stuck v1.4.2 draft. Assisted-By: Claude Signed-off-by: Myasnikov Daniil (cherry picked from commit 22187e069dab4ff6dd441c870fba8a7e893790b6) --- .github/workflows/pull-requests-release.yaml | 27 +++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pull-requests-release.yaml b/.github/workflows/pull-requests-release.yaml index 8bf52a3f5..1d284227e 100644 --- a/.github/workflows/pull-requests-release.yaml +++ b/.github/workflows/pull-requests-release.yaml @@ -159,9 +159,30 @@ jobs: per_page: 100 }); - // Find draft release to publish - const draft = releases.data.find(r => r.tag_name === tag && r.draft); - if (!draft) throw new Error(`Draft release for ${tag} not found`); + // Find draft release to publish. + // + // Normally the draft was created by tags.yaml with tag_name === tag. + // But if the git tag was deleted and re-created between draft creation + // and merge (e.g. the release branch was force-updated), GitHub orphans + // the draft: tag_name becomes "untagged-" while `name` is kept. + // Fall back to matching by `name` and repair the draft's tag_name + // before publishing — otherwise the published release would not point + // at the real git tag. + let draft = releases.data.find(r => r.draft && r.tag_name === tag); + if (!draft) { + const orphan = releases.data.find(r => + r.draft && r.name === tag && /^untagged-/.test(r.tag_name) + ); + if (!orphan) throw new Error(`Draft release for ${tag} not found`); + console.log(`🔧 Repairing orphaned draft ${orphan.id}: tag_name '${orphan.tag_name}' -> '${tag}'`); + const repaired = await github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: orphan.id, + tag_name: tag + }); + draft = repaired.data; + } // Find max semver among published releases (excluding current draft) const publishedReleases = releases.data