Skip to content

Commit d41567b

Browse files
Copilotneilime
andcommitted
Factorize build jobs and make image names dynamic for parallel runs
Co-authored-by: neilime <314088+neilime@users.noreply.github.com>
1 parent c4a2cda commit d41567b

1 file changed

Lines changed: 75 additions & 172 deletions

File tree

.github/workflows/__test-workflow-docker-build-images.yml

Lines changed: 75 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -17,85 +17,77 @@ jobs:
1717
arrange:
1818
name: Arrange
1919
runs-on: ubuntu-latest
20+
outputs:
21+
image-name-prefix: ${{ steps.define-image-name-prefix.outputs.prefix }}
2022
steps:
2123
- run: |
2224
if [ -z "${{ secrets.GITHUB_TOKEN }}" ]; then
2325
echo "GitHub token secret is not set"
2426
exit 1
2527
fi
2628
27-
- name: Delete existing test packages
28-
env:
29-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29+
- id: define-image-name-prefix
3030
run: |
31-
# Delete ephemeral test packages before testing
32-
for IMAGE_NAME in test-mono-arch-signed test-multi-arch-signed test-mono-arch-unsigned test-multi-arch-unsigned; do
33-
gh api \
34-
--method DELETE \
35-
-H "Accept: application/vnd.github+json" \
36-
-H "X-GitHub-Api-Version: 2022-11-28" \
37-
/orgs/${{ github.repository_owner }}/packages/container/ci-github-container%2F"${IMAGE_NAME}" || echo "No existing ${IMAGE_NAME} package to delete"
38-
done
31+
# Create unique image name prefix for parallel runs
32+
if [ "${{ github.event_name }}" = "pull_request" ]; then
33+
PREFIX="test-pr-${{ github.event.pull_request.number }}-${{ github.run_number }}"
34+
else
35+
PREFIX="test-${{ github.ref_name }}-${{ github.run_number }}"
36+
fi
37+
# Replace / with - for branch names
38+
PREFIX=$(echo "$PREFIX" | sed 's/\//-/g')
39+
echo "prefix=$PREFIX" >> "$GITHUB_OUTPUT"
40+
echo "Using image name prefix: $PREFIX"
3941
40-
act-build-signed-images:
41-
name: Act - Build signed images (${{ matrix.arch-type }})
42+
act-build-images:
43+
name: Act - Build images (${{ matrix.arch-type }}, ${{ matrix.sign && 'signed' || 'unsigned' }})
4244
needs: arrange
4345
strategy:
4446
fail-fast: false
4547
matrix:
4648
include:
4749
- arch-type: mono-arch
48-
image-name: test-mono-arch-signed
50+
image-name-suffix: mono-arch-signed
4951
platforms: '["linux/amd64"]'
5052
platform-count: 1
53+
sign: true
54+
expected-tagged-versions: 2
55+
expected-untagged-versions: 2
56+
expected-total-versions: 4
5157
- arch-type: multi-arch
52-
image-name: test-multi-arch-signed
58+
image-name-suffix: multi-arch-signed
5359
platforms: '["linux/amd64","linux/arm64"]'
5460
platform-count: 2
55-
uses: ./.github/workflows/docker-build-images.yml
56-
secrets:
57-
oci-registry-password: ${{ secrets.GITHUB_TOKEN }}
58-
build-secret-github-app-key: ${{ secrets.CI_BOT_APP_PRIVATE_KEY }}
59-
with:
60-
sign: true
61-
images: |
62-
[
63-
{
64-
"name": "${{ matrix.image-name }}",
65-
"context": ".",
66-
"dockerfile": "./tests/application/Dockerfile",
67-
"build-args": { "BUILD_RUN_ID": "${{ github.run_id }}" },
68-
"target": "base",
69-
"platforms": ${{ matrix.platforms }},
70-
"tag": "0.1.0"
71-
}
72-
]
73-
74-
act-build-unsigned-images:
75-
name: Act - Build unsigned images (${{ matrix.arch-type }})
76-
needs: arrange
77-
strategy:
78-
fail-fast: false
79-
matrix:
80-
include:
61+
sign: true
62+
expected-tagged-versions: 2
63+
expected-untagged-versions: 3
64+
expected-total-versions: 5
8165
- arch-type: mono-arch
82-
image-name: test-mono-arch-unsigned
66+
image-name-suffix: mono-arch-unsigned
8367
platforms: '["linux/amd64"]'
8468
platform-count: 1
69+
sign: false
70+
expected-tagged-versions: 1
71+
expected-untagged-versions: 1
72+
expected-total-versions: 2
8573
- arch-type: multi-arch
86-
image-name: test-multi-arch-unsigned
74+
image-name-suffix: multi-arch-unsigned
8775
platforms: '["linux/amd64","linux/arm64"]'
8876
platform-count: 2
77+
sign: false
78+
expected-tagged-versions: 1
79+
expected-untagged-versions: 2
80+
expected-total-versions: 3
8981
uses: ./.github/workflows/docker-build-images.yml
9082
secrets:
9183
oci-registry-password: ${{ secrets.GITHUB_TOKEN }}
9284
build-secret-github-app-key: ${{ secrets.CI_BOT_APP_PRIVATE_KEY }}
9385
with:
94-
sign: false
86+
sign: ${{ matrix.sign }}
9587
images: |
9688
[
9789
{
98-
"name": "${{ matrix.image-name }}",
90+
"name": "${{ needs.arrange.outputs.image-name-prefix }}-${{ matrix.image-name-suffix }}",
9991
"context": ".",
10092
"dockerfile": "./tests/application/Dockerfile",
10193
"build-args": { "BUILD_RUN_ID": "${{ github.run_id }}" },
@@ -105,151 +97,43 @@ jobs:
10597
}
10698
]
10799
108-
assert-signed-images:
109-
name: Assert - Signed images (${{ matrix.arch-type }})
110-
needs: act-build-signed-images
100+
assert-images:
101+
name: Assert - Images (${{ matrix.arch-type }}, ${{ matrix.sign && 'signed' || 'unsigned' }})
102+
needs: [arrange, act-build-images]
111103
runs-on: ubuntu-latest
112104
strategy:
113105
fail-fast: false
114106
matrix:
115107
include:
116108
- arch-type: mono-arch
117-
image-name: test-mono-arch-signed
109+
image-name-suffix: mono-arch-signed
118110
platform-count: 1
119111
platforms: '["linux/amd64"]'
112+
sign: true
120113
expected-tagged-versions: 2
121114
expected-untagged-versions: 2
122115
expected-total-versions: 4
123116
- arch-type: multi-arch
124-
image-name: test-multi-arch-signed
117+
image-name-suffix: multi-arch-signed
125118
platform-count: 2
126119
platforms: '["linux/amd64","linux/arm64"]'
120+
sign: true
127121
expected-tagged-versions: 2
128122
expected-untagged-versions: 3
129123
expected-total-versions: 5
130-
steps:
131-
- name: Login to GitHub Container Registry
132-
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
133-
with:
134-
registry: ghcr.io
135-
username: ${{ github.repository_owner }}
136-
password: ${{ github.token }}
137-
138-
- name: Verify image exists
139-
env:
140-
IMAGE_NAME: ${{ matrix.image-name }}
141-
IMAGE_TAG: 0.1.0
142-
run: |
143-
docker pull ghcr.io/hoverkraft-tech/ci-github-container/"${IMAGE_NAME}":"${IMAGE_TAG}"
144-
145-
- name: Verify package has correct number of versions
146-
env:
147-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
148-
IMAGE_NAME: ${{ matrix.image-name }}
149-
EXPECTED_TOTAL_VERSIONS: ${{ matrix.expected-total-versions }}
150-
EXPECTED_TAGGED_VERSIONS: ${{ matrix.expected-tagged-versions }}
151-
EXPECTED_UNTAGGED_VERSIONS: ${{ matrix.expected-untagged-versions }}
152-
run: |
153-
# Get all versions
154-
versions=$(gh api \
155-
-H "Accept: application/vnd.github+json" \
156-
-H "X-GitHub-Api-Version: 2022-11-28" \
157-
/orgs/${{ github.repository_owner }}/packages/container/ci-github-container%2F"${IMAGE_NAME}"/versions)
158-
159-
total_count=$(echo "$versions" | jq '. | length')
160-
tagged_count=$(echo "$versions" | jq '[.[] | select(.metadata.container.tags | length > 0)] | length')
161-
untagged_count=$(echo "$versions" | jq '[.[] | select(.metadata.container.tags | length == 0)] | length')
162-
163-
echo "Found $total_count total versions ($tagged_count tagged, $untagged_count untagged)"
164-
echo "Expected $EXPECTED_TOTAL_VERSIONS total versions ($EXPECTED_TAGGED_VERSIONS tagged, $EXPECTED_UNTAGGED_VERSIONS untagged)"
165-
166-
if [ "$total_count" -ne "$EXPECTED_TOTAL_VERSIONS" ]; then
167-
echo "ERROR: Expected $EXPECTED_TOTAL_VERSIONS total versions, but found $total_count"
168-
exit 1
169-
fi
170-
171-
if [ "$tagged_count" -ne "$EXPECTED_TAGGED_VERSIONS" ]; then
172-
echo "ERROR: Expected $EXPECTED_TAGGED_VERSIONS tagged versions, but found $tagged_count"
173-
exit 1
174-
fi
175-
176-
if [ "$untagged_count" -ne "$EXPECTED_UNTAGGED_VERSIONS" ]; then
177-
echo "ERROR: Expected $EXPECTED_UNTAGGED_VERSIONS untagged versions, but found $untagged_count"
178-
exit 1
179-
fi
180-
181-
echo "✓ Package version counts are correct"
182-
183-
- name: Verify image manifest and platforms
184-
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
185-
env:
186-
IMAGE_NAME: ${{ matrix.image-name }}
187-
IMAGE_TAG: "0.1.0"
188-
EXPECTED_PLATFORMS: ${{ matrix.platforms }}
189-
EXPECTED_PLATFORM_COUNT: ${{ matrix.platform-count }}
190-
with:
191-
script: |
192-
const assert = require("assert");
193-
const imageName = process.env.IMAGE_NAME;
194-
const imageTag = process.env.IMAGE_TAG;
195-
const image = `ghcr.io/hoverkraft-tech/ci-github-container/${imageName}:${imageTag}`;
196-
197-
const { exitCode, stdout, stderr } = await exec.getExecOutput('docker', ['manifest', 'inspect', '-v', image]);
198-
199-
if (exitCode !== 0 || stderr) {
200-
throw new Error(`Failed to inspect manifest for image: ${image}: ${stderr || stdout}`);
201-
}
202-
203-
const manifest = JSON.parse(stdout);
204-
const expectedPlatformCount = parseInt(process.env.EXPECTED_PLATFORM_COUNT);
205-
206-
assert.equal(manifest.length, expectedPlatformCount, `Expected ${expectedPlatformCount} platforms, got: ${manifest.length}`);
207-
208-
const expectedPlatforms = JSON.parse(process.env.EXPECTED_PLATFORMS);
209-
expectedPlatforms.forEach(platformStr => {
210-
const [os, arch] = platformStr.split('/');
211-
const platformExists = manifest.some(
212-
platform => (
213-
platform?.Descriptor?.platform?.architecture === arch &&
214-
platform?.Descriptor?.platform?.os === os
215-
)
216-
);
217-
218-
assert(platformExists, `Expected platform not found: ${platformStr}`);
219-
});
220-
221-
- name: Install cosign
222-
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
223-
224-
- name: Verify image signature
225-
env:
226-
IMAGE_NAME: ${{ matrix.image-name }}
227-
IMAGE_TAG: 0.1.0
228-
run: |
229-
cosign verify \
230-
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
231-
--certificate-identity-regexp https://github.com/hoverkraft-tech/ci-github-container \
232-
ghcr.io/hoverkraft-tech/ci-github-container/"${IMAGE_NAME}":"${IMAGE_TAG}"
233-
234-
assert-unsigned-images:
235-
name: Assert - Unsigned images (${{ matrix.arch-type }})
236-
needs: act-build-unsigned-images
237-
runs-on: ubuntu-latest
238-
strategy:
239-
fail-fast: false
240-
matrix:
241-
include:
242124
- arch-type: mono-arch
243-
image-name: test-mono-arch-unsigned
125+
image-name-suffix: mono-arch-unsigned
244126
platform-count: 1
245127
platforms: '["linux/amd64"]'
128+
sign: false
246129
expected-tagged-versions: 1
247130
expected-untagged-versions: 1
248131
expected-total-versions: 2
249132
- arch-type: multi-arch
250-
image-name: test-multi-arch-unsigned
133+
image-name-suffix: multi-arch-unsigned
251134
platform-count: 2
252135
platforms: '["linux/amd64","linux/arm64"]'
136+
sign: false
253137
expected-tagged-versions: 1
254138
expected-untagged-versions: 2
255139
expected-total-versions: 3
@@ -263,15 +147,15 @@ jobs:
263147

