1010 required : true
1111 type : string
1212
13+ env :
14+ SEMVER_REF : ${{ inputs.ref || github.ref }}
15+
1316jobs :
14- publish :
15- strategy :
17+ build-amd64 :
18+ strategy : &docker-base-image-matrix
1619 matrix :
1720 docker-base-image : ["debian", "alpine"]
1821 runs-on : ubuntu-latest
2225 with :
2326 ref : ${{ inputs.ref || github.ref }}
2427
25- - name : Set up QEMU
26- uses : docker/setup-qemu-action@v1
27-
2828 - name : Set up Docker Buildx
2929 uses : docker/setup-buildx-action@v4
3030
@@ -34,22 +34,113 @@ jobs:
3434 with :
3535 images : ghcr.io/${{ github.repository }}
3636 tags : |
37- type=semver,pattern=v{{version}},value=${{ inputs.ref }}
38- type=semver,pattern=v{{major}}.{{minor}},value=${{ inputs.ref }}
37+ type=semver,pattern={{version}},value=${{ env.SEMVER_REF }},suffix=-amd64-${{ matrix.docker-base-image }}
38+ type=semver,pattern={{major}}.{{minor}},value=${{ env.SEMVER_REF }},suffix=-amd64-${{ matrix.docker-base-image }}
39+ type=ref,event=tag,suffix=-amd64-${{ matrix.docker-base-image }}
40+ type=ref,event=branch,enable=${{ inputs.ref == '' }},suffix=-amd64-${{ matrix.docker-base-image }}
41+
42+ - name : Docker meta - debug
43+ id : metadebug
44+ uses : docker/metadata-action@v6
45+ with :
46+ images : ghcr.io/${{ github.repository }}
47+ flavor : |
48+ latest=false
49+ suffix=-debug-amd64-${{ matrix.docker-base-image }},onlatest=false
50+ tags : |
51+ type=semver,pattern={{version}},value=${{ env.SEMVER_REF }}
52+ type=semver,pattern={{major}}.{{minor}},value=${{ env.SEMVER_REF }}
3953 type=ref,event=tag
4054 type=ref,event=branch,enable=${{ inputs.ref == '' }}
4155
56+ - name : Docker meta - assertions
57+ id : metaassertions
58+ uses : docker/metadata-action@v6
59+ with :
60+ images : ghcr.io/${{ github.repository }}
61+ flavor : |
62+ latest=false
63+ suffix=-assertions-amd64-${{ matrix.docker-base-image }},onlatest=false
64+ tags : |
65+ type=semver,pattern={{version}},value=${{ env.SEMVER_REF }}
66+ type=semver,pattern={{major}}.{{minor}},value=${{ env.SEMVER_REF }}
67+ type=ref,event=tag
68+ type=ref,event=branch,enable=${{ inputs.ref == '' }}
69+
70+ - name : Log in to GitHub Docker Registry
71+ uses : docker/login-action@v4
72+ with :
73+ registry : ghcr.io
74+ username : ${{ github.actor }}
75+ password : ${{ secrets.GITHUB_TOKEN }}
76+
77+ - name : Build container image - debug
78+ uses : docker/build-push-action@v7
79+ with :
80+ push : true
81+ platforms : linux/amd64
82+ file : ./docker/Dockerfile-${{ matrix.docker-base-image }}
83+ tags : ${{ steps.metadebug.outputs.tags }}
84+ labels : ${{ steps.metadebug.outputs.labels }}
85+ build-args : |
86+ DOCKER_TAG=${{ join(steps.metadebug.outputs.tags ) }}-${{ matrix.docker-base-image }}
87+
88+ - name : Build container image - assertions
89+ uses : docker/build-push-action@v7
90+ with :
91+ push : true
92+ platforms : linux/amd64
93+ file : ./docker/Dockerfile-${{ matrix.docker-base-image }}
94+ tags : ${{ steps.metaassertions.outputs.tags }}
95+ labels : ${{ steps.metaassertions.outputs.labels }}
96+ build-args : |
97+ DOCKER_TAG=${{ join(steps.metaassertions.outputs.tags ) }}-${{ matrix.docker-base-image }}
98+
99+ - name : Build container image - normal
100+ uses : docker/build-push-action@v7
101+ with :
102+ push : true
103+ platforms : linux/amd64
104+ file : ./docker/Dockerfile-${{ matrix.docker-base-image }}
105+ tags : ${{ steps.meta.outputs.tags }}
106+ labels : ${{ steps.meta.outputs.labels }}
107+ build-args : |
108+ DOCKER_TAG=${{ join(steps.meta.outputs.tags ) }}-${{ matrix.docker-base-image }}
109+
110+ build-arm64 :
111+ strategy : *docker-base-image-matrix
112+ runs-on : ubuntu-24.04-arm
113+ steps :
114+ - name : Check out the repo
115+ uses : actions/checkout@v6
116+ with :
117+ ref : ${{ inputs.ref || github.ref }}
118+
119+ - name : Set up Docker Buildx
120+ uses : docker/setup-buildx-action@v4
121+
122+ - name : Docker meta
123+ id : meta
124+ uses : docker/metadata-action@v6
125+ with :
126+ images : ghcr.io/${{ github.repository }}
127+ tags : |
128+ type=semver,pattern={{version}},value=${{ env.SEMVER_REF }},suffix=-arm64-${{ matrix.docker-base-image }}
129+ type=semver,pattern={{major}}.{{minor}},value=${{ env.SEMVER_REF }},suffix=-arm64-${{ matrix.docker-base-image }}
130+ type=ref,event=tag,suffix=-arm64-${{ matrix.docker-base-image }}
131+ type=ref,event=branch,enable=${{ inputs.ref == '' }},suffix=-arm64-${{ matrix.docker-base-image }}
132+
42133 - name : Docker meta - debug
43134 id : metadebug
44135 uses : docker/metadata-action@v6
45136 with :
46137 images : ghcr.io/${{ github.repository }}
47138 flavor : |
48- latest=true
49- suffix=-debug,onlatest=true
139+ latest=false
140+ suffix=-debug-arm64-${{ matrix.docker-base-image }} ,onlatest=false
50141 tags : |
51- type=semver,pattern=v {{version}},value=${{ inputs.ref }}
52- type=semver,pattern=v {{major}}.{{minor}},value=${{ inputs.ref }}
142+ type=semver,pattern={{version}},value=${{ env.SEMVER_REF }}
143+ type=semver,pattern={{major}}.{{minor}},value=${{ env.SEMVER_REF }}
53144 type=ref,event=tag
54145 type=ref,event=branch,enable=${{ inputs.ref == '' }}
55146
@@ -59,11 +150,11 @@ jobs:
59150 with :
60151 images : ghcr.io/${{ github.repository }}
61152 flavor : |
62- latest=true
63- suffix=-assertions,onlatest=true
153+ latest=false
154+ suffix=-assertions-arm64-${{ matrix.docker-base-image }} ,onlatest=false
64155 tags : |
65- type=semver,pattern=v {{version}},value=${{ inputs.ref }}
66- type=semver,pattern=v {{major}}.{{minor}},value=${{ inputs.ref }}
156+ type=semver,pattern={{version}},value=${{ env.SEMVER_REF }}
157+ type=semver,pattern={{major}}.{{minor}},value=${{ env.SEMVER_REF }}
67158 type=ref,event=tag
68159 type=ref,event=branch,enable=${{ inputs.ref == '' }}
69160
@@ -75,36 +166,101 @@ jobs:
75166 password : ${{ secrets.GITHUB_TOKEN }}
76167
77168 - name : Build container image - debug
78- uses : docker/build-push-action@v4
169+ uses : docker/build-push-action@v7
79170 with :
80171 push : true
81- platforms : linux/amd64,linux/ arm64
172+ platforms : linux/arm64
82173 file : ./docker/Dockerfile-${{ matrix.docker-base-image }}
83174 tags : ${{ steps.metadebug.outputs.tags }}
84175 labels : ${{ steps.metadebug.outputs.labels }}
85176 build-args : |
86177 DOCKER_TAG=${{ join(steps.metadebug.outputs.tags ) }}-${{ matrix.docker-base-image }}
87178
88-
89179 - name : Build container image - assertions
90- uses : docker/build-push-action@v4
180+ uses : docker/build-push-action@v7
91181 with :
92182 push : true
93- platforms : linux/amd64,linux/ arm64
183+ platforms : linux/arm64
94184 file : ./docker/Dockerfile-${{ matrix.docker-base-image }}
95185 tags : ${{ steps.metaassertions.outputs.tags }}
96186 labels : ${{ steps.metaassertions.outputs.labels }}
97187 build-args : |
98188 DOCKER_TAG=${{ join(steps.metaassertions.outputs.tags ) }}-${{ matrix.docker-base-image }}
99189
100- # build and publish "normal" image as last to get it listed on top
101190 - name : Build container image - normal
102- uses : docker/build-push-action@v4
191+ uses : docker/build-push-action@v7
103192 with :
104193 push : true
105- platforms : linux/amd64,linux/ arm64
194+ platforms : linux/arm64
106195 file : ./docker/Dockerfile-${{ matrix.docker-base-image }}
107196 tags : ${{ steps.meta.outputs.tags }}
108197 labels : ${{ steps.meta.outputs.labels }}
109198 build-args : |
110199 DOCKER_TAG=${{ join(steps.meta.outputs.tags ) }}-${{ matrix.docker-base-image }}
200+
201+ combine-manifests :
202+ needs : [build-amd64, build-arm64]
203+ strategy : *docker-base-image-matrix
204+ runs-on : ubuntu-latest
205+ steps :
206+ - name : Set up Docker Buildx
207+ uses : docker/setup-buildx-action@v4
208+
209+ - name : Log in to GitHub Docker Registry
210+ uses : docker/login-action@v4
211+ with :
212+ registry : ghcr.io
213+ username : ${{ github.actor }}
214+ password : ${{ secrets.GITHUB_TOKEN }}
215+
216+ - name : Create and push manifests
217+ run : |
218+ REGISTRY="ghcr.io/${{ github.repository }}"
219+
220+ # Determine tag name based on trigger type
221+ if [ "${{ inputs.ref }}" != "" ]; then
222+ # workflow_dispatch with explicit ref/tag
223+ RAW_REF="${{ inputs.ref }}"
224+ elif [ "${{ github.ref_name }}" != "" ]; then
225+ # push:tags trigger
226+ RAW_REF="${{ github.ref_name }}"
227+ else
228+ RAW_REF="${{ github.ref }}"
229+ fi
230+
231+ # Normalize refs/tags/v26.4.0 -> v26.4.0
232+ REF_NAME="${RAW_REF#refs/tags/}"
233+
234+ if [ -z "$REF_NAME" ]; then
235+ echo "Unable to determine tag name from ref: $RAW_REF" >&2
236+ exit 1
237+ fi
238+
239+ # Always create a manifest for the exact pushed tag, and also
240+ # keep the existing semver aliases for plain release tags.
241+ TAGS=("$REF_NAME")
242+ if [[ "$REF_NAME" =~ ^v?([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
243+ VERSION="${BASH_REMATCH[1]}"
244+ MAJOR_MINOR="${VERSION%.*}"
245+ TAGS+=("$VERSION" "$MAJOR_MINOR")
246+ fi
247+
248+ # Deduplicate tags while preserving order
249+ MANIFEST_TAGS=()
250+ declare -A SEEN_TAGS=()
251+ for TAG in "${TAGS[@]}"; do
252+ if [ -n "$TAG" ] && [ -z "${SEEN_TAGS[$TAG]}" ]; then
253+ MANIFEST_TAGS+=("$TAG")
254+ SEEN_TAGS[$TAG]=1
255+ fi
256+ done
257+
258+ echo "Creating manifests for ${{ matrix.docker-base-image }}..."
259+
260+ for IMAGE_SUFFIX in "" "-debug" "-assertions"; do
261+ for TAG in "${MANIFEST_TAGS[@]}"; do
262+ docker buildx imagetools create -t "$REGISTRY:${TAG}${IMAGE_SUFFIX}-${{ matrix.docker-base-image }}" \
263+ "$REGISTRY:${TAG}${IMAGE_SUFFIX}-amd64-${{ matrix.docker-base-image }}" \
264+ "$REGISTRY:${TAG}${IMAGE_SUFFIX}-arm64-${{ matrix.docker-base-image }}"
265+ done
266+ done
0 commit comments