From 8fadb8299cf2c79f82b2d1a819495b073b2e71db Mon Sep 17 00:00:00 2001 From: Micheal Wilkinson Date: Fri, 20 Mar 2026 18:42:53 +0000 Subject: [PATCH] ci(release): upsert release and replace matching assets --- .gitea/workflows/prepare-release.yml | 39 +++++++++++++++++++++------- README.md | 2 +- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/.gitea/workflows/prepare-release.yml b/.gitea/workflows/prepare-release.yml index bc870e5..560405d 100644 --- a/.gitea/workflows/prepare-release.yml +++ b/.gitea/workflows/prepare-release.yml @@ -128,24 +128,26 @@ jobs: fi curl --fail-with-body \ - -X DELETE \ + -X PATCH \ -H "Authorization: token ${RELEASE_TOKEN}" \ -H "Content-Type: application/json" \ - "${release_api}/${existing_release_id}" + "${release_api}/${existing_release_id}" \ + --data "{\"tag_name\":\"${tag}\",\"target\":\"${GITHUB_SHA}\",\"name\":\"${tag}\",\"body\":\"${escaped_release_notes}\",\"draft\":false,\"prerelease\":false}" \ + --output release.json elif [[ "$status_code" != "404" ]]; then echo "Unexpected response while checking release ${tag}: HTTP ${status_code}" >&2 cat release-existing.json >&2 exit 1 + else + curl --fail-with-body \ + -X POST \ + -H "Authorization: token ${RELEASE_TOKEN}" \ + -H "Content-Type: application/json" \ + "${release_api}" \ + --data "{\"tag_name\":\"${tag}\",\"target\":\"${GITHUB_SHA}\",\"name\":\"${tag}\",\"body\":\"${escaped_release_notes}\",\"draft\":false,\"prerelease\":false}" \ + --output release.json fi - curl --fail-with-body \ - -X POST \ - -H "Authorization: token ${RELEASE_TOKEN}" \ - -H "Content-Type: application/json" \ - "${release_api}" \ - --data "{\"tag_name\":\"${tag}\",\"target\":\"${GITHUB_SHA}\",\"name\":\"${tag}\",\"body\":\"${escaped_release_notes}\",\"draft\":false,\"prerelease\":false}" \ - --output release.json - release_id="$(sed -n 's/.*"id"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p' release.json | head -n 1)" if [[ -z "$release_id" ]]; then echo "Failed to parse release id from API response" >&2 @@ -194,6 +196,23 @@ jobs: for asset in dist/*; do name="$(basename "$asset")" + + assets_json="$(curl -sS --fail-with-body \ + -H "Authorization: token ${RELEASE_TOKEN}" \ + -H "Content-Type: application/json" \ + "${release_api}")" + + escaped_name="$(printf '%s' "$name" | sed 's/[][(){}.^$*+?|\\/]/\\&/g')" + existing_asset_id="$(printf '%s' "$assets_json" | tr -d '\n' | sed -n "s/.*{\"id\":\([0-9][0-9]*\)[^}]*\"name\":\"${escaped_name}\".*/\1/p")" + + if [[ -n "$existing_asset_id" ]]; then + curl --fail-with-body \ + -X DELETE \ + -H "Authorization: token ${RELEASE_TOKEN}" \ + -H "Content-Type: application/json" \ + "${release_api}/${existing_asset_id}" + fi + curl --fail-with-body \ -X POST \ -H "Authorization: token ${RELEASE_TOKEN}" \ diff --git a/README.md b/README.md index 3d4cf5c..0dd8742 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ The `Prepare Release` workflow creates a release and uploads prebuilt `vociferat - `windows/arm64` It also uploads `checksums.txt` for integrity verification. -If a release already exists for the same tag, the workflow replaces it so release notes and attached binaries stay in sync. +If a release already exists for the same tag, the workflow updates its release notes and replaces matching asset filenames so reruns stay in sync. ## Reuse In Other Repositories