From b35f0310425ae0ae58a8e0a43cada6980aac1a2d Mon Sep 17 00:00:00 2001 From: pythoninthegrass <4097471+pythoninthegrass@users.noreply.github.com> Date: Tue, 15 Oct 2024 00:29:26 -0500 Subject: [PATCH] wip --- .github/workflows/docker.yml | 189 +++++++++++++++++++++++++---------- 1 file changed, 136 insertions(+), 53 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 4d70a0b330..194cf8adc0 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -5,76 +5,73 @@ on: branches: - 'main' - 'master' - - 'feat/**' tags: - '*.*.*' paths: - - '.dockerignore' - - '.env.example' - - '.github/workflows/**' - - '**.bat' - - '**.ps1' - - '**.py' - - '**.sh' - - 'bin/**' - - 'config/**' - 'Dockerfile*' - - 'musicbot.service' - - 'musicbot/**' - - 'musicbotcmd' - - 'poetry.lock' - 'pyproject.toml' + - 'poetry.lock' - 'requirements.txt' + - '**.py' + - '**.sh' + - '.dockerignore' + - '.env.example' + - '.github/workflows/**' workflow_dispatch: env: REGISTRY_URL: ${{ vars.REGISTRY_URL }} REGISTRY_USER: ${{ vars.REGISTRY_USER }} - REGISTRY_PASS: ${{ secrets.REGISTRY_PASS }} jobs: - push_to_registry: - name: Push Docker image to container registry + build: + name: Build and push Docker image runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - dockerfile: [Dockerfile] - concurrency: - group: ${{ github.workflow }}-${{ matrix.dockerfile }}-${{ github.ref }} - cancel-in-progress: true - permissions: - packages: write - contents: read - actions: read + platform: + - linux/amd64 + - linux/arm64/v8 steps: - name: Check out the repo uses: actions/checkout@v4 - - name: Log into container registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY_URL }} - username: ${{ env.REGISTRY_URL == 'ghcr.io' && github.repository_owner || env.REGISTRY_USER }} - password: ${{ env.REGISTRY_URL == 'ghcr.io' && secrets.GITHUB_TOKEN || env.REGISTRY_PASS }} + - name: Prepare + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + + - name: Set password by container registry + run: | + case "${{ env.REGISTRY_URL }}" in + "ghcr.io") + echo "REGISTRY_PASS=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV + ;; + *) + if [ -n "${{ secrets.REGISTRY_PASS }}" ]; then + echo "REGISTRY_PASS=${{ secrets.REGISTRY_PASS }}" >> $GITHUB_ENV + else + echo "REGISTRY_PASS secret is not set and registry is not recognized. Exiting..." + exit 1 + fi + ;; + esac - name: Extract image name from Dockerfile id: image_name run: | - IMAGE=$(grep "LABEL org.opencontainers.image.title" ${{ matrix.dockerfile }} | cut -d'"' -f2) + IMAGE=$(grep "LABEL org.opencontainers.image.title" Dockerfile | cut -d'"' -f2) echo "IMAGE=$IMAGE" >> $GITHUB_OUTPUT - - name: Extract metadata (tags, labels) for Docker + - name: Docker meta id: meta uses: docker/metadata-action@v5 with: - images: | - ${{ env.REGISTRY_URL }}/${{ env.REGISTRY_URL == 'ghcr.io' && github.repository_owner || env.REGISTRY_USER }}/${{ steps.image_name.outputs.IMAGE }} + images: ${{ env.REGISTRY_URL }}/${{ env.REGISTRY_USER }}/${{ steps.image_name.outputs.IMAGE }} tags: | - type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' }} - type=ref,event=branch + type=raw,value=latest,enable={{is_default_branch}} type=semver,pattern={{version}} - flavor: | - latest=false - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -82,21 +79,107 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - # TODO: fix tagging - # ! 'manifest unknown' via `docker pull ghcr.io/pythoninthegrass/musicbot:feat-update_docker` - # ! `docker pull ghcr.io/pythoninthegrass/musicbot@sha256:40b2474ed9a12a7276196e1e09956c2b94ddd379ba46c6859ed40740ea41039a` works - # ! annotations also only apply to sha256 -- not 'branch/tag' versions - - name: Build and push Docker image + - name: Login to container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY_URL }} + username: ${{ env.REGISTRY_USER }} + password: ${{ env.REGISTRY_PASS }} + + - name: Build and push by digest + id: build uses: docker/build-push-action@v6 with: context: . - file: ./${{ matrix.dockerfile }} - push: true - tags: ${{ steps.meta.outputs.tags }} + file: ./Dockerfile + platforms: ${{ matrix.platform }} labels: ${{ steps.meta.outputs.labels }} - platforms: linux/amd64,linux/arm64/v8 - cache-from: type=registry,ref=${{ steps.meta.outputs.tags }} - cache-to: type=registry,ref=${{ steps.meta.outputs.tags }},mode=max - outputs: > - type=image,name=${{ steps.meta.outputs.tags }}, - annotation-index.org.opencontainers.image.description=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.description'] }} + outputs: type=image,name=${{ env.REGISTRY_URL }}/${{ env.REGISTRY_USER }}/${{ steps.image_name.outputs.IMAGE }},push-by-digest=true,name-canonical=true,push=true + + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ env.PLATFORM_PAIR }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + name: Merge and push multi-platform image + runs-on: ubuntu-latest + needs: + - build + steps: + - name: Check out the repo + uses: actions/checkout@v4 + + - name: Set password by container registry + run: | + case "${{ env.REGISTRY_URL }}" in + "ghcr.io") + echo "REGISTRY_PASS=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV + ;; + *) + if [ -n "${{ secrets.REGISTRY_PASS }}" ]; then + echo "REGISTRY_PASS=${{ secrets.REGISTRY_PASS }}" >> $GITHUB_ENV + else + echo "REGISTRY_PASS secret is not set and registry is not recognized. Exiting..." + exit 1 + fi + ;; + esac + + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract image name from Dockerfile + id: image_name + run: | + IMAGE=$(grep "LABEL org.opencontainers.image.title" Dockerfile | cut -d'"' -f2) + echo "IMAGE=$IMAGE" >> $GITHUB_OUTPUT + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY_URL }}/${{ env.REGISTRY_USER }}/${{ steps.image_name.outputs.IMAGE }} + tags: | + type=raw,value=latest,enable={{is_default_branch}} + type=semver,pattern={{version}} + + - name: Login to container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY_URL }} + username: ${{ env.REGISTRY_USER }} + password: ${{ env.REGISTRY_PASS }} + + - name: Create manifest list and push + working-directory: /tmp/digests + run: | + # Escape the JSON for use in jq + ESCAPED_JSON=$(echo '${{ steps.meta.outputs.json }}' | jq -sR .) + + # Use the escaped JSON in the jq command + TAGS=$(jq -r '.tags | map("-t " + .) | join(" ")' <<< $ESCAPED_JSON) + + # Create the manifest list + docker buildx imagetools create $TAGS \ + $(printf '${{ env.REGISTRY_URL }}/${{ env.REGISTRY_USER }}/${{ steps.image_name.outputs.IMAGE }}@sha256:%s ' *) + + - name: Inspect image + run: | + docker buildx imagetools inspect ${{ env.REGISTRY_URL }}/${{ env.REGISTRY_USER }}/${{ steps.image_name.outputs.IMAGE }}:${{ steps.meta.outputs.version }}