@@ -106,43 +106,124 @@ jobs:
106106 NODE_ENV : test
107107
108108 build :
109- runs-on : ubuntu-24.04-arm
110109 permissions :
111110 contents : read
112111 packages : write
113112 id-token : write
113+ strategy :
114+ fail-fast : false
115+ matrix :
116+ include :
117+ - platform : linux/amd64
118+ runner : ubuntu-24.04
119+ platform_pair : amd64
120+ - platform : linux/arm64
121+ runner : ubuntu-24.04-arm
122+ platform_pair : arm64
123+ runs-on : ${{ matrix.runner }}
114124
115125 steps :
126+ - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
127+ with :
128+ persist-credentials : false
129+
130+ - name : Set lowercase image name
131+ id : image
132+ run : echo "name=ghcr.io/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT"
133+
134+ - name : Set up Docker Buildx
135+ uses : docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
136+
137+ - name : Login to GHCR
138+ if : github.event_name == 'push'
139+ uses : docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
140+ with :
141+ registry : ghcr.io
142+ username : ${{ github.actor }}
143+ password : ${{ secrets.GITHUB_TOKEN }}
144+
116145 - name : Docker meta
117146 id : meta
118147 uses : docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
119148 with :
120- images : |
121- ghcr.io/${{ github.repository }}
122- tags : |
123- type=raw,value={{sha}}
124- type=raw,value=latest
149+ images : ${{ steps.image.outputs.name }}
150+
151+ - name : Build and push by digest
152+ id : build
153+ uses : docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
154+ with :
155+ context : .
156+ platforms : ${{ matrix.platform }}
157+ labels : ${{ steps.meta.outputs.labels }}
158+ outputs : type=image,name=${{ steps.image.outputs.name }},push-by-digest=true,name-canonical=true,push=${{ github.event_name == 'push' }}
159+ cache-from : type=gha,scope=${{ matrix.platform_pair }}
160+ cache-to : type=gha,mode=max,scope=${{ matrix.platform_pair }}
161+
162+ - name : Export digest
163+ if : github.event_name == 'push'
164+ run : |
165+ mkdir -p /tmp/digests
166+ digest="${{ steps.build.outputs.digest }}"
167+ touch "/tmp/digests/${digest#sha256:}"
168+
169+ - name : Upload digest
170+ if : github.event_name == 'push'
171+ uses : actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v6.0.1
172+ with :
173+ name : digest-${{ matrix.platform_pair }}
174+ path : /tmp/digests/*
175+ if-no-files-found : error
176+ retention-days : 1
177+
178+ build-merge :
179+ if : github.event_name == 'push'
180+ needs : [build]
181+ runs-on : ubuntu-24.04
182+ permissions :
183+ contents : read
184+ packages : write
185+
186+ steps :
187+ - name : Set lowercase image name
188+ id : image
189+ run : echo "name=ghcr.io/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT"
190+
191+ - name : Download digests
192+ uses : actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
193+ with :
194+ pattern : digest-*
195+ path : /tmp/digests
196+ merge-multiple : true
197+
198+ - name : Set up Docker Buildx
199+ uses : docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
125200
126201 - name : Login to GHCR
127- if : github.ref == 'refs/heads/main'
128202 uses : docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
129203 with :
130204 registry : ghcr.io
131205 username : ${{ github.actor }}
132206 password : ${{ secrets.GITHUB_TOKEN }}
133207
134- - name : Build and maybe Push Docker image
135- uses : docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
208+ - name : Docker meta
209+ id : meta
210+ uses : docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
136211 with :
137- push : ${{ github.ref == 'refs/heads/main' }}
138- tags : ${{ steps.meta.outputs.tags }}
139- labels : ${{ steps.meta.outputs.labels }}
140- # cache-from: type=gha
141- # cache-to: type=gha,mode=max
212+ images : ${{ steps.image.outputs.name }}
213+ tags : |
214+ type=raw,value={{sha}}
215+ type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
216+
217+ - name : Create and push manifest
218+ working-directory : /tmp/digests
219+ run : |
220+ docker buildx imagetools create \
221+ $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta.outputs.json }}') \
222+ $(printf '${{ steps.image.outputs.name }}@sha256:%s ' *)
142223
143224 deploy :
144225 if : github.ref == 'refs/heads/main'
145- needs : [lint, test, typecheck, build]
226+ needs : [lint, test, typecheck, build-merge ]
146227 runs-on : ubuntu-slim
147228 environment :
148229 name : prod
0 commit comments