From d85bf17171fd0faefbbd54df44bef573991aa7f8 Mon Sep 17 00:00:00 2001 From: viettranx Date: Wed, 3 Jun 2026 21:42:24 +0700 Subject: [PATCH] ci(release): build docker images directly for stable tags --- .github/workflows/release.yaml | 238 +++++---------------------------- 1 file changed, 37 insertions(+), 201 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index f384c287..f4b3636a 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -161,100 +161,27 @@ jobs: strategy: fail-fast: false matrix: - variant: [base, latest, full] - platform: [linux/amd64, linux/arm64] include: - variant: base + suffix: "-base" enable_embedui: "false" enable_python: "false" enable_full_skills: "false" - variant: latest + suffix: "" enable_embedui: "true" enable_python: "true" enable_full_skills: "false" - variant: full + suffix: "-full" enable_embedui: "true" enable_python: "true" enable_full_skills: "true" - - platform: linux/amd64 - runner: ubuntu-latest - arch: amd64 - - platform: linux/arm64 - runner: ubuntu-24.04-arm - arch: arm64 - runs-on: ${{ matrix.runner }} + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: docker/setup-buildx-action@v3 - - - name: Log in to GHCR - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Log in to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and push by digest - id: build - uses: docker/build-push-action@v6 - with: - context: . - platforms: ${{ matrix.platform }} - outputs: type=image,"name=${{ env.GHCR_IMAGE }},${{ env.DOCKERHUB_IMAGE }}",push-by-digest=true,name-canonical=true,push=true - build-args: | - ENABLE_OTEL=false - ENABLE_EMBEDUI=${{ matrix.enable_embedui }} - ENABLE_PYTHON=${{ matrix.enable_python }} - ENABLE_FULL_SKILLS=${{ matrix.enable_full_skills }} - VERSION=v${{ needs.release.outputs.version }} - cache-from: type=gha,scope=${{ matrix.variant }}-${{ matrix.arch }} - cache-to: type=gha,mode=max,scope=${{ matrix.variant }}-${{ matrix.arch }} - provenance: false - - - name: Export digest - run: | - mkdir -p /tmp/digests - digest="${{ steps.build.outputs.digest }}" - touch "/tmp/digests/${digest#sha256:}" - - - uses: actions/upload-artifact@v4 - with: - name: digests-${{ matrix.variant }}-${{ matrix.arch }} - path: /tmp/digests/* - if-no-files-found: error - retention-days: 1 - - # Combine per-platform digests into multi-arch manifests and push final tags - # to both GHCR and Docker Hub. One job per variant runs in parallel. - docker-merge: - needs: [release, docker-build] - if: needs.release.outputs.released == 'true' - runs-on: ubuntu-latest - timeout-minutes: 15 - strategy: - fail-fast: false - matrix: - include: - - variant: base - suffix: "-base" - - variant: latest - suffix: "" - - variant: full - suffix: "-full" - steps: - - name: Download digests - uses: actions/download-artifact@v4 - with: - path: /tmp/digests - pattern: digests-${{ matrix.variant }}-* - merge-multiple: true + - uses: docker/setup-qemu-action@v3 - uses: docker/setup-buildx-action@v3 @@ -283,108 +210,34 @@ jobs: type=raw,value=latest,enable=${{ matrix.suffix == '' }},suffix= type=raw,value=${{ matrix.variant }},enable=${{ matrix.suffix != '' }} - - name: Create manifest list and push - working-directory: /tmp/digests - run: | - # Compose -t flags from metadata-action tags (newline-separated). - GHCR_IMAGE="${{ env.GHCR_IMAGE }}" - DOCKERHUB_IMAGE="${{ env.DOCKERHUB_IMAGE }}" - GHCR_TAG_ARGS=() - DOCKERHUB_TAG_ARGS=() - while IFS= read -r tag; do - if [[ "$tag" == "$GHCR_IMAGE:"* ]]; then - GHCR_TAG_ARGS+=("-t" "$tag") - elif [[ "$tag" == "$DOCKERHUB_IMAGE:"* ]]; then - DOCKERHUB_TAG_ARGS+=("-t" "$tag") - fi - done <<< "${{ steps.meta.outputs.tags }}" - # Compose source digest refs pushed to each registry by docker-build. - GHCR_DIGEST_ARGS=() - DOCKERHUB_DIGEST_ARGS=() - for f in *; do - GHCR_DIGEST_ARGS+=("$GHCR_IMAGE@sha256:$f") - DOCKERHUB_DIGEST_ARGS+=("$DOCKERHUB_IMAGE@sha256:$f") - done - set -x - docker buildx imagetools create "${GHCR_TAG_ARGS[@]}" "${GHCR_DIGEST_ARGS[@]}" - docker buildx imagetools create "${DOCKERHUB_TAG_ARGS[@]}" "${DOCKERHUB_DIGEST_ARGS[@]}" + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + ENABLE_OTEL=false + ENABLE_EMBEDUI=${{ matrix.enable_embedui }} + ENABLE_PYTHON=${{ matrix.enable_python }} + ENABLE_FULL_SKILLS=${{ matrix.enable_full_skills }} + VERSION=v${{ needs.release.outputs.version }} + cache-from: type=gha,scope=release-${{ matrix.variant }} + cache-to: type=gha,mode=max,scope=release-${{ matrix.variant }} + provenance: false - - name: Inspect manifest - run: | - docker buildx imagetools inspect \ - "${{ env.GHCR_IMAGE }}:v${{ needs.release.outputs.version }}${{ matrix.suffix }}" - - # Build web UI Docker image per platform on native runners. + # Build web UI Docker image. docker-web-build: needs: release if: needs.release.outputs.released == 'true' timeout-minutes: 30 - strategy: - fail-fast: false - matrix: - platform: [linux/amd64, linux/arm64] - include: - - platform: linux/amd64 - runner: ubuntu-latest - arch: amd64 - - platform: linux/arm64 - runner: ubuntu-24.04-arm - arch: arm64 - runs-on: ${{ matrix.runner }} + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: docker/setup-buildx-action@v3 - - - name: Log in to GHCR - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Log in to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and push by digest - id: build - uses: docker/build-push-action@v6 - with: - context: ui/web - platforms: ${{ matrix.platform }} - outputs: type=image,"name=${{ env.GHCR_IMAGE }}-web,${{ env.DOCKERHUB_IMAGE }}-web",push-by-digest=true,name-canonical=true,push=true - cache-from: type=gha,scope=web-${{ matrix.arch }} - cache-to: type=gha,mode=max,scope=web-${{ matrix.arch }} - provenance: false - - - name: Export digest - run: | - mkdir -p /tmp/digests - digest="${{ steps.build.outputs.digest }}" - touch "/tmp/digests/${digest#sha256:}" - - - uses: actions/upload-artifact@v4 - with: - name: digests-web-${{ matrix.arch }} - path: /tmp/digests/* - if-no-files-found: error - retention-days: 1 - - docker-web-merge: - needs: [release, docker-web-build] - if: needs.release.outputs.released == 'true' - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - name: Download digests - uses: actions/download-artifact@v4 - with: - path: /tmp/digests - pattern: digests-web-* - merge-multiple: true + - uses: docker/setup-qemu-action@v3 - uses: docker/setup-buildx-action@v3 @@ -412,38 +265,21 @@ jobs: type=raw,value=v${{ needs.release.outputs.version }} type=raw,value=latest - - name: Create manifest list and push - working-directory: /tmp/digests - run: | - GHCR_IMAGE="${{ env.GHCR_IMAGE }}-web" - DOCKERHUB_IMAGE="${{ env.DOCKERHUB_IMAGE }}-web" - GHCR_TAG_ARGS=() - DOCKERHUB_TAG_ARGS=() - while IFS= read -r tag; do - if [[ "$tag" == "$GHCR_IMAGE:"* ]]; then - GHCR_TAG_ARGS+=("-t" "$tag") - elif [[ "$tag" == "$DOCKERHUB_IMAGE:"* ]]; then - DOCKERHUB_TAG_ARGS+=("-t" "$tag") - fi - done <<< "${{ steps.meta.outputs.tags }}" - GHCR_DIGEST_ARGS=() - DOCKERHUB_DIGEST_ARGS=() - for f in *; do - GHCR_DIGEST_ARGS+=("$GHCR_IMAGE@sha256:$f") - DOCKERHUB_DIGEST_ARGS+=("$DOCKERHUB_IMAGE@sha256:$f") - done - set -x - docker buildx imagetools create "${GHCR_TAG_ARGS[@]}" "${GHCR_DIGEST_ARGS[@]}" - docker buildx imagetools create "${DOCKERHUB_TAG_ARGS[@]}" "${DOCKERHUB_DIGEST_ARGS[@]}" - - - name: Inspect manifest - run: | - docker buildx imagetools inspect \ - "${{ env.GHCR_IMAGE }}-web:v${{ needs.release.outputs.version }}" + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: ui/web + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha,scope=release-web + cache-to: type=gha,mode=max,scope=release-web + provenance: false # Notify Discord on new release (runs even if docker jobs fail) notify-discord: - needs: [release, build-binaries, docker-merge, docker-web-merge] + needs: [release, build-binaries, docker-build, docker-web-build] if: always() && needs.release.outputs.released == 'true' && !cancelled() runs-on: ubuntu-latest timeout-minutes: 5