diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml index 407dc24..2bf6248 100644 --- a/.forgejo/workflows/build.yml +++ b/.forgejo/workflows/build.yml @@ -173,24 +173,51 @@ jobs: # same source code as the preceding main-push build but with an # immutable version tag — they need the XPI too, otherwise the # versioned image ships without the signed extension. + # + # Tag-push vs main-push race (operator-flagged 2026-05-27 after + # v26.05.27.0 hit it): a release cut fires BOTH workflows almost + # simultaneously. Main-push runs sign-extension (1-5min AMO round + # trip) before publishing the ext- release; tag-push + # skips sign-extension (gated to main) and races straight to + # this download step. Tag-push lost every time. Fix: poll the + # ext- release endpoint with a sleep+retry loop (30s + # for up to 10min total) before giving up. Main-push's signing + # eventually wins and tag-push picks the release up on a later + # iteration. if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') env: TOKEN: ${{ secrets.RELEASE_TOKEN }} run: | set -eux VERSION=$(grep -E '"version"' extension/package.json | head -1 | sed -E 's/.*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/') - # Look up the ext- release; extract the .xpi asset's - # browser_download_url (Forgejo's /releases/assets/ endpoint - # returns ASSET METADATA, not the binary blob — operator-flagged - # 2026-05-26: my prior code curl'd the metadata endpoint without - # -f and wrote the resulting 404-page-not-found text into - # fabledcurator-*.xpi, which Firefox then rejected as "corrupt"). - # browser_download_url is the canonical binary endpoint and is - # also publicly accessible (no token needed) but we pass the - # token anyway for symmetry with private-repo support. - curl -sf -H "Authorization: token $TOKEN" \ - "https://git.fabledsword.com/api/v1/repos/bvandeusen/FabledCurator/releases/tags/ext-$VERSION" \ - -o release.json + # Poll for the ext- release. main-push's sign-extension + # step (AMO round-trip, 1-5min) needs to finish + upload before + # tag-push can fetch. 30s * 20 = up to 10min wait, then hard-fail. + for attempt in $(seq 1 20); do + STATUS=$(curl -s -o release.json -w "%{http_code}" \ + -H "Authorization: token $TOKEN" \ + "https://git.fabledsword.com/api/v1/repos/bvandeusen/FabledCurator/releases/tags/ext-$VERSION" || echo 000) + if [ "$STATUS" = "200" ]; then + echo "Found ext-$VERSION release on attempt $attempt" + break + fi + if [ "$attempt" = "20" ]; then + echo "ERROR: ext-$VERSION release not available after 10min of polling" + echo "Last HTTP status: $STATUS" + exit 1 + fi + echo "Attempt $attempt: ext-$VERSION not yet published (HTTP $STATUS); sleeping 30s" + sleep 30 + done + # Extract the .xpi asset's browser_download_url (Forgejo's + # /releases/assets/ endpoint returns ASSET METADATA, not + # the binary blob — operator-flagged 2026-05-26: my prior + # code curl'd the metadata endpoint without -f and wrote the + # resulting 404-page-not-found text into fabledcurator-*.xpi, + # which Firefox then rejected as "corrupt"). + # browser_download_url is the canonical binary endpoint and + # is also publicly accessible (no token needed) but we pass + # the token anyway for symmetry with private-repo support. DOWNLOAD_URL=$(python3 -c "import json; r=json.load(open('release.json')); xpis=[a for a in r.get('assets', []) if a.get('name','').endswith('.xpi')]; print(xpis[0]['browser_download_url'])") test -n "$DOWNLOAD_URL" echo "Downloading XPI from: $DOWNLOAD_URL"