Delete incomplete prereleases by release ID (#59903)

## Why

A release can be replaced under the same tag during asset upload. Cleanup by tag could then delete the replacement release.

## What changed

Move GitHub release publication into `.github/scripts/publish-github-release.sh`. Create releases through the API and capture their IDs so an exit trap deletes only the newly created prerelease if asset upload fails. Clear the trap after upload so a metadata update failure preserves the uploaded assets.

Keep existing releases and tags intact, verify tags before creating releases, and continue creating stable releases as drafts until upload completes.

## Testing

Extend the publication test to cover upload failures, retries, metadata update failures, stable drafts, replacement releases, and missing tags. The focused test passes.

GitOrigin-RevId: a310d5b77a66dc6a9cf2d136c280d968f0e7a28f
This commit is contained in:
jif
2026-11-06 12:52:36 +00:00
committed by copyberry
parent b8725c1896
commit e3fe1ade2c
3 changed files with 122 additions and 118 deletions
+40
View File
@@ -0,0 +1,40 @@
#!/usr/bin/env bash
set -euo pipefail
repo_api="repos/$GITHUB_REPOSITORY"
# Look up this tag, including drafts. A lookup error must abort publication.
# shellcheck disable=SC2016
exists="$(gh api graphql \
-f query='query($owner:String!,$repo:String!,$tag:String!){repository(owner:$owner,name:$repo){release(tagName:$tag){databaseId}}}' \
-f owner="$GITHUB_REPOSITORY_OWNER" \
-f repo="${GITHUB_REPOSITORY#*/}" \
-f tag="$GITHUB_REF_NAME" \
--jq '.data.repository.release != null')"
if [[ "$exists" == false ]]; then
# The create API would create a missing tag from the default branch.
gh api --silent "$repo_api/git/ref/tags/$GITHUB_REF_NAME"
draft=true
if [[ "$PRERELEASE" == true ]]; then
# Create prereleases directly to preserve the prereleased event.
draft=false
fi
release_id="$(gh api --method POST "$repo_api/releases" \
-f tag_name="$GITHUB_REF_NAME" -f name="$RELEASE_NAME" -F "body=@$RELEASE_NOTES" \
-F draft="$draft" -F prerelease="$PRERELEASE" -f make_latest=false --jq '.id')"
if [[ "$PRERELEASE" == true ]]; then
# A maintainer can replace a release under the same tag during upload.
trap '
echo "Removing incomplete prerelease $release_id" >&2
gh api --method DELETE "$repo_api/releases/$release_id" || true
' EXIT
fi
fi
mapfile -d '' assets < <(find dist -type f -print0 | sort -z)
gh release upload "$GITHUB_REF_NAME" "${assets[@]}" --repo "$GITHUB_REPOSITORY" --clobber
trap - EXIT
gh release edit "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" \
--title "$RELEASE_NAME" --notes-file "$RELEASE_NOTES" --prerelease="$PRERELEASE" \
--draft=false --latest="$MAKE_LATEST"