name: Docker # This workflow uses actions that are not certified by GitHub. # They are provided by a third-party and are governed by # separate terms of service, privacy policy, and support # documentation. on: schedule: - cron: "25 0 * * *" push: branches: ["main"] # Publish semver tags as releases. tags: ["v*.*.*"] pull_request: branches: ["main"] workflow_dispatch: env: # Use docker.io for Docker Hub if empty REGISTRY: ghcr.io # github.repository as / IMAGE_NAME: ${{ github.repository }} jobs: # test: # runs-on: ubuntu-latest # permissions: # contents: read # packages: write # id-token: write # steps: # - name: Checkout repository # uses: actions/checkout@v4 # - name: Set up Docker Buildx # uses: docker/setup-buildx-action@v3 # - name: Test # id: test # uses: docker/build-push-action@v6 # with: # context: . # platforms: linux/amd64 # cache-from: type=gha,scope=x64 # pull: true # cache-to: type=gha,mode=max,scope=x64 # target: test build: # needs: test runs-on: ubuntu-latest permissions: contents: read packages: write id-token: write strategy: matrix: platform: [linux/amd64, linux/arm64] steps: - name: Checkout repository uses: actions/checkout@v4 - name: Prepare variables id: vars run: | SURFIX=$(echo ${{ matrix.platform }} | cut -d'/' -f2) echo "SURFIX=$SURFIX" >> $GITHUB_OUTPUT # Generate a unique local tag for the image echo "LOCAL_TAG=local-${{ github.sha }}-$SURFIX" >> $GITHUB_OUTPUT - name: Set up QEMU uses: docker/setup-qemu-action@v3 # Set up BuildKit Docker container builder - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 # Extract metadata (tags, labels) for Docker - name: Extract Docker metadata id: meta uses: docker/metadata-action@v5 with: tags: | type=ref,event=branch type=ref,event=pr type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}} type=raw,enable=${{ github.ref_type == 'tag' }}, value=latest images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - name: Set up apt cache uses: actions/cache@v4 id: cache with: path: | var-cache-apt var-lib-apt /root/.cache/uv key: cache-${{ hashFiles('Dockerfile') }}-${{ steps.vars.outputs.SURFIX }} - name: Inject cache into docker uses: reproducible-containers/buildkit-cache-dance@v3.1.2 with: cache-map: | { "var-cache-apt": "/var/cache/apt", "var-lib-apt": "/var/lib/apt", "root-cache-uv": "/root/.cache/uv" } skip-extraction: ${{ steps.cache.outputs.cache-hit }} # Build and export Docker image for each platform (without pushing) - name: Build Docker image id: build uses: docker/build-push-action@v6 with: context: . pull: true push: false load: true # Export to local Docker instead of pushing tags: ${{ steps.vars.outputs.LOCAL_TAG }} labels: ${{ steps.meta.outputs.labels }} platforms: ${{ matrix.platform }} cache-from: type=gha,scope=${{ matrix.platform }} cache-to: type=gha,mode=max,scope=${{ matrix.platform }} build-args: GITHUB_BUILD=true,VERSION=${{ github.ref_type == 'tag' && github.ref_name || github.sha }} outputs: type=docker,dest=/tmp/image-${{ steps.vars.outputs.SURFIX }}.tar # Upload the tarball as an artifact - name: Upload image artifact uses: actions/upload-artifact@v4 with: name: docker-image-${{ steps.vars.outputs.SURFIX }} path: /tmp/image-${{ steps.vars.outputs.SURFIX }}.tar retention-days: 1 merge-and-push: needs: build runs-on: ubuntu-latest if: github.event_name != 'pull_request' permissions: contents: read packages: write id-token: write steps: - name: Checkout repository uses: actions/checkout@v4 # Install the cosign tool - name: Install cosign uses: sigstore/cosign-installer@v3 # Set up Docker Buildx - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 # Log into registry - name: Log into registry ${{ env.REGISTRY }} uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} # Extract Docker metadata for tagging - name: Extract Docker metadata id: meta uses: docker/metadata-action@v5 with: tags: | type=ref,event=branch type=ref,event=pr type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}} images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # Download all image artifacts - name: Download AMD64 image uses: actions/download-artifact@v4 with: name: docker-image-amd64 path: /tmp - name: Download ARM64 image uses: actions/download-artifact@v4 with: name: docker-image-arm64 path: /tmp # Load images into Docker - name: Load images run: | docker load --input /tmp/image-amd64.tar docker load --input /tmp/image-arm64.tar # Create manifest lists and push - name: Create and push manifest lists run: | TAGS="${{ steps.meta.outputs.tags }}" args="" docker tag local-${{ github.sha }}-amd64 ${{github.ref_name}}-amd64 docker push ${{github.ref_name}}-amd64 docker tag local-${{ github.sha }}-arm64 ${{github.ref_name}}-arm64 docker push ${{github.ref_name}}-arm64 # Create tag arguments for tag in $TAGS; do args="$args -t $tag" done if [ "${{ github.ref_type }}" == "tag" ]; then args="$args -t latest" fi echo $args docker buildx imagetools create --pull=false $args \ ${{github.ref_name}}-amd64 \ ${{github.ref_name}}-arm64 # Sign the manifest - name: Sign the manifests env: TAGS: ${{ steps.meta.outputs.tags }} run: | for TAG in $TAGS; do cosign sign --yes $TAG done