diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 8d1dc317..6e89d541 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -98,6 +98,31 @@ jobs: echo "code=${COMMIT_COUNT}" >> "$GITHUB_OUTPUT" echo "::notice::APK version: ${VERSION_NAME} (code=${COMMIT_COUNT})" + # Checked BEFORE the expensive work, not after it. "Attach APK to gitea + # Release" below resolves the release by tag and fails if it is absent — + # but that is the final step, so a tag pushed without a release built an + # APK for several minutes first and only then discovered it had nowhere to + # put it. Same check, seconds in instead of minutes. + # + # Releases are normally created through the API (which creates the tag and + # the release together, so this passes). A bare `git push origin vX` is the + # case this catches. + - name: Release must exist for this tag + shell: bash + working-directory: ${{ github.workspace }} + env: + CI_TOKEN: ${{ secrets.CI_TOKEN }} + run: | + set -euo pipefail + TAG="${GITHUB_REF#refs/tags/}" + if ! curl -fsSL -o /dev/null \ + -H "Authorization: token ${CI_TOKEN}" \ + "https://git.fabledsword.com/api/v1/repos/${GITHUB_REPOSITORY}/releases/tags/${TAG}"; then + echo "::error::no release exists for ${TAG}. Create the release (which creates the tag) rather than pushing a bare tag — otherwise there is nothing to attach the APK to." + exit 1 + fi + echo "::notice::release found for ${TAG}" + - name: Cache Gradle dirs uses: actions/cache@v4 with: @@ -376,4 +401,25 @@ jobs: exit 1 fi - echo "::notice::${TAG} verified — APK attached: ${APK}" + echo "::notice::APK attached: ${APK}" + + # The other half. Checking only the APK would report success on a release + # whose image push failed — which is precisely the second thing that was + # missing when v2026.08.07 had to be re-cut. `always()` on this job means + # it runs even when image-release failed, so without this the guard would + # cheerfully verify an incomplete release. + - name: Immutable image tag must exist + shell: bash + run: | + set -euo pipefail + TAG="${GITHUB_REF#refs/tags/}" + IMAGE="git.fabledsword.com/bvandeusen/minstrel" + + echo "${{ secrets.CI_TOKEN }}" \ + | docker login git.fabledsword.com -u "${{ github.actor }}" --password-stdin + + if ! docker manifest inspect "${IMAGE}:${TAG}" > /dev/null 2>&1; then + echo "::error::image ${IMAGE}:${TAG} was never pushed — the release tag has no immutable image, so there is nothing to pin or roll back to. Re-run this workflow run." + exit 1 + fi + echo "::notice::image verified: ${IMAGE}:${TAG}"