264148
- name: Verify image exists
265149
env:
266-
IMAGE_NAME: ${{ matrix.image-name }}
150+
IMAGE_NAME: ${{ needs.arrange.outputs.image-name-prefix }}-${{ matrix.image-name-suffix }}
267151
IMAGE_TAG: 0.1.0
268152
run: |
269153
docker pull ghcr.io/hoverkraft-tech/ci-github-container/"${IMAGE_NAME}":"${IMAGE_TAG}"
270154
271155
- name: Verify package has correct number of versions
272156
env:
273157
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
274-
IMAGE_NAME: ${{ matrix.image-name }}
158+
IMAGE_NAME: ${{ needs.arrange.outputs.image-name-prefix }}-${{ matrix.image-name-suffix }}
275159
EXPECTED_TOTAL_VERSIONS: ${{ matrix.expected-total-versions }}
276160
EXPECTED_TAGGED_VERSIONS: ${{ matrix.expected-tagged-versions }}
277161
EXPECTED_UNTAGGED_VERSIONS: ${{ matrix.expected-untagged-versions }}
@@ -309,7 +193,7 @@ jobs:
309193
- name: Verify image manifest and platforms
310194
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
311195
env:
312-
IMAGE_NAME: ${{ matrix.image-name }}
196+
IMAGE_NAME: ${{ needs.arrange.outputs.image-name-prefix }}-${{ matrix.image-name-suffix }}
313197
IMAGE_TAG: "0.1.0"
314198
EXPECTED_PLATFORMS: ${{ matrix.platforms }}
315199
EXPECTED_PLATFORM_COUNT: ${{ matrix.platform-count }}
@@ -345,11 +229,28 @@ jobs:
345229
});
346230
347231
- name: Install cosign
232+
if: matrix.sign
233+
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
234+
235+
- name: Verify image signature
236+
if: matrix.sign
237+
env:
238+
IMAGE_NAME: ${{ needs.arrange.outputs.image-name-prefix }}-${{ matrix.image-name-suffix }}
239+
IMAGE_TAG: 0.1.0
240+
run: |
241+
cosign verify \
242+
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
243+
--certificate-identity-regexp https://github.com/hoverkraft-tech/ci-github-container \
244+
ghcr.io/hoverkraft-tech/ci-github-container/"${IMAGE_NAME}":"${IMAGE_TAG}"
245+
246+
- name: Install cosign for unsigned verification
247+
if: ${{ !matrix.sign }}
348248
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
349249

