1717 - uses : actions/checkout@v6
1818 - uses : nextstrain/.github/actions/shellcheck@master
1919
20- # Build multi-platform builder and final images with caching from Docker Hub
21- # and GitHub Container Registry; push to GitHub Container Registry.
22- build :
20+ vars :
2321 runs-on : ubuntu-latest
2422 steps :
25-
26- - uses : actions/checkout@v6
27-
28- - uses : actions/setup-python@v6
29- with :
30- python-version : ' >=3.8'
31-
3223 - name : Set $CACHE_DATE
3324 run : echo "CACHE_DATE=$(date --utc +%Y%m%dT%H%M%SZ)" | tee -a "$GITHUB_ENV"
3425
4233 # and hyphens.
4334 run : echo "TAG=branch-${GITHUB_REF_NAME//[^A-Za-z0-9._-]/-}" | tee -a "$GITHUB_ENV"
4435
45- - uses : docker/setup-qemu-action@v3
36+ outputs :
37+ cache-date : ${{ env.CACHE_DATE }}
38+ tag : ${{ env.TAG }}
39+
40+ # Build platform-specific builder and final images with caching from Docker
41+ # Hub and GitHub Container Registry; push to GitHub Container Registry.
42+ build :
43+ name : build (${{ matrix.platform }})
44+ needs : vars
45+ runs-on : ${{ matrix.runner }}
46+ strategy :
47+ matrix :
48+ include :
49+ - platform : linux/amd64
50+ arch : amd64
51+ runner : ubuntu-latest
52+
53+ - platform : linux/arm64
54+ arch : arm64
55+ runner : ubuntu-24.04-arm
56+ steps :
57+
58+ - uses : actions/checkout@v6
59+
60+ - uses : actions/setup-python@v6
61+ with :
62+ python-version : ' >=3.8'
4663
4764 # GITHUB_TOKEN is unreliable¹ so use a token from nextstrain-bot.
4865 # ¹ https://github.com/docker/build-push-action/issues/463#issuecomment-939394233
@@ -52,21 +69,29 @@ jobs:
5269 username : nextstrain-bot
5370 password : ${{ secrets.GH_TOKEN_NEXTSTRAIN_BOT_MANAGE_PACKAGES }}
5471
55- - run : ./devel/build -p linux/amd64,linux/arm64 -r ghcr.io -t "$TAG" -l logs/
72+ - run : |
73+ ./devel/build \
74+ -p ${{ matrix.platform }} \
75+ -r ghcr.io \
76+ -t "$TAG-${{ matrix.arch }}" \
77+ -l logs-${{ matrix.arch }}/
78+ env:
79+ TAG: ${{ needs.vars.outputs.tag }}
80+ CACHE_DATE: ${{ needs.vars.outputs.cache-date }}
5681
5782 - if : always()
5883 name : Upload build logs as artifacts
5984 uses : actions/upload-artifact@v6
6085 with :
61- name : build-logs
62- path : logs/
86+ name : build-logs-${{ matrix.arch }}
87+ path : logs-${{ matrix.arch }} /
6388
6489 - if : always()
6590 name : Summarize build logs for the GitHub Actions run summary page
6691 run : |
67- for log in logs/*; do
92+ for log in logs-${{ matrix.arch }} /*; do
6893 {
69- echo "## $(basename "$log")"
94+ echo "## [${{ matrix.platform }}] $(basename "$log")"
7095 echo ''
7196 echo '```'
7297 ./devel/summarize-buildkit-output "$log" 2>&1
@@ -75,19 +100,55 @@ jobs:
75100 } >> "$GITHUB_STEP_SUMMARY"
76101 done
77102
78- outputs :
79- tag : ${{ env.TAG }}
103+ # Merge platform-specific images into multi-platform images
104+ merge-builds :
105+ needs : [vars, build]
106+ runs-on : ubuntu-latest
107+ env :
108+ TAG : ${{ needs.vars.outputs.tag }}
109+ steps :
110+ - uses : docker/login-action@v3
111+ with :
112+ registry : ghcr.io
113+ username : nextstrain-bot
114+ password : ${{ secrets.GH_TOKEN_NEXTSTRAIN_BOT_MANAGE_PACKAGES }}
115+
116+ - name : Create base-builder-build-platform image
117+ run : |
118+ docker buildx imagetools create \
119+ -t "ghcr.io/nextstrain/base-builder-build-platform:$TAG" \
120+ "ghcr.io/nextstrain/base-builder-build-platform:$TAG-amd64" \
121+ "ghcr.io/nextstrain/base-builder-build-platform:$TAG-arm64"
122+
123+ - name : Create base-builder-target-platform image
124+ run : |
125+ docker buildx imagetools create \
126+ -t "ghcr.io/nextstrain/base-builder-target-platform:$TAG" \
127+ "ghcr.io/nextstrain/base-builder-target-platform:$TAG-amd64" \
128+ "ghcr.io/nextstrain/base-builder-target-platform:$TAG-arm64"
129+
130+ - name : Create base image
131+ run : |
132+ docker buildx imagetools create \
133+ -t "ghcr.io/nextstrain/base:$TAG" \
134+ "ghcr.io/nextstrain/base:$TAG-amd64" \
135+ "ghcr.io/nextstrain/base:$TAG-arm64"
80136
81137 # Run tests with the final image from GitHub Container Registry.
82138 test :
83139 name : test (${{ matrix.platform }})
84- needs : build
85- runs-on : ubuntu-latest
140+ needs : [vars, merge-builds]
141+ runs-on : ${{ matrix.runner }}
86142 strategy :
87143 matrix :
88- platform :
89- - linux/amd64
90- - linux/arm64
144+ include :
145+ - platform : linux/amd64
146+ runner : ubuntu-latest
147+ - platform : linux/arm64
148+ # TODO: use ubuntu-24.04-arm and remove emulation when Nextstrain
149+ # CLI can be installed natively on aarch64.¹
150+ # ¹ <https://github.com/nextstrain/cli/pull/490>
151+ runner : ubuntu-latest
91152 permissions :
92153 contents : read
93154 id-token : write
@@ -108,9 +169,7 @@ jobs:
108169 with :
109170 python-version : ~3
110171
111- # The ubuntu-latest runner is linux/amd64 so anything else will
112- # run with emulation, which is still better than nothing.
113- - if : matrix.platform != 'linux/amd64'
172+ - if : matrix.platform == 'linux/arm64'
114173 uses : docker/setup-qemu-action@v3
115174
116175 - uses : actions/checkout@v6
@@ -119,21 +178,21 @@ jobs:
119178
120179 - run : make test
121180 env :
122- IMAGE : ghcr.io/nextstrain/base:${{ needs.build .outputs.tag }}
181+ IMAGE : ghcr.io/nextstrain/base:${{ needs.vars .outputs.tag }}
123182 DOCKER_DEFAULT_PLATFORM : ${{ matrix.platform }}
124183
125184 - uses : nextstrain/.github/actions/setup-nextstrain-cli@master
126185
127186 - name : Run zika-tutorial
128187 run : |
129188 git clone https://github.com/nextstrain/zika-tutorial
130- nextstrain build --image ghcr.io/nextstrain/base:${{ needs.build .outputs.tag }} zika-tutorial -F
189+ nextstrain build --image ghcr.io/nextstrain/base:${{ needs.vars .outputs.tag }} zika-tutorial -F
131190 env :
132191 DOCKER_DEFAULT_PLATFORM : ${{ matrix.platform }}
133192
134193 validate-platforms :
135194 name : Validate platforms
136- needs : build
195+ needs : [vars, merge-builds]
137196 runs-on : ubuntu-latest
138197 steps :
139198 - uses : actions/checkout@v6
@@ -147,13 +206,13 @@ jobs:
147206 password : ${{ secrets.GH_TOKEN_NEXTSTRAIN_BOT_MANAGE_PACKAGES }}
148207
149208 - name : Validate final images
150- run : ./devel/validate-platforms -r ghcr.io -t ${{ needs.build .outputs.tag }}
209+ run : ./devel/validate-platforms -r ghcr.io -t ${{ needs.vars .outputs.tag }}
151210
152211 # "Push" (copy) the builder and final images from GitHub Container Registry to
153212 # Docker Hub, where they will persist. Do this regardless of test results.
154213 push-branch :
155- if : startsWith(needs.build .outputs.tag, 'branch-') && github.event_name != 'pull_request'
156- needs : build
214+ if : startsWith(needs.vars .outputs.tag, 'branch-') && github.event_name != 'pull_request'
215+ needs : [vars, merge-builds]
157216 runs-on : ubuntu-latest
158217 steps :
159218 - uses : actions/checkout@v6
@@ -171,13 +230,13 @@ jobs:
171230 password : ${{ secrets.DOCKER_TOKEN }}
172231
173232 - name : Copy $TAG images to Docker Hub
174- run : ./devel/copy-images -i ghcr.io -o docker.io -t ${{ needs.build .outputs.tag }}
233+ run : ./devel/copy-images -i ghcr.io -o docker.io -t ${{ needs.vars .outputs.tag }}
175234
176235 # "Push" (copy) the builder and final images from GitHub Container Registry to
177236 # Docker Hub, where they will persist. Only do this if tests pass.
178237 push-build :
179- if : startsWith(needs.build .outputs.tag, 'build-')
180- needs : [build , test, validate-platforms]
238+ if : startsWith(needs.vars .outputs.tag, 'build-')
239+ needs : [vars, merge-builds , test, validate-platforms]
181240 runs-on : ubuntu-latest
182241 steps :
183242 - uses : actions/checkout@v6
@@ -196,7 +255,7 @@ jobs:
196255
197256 - name : Copy $TAG + latest images to Docker Hub
198257 run : |
199- ./devel/copy-images -i ghcr.io -o docker.io -t ${{ needs.build .outputs.tag }} -l
258+ ./devel/copy-images -i ghcr.io -o docker.io -t ${{ needs.vars .outputs.tag }} -l
200259
201260 # Run pathogen repo CI builds with the final image
202261 # This is running pathogen-repo-ci@v0 for pathogen repos that do not conform
@@ -206,7 +265,7 @@ jobs:
206265 test-pathogen-repo-ci-v0 :
207266 # Only one of push-{branch,build} runs for any given workflow run, and
208267 # we're ok with either of them.
209- needs : [build , push-branch, push-build]
268+ needs : [vars , push-branch, push-build]
210269 if : |2
211270 success()
212271 || needs.push-branch.result == 'success'
@@ -227,7 +286,7 @@ jobs:
227286 runtimes : |
228287 - docker
229288 env : |
230- NEXTSTRAIN_DOCKER_IMAGE: nextstrain/base:${{ needs.build .outputs.tag }}
289+ NEXTSTRAIN_DOCKER_IMAGE: nextstrain/base:${{ needs.vars .outputs.tag }}
231290 artifact-name : ${{ matrix.pathogen }}-outputs
232291 continue-on-error : true
233292 secrets : inherit
@@ -239,7 +298,7 @@ jobs:
239298 test-pathogen-repo-ci :
240299 # Only one of push-{branch,build} runs for any given workflow run, and
241300 # we're ok with either of them.
242- needs : [build , push-branch, push-build]
301+ needs : [vars , push-branch, push-build]
243302 if : |2
244303 success()
245304 || needs.push-branch.result == 'success'
@@ -267,15 +326,15 @@ jobs:
267326 runtimes : |
268327 - docker
269328 env : |
270- NEXTSTRAIN_DOCKER_IMAGE: nextstrain/base:${{ needs.build .outputs.tag }}
329+ NEXTSTRAIN_DOCKER_IMAGE: nextstrain/base:${{ needs.vars .outputs.tag }}
271330 artifact-name : ${{ matrix.pathogen }}-outputs
272331 continue-on-error : true
273332 secrets : inherit
274333
275334 # Delete the builder and final images from GitHub Container Registry.
276335 cleanup-registry :
277336 if : always()
278- needs : [build , test, validate-platforms, push-branch, push-build]
337+ needs : [vars, merge-builds , test, validate-platforms, push-branch, push-build]
279338 runs-on : ubuntu-latest
280339 steps :
281340 - uses : actions/checkout@v6
@@ -285,6 +344,5 @@ jobs:
285344 github-token : ${{ secrets.GH_TOKEN_NEXTSTRAIN_BOT_MANAGE_PACKAGES }}
286345 script : |
287346 const script = require('./devel/delete-from-ghcr.js');
288- const tag = "${{ needs.build.outputs.tag }}";
289- const token = "${{ secrets.GH_TOKEN_NEXTSTRAIN_BOT_MANAGE_PACKAGES }}";
290- script({fetch, octokit: github, tag, token});
347+ const tag = "${{ needs.vars.outputs.tag }}";
348+ script({octokit: github, tag});
0 commit comments