From 075509172165df0cee2cf5d16511da802c0d88ed Mon Sep 17 00:00:00 2001 From: alvinlollo Date: Tue, 22 Sep 2026 22:06:33 +1000 Subject: [PATCH] ci: add 3-try retry loop and timeouts for ISO release upload --- .gitea/workflows/build-iso.yaml | 108 ++++++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 18 deletions(-) diff --git a/.gitea/workflows/build-iso.yaml b/.gitea/workflows/build-iso.yaml index 3a3f299..8af6c95 100644 --- a/.gitea/workflows/build-iso.yaml +++ b/.gitea/workflows/build-iso.yaml @@ -90,11 +90,22 @@ jobs: TAG_NAME: ${{ steps.tag.outputs.tag_name }} RELEASE_NAME: ${{ steps.tag.outputs.release_name }} run: | - set -euo pipefail + set -eu shopt -s nullglob - test -n "$GITEA_TOKEN" - test -n "$TAG_NAME" - test -n "$RELEASE_NAME" + tmpdir=$(mktemp -d) + trap 'rm -rf "$tmpdir"' EXIT + if [ -z "$GITEA_TOKEN" ]; then + echo "❌ GITEA_TOKEN is empty" >&2 + exit 1 + fi + if [ -z "$TAG_NAME" ]; then + echo "❌ TAG_NAME is empty" >&2 + exit 1 + fi + if [ -z "$RELEASE_NAME" ]; then + echo "❌ RELEASE_NAME is empty" >&2 + exit 1 + fi # Pre-flight: confirm the internal Gitea API is reachable so failures are clear if ! curl -sfS -o /dev/null "$GITEA_API/version"; then @@ -119,6 +130,10 @@ jobs: exit 1 fi sha=$(sha256sum "$iso" | awk '{print $1}') + if [ -z "$sha" ]; then + echo "❌ Failed to compute SHA-256 for '$iso'" >&2 + exit 1 + fi echo " ✅ $fname: $(( size / 1024 / 1024 )) MiB, sha256=$sha" sha256sums+=("$sha") done @@ -130,28 +145,85 @@ jobs: body+="$line" done - # Create the release + # Create the release (curl result written to a file, checked with if) payload=$(jq -nc --arg tag "$TAG_NAME" --arg name "$RELEASE_NAME" --arg body "$body" \ '{tag_name:$tag,name:$name,body:$body}') - RELEASE_ID=$(curl -sf -X POST \ - -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_API/repos/$REPOSITORY/releases" \ - -d "$payload" | jq -er '.id') + if ! curl -sf -X POST \ + -H "Authorization: token $GITEA_TOKEN" \ + -H "Content-Type: application/json" \ + "$GITEA_API/repos/$REPOSITORY/releases" \ + -d "$payload" -o "$tmpdir/release.json"; then + echo "❌ Failed to create release $TAG_NAME" >&2 + exit 1 + fi + if ! RELEASE_ID=$(jq -er '.id' "$tmpdir/release.json"); then + echo "❌ Release response contained no id" >&2 + exit 1 + fi echo " ✅ Created release $TAG_NAME (ID: $RELEASE_ID)" - # Upload each ISO as a release asset + # Upload each ISO as a release asset, up to 3 attempts per file + MAX_ATTEMPTS=3 for i in "${!isos[@]}"; do - fname=$(basename "${isos[$i]}") - size=$(stat -c %s "${isos[$i]}") + iso=${isos[$i]} + fname=$(basename "$iso") + size=$(stat -c %s "$iso") echo "Uploading $fname ($(( size / 1024 / 1024 )) MiB) to release $TAG_NAME..." - curl -sf -X POST \ - -H "Authorization: token $GITEA_TOKEN" \ - -F "attachment=@${isos[$i]}" \ - "$GITEA_API/repos/$REPOSITORY/releases/$RELEASE_ID/assets" | jq -er '.browser_download_url' - echo " ✅ Uploaded $fname" + uploaded=0 + attempt=1 + while [ "$attempt" -le "$MAX_ATTEMPTS" ]; do + # A previous attempt may have saved the asset but lost the + # response; Gitea rejects duplicate names, so only after the + # first attempt check for and remove same-name leftovers + if [ "$attempt" -gt 1 ]; then + if curl -sf -H "Authorization: token $GITEA_TOKEN" \ + "$GITEA_API/repos/$REPOSITORY/releases/$RELEASE_ID/assets" \ + -o "$tmpdir/assets.json"; then + asset_ids=$(jq -r --arg name "$fname" \ + '.[] | select(.name == $name) | .id' "$tmpdir/assets.json") + while read -r asset_id; do + if [ -n "$asset_id" ]; then + echo " ↻ Removing leftover asset id=$asset_id from a previous attempt" + if ! curl -sf -X DELETE -H "Authorization: token $GITEA_TOKEN" \ + "$GITEA_API/repos/$REPOSITORY/releases/$RELEASE_ID/assets/$asset_id" \ + -o /dev/null; then + echo " ⚠️ Could not remove leftover asset id=$asset_id (continuing)" >&2 + fi + fi + done <<< "$asset_ids" + fi + fi + + if curl -sf -X POST --max-time 600 \ + -H "Authorization: token $GITEA_TOKEN" \ + -F "attachment=@$iso" \ + "$GITEA_API/repos/$REPOSITORY/releases/$RELEASE_ID/assets" \ + -o "$tmpdir/upload.json"; then + if download_url=$(jq -er '.browser_download_url' "$tmpdir/upload.json"); then + echo " ✅ Uploaded $fname (attempt $attempt/$MAX_ATTEMPTS): $download_url" + uploaded=1 + break + fi + echo " ⚠️ Upload of $fname returned no download URL (attempt $attempt/$MAX_ATTEMPTS)" >&2 + else + echo " ⚠️ Upload of $fname failed (attempt $attempt/$MAX_ATTEMPTS)" >&2 + fi + + if [ "$attempt" -lt "$MAX_ATTEMPTS" ]; then + sleep $(( attempt * 10 )) + fi + attempt=$(( attempt + 1 )) + done + + if [ "$uploaded" -ne 1 ]; then + echo "❌ Failed to upload $fname after $MAX_ATTEMPTS attempts — aborting." >&2 + exit 1 + fi done + echo "✅ All ISOs uploaded to release $TAG_NAME" + exit 0 + - name: Keep only latest 2 releases if: success() env: