1+ # Based on https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners
2+
3+ name : Publish Docker image to Dockerhub
4+
5+ concurrency :
6+ group : ${{ github.workflow }}-${{ github.ref }}
7+ cancel-in-progress : true
8+
9+ on :
10+ workflow_dispatch :
11+ push :
12+ branches :
13+ - ' main'
14+ tags :
15+ - ' *.*.*'
16+ # don't trigger if just updating docs
17+ paths-ignore :
18+ - ' README.md'
19+ - ' .github/**'
20+ - ' .vscode/**'
21+ - ' .devcontainer/**'
22+ # use release instead of tags once version is correctly parsed
23+ # https://github.com/docker/metadata-action/issues/422
24+ # https://github.com/docker/metadata-action/issues/240
25+ # release:
26+ # types: [ published ]
27+
28+ # define in GH Repository -> Actions -> Variables (or act .variables) to enable pushing to registries
29+ # -- will only push to registries that are defined
30+ # EX
31+ # DOCKERHUB_SLUG=foxxmd/multi-scrobbler
32+ # GHCR_SLUG=ghcr.io/foxxmd/multi-scrobbler
33+
34+ jobs :
35+
36+ build :
37+ name : Build OCI Images
38+ if : ${{ github.event_name != 'pull_request' && (vars.DOCKERHUB_SLUG != '' || vars.GHCR_SLUG != '') }}
39+ runs-on : ${{ matrix.os }}
40+ permissions :
41+ packages : write
42+ contents : read
43+ strategy :
44+ fail-fast : false
45+ matrix :
46+ include :
47+ - os : ubuntu-latest
48+ arch : amd64
49+ platform : linux/amd64
50+ - os : ubuntu-24.04-arm
51+ arch : arm64
52+ platform : linux/arm64
53+ steps :
54+ - name : Prepare
55+ run : |
56+ platform=${{ matrix.platform }}
57+ echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
58+
59+ # list all registries to push to and join all non-empty with comma
60+ # https://unix.stackexchange.com/a/693165/116849
61+ # https://stackoverflow.com/a/9429887/1469797
62+ strings=("${{vars.DOCKERHUB_SLUG}}" "${{vars.GHCR_SLUG}}")
63+ for i in ${!strings[@]}; do [[ -z ${strings[i]} ]] && unset strings[i]; done
64+ joined_string=$(IFS=, ; echo "${strings[*]}")
65+ echo "REGISTRIES_JOINED=$joined_string" >> $GITHUB_ENV
66+
67+ - name : Check out the repo
68+ uses : actions/checkout@v4
69+
70+ - name : Set short git commit SHA
71+ id : appvars
72+ # https://dev.to/hectorleiva/github-actions-and-creating-a-short-sha-hash-8b7
73+ # short sha available under env.COMMIT_SHORT_SHA
74+ run : |
75+ calculatedSha=$(git rev-parse --short HEAD)
76+ branchName=$(git rev-parse --abbrev-ref HEAD)
77+ echo "COMMIT_SHORT_SHA=$calculatedSha" >> $GITHUB_ENV
78+ echo "COMMIT_BRANCH=$branchName" >> $GITHUB_ENV
79+
80+ - name : Get App Version
81+ id : appversion
82+ env :
83+ # use release instead of tags once version is correctly parsed
84+ # APP_VERSION: ${{ github.event.release.tag_name }}
85+
86+ # https://github.com/actions/runner/issues/409#issuecomment-752775072
87+ # https://stackoverflow.com/a/69919067/1469797
88+ APP_VERSION : ${{ contains(github.ref, 'refs/tags/') && github.ref_name || format('{0}-{1}', env.COMMIT_BRANCH, env.COMMIT_SHORT_SHA ) }}
89+ run : |
90+ echo appversion=$APP_VERSION >>${GITHUB_OUTPUT}
91+
92+ - name : Login to Docker Hub
93+ if : ${{ github.event_name != 'pull_request' && vars.DOCKERHUB_SLUG != '' }}
94+ uses : docker/login-action@v3
95+ with :
96+ username : ${{ secrets.DOCKER_USERNAME }}
97+ password : ${{ secrets.DOCKER_PASSWORD }}
98+
99+ - name : Login to GitHub Container Registry
100+ if : ${{ github.event_name != 'pull_request' && vars.GHCR_SLUG != '' }}
101+ uses : docker/login-action@v3
102+ with :
103+ registry : ghcr.io
104+ username : ${{ github.repository_owner }}
105+ password : ${{ secrets.GITHUB_TOKEN }}
106+
107+ # metadata extract for docker labels/image names is done in merge job
108+
109+ - name : Set up Docker Buildx
110+ uses : docker/setup-buildx-action@v3
111+
112+ # https://github.com/docker/build-push-action/issues/671#issuecomment-1619353328
113+ # for caching
114+ - name : Build and push by digest
115+ id : build
116+ uses : docker/build-push-action@v6
117+ with :
118+ context : .
119+ file : ./docker/Dockerfile
120+ build-args : |
121+ APP_BUILD_VERSION=${{steps.appversion.outputs.appversion}}
122+ SOURCE=${{inputs.pip_source}}
123+ platforms : ${{ matrix.platform }}
124+ labels : ${{ steps.meta.outputs.labels }}
125+ outputs : type=image,"name=${{ env.REGISTRIES_JOINED }}",push-by-digest=true,name-canonical=true,push=true
126+ # cache-from: type=gha,scope=build-${{ env.PLATFORM_PAIR }}
127+ # cache-to: type=gha,scope=build-${{ env.PLATFORM_PAIR }}
128+
129+ - name : Export digest
130+ run : |
131+ mkdir -p /tmp/digests
132+ digest="${{ steps.build.outputs.digest }}"
133+ touch "/tmp/digests/${digest#sha256:}"
134+
135+ - name : Upload digest
136+ uses : actions/upload-artifact@v4
137+ with :
138+ name : digests-${{ env.PLATFORM_PAIR }}
139+ path : /tmp/digests/*
140+ if-no-files-found : error
141+ retention-days : 1
142+
143+ merge :
144+ name : Merge OCI Images and Push
145+ if : ${{ github.event_name != 'pull_request' && (vars.DOCKERHUB_SLUG != '' || vars.GHCR_SLUG != '') }}
146+ runs-on : ubuntu-latest
147+ permissions :
148+ packages : write
149+ contents : read
150+ needs :
151+ - build
152+ steps :
153+ - name : Download digests
154+ uses : actions/download-artifact@v4
155+ with :
156+ path : /tmp/digests
157+ pattern : digests-*
158+ merge-multiple : true
159+
160+ - name : Login to Docker Hub
161+ if : ${{ github.event_name != 'pull_request' && vars.DOCKERHUB_SLUG != '' }}
162+ uses : docker/login-action@v3
163+ with :
164+ username : ${{ secrets.DOCKER_USERNAME }}
165+ password : ${{ secrets.DOCKER_PASSWORD }}
166+
167+ - name : Login to GitHub Container Registry
168+ if : ${{ github.event_name != 'pull_request' && vars.GHCR_SLUG != '' }}
169+ uses : docker/login-action@v3
170+ with :
171+ registry : ghcr.io
172+ username : ${{ github.repository_owner }}
173+ password : ${{ secrets.GITHUB_TOKEN }}
174+
175+ - name : Set up Docker Buildx
176+ uses : docker/setup-buildx-action@v3
177+
178+ - name : Extract metadata (tags, labels)
179+ id : meta
180+ uses : docker/metadata-action@v5
181+ with :
182+ images : |
183+ ${{ vars.DOCKERHUB_SLUG }}
184+ ${{ vars.GHCR_SLUG }}
185+ # generate Docker tags based on the following events/attributes
186+ # https://github.com/docker/metadata-action/issues/247#issuecomment-1511259674 for NOT is default branch, eventually
187+ tags : |
188+ type=edge
189+
190+ # push with branch name as tag if not master/main
191+ type=ref,event=branch,enable=${{ !endsWith(github.ref, 'main') }}
192+
193+ # tag non-prelease as latest -- has a higher priority than regular tag so it shows first in registries
194+ type=match,pattern=\d.\d.\d$,priority=901
195+
196+ # tag all semver (include pre-release)
197+ type=semver,pattern={{version}}
198+ # flavor: |
199+ # latest=false
200+ labels : |
201+ org.opencontainers.image.title=Docker Proxy Filter
202+ org.opencontainers.image.description=Filter respones and content from Docker API through an http socket
203+ org.opencontainers.image.vendor=FoxxMD
204+
205+ - name : Create manifest list and push dockerhub
206+ if : ${{ vars.DOCKERHUB_SLUG != '' }}
207+ working-directory : /tmp/digests
208+ run : |
209+ docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
210+ $(printf '${{ vars.DOCKERHUB_SLUG }}@sha256:%s ' *)
211+
212+ - name : Create manifest list and push gchr
213+ if : ${{ vars.GHCR_SLUG != '' }}
214+ working-directory : /tmp/digests
215+ run : |
216+ docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
217+ $(printf '${{ vars.GHCR_SLUG }}@sha256:%s ' *)
218+
219+ - name : Inspect image dockerhub
220+ if : ${{ vars.DOCKERHUB_SLUG != '' }}
221+ run : |
222+ docker buildx imagetools inspect ${{ vars.DOCKERHUB_SLUG }}:${{ steps.meta.outputs.version }}
223+
224+ - name : Inspect image ghcr
225+ if : ${{ vars.GHCR_SLUG != '' }}
226+ run : |
227+ docker buildx imagetools inspect ${{ vars.GHCR_SLUG }}:${{ steps.meta.outputs.version }}
0 commit comments