Skip to content

Commit 5009333

Browse files
authored
Merge pull request #121 from Staffbase/BLO-4373-enable-multi-arch-builds-for-gitops-action
BLO-4373-enable-multi-arch-builds-for-gitops-action
2 parents bc2aa9e + 34b9057 commit 5009333

File tree

2 files changed

+60
-11
lines changed

2 files changed

+60
-11
lines changed

README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
# 🚀 GitHub Action for GitOps
22

3-
This GitHub Action can be used for our GitOps workflow. The GitHub Action will build and push the Docker image for your service and deploys
3+
This GitHub Action can be used for our GitOps workflow. The GitHub Action will build and push the Docker image for your
4+
service and deploys
45
the new version at your Kubernetes clusters.
56

67
## Requirement
78

8-
When you want to use this GitHub Action your GitHub repository should have a `dev` and `master` / `main` branch and it should use tags for
9+
When you want to use this GitHub Action your GitHub repository should have a `dev` and `master` / `main` branch and it
10+
should use tags for
911
releases.
1012

1113
- For the `dev` branch we will change the files specified under `gitops-dev`.
@@ -119,6 +121,7 @@ jobs:
119121
| `docker-build-secrets` | List of secrets to expose to the build (e.g., key=string, GIT_AUTH_TOKEN=mytoken) | |
120122
| `docker-build-secret-files` | List of secret files to expose to the build (e.g., key=filename, MY_SECRET=./secret.txt) | |
121123
| `docker-build-target` | Sets the target stage to build like: "runtime" | |
124+
| `docker-build-platforms` | Sets the target platforms for build | linux/amd64 |
122125
| `docker-build-provenance` | Generate [provenance](https://docs.docker.com/build/attestations/slsa-provenance/) attestation for the build | `false` |
123126
| `docker-disable-retagging` | Disables retagging of existing images and run a new build instead | `false` |
124127
| `gitops-organization` | GitHub Organization for GitOps | `Staffbase` |
@@ -140,7 +143,8 @@ jobs:
140143

141144
## Contributing
142145

143-
Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us.
146+
Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull
147+
requests to us.
144148

145149
## License
146150

@@ -161,4 +165,5 @@ This project is licensed under the Apache-2.0 License - see the [LICENSE.md](LIC
161165

162166
## Releasing new versions
163167

164-
Go to the release overview page and publish the draft release with a new version number. Make sure to update the floating version commit.
168+
Go to the release overview page and publish the draft release with a new version number. Make sure to update the
169+
floating version commit.

action.yml

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ inputs:
3939
docker-build-target:
4040
description: "Sets the target stage to build"
4141
required: false
42+
docker-build-platforms:
43+
description: "Sets the target platforms for build"
44+
required: false
45+
default: 'linux/amd64'
4246
docker-build-provenance:
4347
description: "Generate provenance attestation for the build"
4448
required: false
@@ -151,6 +155,34 @@ runs:
151155
echo "tag=$TAG" >> $GITHUB_OUTPUT
152156
echo "tag_list=$TAG_LIST" >> $GITHUB_OUTPUT
153157
158+
- name: Verify Architecture Match
159+
shell: bash
160+
if: steps.preparation.outputs.build == 'true'
161+
run: |
162+
RUNNER_ARCH="${{ runner.arch }}" # X64 (AMD64) or ARM64
163+
TARGET_PLATFORMS="${{ inputs.docker-build-platforms }}"
164+
165+
echo "Runner CPU Architecture: $RUNNER_ARCH"
166+
echo "Requested Build Platforms: $TARGET_PLATFORMS"
167+
168+
# Check for AMD64 mismatch (Runner is X64, but user requests ONLY arm64, OR user requests multi-arch which requires emulation)
169+
if [[ "$RUNNER_ARCH" == "X64" ]]; then
170+
if [[ "$TARGET_PLATFORMS" == *"linux/arm64"* ]]; then
171+
echo "::error::Runner is X64 (Intel/AMD) but build includes 'linux/arm64'. This requires emulation. Aborting strictly."
172+
exit 1
173+
fi
174+
fi
175+
176+
# Check for ARM64 mismatch
177+
if [[ "$RUNNER_ARCH" == "ARM64" ]]; then
178+
if [[ "$TARGET_PLATFORMS" == *"linux/amd64"* ]]; then
179+
echo "::error::Runner is ARM64 (Apple Silicon/Graviton) but build includes 'linux/amd64'. This requires emulation. Aborting strictly."
180+
exit 1
181+
fi
182+
fi
183+
184+
echo "Architecture match verified for native build ✅"
185+
154186
- name: Set up Docker Buildx
155187
if: inputs.docker-username != '' && inputs.docker-password != ''
156188
uses: docker/setup-buildx-action@v3
@@ -177,7 +209,7 @@ runs:
177209
tags: ${{ steps.preparation.outputs.tag_list }}
178210
secrets: ${{ inputs.docker-build-secrets }}
179211
secret-files: ${{ inputs.docker-build-secret-files }}
180-
platforms: linux/amd64
212+
platforms: ${{ inputs.docker-build-platforms }}
181213
cache-from: type=gha
182214
cache-to: type=gha,mode=max
183215
provenance: ${{ inputs.docker-build-provenance }}
@@ -189,27 +221,38 @@ runs:
189221
shell: bash
190222
run: |
191223
CHECK_EXISTING_TAGS="master-${GITHUB_SHA::8} main-${GITHUB_SHA::8}"
192-
CONTENT_TYPE="application/vnd.docker.distribution.manifest.v2+json"
224+
# Accept both single-arch manifests and multi-arch manifest lists/indexes
225+
ACCEPT_HEADER="application/vnd.docker.distribution.manifest.v2+json, application/vnd.docker.distribution.manifest.list.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.image.index.v1+json"
193226
194227
echo "CHECK_EXISTING_TAGS: ${CHECK_EXISTING_TAGS}"
195228
echo "RELEASE_TAG: ${RELEASE_TAG:1}"
196229
echo "Check if an image already exists for ${{ inputs.docker-image }}:main|master-${GITHUB_SHA::8} 🐋 ⬇"
197230
198231
foundImage=false
232+
DETECTED_CONTENT_TYPE=""
233+
DIGEST=""
199234
200235
end=$((SECONDS+300))
201236
while [ $SECONDS -lt $end ]; do
202237
203238
MANIFEST=""
204239
for tag in $CHECK_EXISTING_TAGS; do
205-
MANIFEST=$(curl -H "Accept: ${CONTENT_TYPE}" -u '${{ inputs.docker-username }}:${{ inputs.docker-password }}' "${{ inputs.docker-registry-api }}${{ inputs.docker-image}}/manifests/${tag}")
240+
# Dump headers to file to extract Content-Type and Digest later
241+
MANIFEST=$(curl -s -D headers.txt -H "Accept: ${ACCEPT_HEADER}" -u '${{ inputs.docker-username }}:${{ inputs.docker-password }}' "${{ inputs.docker-registry-api }}${{ inputs.docker-image}}/manifests/${tag}")
206242
207243
if [[ $MANIFEST == *"errors"* ]]; then
208244
echo "No image found for ${{ inputs.docker-image }}:${tag} 🚫"
209245
continue
210246
else
211247
echo "Image found for ${{ inputs.docker-image }}:${tag} 🐋 ⬇"
212248
foundImage=true
249+
250+
# Extract the Content-Type returned by registry
251+
DETECTED_CONTENT_TYPE=$(grep -i "^Content-Type:" headers.txt | cut -d' ' -f2 | tr -d '\r')
252+
253+
# Extract the correct digest from headers (works for lists and single images)
254+
DIGEST=$(grep -i "^Docker-Content-Digest:" headers.txt | cut -d' ' -f2 | tr -d '\r')
255+
213256
break 2
214257
fi
215258
done
@@ -223,11 +266,12 @@ runs:
223266
fi
224267
225268
echo "Retagging image with release version and :latest tags for ${{ inputs.docker-image }} 🏷"
226-
curl --fail-with-body -X PUT -H "Content-Type: ${CONTENT_TYPE}" -u '${{ inputs.docker-username }}:${{ inputs.docker-password }}' -d "${MANIFEST}" "${{ inputs.docker-registry-api }}${{ inputs.docker-image}}/manifests/${{ steps.preparation.outputs.tag }}"
227-
curl --fail-with-body -X PUT -H "Content-Type: ${CONTENT_TYPE}" -u '${{ inputs.docker-username }}:${{ inputs.docker-password }}' -d "${MANIFEST}" "${{ inputs.docker-registry-api }}${{ inputs.docker-image}}/manifests/${{ steps.preparation.outputs.latest }}"
269+
echo "Using Content-Type: ${DETECTED_CONTENT_TYPE}"
270+
271+
# Use the detected Content-Type to PUT the manifest back
272+
curl --fail-with-body -X PUT -H "Content-Type: ${DETECTED_CONTENT_TYPE}" -u '${{ inputs.docker-username }}:${{ inputs.docker-password }}' -d "${MANIFEST}" "${{ inputs.docker-registry-api }}${{ inputs.docker-image}}/manifests/${{ steps.preparation.outputs.tag }}"
273+
curl --fail-with-body -X PUT -H "Content-Type: ${DETECTED_CONTENT_TYPE}" -u '${{ inputs.docker-username }}:${{ inputs.docker-password }}' -d "${MANIFEST}" "${{ inputs.docker-registry-api }}${{ inputs.docker-image}}/manifests/${{ steps.preparation.outputs.latest }}"
228274
229-
# Get the digest of the image
230-
DIGEST=$(echo $MANIFEST | jq .config.digest | tr -d '"')
231275
echo "digest=$DIGEST" >> $GITHUB_OUTPUT
232276
233277
- name: Checkout GitOps Repository

0 commit comments

Comments
 (0)