From a43e9fe12229b6a5604e6c741fea7bd6a3e75a0d Mon Sep 17 00:00:00 2001 From: jwinterm Date: Sun, 13 Sep 2026 13:18:22 -0400 Subject: [PATCH] fix(ci): publish tag builds to the release, where they can be fetched back Run artifacts upload fine, but this Gitea reports zero artifacts for every run through its REST API, and the web download route answers "Not found." under token, bearer and basic auth alike. A signed build was therefore unreachable from anywhere except the browser session that produced it. Release assets do work: create, upload, list and download all round-trip with an ordinary token, so tag builds now attach their output to the tag's release as well as to the run. Retrieval must use browser_download_url; the asset-id API path returns the asset's JSON metadata even when asked for octet-stream. The step is fail-safe on purpose. With no token, no resolvable release, or a non-201 upload it explains itself and exits 0 rather than turning a green build red. The macOS upload also gains if-no-files-found, without which an empty publish passes silently. --- .gitea/workflows/build-linux.yml | 38 +++++++++++++++++++++++++++ .gitea/workflows/build-macos.yml | 44 ++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/.gitea/workflows/build-linux.yml b/.gitea/workflows/build-linux.yml index d029cfe2..d3da5840 100644 --- a/.gitea/workflows/build-linux.yml +++ b/.gitea/workflows/build-linux.yml @@ -154,3 +154,41 @@ jobs: name: wowlet-x86_64-linux-AppImage path: wowlet-x86_64.AppImage if-no-files-found: error + + - name: publish the AppImage to the tag's release + # The artifact above uploads fine but this Gitea's REST listing reports + # zero artifacts for every run, so a tag build's output cannot be fetched + # back through the API. Release assets can, so publish there as well. + # Fail-safe by design: with no usable token this says why and exits 0, + # it never turns a green build red. + if: startsWith(github.ref, 'refs/tags/') + env: + RELEASE_TOKEN: ${{ github.token }} + run: | + set -eu + FILE=wowlet-x86_64.AppImage + TAG="${GITHUB_REF#refs/tags/}" + API="${GITHUB_SERVER_URL:-https://git.such.software}/api/v1/repos/$GITHUB_REPOSITORY" + if [ -z "${RELEASE_TOKEN:-}" ]; then + echo "no token available to this runner, skipping the release upload" >&2 + exit 0 + fi + H="Authorization: token $RELEASE_TOKEN" + # Single-line python on purpose: a continuation line at column 0 would + # end this block scalar and break the workflow's YAML. `|| true` keeps + # a malformed response from aborting the step under `set -e`. + rid=$(curl -sS -H "$H" "$API/releases/tags/$TAG" | python3 -c "import json,sys;print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true) + if [ -z "$rid" ]; then + rid=$(curl -sS -H "$H" -H "Content-Type: application/json" -X POST \ + -d "{\"tag_name\":\"$TAG\",\"name\":\"wowlet $TAG\"}" "$API/releases" | python3 -c "import json,sys;print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true) + fi + if [ -z "$rid" ]; then + echo "could not resolve or create a release for $TAG, skipping the upload" >&2 + exit 0 + fi + code=$(curl -sS -H "$H" -o /dev/null -w '%{http_code}' -X POST \ + -F "attachment=@$FILE" "$API/releases/$rid/assets?name=$(basename "$FILE")") + echo "release asset upload returned HTTP $code" + if [ "$code" != "201" ]; then + echo "the release upload did not return 201; the run artifact still holds the build" >&2 + fi diff --git a/.gitea/workflows/build-macos.yml b/.gitea/workflows/build-macos.yml index ddaecaa4..6b8b9c52 100644 --- a/.gitea/workflows/build-macos.yml +++ b/.gitea/workflows/build-macos.yml @@ -247,3 +247,47 @@ jobs: name: wowlet-macos path: build/wowlet-macos-*.zip retention-days: 14 + # Without this an empty upload passes silently, which is how a signed + # build can appear to publish while shipping nothing. + if-no-files-found: error + + - name: publish the signed zip to the tag's release + # Same reason as the Linux job: run artifacts upload but this Gitea's + # REST listing returns zero for every run, so the notarized zip cannot + # be fetched back through the API. Release assets can be. Fail-safe: + # with no usable token this says why and exits 0. + if: startsWith(github.ref, 'refs/tags/') + env: + RELEASE_TOKEN: ${{ github.token }} + run: | + set -eu + FILE=$(ls build/wowlet-macos-*.zip 2>/dev/null | head -1) + if [ -z "$FILE" ]; then + echo "no macOS zip to publish; the packaging step should have failed first" >&2 + exit 0 + fi + TAG="${GITHUB_REF#refs/tags/}" + API="${GITHUB_SERVER_URL:-https://git.such.software}/api/v1/repos/$GITHUB_REPOSITORY" + if [ -z "${RELEASE_TOKEN:-}" ]; then + echo "no token available to this runner, skipping the release upload" >&2 + exit 0 + fi + H="Authorization: token $RELEASE_TOKEN" + # Single-line python on purpose: a continuation line at column 0 would + # end this block scalar and break the workflow's YAML. `|| true` keeps + # a malformed response from aborting the step under `set -e`. + rid=$(curl -sS -H "$H" "$API/releases/tags/$TAG" | python3 -c "import json,sys;print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true) + if [ -z "$rid" ]; then + rid=$(curl -sS -H "$H" -H "Content-Type: application/json" -X POST \ + -d "{\"tag_name\":\"$TAG\",\"name\":\"wowlet $TAG\"}" "$API/releases" | python3 -c "import json,sys;print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true) + fi + if [ -z "$rid" ]; then + echo "could not resolve or create a release for $TAG, skipping the upload" >&2 + exit 0 + fi + code=$(curl -sS -H "$H" -o /dev/null -w '%{http_code}' -X POST \ + -F "attachment=@$FILE" "$API/releases/$rid/assets?name=$(basename "$FILE")") + echo "release asset upload returned HTTP $code" + if [ "$code" != "201" ]; then + echo "the release upload did not return 201; the run artifact still holds the build" >&2 + fi