# Based on https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners name: Publish Docker image to Dockerhub concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true on: workflow_dispatch: push: branches: - 'master' tags: - '*.*.*' # don't trigger if just updating docs paths-ignore: - 'README.md' - '.github/**' - 'flatpak/**' # use release instead of tags once version is correctly parsed # https://github.com/docker/metadata-action/issues/422 # https://github.com/docker/metadata-action/issues/240 # release: # types: [ published ] # define in GH Repository -> Actions -> Variables (or act .variables) to enable pushing to registries # -- will only push to registries that are defined # EX # DOCKERHUB_SLUG=foxxmd/multi-scrobbler # GHCR_SLUG=ghcr.io/foxxmd/multi-scrobbler jobs: test: if: github.event_name != 'pull_request' uses: ./.github/workflows/testAndSanity.yml build: name: Build OCI Images if: ${{ github.event_name != 'pull_request' && (vars.DOCKERHUB_SLUG != '' || vars.GHCR_SLUG != '') }} needs: test runs-on: ${{ matrix.os }} permissions: packages: write contents: read strategy: fail-fast: false matrix: include: - os: ubuntu-latest arch: amd64 platform: linux/amd64 - os: ubuntu-24.04-arm arch: arm64 platform: linux/arm64 steps: - name: Prepare run: | platform=${{ matrix.platform }} echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV # list all registries to push to and join all non-empty with comma # https://unix.stackexchange.com/a/693165/116849 # https://stackoverflow.com/a/9429887/1469797 strings=("${{vars.DOCKERHUB_SLUG}}" "${{vars.GHCR_SLUG}}") for i in ${!strings[@]}; do [[ -z ${strings[i]} ]] && unset strings[i]; done joined_string=$(IFS=, ; echo "${strings[*]}") echo "REGISTRIES_JOINED=$joined_string" >> $GITHUB_ENV - name: Check out the repo uses: actions/checkout@v4 - name: Set short git commit SHA id: appvars # https://dev.to/hectorleiva/github-actions-and-creating-a-short-sha-hash-8b7 # short sha available under env.COMMIT_SHORT_SHA run: | calculatedSha=$(git rev-parse --short HEAD) branchName=$(git rev-parse --abbrev-ref HEAD) echo "COMMIT_SHORT_SHA=$calculatedSha" >> $GITHUB_ENV echo "COMMIT_BRANCH=$branchName" >> $GITHUB_ENV - name: Get App Version id: appversion env: # use release instead of tags once version is correctly parsed #APP_VERSION: ${{ github.event.release.tag_name }} # https://github.com/actions/runner/issues/409#issuecomment-752775072 # https://stackoverflow.com/a/69919067/1469797 APP_VERSION: ${{ contains(github.ref, 'refs/tags/') && github.ref_name || format('{0}-{1}', env.COMMIT_BRANCH, env.COMMIT_SHORT_SHA ) }} run: | echo appversion=$APP_VERSION >>${GITHUB_OUTPUT} - name: Login to Docker Hub if: ${{ github.event_name != 'pull_request' && vars.DOCKERHUB_SLUG != '' }} uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Login to GitHub Container Registry if: ${{ github.event_name != 'pull_request' && vars.GHCR_SLUG != '' }} uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} # metadata extract for docker labels/image names is done in merge job - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 # https://github.com/docker/build-push-action/issues/671#issuecomment-1619353328 # for caching - name: Build and push by digest id: build uses: docker/build-push-action@v6 with: build-args: | APP_BUILD_VERSION=${{steps.appversion.outputs.appversion}} platforms: ${{ matrix.platform }} labels: ${{ steps.meta.outputs.labels }} outputs: type=image,"name=${{ env.REGISTRIES_JOINED }}",push-by-digest=true,name-canonical=true,push=true #cache-from: type=gha,scope=build-${{ env.PLATFORM_PAIR }} #cache-to: type=gha,scope=build-${{ env.PLATFORM_PAIR }} - 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 OCI Images and Push if: ${{ github.event_name != 'pull_request' && (vars.DOCKERHUB_SLUG != '' || vars.GHCR_SLUG != '') }} runs-on: ubuntu-latest permissions: packages: write contents: read needs: - build - test steps: - name: Download digests uses: actions/download-artifact@v4 with: path: /tmp/digests pattern: digests-* merge-multiple: true - name: Login to Docker Hub if: ${{ github.event_name != 'pull_request' && vars.DOCKERHUB_SLUG != '' }} uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Login to GitHub Container Registry if: ${{ github.event_name != 'pull_request' && vars.GHCR_SLUG != '' }} uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Extract metadata (tags, labels) id: meta uses: docker/metadata-action@v5 with: images: | ${{ vars.DOCKERHUB_SLUG }} ${{ vars.GHCR_SLUG }} # generate Docker tags based on the following events/attributes # https://github.com/docker/metadata-action/issues/247#issuecomment-1511259674 for NOT is default branch, eventually tags: | type=edge # push with branch name as tag if not master/main type=ref,event=branch,enable=${{ !endsWith(github.ref, 'master') }} # tag non-prelease as latest -- has a higher priority than regular tag so it shows first in registries type=match,pattern=\d.\d.\d$,priority=901 # tag all semver (include pre-release) type=semver,pattern={{version}} # flavor: | # latest=false labels: | org.opencontainers.image.title=Multi-Scrobbler org.opencontainers.image.description=Scrobble from many sources to many clients org.opencontainers.image.vendor=FoxxMD - name: Create manifest list and push dockerhub if: ${{ vars.DOCKERHUB_SLUG != '' }} working-directory: /tmp/digests run: | docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ $(printf '${{ vars.DOCKERHUB_SLUG }}@sha256:%s ' *) - name: Create manifest list and push gchr if: ${{ vars.GHCR_SLUG != '' }} working-directory: /tmp/digests run: | docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ $(printf '${{ vars.GHCR_SLUG }}@sha256:%s ' *) - name: Inspect image dockerhub if: ${{ vars.DOCKERHUB_SLUG != '' }} run: | docker buildx imagetools inspect ${{ vars.DOCKERHUB_SLUG }}:${{ steps.meta.outputs.version }} - name: Inspect image ghcr if: ${{ vars.GHCR_SLUG != '' }} run: | docker buildx imagetools inspect ${{ vars.GHCR_SLUG }}:${{ steps.meta.outputs.version }}