Skip to content

Commit 6f494e5

Browse files
authored
ci: refactor build-push to use native arm64 build (#813)
* ci: refactor build-push to use native arm64 build * ci: fix issue with lower-casing arch * ci: use correct runner label for arm * chore: remove unused workflow The registry_package event will never trigger when the package is uploaded (by build-push) with the GITHUB_TOKEN identity. * chore: major refactor step * chore: fix issues * chore: fix arch env * chore: more fixing * chore: update reference format for size compare * chore: several improvements * chore: correct imagetools create and add manifest * chore: add forgotten line continuation * chore: correct manifest * chore: move-over all tests to the build-push workflow * chore: quote annotations * chore: debug annotations later * chore: completely ignore the annotions for now * chore: don't use harden-runner in container job * chore: split integration test to seprate workflow This is needed because it does not seem possible to aquired the correct SHA otherwise. * chore: fix issues in workflow file * chore: switch strategy (again) to work around GitHub limitations * chore: reinstate cache * chore: correct concurrency of integration tests * chore: select correct working directory * chore: remove concurrency from reusable workflow * chore: correct digests download path * chore: fix cpp tests by moving conan home * chore: disable word splitting warning when we intend to split words * chore: fail tests if the test run has failures * chore: disable safe bash in container, github uses sh * chore: move shellcheck disable to correct line * chore: make container size diff more appealing * chore: try to fix rust usage in ci
1 parent 798ab61 commit 6f494e5

File tree

7 files changed

+212
-139
lines changed

7 files changed

+212
-139
lines changed

.devcontainer/cpp/Dockerfile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ RUN python3 -m pip install --break-system-packages --require-hashes --no-cache-d
3232
&& rm -rf /tmp/requirements.txt
3333

3434
# Set default environment options for CMake and ccache
35-
ENV CMAKE_GENERATOR="Ninja"
36-
ENV CMAKE_EXPORT_COMPILE_COMMANDS="On"
3735
ENV CCACHE_DIR=/cache/.ccache
36+
ENV CMAKE_EXPORT_COMPILE_COMMANDS="On"
37+
ENV CMAKE_GENERATOR="Ninja"
38+
ENV CONAN_HOME=/opt/conan
3839
ENV CPM_SOURCE_CACHE=/cache/.cpm-cache
3940

4041
# Install clang toolchain and mull mutation testing framework

.devcontainer/rust/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ RUN wget -qO /usr/local/share/ca-certificates/Cisco_Umbrella_Root_CA.crt https:/
2424

2525
# Install rust
2626
ENV CARGO_HOME=/usr/local/cargo \
27+
RUSTUP_HOME=/usr/local/rustup \
2728
PATH=/usr/local/cargo/bin:"$PATH"
2829
RUN rustup set profile minimal \
2930
&& rustup default ${RUST_VERSION} \

.github/actions/container-size-diff/container-size-diff.sh

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,38 @@ get_sizes_from_manifest() {
2323
get_sizes_from_manifest ${FROM_CONTAINER} FROM_CONTAINER_SIZES
2424
get_sizes_from_manifest ${TO_CONTAINER} TO_CONTAINER_SIZES
2525

26-
echo "## Compressed layer size comparison"
26+
echo "## 📊 Container Size Analysis"
2727
echo
28-
echo "Comparing \`${FROM_CONTAINER}\` to \`${TO_CONTAINER}\`"
28+
echo "Comparing compressed layer sizes of:"
29+
echo "📦 Base: \`${FROM_CONTAINER}\`"
30+
echo "📦 Current: \`${TO_CONTAINER}\`"
2931
echo
30-
echo "| OS/Platform | Previous Size | Current Size | Delta |"
31-
echo "|-------------|---------------|--------------|-------|"
32+
33+
echo "### 📈 Size Comparison Table"
34+
echo
35+
echo "| OS/Platform | Previous Size | Current Size | Change | Trend |"
36+
echo "|-------------|:-------------:|:------------:|:------:|:-----:|"
37+
3238
for PLATFORM in "${!FROM_CONTAINER_SIZES[@]}";
3339
do
3440
BASE_SIZE=${FROM_CONTAINER_SIZES[${PLATFORM}]}
3541
HEAD_SIZE=${TO_CONTAINER_SIZES[${PLATFORM}]}
42+
DELTA=$((${HEAD_SIZE} - ${BASE_SIZE}))
43+
PERCENT_CHANGE=$(python -c "print('{:+0.2f}'.format(((${HEAD_SIZE} - ${BASE_SIZE}) / ${BASE_SIZE}) * 100))")
44+
45+
if (( DELTA < 0 )); then
46+
ICON="🔽"
47+
MD_COLOR_START="<span style=\"color:green\">"
48+
MD_COLOR_END="</span>"
49+
elif (( DELTA > 0 )); then
50+
ICON="🔼"
51+
MD_COLOR_START="<span style=\"color:red\">"
52+
MD_COLOR_END="</span>"
53+
else
54+
ICON="🔄"
55+
MD_COLOR_START=""
56+
MD_COLOR_END=""
57+
fi
3658

37-
echo "| ${PLATFORM} | $(numfmt --to iec --format '%.2f' ${BASE_SIZE}) | $(numfmt --to iec --format '%.2f' ${HEAD_SIZE}) | $(numfmt --to iec --format '%.2f' -- $((${HEAD_SIZE} - ${BASE_SIZE}))) $(python -c "print('({:+0.2f}%)'.format(((${HEAD_SIZE} - ${BASE_SIZE}) / ${BASE_SIZE}) * 100))") |";
59+
echo "| ${PLATFORM} | $(numfmt --to iec --format '%.2f' ${BASE_SIZE}) | $(numfmt --to iec --format '%.2f' ${HEAD_SIZE}) | ${MD_COLOR_START}$(numfmt --to iec --format '%.2f' ${DELTA}) (${PERCENT_CHANGE}%)${MD_COLOR_END} | ${ICON} |"
3860
done

.github/workflows/build-push.yml

Lines changed: 129 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,13 @@ env:
2020

2121
jobs:
2222
build-push:
23-
runs-on: ubuntu-latest
24-
permissions:
25-
attestations: write
26-
# dependency-submission needs contents write permission.
27-
contents: write
28-
# attest-build-provenance needs id-token write permission.
29-
id-token: write
30-
packages: write
31-
pull-requests: write
3223
strategy:
3324
matrix:
3425
flavor: ["cpp", "rust"]
26+
runner: ["ubuntu-latest", "ubuntu-24.04-arm"]
27+
runs-on: ${{ matrix.runner }}
28+
permissions:
29+
packages: write
3530
steps:
3631
- uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
3732
with:
@@ -46,72 +41,125 @@ jobs:
4641
registry: ${{ env.REGISTRY }}
4742
username: ${{ github.actor }}
4843
password: ${{ secrets.GITHUB_TOKEN }}
49-
- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
50-
if: matrix.flavor == 'cpp'
51-
id: buildkit-cache
52-
with:
53-
path: root-ccache
54-
key: buildkit-cache-${{ github.run_id }}
55-
restore-keys: |
56-
buildkit-cache
57-
- uses: reproducible-containers/buildkit-cache-dance@653a570f730e3b9460adc576db523788ba59a0d7 # v3.2.0
58-
if: matrix.flavor == 'cpp'
59-
with:
60-
cache-map: |
61-
{
62-
"root-ccache": "/root/.ccache"
63-
}
64-
skip-extraction: ${{ steps.buildkit-cache.outputs.cache-hit }}
6544
- uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
66-
id: metadata
6745
env:
68-
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
46+
DOCKER_METADATA_SET_OUTPUT_ENV: false
47+
id: metadata
6948
with:
7049
images: ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}
71-
# Generate Docker tags based on the following events/attributes
72-
tags: |
73-
type=raw,value=latest,enable={{is_default_branch}}
74-
type=ref,event=pr
75-
type=semver,pattern={{raw}}
76-
type=semver,pattern={{version}}
77-
type=semver,pattern={{major}}.{{minor}}
78-
type=semver,pattern={{major}}
7950
# Generate image LABEL for devcontainer.metadata
8051
# the sed expression is a workaround for quotes being eaten in arrays (e.g. ["x", "y", "z"] -> ["x",y,"z"])
8152
- run: echo "metadata=$(jq -cj '[.]' .devcontainer/${{ matrix.flavor }}/devcontainer-metadata-vscode.json | sed 's/,"/, "/g')" >> "$GITHUB_OUTPUT"
8253
id: devcontainer-metadata
8354
- run: echo "git-commit-epoch=$(git log -1 --pretty=%ct)" >> "$GITHUB_OUTPUT"
8455
id: devcontainer-epoch
56+
- run: echo "arch=${RUNNER_ARCH@L}" >> "$GITHUB_OUTPUT"
57+
id: devcontainer-arch
8558
- uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
8659
id: build-and-push
8760
env:
8861
SOURCE_DATE_EPOCH: ${{ steps.devcontainer-epoch.outputs.git-commit-epoch }}
8962
with:
9063
file: .devcontainer/${{ matrix.flavor }}/Dockerfile
91-
platforms: linux/amd64,linux/arm64
9264
push: ${{ github.event_name != 'merge_group' }}
93-
tags: ${{ steps.metadata.outputs.tags }}
65+
tags: ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}
9466
labels: |
9567
${{ steps.metadata.outputs.labels }}
9668
devcontainer.metadata=${{ steps.devcontainer-metadata.outputs.metadata }}
9769
annotations: ${{ steps.metadata.outputs.annotations }}
9870
sbom: true
99-
cache-from: type=gha,scope=${{ github.repository }}-${{ matrix.flavor }}
100-
cache-to: type=gha,mode=max,scope=${{ github.repository }}-${{ matrix.flavor }}
71+
outputs: type=image,push-by-digest=true,name-canonical=true
72+
cache-to: type=gha,mode=max,scope=${{ github.repository }}-${{ matrix.flavor }}-${{ matrix.runner }}
73+
cache-from: type=gha,scope=${{ github.repository }}-${{ matrix.flavor }}-${{ matrix.runner }}
74+
- name: Export digest
75+
run: |
76+
mkdir -p ${{ runner.temp }}/digests
77+
digest="${{ steps.build-and-push.outputs.digest }}"
78+
touch "${{ runner.temp }}/digests/${digest#sha256:}"
79+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
80+
with:
81+
name: digests-${{ matrix.flavor }}-${{ steps.devcontainer-arch.outputs.arch }}
82+
path: ${{ runner.temp }}/digests/*
83+
if-no-files-found: error
84+
retention-days: 1
85+
86+
merge-image:
87+
strategy:
88+
matrix:
89+
flavor: ["cpp", "rust"]
90+
runs-on: ubuntu-latest
91+
needs: build-push
92+
permissions:
93+
attestations: write
94+
# dependency-submission needs contents write permission.
95+
contents: write
96+
# attest-build-provenance needs id-token write permission.
97+
id-token: write
98+
packages: write
99+
pull-requests: write
100+
steps:
101+
- uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
102+
with:
103+
egress-policy: audit
104+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
105+
with:
106+
persist-credentials: false
107+
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
108+
with:
109+
path: ${{ runner.temp }}/digests
110+
pattern: digests-${{ matrix.flavor }}-*
111+
merge-multiple: true
112+
- uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
113+
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
114+
if: github.event_name != 'merge_group'
115+
with:
116+
registry: ${{ env.REGISTRY }}
117+
username: ${{ github.actor }}
118+
password: ${{ secrets.GITHUB_TOKEN }}
119+
- uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
120+
id: metadata
121+
env:
122+
DOCKER_METADATA_ANNOTATIONS_LEVELS: index
123+
DOCKER_METADATA_SET_OUTPUT_ENV: false
124+
with:
125+
images: ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}
126+
# Generate Docker tags based on the following events/attributes
127+
tags: |
128+
type=raw,value=latest,enable={{is_default_branch}}
129+
type=ref,event=pr
130+
type=semver,pattern={{raw}}
131+
type=semver,pattern={{version}}
132+
type=semver,pattern={{major}}.{{minor}}
133+
type=semver,pattern={{major}}
134+
- name: Create manifest list and push
135+
working-directory: ${{ runner.temp }}/digests
136+
run: |
137+
set -Eeuo pipefail
138+
# shellcheck disable=SC2046
139+
docker buildx imagetools create \
140+
$(echo '${{ steps.metadata.outputs.json }}' | jq -r '.tags | map("--tag " + .) | join(" ")') \
141+
$(printf '${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}@sha256:%s ' *)
142+
- name: Inspect manifest and extract digest
143+
id: inspect-manifest
144+
run: |
145+
set -Eeuo pipefail
146+
output=$(docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}:${{ steps.metadata.outputs.version }} --format '{{json .}}')
147+
digest=$(echo "$output" | jq -r '.manifest.digest // .manifests[0].digest')
148+
echo "digest=$digest" >> "$GITHUB_OUTPUT"
101149
- uses: ./.github/actions/container-size-diff
102150
id: container-size-diff
103151
with:
104152
from-container: ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}:latest
105-
to-container: ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}@${{ steps.build-and-push.outputs.digest }}
153+
to-container: ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}:${{ steps.metadata.outputs.version }}
106154
- uses: marocchino/sticky-pull-request-comment@67d0dec7b07ed060a405f9b2a64b8ab319fdd7db # v2.9.2
107155
with:
108156
header: container-size-diff-${{ matrix.flavor }}
109157
message: |
110158
${{ steps.container-size-diff.outputs.size-diff-markdown }}
111159
- uses: anchore/sbom-action@e11c554f704a0b820cbf8c51673f6945e0731532 # v0.20.0
112-
if: steps.build-and-push.outputs.digest != '' && github.event_name != 'merge_group'
160+
if: steps.inspect-manifest.outputs.digest != '' && github.event_name != 'merge_group'
113161
with:
114-
image: ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}@${{ steps.build-and-push.outputs.digest }}
162+
image: ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}@${{ steps.inspect-manifest.outputs.digest }}
115163
dependency-snapshot: true
116164
- uses: actions/dependency-review-action@da24556b548a50705dd671f47852072ea4c105d9 # v4.7.1
117165
if: github.event_name == 'pull_request'
@@ -122,22 +170,22 @@ jobs:
122170
if: github.event_name != 'merge_group'
123171
with:
124172
subject-name: ${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}
125-
subject-digest: ${{ steps.build-and-push.outputs.digest }}
173+
subject-digest: ${{ steps.inspect-manifest.outputs.digest }}
126174
push-to-registry: true
127175
- name: Verify attestation
128176
if: github.event_name != 'merge_group'
129177
env:
130178
GH_TOKEN: ${{ github.token }}
131179
run: |
132-
gh attestation verify --repo ${{ github.repository }} oci://${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}@${{ steps.build-and-push.outputs.digest }}
180+
gh attestation verify --repo ${{ github.repository }} oci://${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}@${{ steps.inspect-manifest.outputs.digest }}
133181
- name: Upload provenance to release
134182
if: startsWith(github.ref, 'refs/tags/')
135183
env:
136184
GH_TOKEN: ${{ github.token }}
137185
run: |
138-
RAW_SHA=${{ steps.build-and-push.outputs.digest }}
186+
RAW_SHA=${{ steps.inspect-manifest.outputs.digest }}
139187
FORMATTED_SHA=${RAW_SHA//:/_}
140-
gh attestation verify --repo ${{ github.repository }} oci://${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}@${{ steps.build-and-push.outputs.digest }} --format json --jq '.[] | .attestation.bundle.dsseEnvelope | select(.payloadType == "application/vnd.in-toto+json").payload' | base64 -d | jq . > "${{ github.repository_owner }}-${{ github.event.repository.name }}-${{ matrix.flavor }}_${FORMATTED_SHA}.intoto.jsonl"
188+
gh attestation verify --repo ${{ github.repository }} oci://${{ env.REGISTRY }}/${{ github.repository }}-${{ matrix.flavor }}@${{ steps.inspect-manifest.outputs.digest }} --format json --jq '.[] | .attestation.bundle.dsseEnvelope | select(.payloadType == "application/vnd.in-toto+json").payload' | base64 -d | jq . > "${{ github.repository_owner }}-${{ github.event.repository.name }}-${{ matrix.flavor }}_${FORMATTED_SHA}.intoto.jsonl"
141189
gh release upload ${{ github.ref_name }} ./*.intoto.jsonl
142190
- name: Update package details in release
143191
if: startsWith(github.ref, 'refs/tags/')
@@ -146,12 +194,45 @@ jobs:
146194
run: |
147195
UPDATED_NOTES=$(gh release view ${{ github.ref_name }} --json body -q '.body')
148196
UPDATED_NOTES=${UPDATED_NOTES//'{{ amp-devcontainer-${{ matrix.flavor }}-version }}'/'${{ github.ref_name }}'}
149-
UPDATED_NOTES=${UPDATED_NOTES//'{{ amp-devcontainer-${{ matrix.flavor }}-sha }}'/'${{ steps.build-and-push.outputs.digest }}'}
197+
UPDATED_NOTES=${UPDATED_NOTES//'{{ amp-devcontainer-${{ matrix.flavor }}-sha }}'/'${{ steps.inspect-manifest.outputs.digest }}'}
150198
gh release edit ${{ github.ref_name }} --notes "${UPDATED_NOTES}"
199+
200+
integration-test:
201+
if: github.event_name == 'pull_request'
202+
strategy:
203+
matrix:
204+
flavor: [cpp, rust]
205+
runner: ["ubuntu-latest", "ubuntu-24.04-arm"]
206+
needs: merge-image
207+
secrets: inherit
208+
uses: ./.github/workflows/integration-test.yml
209+
with:
210+
flavor: ${{ matrix.flavor }}
211+
runner: ${{ matrix.runner }}
212+
151213
acceptance-test:
152214
if: github.event_name == 'pull_request'
153-
needs: build-push
215+
needs: merge-image
154216
secrets: inherit
155217
uses: ./.github/workflows/acceptance-test.yml
156218
with:
157219
flavor: cpp
220+
221+
publish-test-results:
222+
runs-on: ubuntu-latest
223+
permissions:
224+
checks: write
225+
pull-requests: write
226+
needs: [acceptance-test, integration-test]
227+
if: always()
228+
steps:
229+
- uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
230+
with:
231+
egress-policy: audit
232+
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
233+
with:
234+
merge-multiple: true
235+
pattern: test-results-*
236+
- uses: EnricoMi/publish-unit-test-result-action@3a74b2957438d0b6e2e61d67b05318aa25c9e6c6 # v2.20.0
237+
with:
238+
files: test-report-*.xml

.github/workflows/ci.yml

Lines changed: 0 additions & 66 deletions
This file was deleted.

0 commit comments

Comments
 (0)