1- name : Build
2- on : [ push, pull_request, workflow_dispatch ]
1+ name : Build / Test / Push
2+
3+ on :
4+ push :
5+ branches :
6+ - ' **'
7+ workflow_dispatch :
8+
39env :
4- REGISTRY : ghcr.io
10+ DOCKER_METADATA_SET_OUTPUT_ENV : ' true '
511
612jobs :
7- # TODO: DRY w/release.yml
8- setup :
9- runs-on : ubuntu-latest
10-
13+ build :
14+ runs-on : ${{ matrix.runner }}
15+ outputs :
16+ build-image-arm : ${{ steps.gen-output.outputs.image-arm64 }}
17+ build-image-x64 : ${{ steps.gen-output.outputs.image-x64 }}
18+ strategy :
19+ fail-fast : false
20+ matrix :
21+ runner :
22+ - ubuntu-24.04
23+ - ubuntu-24.04-arm
1124 steps :
12- # See https://github.com/docker/build-push-action/blob/v2.10.0/TROUBLESHOOTING.md#repository-name-must-be-lowercase
13- - name : Sanitize image name
14- uses : actions/github-script@v6
15- id : image-name
25+ - name : Checkout code
26+ uses : actions/checkout@v4
27+
28+ - name : Set up Docker Buildx
29+ uses : docker/setup-buildx-action@v3
30+
31+ - name : Login to GitHub Container Registry
32+ uses : docker/login-action@v3
1633 with :
17- result-encoding : string
18- script : return '${{ env.REGISTRY }}/${{ github.repository }}'.toLowerCase()
34+ registry : ghcr.io
35+ username : ${{ github.actor }}
36+ password : ${{ secrets.GITHUB_TOKEN }}
1937
20- - name : Get short SHA
38+ - name : Docker meta
39+ id : meta
40+ uses : docker/metadata-action@v5
41+ with :
42+ images : ghcr.io/${{ github.repository }}
43+ # note Specifies a single tag to ensure the default doesn't add more than one.
44+ # The actual tag is not used, this is just used to sanitize the registry name
45+ # and produce labels.
46+ tags : type=sha
47+
48+ - name : Sanitize registry repository name
49+ id : get-reg
2150 run : |
22- echo SHORT_SHA="${GITHUB_SHA:0:7}" >> $GITHUB_ENV
51+ echo "registry=$(echo '${{ steps.meta.outputs.tags }}' | cut -f1 -d:)" | tee -a "$GITHUB_OUTPUT"
2352
24- outputs :
25- base_image_name : ${{ steps.image-name.outputs.result }}
26- build_image : ${{ steps.image-name.outputs.result }}:${{ env.SHORT_SHA }}
53+ - name : Build/push the arch-specific image
54+ id : build
55+ uses : docker/build-push-action@v6
56+ with :
57+ # @todo GHA caching needs tuning, these tend not to hit. Perhaps switch to type=registry?
58+ cache-from : type=gha
59+ cache-to : type=gha,mode=max
60+ labels : ${{ steps.meta.outputs.labels }}
61+ provenance : mode=max
62+ sbom : true
63+ tags : ${{ steps.get-reg.outputs.registry }}
64+ outputs : type=image,push-by-digest=true,push=true
65+
66+ - name : Write arch-specific image digest to outputs
67+ id : gen-output
68+ run : |
69+ echo "image-${RUNNER_ARCH,,}=${{ steps.get-reg.outputs.registry }}@${{ steps.build.outputs.digest }}" | tee -a "$GITHUB_OUTPUT"
2770
28- build :
29- if : github.event_name != 'release'
30- needs : setup
71+ merge :
72+ runs-on : ubuntu-24.04
73+ needs :
74+ - build
3175 env :
32- BUILD_IMAGE : ${{ needs.setup.outputs.build_image }}
33-
34- runs-on : ubuntu-latest
35-
36- permissions :
37- packages : write
38-
76+ DOCKER_APP_IMAGE_ARM64 : ${{ needs.build.outputs.build-image-arm }}
77+ DOCKER_APP_IMAGE_X64 : ${{ needs.build.outputs.build-image-x64 }}
78+ outputs :
79+ build-image : ${{ steps.meta.outputs.tags }}
3980 steps :
40- - name : Checkout repository
41- uses : actions/checkout@v3
81+ - name : Checkout code
82+ uses : actions/checkout@v4
83+
84+ - name : Set up Docker Buildx
85+ uses : docker/setup-buildx-action@v3
4286
43- - name : Log in to the Container registry
44- uses : docker/login-action@v2
87+ - name : Login to GitHub Container Registry
88+ uses : docker/login-action@v3
4589 with :
46- registry : ${{ env.REGISTRY }}
90+ registry : ghcr.io
4791 username : ${{ github.actor }}
4892 password : ${{ secrets.GITHUB_TOKEN }}
4993
50- - name : Get build start time
51- run : |
52- echo BUILD_TIMESTAMP="$(date --utc --iso-8601=seconds)" >> $GITHUB_ENV
53-
54- - name : Build and push Docker image
55- uses : docker/build-push-action@v3
94+ - name : Docker meta
95+ id : meta
96+ uses : docker/metadata-action@v5
5697 with :
57- context : .
58- push : true
59- tags : ${{ env.BUILD_IMAGE }}
60- build-args : |
61- BUILD_TIMESTAMP=${{ env.BUILD_TIMESTAMP }}
62- BUILD_URL=https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
63- DOCKER_TAG=${{ env.BUILD_IMAGE }}
64- GIT_BRANCH=${{ github.ref_name }}
65- GIT_COMMIT=${{ github.sha }}
66- GIT_URL=${{ github.repositoryUrl }}
98+ images : ghcr.io/${{ github.repository }}
99+ tags : |
100+ type=sha,suffix=-build-${{ github.run_id }}_${{ github.run_attempt }}
67101
68- outputs :
69- build_image : ${{ env.BUILD_IMAGE }}
102+ - name : Push the multi-platform image
103+ run : |
104+ docker buildx imagetools create \
105+ --tag "$DOCKER_METADATA_OUTPUT_TAGS" \
106+ "$DOCKER_APP_IMAGE_ARM64" "$DOCKER_APP_IMAGE_X64"
70107
71108 test :
72- if : github.event_name != 'release'
73- needs : build
74-
75109 runs-on : ubuntu-latest
76-
110+ needs :
111+ - merge
77112 container :
78- image : ${{ needs.build.outputs.build_image }}
79-
113+ image : ${{ needs.merge.outputs.build-image }}
80114 defaults :
81115 run :
82116 working-directory : /opt/app
83-
84117 services :
85118 db :
86119 image : postgres
87120 env :
88121 POSTGRES_USER : root
89122 POSTGRES_PASSWORD : root
90-
91123 steps :
92124 - name : Run tests
93125 env :
@@ -110,38 +142,36 @@ jobs:
110142 name : artifacts
111143 path : artifacts/**
112144
113- # TODO: DRY w/release.yml
114145 push :
115- if : github.event_name != 'release'
116-
117- needs : [ setup, build, test ]
146+ runs-on : ubuntu-24.04
147+ needs :
148+ - merge
149+ - test
118150 env :
119- BASE_IMAGE_NAME : ${{ needs.setup.outputs.base_image_name }}
120- BUILD_IMAGE : ${{ needs.build.outputs.build_image }}
121-
122- runs-on : ubuntu-latest
123-
124- permissions :
125- packages : write
126-
151+ DOCKER_APP_IMAGE : ${{ needs.merge.outputs.build-image }}
127152 steps :
128- - name : Extract metadata (tags, labels) for Docker
129- id : meta
130- uses : docker/metadata-action@v4
131- with :
132- images : ${{ env.BASE_IMAGE_NAME }}
153+ - name : Checkout code
154+ uses : actions/checkout@v4
133155
134- - name : Log in to the Container registry
135- uses : docker/login-action@v2
156+ - name : Login to GitHub Container Registry
157+ uses : docker/login-action@v3
136158 with :
137- registry : ${{ env.REGISTRY }}
159+ registry : ghcr.io
138160 username : ${{ github.actor }}
139161 password : ${{ secrets.GITHUB_TOKEN }}
140162
141- - name : Tag and push image
142- uses : akhilerm/tag-push-action@v2.1.0
163+ - name : Produce permanent image tags
164+ id : branch-meta
165+ uses : docker/metadata-action@v5
143166 with :
144- src : ${{ env.BUILD_IMAGE }}
145- dst : |
146- ${{ steps.meta.outputs.tags }}
167+ images : ghcr.io/${{ github.repository }}
168+ tags : |
169+ type=sha
170+ type=ref,event=branch
171+ type=raw,value=latest,enable={{is_default_branch}}
147172
173+ - name : Retag and push the image
174+ run : |
175+ docker pull "$DOCKER_APP_IMAGE"
176+ echo "$DOCKER_METADATA_OUTPUT_TAGS" | tr ' ' '\n' | xargs -n1 docker tag "$DOCKER_APP_IMAGE"
177+ docker push --all-tags "$(echo "$DOCKER_APP_IMAGE" | cut -f1 -d:)"
0 commit comments