11name : build-app
2- description : Build and Push Docker Image
2+ description : Builds one backend image for a single platform and pushes it by digest. Tags are applied later, to the merged manifest, by `merge-image`.
33inputs :
44 dockerfile :
55 required : true
66 description : Dockerfile path
7+ image :
8+ required : true
9+ description : Image name (e.g. `api`)
10+ platform :
11+ required : true
12+ description : Target platform (e.g. `linux/amd64`). Should match the runner's native architecture so no QEMU emulation is needed.
713 push :
814 required : true
9- description : Push image to registry
10- image :
15+ description : If true, pushes the untagged per-platform image and uploads its digest as an artifact
16+ registry :
1117 required : true
12- description : Image name
13- platforms :
18+ description : Container registry to push the image to
19+ registry-username :
1420 required : true
15- description : Image platforms
16- tag-prefix :
21+ description : Username to log in to the container registry
22+ registry-password :
1723 required : true
18- description : Tag prefix (e.g. 'rn' for 'rn-123-a1')
24+ description : Password to log in to the container registry
1925
2026runs :
2127 using : composite
22-
28+
2329 steps :
24- - name : Extract metadata (tags, labels) for Docker
30+ - name : Set up Docker Buildx
31+ uses : docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0
32+
33+ - name : Log in to Container Registry
34+ uses : docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
35+ with :
36+ registry : ${{ inputs.registry }}
37+ username : ${{ inputs.registry-username }}
38+ password : ${{ inputs.registry-password }}
39+
40+ # Image references must be lowercase, but the owner is `OpenShock`.
41+ - name : Resolve image name
42+ id : image
43+ shell : bash
44+ env :
45+ IMAGE : ${{ inputs.registry }}/${{ github.repository_owner }}/${{ inputs.image }}
46+ run : echo "name=${IMAGE,,}" >> "$GITHUB_OUTPUT"
47+
48+ # Only labels are used here; tags go on the multi-arch manifest in `merge-image`.
49+ - name : Extract metadata (labels) for Docker
2550 id : meta
2651 uses : docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
2752 with :
28- images : ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ inputs.image }}
29- flavor : |
30- latest=false
31- tags : |
32- type=raw,value=${{ inputs.tag-prefix }}-${{ github.run_number }}-a${{ github.run_attempt }}
53+ images : ${{ steps.image.outputs.name }}
3354
34- - name : Build and push
55+ - name : Build and push Docker image by digest
56+ id : build
3557 uses : docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
3658 with :
3759 context : .
3860 file : ${{ inputs.dockerfile }}
39- push : ${{ inputs.push }}
40- tags : ${{ steps.meta.outputs.tags }}
61+ platforms : ${{ inputs.platform }}
4162 labels : ${{ steps.meta.outputs.labels }}
42- platforms : ${{ inputs.platforms }}
63+ outputs : type=image,name=${{ steps.image.outputs.name }},push-by-digest=true,name-canonical=true,push=${{ inputs.push }}
64+ # Scoped per image *and* platform: six build jobs now share this cache, and an unscoped
65+ # `type=gha` gives them all one scope, where each one evicts the others' layers.
4366 cache-from : |
44- type=gha
67+ type=gha,scope=${{ inputs.image }}-${{ inputs.platform }}
4568 cache-to : |
46- type=gha
69+ type=gha,mode=max,scope=${{ inputs.image }}-${{ inputs.platform }}
70+
71+ # The merge job needs to know which digests belong to this image, so the image name is part of
72+ # the artifact name and not just the platform.
73+ - name : Export digest
74+ id : digest
75+ if : inputs.push == 'true'
76+ shell : bash
77+ env :
78+ DIGEST : ${{ steps.build.outputs.digest }}
79+ IMAGE : ${{ inputs.image }}
80+ PLATFORM : ${{ inputs.platform }}
81+ run : |
82+ set -euo pipefail
83+ mkdir -p "$RUNNER_TEMP/digests"
84+ touch "$RUNNER_TEMP/digests/${DIGEST#sha256:}"
85+ echo "artifact-name=digests-${IMAGE}-${PLATFORM//\//-}" >> "$GITHUB_OUTPUT"
86+
87+ - name : Upload digest
88+ if : inputs.push == 'true'
89+ uses : actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
90+ with :
91+ name : ${{ steps.digest.outputs.artifact-name }}
92+ path : ${{ runner.temp }}/digests/*
93+ if-no-files-found : error
94+ retention-days : 1
0 commit comments