@@ -3,20 +3,33 @@ name: Publish Docker image
33on :
44 release :
55 types : [published]
6- push :
7- branches :
8- - " *"
6+ push :
7+ branches : ["*"]
98 pull_request : {}
109
10+ permissions :
11+ packages : write
12+ contents : write
13+ attestations : write
14+ id-token : write
15+
1116jobs :
12- push_to_registry :
13- name : Build (and push if publishing release)
14- runs-on : ubuntu-latest
15- permissions :
16- packages : write
17- contents : write
18- attestations : write
19- id-token : write
17+ build :
18+ name : Build ${{ matrix.platform }}
19+ strategy :
20+ fail-fast : false
21+ matrix :
22+ include :
23+ - arch : amd64
24+ platform : linux/amd64
25+ runner : ubuntu-latest
26+ tag_suffix : -amd64
27+ - arch : arm64
28+ platform : linux/arm64
29+ runner : ubuntu-24.04-arm
30+ tag_suffix : -arm64
31+
32+ runs-on : ${{ matrix.runner }}
2033
2134 steps :
2235 - name : Check out the repo
@@ -25,70 +38,86 @@ jobs:
2538 lfs : ' true'
2639 submodules : ' recursive'
2740
28- # Only log in when we actually intend to push (release event).
2941 - name : Log in to Docker Hub
3042 if : github.event_name == 'release'
31- uses : docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
43+ uses : docker/login-action@v3
3244 with :
3345 username : ${{ secrets.DOCKERHUB_USERNAME }}
3446 password : ${{ secrets.DOCKERHUB_PASSWORD }}
3547
36- # Multi-arch setup only needed for release builds.
37- - name : Set up QEMU (release only)
38- if : github.event_name == 'release'
39- uses : docker/setup-qemu-action@v3
40-
41- - name : Set up Docker Buildx (release only)
42- if : github.event_name == 'release'
43- uses : docker/setup-buildx-action@v3
44-
45- - name : Extract metadata (tags, labels) for Docker
48+ - name : Extract metadata (tags, labels)
4649 id : meta
47- uses : docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
50+ uses : docker/metadata-action@v5
4851 with :
4952 images : alloverse/alloplace3
5053
51- # Validation build for pushes/PRs : single-arch, no push.
52- - name : Build Docker image (validation, no push)
54+ # Validation builds (push/PR) : single-arch, no push
55+ - name : Build image (validation only , no push)
5356 if : github.event_name != 'release'
54- uses : docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
57+ uses : docker/build-push-action@v6
5558 with :
5659 context : .
5760 file : ./Dockerfile
61+ platforms : ${{ matrix.platform }}
5862 push : false
59- platforms : linux/amd64
6063 tags : ${{ steps.meta.outputs.tags }}
6164 labels : ${{ steps.meta.outputs.labels }}
6265
63- # Release build: multi-platform and pushed.
64- - name : Build & push Docker image (multi-platform, release)
66+ # Release builds: push single-arch image with suffix
67+ - name : Build & push image (release)
6568 if : github.event_name == 'release'
66- id : push
67- uses : docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
69+ id : push_single
70+ uses : docker/build-push-action@v6
6871 with :
6972 context : .
7073 file : ./Dockerfile
71- platforms : linux/amd64,linux/arm64
74+ platforms : ${{ matrix.platform }}
7275 push : true
73- tags : ${{ steps.meta.outputs.tags }}
76+ provenance : false
77+ sbom : false
78+ tags : alloverse/alloplace3:${{ github.event.release.tag_name }}${{ matrix.tag_suffix }}
7479 labels : ${{ steps.meta.outputs.labels }}
7580
76- # Attestation only makes sense when an image was pushed.
81+ publish_manifest :
82+ name : Create multi-arch tag(s), attest, & update notes
83+ needs : build
84+ if : github.event_name == 'release'
85+ runs-on : ubuntu-latest
86+ steps :
87+ - name : Log in to Docker Hub
88+ uses : docker/login-action@v3
89+ with :
90+ username : ${{ secrets.DOCKERHUB_USERNAME }}
91+ password : ${{ secrets.DOCKERHUB_PASSWORD }}
92+
93+ - name : Create multi-arch manifest (tag + latest)
94+ run : |
95+ IMAGE=alloverse/alloplace3:${{ github.event.release.tag_name }}
96+ docker buildx imagetools create \
97+ -t "${IMAGE}" \
98+ -t alloverse/alloplace3:latest \
99+ "${IMAGE}-amd64" \
100+ "${IMAGE}-arm64"
101+
102+ - name : Inspect manifest (get digest)
103+ id : insp
104+ run : |
105+ IMAGE=alloverse/alloplace3:${{ github.event.release.tag_name }}
106+ docker buildx imagetools inspect --raw "$IMAGE" | sha256sum | awk '{print "sha256:"$1}' > digest.txt
107+ echo "digest=$(cat digest.txt)" >> $GITHUB_OUTPUT
108+
77109 - name : Generate artifact attestation
78- if : github.event_name == 'release'
79110 uses : actions/attest-build-provenance@v2
80111 with :
81112 subject-name : index.docker.io/alloverse/alloplace3
82- subject-digest : ${{ steps.push .outputs.digest }}
113+ subject-digest : ${{ steps.insp .outputs.digest }}
83114 push-to-registry : true
84115
85- # Append Docker image info to the release notes
86116 - name : Update release notes with Docker instructions
87- if : github.event_name == 'release'
88117 uses : actions/github-script@v7
89118 env :
90119 IMAGE_BASE : alloverse/alloplace3
91- IMAGE_DIGEST : ${{ steps.push .outputs.digest }}
120+ IMAGE_DIGEST : ${{ steps.insp .outputs.digest }}
92121 with :
93122 script : |
94123 const rel = context.payload.release;
@@ -102,11 +131,12 @@ jobs:
102131 '',
103132 '```bash',
104133 `docker pull ${image}`,
134+ `docker pull ${process.env.IMAGE_BASE}:latest`,
105135 `docker run --rm -it -p 9080:9080 ${image}`,
106136 '```',
107137 '',
108- 'Multi-arch : `linux/amd64, linux/arm64`.',
109- process.env.IMAGE_DIGEST ? `Digest : \`${process.env.IMAGE_DIGEST}\`.` : '',
138+ 'Architectures : `linux/amd64, linux/arm64`.',
139+ process.env.IMAGE_DIGEST ? `Manifest digest : \`${process.env.IMAGE_DIGEST}\`.` : '',
110140 ''
111141 ].join('\n');
112142 const body = (rel.body || '') + '\n\n' + snippet;
0 commit comments