1717 - .github/workflows/release.yml
1818 - .github/workflows/auto-merge.yml
1919 - .github/workflows/ruff.yml
20- release :
21- types : [published]
20+ workflow_run :
21+ workflows : [ "Release" ]
22+ types :
23+ - completed
2224 workflow_dispatch :
2325
26+ env :
27+ LATEST_PYTHON_VERSION : " 3.13"
28+
2429jobs :
25- build-and-push :
30+ metadata :
2631 runs-on : ubuntu-latest
32+ if : |-
33+ github.event_name != 'workflow_run' ||
34+ (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success')
2735 permissions :
2836 contents : read
29- packages : write
37+ outputs :
38+ LATEST_RELEASE : ${{ steps.workflow.outputs.LATEST_RELEASE || steps.api.outputs.LATEST_RELEASE }}
3039
40+ steps :
41+ - name : Get latest release from previous workflow
42+ id : workflow
43+ if : github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success'
44+ run : |
45+ tag=${{ github.event.workflow_run.head_branch }}
46+ echo "LATEST_RELEASE=${tag#refs/tags/}" >> $GITHUB_OUTPUT
47+
48+ - name : Get latest release from api
49+ id : api
50+ if : github.event_name != 'workflow_run'
51+ run : |
52+ gh api repos/${{ github.repository }}/releases/latest | jq -r '.tag_name' | xargs -0 printf "LATEST_RELEASE=%s" >> $GITHUB_OUTPUT
53+ env :
54+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
55+
56+
57+ build :
58+ runs-on : ubuntu-latest
59+ needs : metadata
60+ permissions :
61+ contents : read
62+ packages : write
63+ concurrency :
64+ group : ${{ github.workflow }}-${{ needs.metadata.outputs.LATEST_RELEASE }}-${{ matrix.python_version }}${{ matrix.python_variant }}-${{ matrix.platform }}
65+ cancel-in-progress : true
66+ strategy :
67+ fail-fast : true
68+ matrix :
69+ python_version :
70+ - " 3.9"
71+ - " 3.10"
72+ - " 3.11"
73+ - " 3.12"
74+ - " 3.13"
75+ python_variant :
76+ - " "
77+ - " -slim"
78+ platform :
79+ - linux/amd64
80+ - linux/arm64
81+ - linux/arm
3182 steps :
3283 - name : Checkout
3384 uses : actions/checkout@v5
85+ with :
86+ ref : ${{ needs.metadata.outputs.LATEST_RELEASE}}
3487
3588 - name : Set up QEMU
3689 uses : docker/setup-qemu-action@v3
@@ -46,22 +99,149 @@ jobs:
4699 username : ${{ github.repository_owner }}
47100 password : ${{ secrets.GIT_TOKEN }}
48101
49- - name : Extract metadata
50- id : meta
102+ - name : Generate Image Name and Scope
103+ id : image
104+ run : |
105+ echp "IMAGE=ghcr.io/${{ github.repository }}" >> $GITHUB_OUTPUT
106+ echo "SCOPE=${{ hashFiles('**/pdm.lock') }}-${{ matrix.python_version }}${{ matrix.python_variant }}-${{ matrix.platform }}" >> $GITHUB_OUTPUT
107+ platform="${{ matrix.platform }}"
108+ echo "ARTIFACT=${{ matrix.python_version }}${{ matrix.python_variant }}-${platform/\//-}-digests" >> $GITHUB_OUTPUT
109+
110+ - name : Generate Labels
51111 uses : docker/metadata-action@v5
112+ id : metadata
52113 with :
53- images : ghcr.io/${{ github.repository }}
54- tags : |
55- type=edge,value=nightly
56- type=sha,event=branch
57- type=ref,event=tag
58- type=ref,event=pr
59-
60- - name : Build and push
114+ images : ${{ steps.image.outputs.IMAGE }}
115+
116+ - name : Build and Publish
61117 uses : docker/build-push-action@v6
118+ id : build
62119 with :
63120 context : .
64- file : Dockerfile
121+ platforms : ${{ matrix.platform }}
65122 push : ${{ github.event_name != 'pull_request' }}
66- tags : ${{ steps.meta.outputs.tags }}
67- labels : ${{ steps.meta.outputs.labels }}
123+ build-args : |
124+ PYTHON_IMAGE=${{ matrix.python_version }}
125+ VARIANT=${{ matrix.python_variant }}
126+ labels : ${{ steps.metadata.outputs.labels }}
127+ cache-from : type=gha,scope=${{ steps.image.outputs.SCOPE }}
128+ cache-to : type=gha,scope=${{ steps.image.outputs.SCOPE }},mode=max
129+ outputs : type=image,name=${{ steps.image.outputs.IMAGE }},push-by-digest=true,name-canonical=true,push=true
130+
131+ - name : Export digest
132+ run : |
133+ mkdir -p /tmp/digests/
134+ digest="${{ steps.build.outputs.digest }}"
135+ touch "/tmp/digests/${digest#sha256:}"
136+
137+ - name : Upload digest
138+ uses : actions/upload-artifact@v4
139+ with :
140+ name : ${{ steps.image.outputs.ARTIFACT }}
141+ path : /tmp/digests/*
142+ if-no-files-found : error
143+ retention-days : 1
144+
145+ push :
146+ runs-on : ubuntu-latest
147+ needs : [metadata, build]
148+ strategy :
149+ matrix :
150+ python_version :
151+ - " 3.9"
152+ - " 3.10"
153+ - " 3.11"
154+ - " 3.12"
155+ - " 3.13"
156+ python_variant :
157+ - " "
158+ - " -slim"
159+
160+ steps :
161+ - name : Checkout
162+ uses : actions/checkout@v5
163+ with :
164+ ref : ${{ needs.metadata.outputs.LATEST_RELEASE }}
165+
166+ - name : Download digests
167+ uses : actions/download-artifact@v5
168+ with :
169+ path : /tmp/artifacts
170+ pattern : " *-digests"
171+
172+ - name : Copy digests
173+ run : |
174+ mkdir -p /tmp/digests
175+ cp /tmp/artifacts/${{ matrix.python_version }}${{ matrix.python_variant }}-*-digests/* /tmp/digests
176+
177+ - name : Set up Docker Buildx
178+ uses : docker/setup-buildx-action@v3
179+
180+ - name : Login to GitHub Container Registry
181+ uses : docker/login-action@v3
182+ if : github.event_name != 'pull_request'
183+ with :
184+ registry : ghcr.io
185+ username : ${{ github.repository_owner }}
186+ password : ${{ secrets.GIT_TOKEN }}
187+
188+ - name : Generate Image Name
189+ id : image
190+ run : |
191+ echo "IMAGE=ghcr.io/${{ github.repository }}" >> $GITHUB_OUTPUT
192+
193+ - name : Generate Tags
194+ uses : docker/metadata-action@v5
195+ id : metadata
196+ with :
197+ context : git
198+ images : |
199+ ghcr.io/${{ github.repository }}
200+ flavor : |
201+ suffix=-py${{ matrix.python_version }}${{ matrix.python_variant }},onlatest=true
202+ tags : |
203+ type=edge,value=nightly
204+ type=ref,event=pr
205+ type=sha,event=branch
206+ type=semver,pattern={{version}}
207+ type=semver,pattern={{major}}.{{minor}}
208+ type=semver,pattern={{major}}
209+
210+ - name : Create manifest list and push
211+ working-directory : /tmp/digests
212+ run : |
213+ docker buildx imagetools create --dry-run $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
214+ $(printf '${{ steps.image.outputs.IMAGE }}@sha256:%s ' *)
215+ docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
216+ $(printf '${{ steps.image.outputs.IMAGE }}@sha256:%s ' *)
217+
218+ - name : Generate Tags
219+ uses : docker/metadata-action@v5
220+ id : metadata-latest
221+ if : matrix.python_version == env.LATEST_PYTHON_VERSION
222+ with :
223+ context : git
224+ images : |
225+ ghcr.io/${{ github.repository }}
226+ flavor : |
227+ suffix=${{ matrix.python_variant }},onlatest=true
228+ tags : |
229+ type=semver,pattern={{version}}
230+ type=semver,pattern={{major}}.{{minor}}
231+ type=semver,pattern={{major}}
232+
233+ - name : Create manifest list and push for latest python version
234+ if : matrix.python_version == env.LATEST_PYTHON_VERSION
235+ working-directory : /tmp/digests
236+ run : |
237+ docker buildx imagetools create --dry-run $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
238+ $(printf '${{ steps.image.outputs.IMAGE }}@sha256:%s ' *)
239+ docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
240+ $(printf '${{ steps.image.outputs.IMAGE }}@sha256:%s ' *)
241+
242+ - name : Docker Hub Description
243+ uses : peter-evans/dockerhub-description@v4
244+ with :
245+ username : ${{ secrets.DOCKERHUB_USERNAME }}
246+ password : ${{ secrets.DOCKERHUB_PASSWORD }}
247+ short-description : ${{ github.event.repository.description }}
0 commit comments