Skip to content

Publish Docker image to Dockerhub #338

Publish Docker image to Dockerhub

Publish Docker image to Dockerhub #338

Workflow file for this run

# 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: ubuntu-latest
permissions:
packages: write
contents: read
strategy:
fail-fast: false
matrix:
# does this need os/arch instead of platform? https://learn.arm.com/learning-paths/cross-platform/github-arm-runners/actions/
# platform:
# - linux/amd64
# - linux/arm64
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
# REMOVE(??) once arm runners are publicly available
# https://github.com/orgs/community/discussions/142209#discussioncomment-11107737
# https://github.com/github/roadmap/issues/970
# - name: Set up QEMU
# uses: docker/setup-qemu-action@v3
- 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 }}