@@ -7,41 +7,57 @@ name: Docker
77
88on :
99 push :
10- branches : [ " master", " develop" ]
10+ branches : [ ' master', ' develop', 'feature/*' ]
1111 # Publish semver tags as releases.
12- tags : [ 'v*.*.* ', 'v*.*', 'v*.*.*-beta*' ]
12+ tags : [ 'v*.*', 'v*. *.*', 'v*.*.*-beta*' ]
1313 pull_request :
14- branches : [ " master" ]
14+ branches : [ ' master', 'develop', 'feature/*' ]
1515
1616env :
1717 # Use docker.io for Docker Hub if empty
1818 REGISTRY : ghcr.io
1919 # github.repository as <account>/<repo>
2020 IMAGE_NAME : ${{ github.repository }}
2121
22-
2322jobs :
2423 build :
25-
26- runs-on : ubuntu-latest
24+ name : Build (${{ matrix.platform }})
25+ runs-on : ${{ matrix.runner }}
26+ strategy :
27+ fail-fast : false
28+ matrix :
29+ include :
30+ - platform : linux/amd64
31+ runner : ubuntu-22.04
32+ - platform : linux/arm64
33+ runner : ubuntu-22.04-arm
2734 permissions :
2835 contents : read
2936 packages : write
30- # This is used to complete the identity challenge
31- # with sigstore/fulcio when running outside of PRs.
3237 id-token : write
38+ outputs :
39+ image-name : ${{ steps.meta.outputs.tags }}
40+ labels : ${{ steps.meta.outputs.labels }}
3341
3442 steps :
3543 - name : Checkout repository
3644 uses : actions/checkout@v4
45+
46+ # Ensure repository/image name is lowercase for Docker registry
47+ - name : Set lowercase image name
48+ id : image
49+ run : |
50+ image="${IMAGE_NAME}"
51+ echo "lower=${image,,}" >> "$GITHUB_OUTPUT"
52+ echo "IMAGE_NAME_LC=${image,,}" >> "$GITHUB_ENV"
53+ env :
54+ IMAGE_NAME : ${{ env.IMAGE_NAME }}
3755
38- # Install the cosign tool except on PR
39- # https://github.com/sigstore/cosign-installer
40- - name : Install cosign
41- if : github.event_name != 'pull_request'
42- uses : sigstore/cosign-installer@6e04d228eb30da1757ee4e1dd75a0ec73a653e06 # v3.1.1
43- with :
44- cosign-release : ' v2.1.1'
56+ - name : Prepare platform name
57+ id : platform
58+ run : |
59+ platform=${{ matrix.platform }}
60+ echo "name=${platform//\//-}" >> $GITHUB_OUTPUT
4561
4662 # Set up BuildKit Docker container builder to be able to build
4763 # multi-platform images and export cache
@@ -65,18 +81,118 @@ jobs:
6581 id : meta
6682 uses : docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0
6783 with :
68- images : ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
84+ images : ${{ env.REGISTRY }}/${{ steps.image.outputs.lower }}
85+ flavor : |
86+ latest=false
87+ tags : |
88+ type=raw,value=${{ github.sha }}-${{ steps.platform.outputs.name }}
6989
7090 # Build and push Docker image with Buildx (don't push on PR)
7191 # https://github.com/docker/build-push-action
72- - name : Build and push Docker image
73- id : build-and-push
92+ - name : Build and push Docker image by digest
93+ id : build
7494 uses : docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0
7595 with :
7696 context : .
77- push : ${{ github.event_name != 'pull_request' }}
78- tags : ${{ steps.meta.outputs.tags }}
97+ platforms : ${{ matrix.platform }}
7998 labels : ${{ steps.meta.outputs.labels }}
80- cache-from : type=gha
81- cache-to : type=gha,mode=max
82- platforms : linux/amd64,linux/arm64
99+ outputs : type=image,name=${{ env.REGISTRY }}/${{ steps.image.outputs.lower }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
100+ cache-from : type=gha,scope=build-${{ steps.platform.outputs.name }}
101+ cache-to : type=gha,mode=max,scope=build-${{ steps.platform.outputs.name }}
102+ provenance : false
103+ sbom : false
104+
105+ - name : Export digest
106+ if : github.event_name != 'pull_request'
107+ run : |
108+ mkdir -p /tmp/digests
109+ digest="${{ steps.build.outputs.digest }}"
110+ touch "/tmp/digests/${digest#sha256:}"
111+
112+ - name : Upload digest
113+ if : github.event_name != 'pull_request'
114+ uses : actions/upload-artifact@v4
115+ with :
116+ name : digests-${{ steps.platform.outputs.name }}
117+ path : /tmp/digests/*
118+ if-no-files-found : error
119+ retention-days : 1
120+
121+ merge :
122+ name : Create multi-arch manifest
123+ runs-on : ubuntu-22.04
124+ needs : build
125+ if : github.event_name != 'pull_request'
126+ permissions :
127+ contents : read
128+ packages : write
129+ id-token : write
130+
131+ steps :
132+ - name : Download digests
133+ uses : actions/download-artifact@v4
134+ with :
135+ pattern : digests-*
136+ path : /tmp/digests
137+ merge-multiple : true
138+
139+ - name : Set up Docker Buildx
140+ uses : docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
141+
142+ - name : Log into registry ${{ env.REGISTRY }}
143+ uses : docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
144+ with :
145+ registry : ${{ env.REGISTRY }}
146+ username : ${{ github.actor }}
147+ password : ${{ secrets.GITHUB_TOKEN }}
148+
149+ # Ensure repository/image name is lowercase for Docker registry
150+ - name : Set lowercase image name
151+ id : image
152+ run : |
153+ image="${IMAGE_NAME}"
154+ echo "lower=${image,,}" >> "$GITHUB_OUTPUT"
155+ echo "IMAGE_NAME_LC=${image,,}" >> "$GITHUB_ENV"
156+ env :
157+ IMAGE_NAME : ${{ env.IMAGE_NAME }}
158+
159+ # Extract metadata (tags, labels) for Docker
160+ # https://github.com/docker/metadata-action
161+ - name : Extract Docker metadata
162+ id : meta
163+ uses : docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0
164+ with :
165+ images : ${{ env.REGISTRY }}/${{ steps.image.outputs.lower }}
166+
167+ - name : Create manifest list and push
168+ id : create-manifest
169+ working-directory : /tmp/digests
170+ run : |
171+ docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
172+ $(printf '${{ env.REGISTRY }}/${{ steps.image.outputs.lower }}@sha256:%s ' *)
173+
174+ # Get the digest of the manifest
175+ manifest_digest=$(docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ steps.image.outputs.lower }}:${{ steps.meta.outputs.version }} --format '{{json .Manifest}}' | jq -r '.digest // .Digest // empty')
176+ if [ -z "$manifest_digest" ]; then
177+ manifest_digest=$(docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ steps.image.outputs.lower }}:${{ steps.meta.outputs.version }} --format '{{.Digest}}')
178+ fi
179+ echo "digest=${manifest_digest}" >> $GITHUB_OUTPUT
180+
181+ - name : Inspect image
182+ run : |
183+ docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ steps.image.outputs.lower }}:${{ steps.meta.outputs.version }}
184+
185+ # Install cosign (before using it)
186+ - name : Install cosign
187+ 188+ with :
189+ cosign-release : ' v2.2.4'
190+
191+ # Sign the pushed image by digest (skip on PRs)
192+ - name : Sign image with cosign
193+ if : github.event_name != 'pull_request'
194+ env :
195+ DIGEST : ${{ steps.create-manifest.outputs.digest }}
196+ TAGS : ${{ steps.meta.outputs.tags }}
197+ run : |
198+ echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}
0 commit comments