From 41929129ceb829272a0b346ae90a2a1f01754e21 Mon Sep 17 00:00:00 2001 From: Denys Vitali Date: Sat, 24 Jan 2026 15:21:11 +0100 Subject: [PATCH] ci: build & release docker image --- .github/workflows/docker-release.yml | 159 +++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 .github/workflows/docker-release.yml diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml new file mode 100644 index 000000000..3ad396edc --- /dev/null +++ b/.github/workflows/docker-release.yml @@ -0,0 +1,159 @@ +name: Docker Release + +on: + push: + branches: + - main + tags: + - "v*" + +jobs: + # Determine tags to use for all platforms + determine-tags: + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + tags: ${{ steps.determine_tags.outputs.tags }} + image_name: ${{ steps.determine_tags.outputs.image_name }} + steps: + - name: Determine tags + id: determine_tags + run: | + IMAGE_NAME=ghcr.io/${{ github.repository_owner }}/clawdbot + + if [[ $GITHUB_REF == refs/heads/main ]]; then + echo "tags=${IMAGE_NAME}:latest" >> $GITHUB_OUTPUT + echo "image_name=${IMAGE_NAME}" >> $GITHUB_OUTPUT + elif [[ $GITHUB_REF == refs/tags/v* ]]; then + VERSION=$(echo ${GITHUB_REF#refs/tags/v}) + echo "tags=${IMAGE_NAME}:${VERSION},${IMAGE_NAME}:latest" >> $GITHUB_OUTPUT + echo "image_name=${IMAGE_NAME}" >> $GITHUB_OUTPUT + fi + + # Build amd64 image + build-amd64: + runs-on: ubuntu-latest + needs: determine-tags + permissions: + packages: write + contents: read + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: false + + - name: Checkout submodules (retry) + run: | + set -euo pipefail + git submodule sync --recursive + for attempt in 1 2 3 4 5; do + if git -c protocol.version=2 submodule update --init --force --depth=1 --recursive; then + exit 0 + fi + echo "Submodule update failed (attempt $attempt/5). Retrying…" + sleep $((attempt * 10)) + done + exit 1 + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push amd64 image + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64 + push: true + tags: ${{ needs.determine-tags.outputs.tags }}-amd64 + cache-from: type=gha + cache-to: type=gha,mode=max + + # Build arm64 image + build-arm64: + runs-on: ubuntu-latest-arm64 + needs: determine-tags + permissions: + packages: write + contents: read + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: false + + - name: Checkout submodules (retry) + run: | + set -euo pipefail + git submodule sync --recursive + for attempt in 1 2 3 4 5; do + if git -c protocol.version=2 submodule update --init --force --depth=1 --recursive; then + exit 0 + fi + echo "Submodule update failed (attempt $attempt/5). Retrying…" + sleep $((attempt * 10)) + done + exit 1 + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push arm64 image + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/arm64 + push: true + tags: ${{ needs.determine-tags.outputs.tags }}-arm64 + cache-from: type=gha + cache-to: type=gha,mode=max + + # Create multi-platform manifest + create-manifest: + runs-on: ubuntu-latest + needs: [determine-tags, build-amd64, build-arm64] + permissions: + packages: write + contents: read + steps: + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Create and push manifest + run: | + # Split tags string into array + IFS=',' read -r -a TAGS <<<"${{ needs.determine-tags.outputs.tags }}" + IMAGE_NAME="${{ needs.determine-tags.outputs.image_name }}" + + for TAG in "${TAGS[@]}"; do + # Create manifest + docker manifest create ${TAG} \ + ${TAG}-amd64 \ + ${TAG}-arm64 + + # Annotate manifest + docker manifest annotate ${TAG} ${TAG}-amd64 --os linux --arch amd64 + docker manifest annotate ${TAG} ${TAG}-arm64 --os linux --arch arm64 --variant v8 + + # Push manifest + docker manifest push ${TAG} + done