350250
- name: Verify image is NOT signed (should fail)
251+
if: ${{ !matrix.sign }}
351252
env:
352-
IMAGE_NAME: ${{ matrix.image-name }}
253+
IMAGE_NAME: ${{ needs.arrange.outputs.image-name-prefix }}-${{ matrix.image-name-suffix }}
353254
IMAGE_TAG: 0.1.0
354255
continue-on-error: true
355256
id: verify-unsigned
@@ -360,7 +261,7 @@ jobs:
360261
ghcr.io/hoverkraft-tech/ci-github-container/"${IMAGE_NAME}":"${IMAGE_TAG}"
361262
362263
- name: Assert verification failed (image should not be signed)
363-
if: steps.verify-unsigned.outcome == 'success'
264+
if: ${{ !matrix.sign && steps.verify-unsigned.outcome == 'success' }}
364265
run: |
365266
echo "ERROR: Image should not be signed but signature verification succeeded"
366267
exit 1
@@ -491,17 +392,19 @@ jobs:
491392
name: Cleanup ephemeral test packages
492393
if: always()
493394
needs:
494-
- assert-signed-images
495-
- assert-unsigned-images
395+
- arrange
396+
- assert-images
496397
- assert-build-args-secrets-and-registry-caching
497398
runs-on: ubuntu-latest
498399
steps:
499400
- name: Delete ephemeral test packages
500401
env:
501402
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
403+
IMAGE_PREFIX: ${{ needs.arrange.outputs.image-name-prefix }}
502404
run: |
503405
# Delete ephemeral test packages created during testing
504-
for IMAGE_NAME in test-mono-arch-signed test-multi-arch-signed test-mono-arch-unsigned test-multi-arch-unsigned; do
406+
for SUFFIX in mono-arch-signed multi-arch-signed mono-arch-unsigned multi-arch-unsigned; do
407+
IMAGE_NAME="${IMAGE_PREFIX}-${SUFFIX}"
505408
gh api \
506409
--method DELETE \
507410
-H "Accept: application/vnd.github+json" \

0 commit comments

Comments
 (0)