diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 0847ca76c..08135cb4e 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -29,6 +29,7 @@ jobs: if: github.ref == format('refs/heads/{0}', github.event.repository.default_branch) || github.event_name == 'workflow_dispatch' outputs: new_tag: ${{ steps.tag_version.outputs.next_version }} + commit_sha: ${{ steps.tag_version.outputs.commit_sha }} steps: - name: Checkout code uses: actions/checkout@v6 @@ -37,6 +38,7 @@ jobs: ref: ${{ github.event.inputs.branch }} token: ${{ secrets.GITHUB_TOKEN }} + # Compute-only: tag is pushed by finalize_release after everything succeeds. - name: Read app version and calculate next Docker build version id: tag_version run: | @@ -64,26 +66,7 @@ jobs: echo "Calculated next Docker version: $NEXT_VERSION" echo "next_version=$NEXT_VERSION" >> $GITHUB_OUTPUT - - - name: Create and Push Tag - run: | - git config --global user.name 'github-actions[bot]' - git config --global user.email 'github-actions[bot]@users.noreply.github.com' - - NEXT_TAG="${{ steps.tag_version.outputs.next_version }}" - COMMIT_SHA=$(git rev-parse HEAD) - echo "Tagging commit $COMMIT_SHA with $NEXT_TAG" - - git tag -a "$NEXT_TAG" -m "Docker build $NEXT_TAG" - echo "Pushing tag $NEXT_TAG to origin" - git push origin "$NEXT_TAG" - - - name: Verify Tag Push - run: | - echo "Checking if tag ${{ steps.tag_version.outputs.next_version }} exists remotely..." - sleep 5 - git ls-remote --tags origin | grep "refs/tags/${{ steps.tag_version.outputs.next_version }}" || (echo "Tag push verification failed!" && exit 1) - echo "Tag successfully pushed." + echo "commit_sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT build: needs: tag_release @@ -204,10 +187,42 @@ jobs: if-no-files-found: error retention-days: 1 - create_manifest: + # Release gate: require both arches for every variant, else block publishing. + # Release-only; skipped on dev so the tolerant create_manifest path is kept. + verify_digests: runs-on: ubuntu-latest needs: [tag_release, build] - if: ${{ !cancelled() }} + if: ${{ always() && needs.tag_release.result == 'success' && needs.tag_release.outputs.new_tag != '' }} + steps: + - name: Download all digests + uses: actions/download-artifact@v8 + with: + pattern: digests-* + path: /tmp/digests + merge-multiple: false + + - name: Require both arches for every required variant + run: | + fail=0 + check() { + c=$(find /tmp/digests -type f -path "*/digests-$1-*/*" 2>/dev/null | wc -l | tr -d ' ') + if [ "$c" -lt 2 ]; then + echo "::error::$1 has $c/2 arch digests — blocking release" + fail=1 + else + echo "OK: $1 ($c/2)" + fi + } + check backend-cpu + check backend-cuda + check backend-cuda126 + check web-cpu + [ "$fail" -eq 0 ] || exit 1 + + create_manifest: + runs-on: ubuntu-latest + needs: [tag_release, build, verify_digests] + if: ${{ !cancelled() && needs.verify_digests.result != 'failure' }} permissions: packages: write contents: read @@ -316,3 +331,38 @@ jobs: run: | echo "Multi-arch manifest created for ${{ matrix.name }}!" echo "Tags: $(jq -cr '.tags | join(", ")' <<< "$DOCKER_METADATA_OUTPUT_JSON")" + + # Push the git tag only after build, gate, and manifest publish all succeed. + finalize_release: + runs-on: ubuntu-latest + needs: [tag_release, create_manifest] + if: ${{ success() && needs.tag_release.outputs.new_tag != '' }} + permissions: + contents: write + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + fetch-depth: 0 + ref: ${{ github.event.inputs.branch }} + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Create and push git tag + run: | + git config --global user.name 'github-actions[bot]' + git config --global user.email 'github-actions[bot]@users.noreply.github.com' + + NEXT_TAG="${{ needs.tag_release.outputs.new_tag }}" + COMMIT_SHA="${{ needs.tag_release.outputs.commit_sha }}" + echo "Tagging commit $COMMIT_SHA with $NEXT_TAG" + + git tag -a "$NEXT_TAG" "$COMMIT_SHA" -m "Docker build $NEXT_TAG" + echo "Pushing tag $NEXT_TAG to origin" + git push origin "$NEXT_TAG" + + - name: Verify tag push + run: | + echo "Checking if tag ${{ needs.tag_release.outputs.new_tag }} exists remotely..." + sleep 5 + git ls-remote --tags origin | grep "refs/tags/${{ needs.tag_release.outputs.new_tag }}" || (echo "Tag push verification failed!" && exit 1) + echo "Tag successfully pushed."