Skip to content

Commit 9bc7363

Browse files
committed
tests(docker/create-images-manifests): add use case coverage
Signed-off-by: Emilien Escalle <emilien.escalle@escemi.com>
1 parent 77f7324 commit 9bc7363

4 files changed

Lines changed: 224 additions & 1 deletion

File tree

.github/workflows/__main-ci.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,14 @@ jobs:
4646
"application-test",
4747
"test-build-args-secrets",
4848
"test-caching-mono-arch-gha",
49-
"test-caching-multi-arch-gha"
49+
"test-caching-multi-arch-gha",
50+
"test-create-manifests-clone-tag",
51+
"test-multi-registry-inputs",
52+
"test-prune-${{ github.run_number }}",
53+
"test-${{ github.ref_name }}-${{ github.run_number }}-mono-arch-signed",
54+
"test-${{ github.ref_name }}-${{ github.run_number }}-multi-arch-signed",
55+
"test-${{ github.ref_name }}-${{ github.run_number }}-mono-arch-unsigned",
56+
"test-${{ github.ref_name }}-${{ github.run_number }}-multi-arch-unsigned"
5057
]
5158
5259
clean-with-cache:
@@ -61,6 +68,8 @@ jobs:
6168
prune-cache-images: true
6269
images: |
6370
[
71+
"test-multi-registry-inputs",
72+
"test-prune-${{ github.run_number }}",
6473
"test-caching-mono-arch-registry",
6574
"test-caching-multi-arch-registry"
6675
]

.github/workflows/__shared-ci.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ jobs:
2525
contents: read
2626
packages: write
2727

28+
test-action-docker-create-images-manifests:
29+
needs: linter
30+
uses: ./.github/workflows/__test-action-docker-create-images-manifests.yml
31+
permissions:
32+
contents: read
33+
id-token: write
34+
issues: read
35+
packages: write
36+
pull-requests: read
37+
2838
test-action-docker-prune-pull-requests-image-tags:
2939
needs: linter
3040
# yamllint disable-line rule:line-length
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
---
2+
name: Test for "docker/create-images-manifests" action
3+
run-name: Test for "docker/create-images-manifests" action
4+
5+
on: # yamllint disable-line rule:truthy
6+
workflow_call:
7+
8+
permissions: {}
9+
10+
jobs:
11+
build-original-tag:
12+
name: Arrange - Build original tag
13+
uses: ./.github/workflows/docker-build-images.yml
14+
permissions:
15+
contents: read
16+
id-token: write
17+
issues: read
18+
packages: write
19+
pull-requests: read
20+
secrets:
21+
oci-registry-password: ${{ secrets.GITHUB_TOKEN }}
22+
with:
23+
sign: false
24+
images: |
25+
[
26+
{
27+
"name": "test-create-manifests-clone-tag",
28+
"context": ".",
29+
"dockerfile": "./tests/application/Dockerfile",
30+
"target": "prod",
31+
"platforms": ["linux/amd64"],
32+
"tag": "1.0.0-rc.0"
33+
}
34+
]
35+
36+
clone-tag:
37+
name: Act/Assert - Clone 1.0.0-rc.0 to 1.0.0
38+
needs: build-original-tag
39+
runs-on: ubuntu-latest
40+
permissions:
41+
contents: read
42+
packages: write
43+
steps:
44+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
45+
with:
46+
persist-credentials: false
47+
48+
- uses: ./actions/docker/setup
49+
with:
50+
oci-registry: ghcr.io
51+
oci-registry-username: ${{ github.repository_owner }}
52+
oci-registry-password: ${{ secrets.GITHUB_TOKEN }}
53+
54+
- id: create-images-manifests-input
55+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
56+
env:
57+
BUILT_IMAGES_OUTPUT: ${{ needs.build-original-tag.outputs.built-images }}
58+
with:
59+
script: |
60+
const builtImages = JSON.parse(process.env.BUILT_IMAGES_OUTPUT);
61+
62+
const imageName = "test-create-manifests-clone-tag";
63+
const originalImage = builtImages[imageName];
64+
if (!originalImage) {
65+
throw new Error(`Missing "${imageName}" entry in "built-images" output`);
66+
}
67+
68+
const cloneInput = {
69+
[imageName]: {
70+
...originalImage,
71+
tags: ["1.0.0"],
72+
images: [`${originalImage.registry}/${originalImage.repository}:1.0.0-rc.0`],
73+
"multi-platform": true,
74+
},
75+
};
76+
77+
core.setOutput("built-images", JSON.stringify(cloneInput));
78+
79+
- id: clone-tag
80+
uses: ./actions/docker/create-images-manifests
81+
with:
82+
oci-registry: ghcr.io
83+
oci-registry-username: ${{ github.repository_owner }}
84+
oci-registry-password: ${{ secrets.GITHUB_TOKEN }}
85+
built-images: ${{ steps.create-images-manifests-input.outputs.built-images }}
86+
87+
- name: Assert - Cloned image digest and tag
88+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
89+
env:
90+
ORIGINAL_BUILT_IMAGES_OUTPUT: ${{ needs.build-original-tag.outputs.built-images }}
91+
CLONED_BUILT_IMAGES_OUTPUT: ${{ steps.clone-tag.outputs.built-images }}
92+
with:
93+
script: |
94+
const assert = require("assert");
95+
96+
const imageName = "test-create-manifests-clone-tag";
97+
98+
const originalBuiltImages = JSON.parse(process.env.ORIGINAL_BUILT_IMAGES_OUTPUT);
99+
const clonedBuiltImages = JSON.parse(process.env.CLONED_BUILT_IMAGES_OUTPUT);
100+
101+
const originalImage = originalBuiltImages[imageName];
102+
const clonedImage = clonedBuiltImages[imageName];
103+
104+
assert(originalImage, `Missing "${imageName}" in original built-images output`);
105+
assert(clonedImage, `Missing "${imageName}" in cloned built-images output`);
106+
107+
assert.equal(clonedImage.tags.length, 1, `Expected one cloned tag for "${imageName}"`);
108+
assert.equal(clonedImage.tags[0], "1.0.0", `Unexpected cloned tag for "${imageName}"`);
109+
110+
assert.match(clonedImage.digest, /^sha256:[a-f0-9]{64}$/, `Invalid digest format for "${imageName}"`);
111+
assert.equal(
112+
clonedImage.digest,
113+
originalImage.digest,
114+
`Digest mismatch for "${imageName}": expected cloned digest to match original digest`,
115+
);
116+
117+
const expectedClonedImage = `${clonedImage.registry}/${clonedImage.repository}:1.0.0@${clonedImage.digest}`;
118+
assert(
119+
clonedImage.images.includes(expectedClonedImage),
120+
`Expected cloned image reference not found: ${expectedClonedImage}`,
121+
);

actions/docker/create-images-manifests/README.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,89 @@ Registry credentials are resolved by role using the same keys as `oci-registry`.
179179
<!-- secrets:start -->
180180
<!-- secrets:end -->
181181
<!-- examples:start -->
182+
183+
## Examples
184+
185+
### Clone an existing tag to a new tag
186+
187+
This example first builds and publishes an original tag (`1.0.0-rc.0`) with the reusable workflow `.github/workflows/docker-build-images.yml`, then copies that tag to `1.0.0` using this action.
188+
189+
```yaml
190+
jobs:
191+
build-original-tag:
192+
uses: hoverkraft-tech/ci-github-container/.github/workflows/docker-build-images.yml@<sha> # x.y.z
193+
permissions:
194+
contents: read
195+
id-token: write
196+
packages: write
197+
secrets:
198+
oci-registry-password: ${{ secrets.GITHUB_TOKEN }}
199+
with:
200+
sign: false
201+
images: |
202+
[
203+
{
204+
"name": "application",
205+
"context": ".",
206+
"dockerfile": "./tests/application/Dockerfile",
207+
"target": "prod",
208+
"platforms": ["linux/amd64"],
209+
"tag": "1.0.0-rc.0"
210+
}
211+
]
212+
213+
clone-image-tag:
214+
needs: build-original-tag
215+
runs-on: ubuntu-latest
216+
permissions:
217+
contents: read
218+
packages: write
219+
steps:
220+
- uses: actions/checkout@<sha> # vx.y.z
221+
with:
222+
persist-credentials: false
223+
224+
- uses: hoverkraft-tech/ci-github-container/actions/docker/setup@<sha> # x.y.z
225+
with:
226+
oci-registry: ghcr.io
227+
oci-registry-username: ${{ github.repository_owner }}
228+
oci-registry-password: ${{ secrets.GITHUB_TOKEN }}
229+
230+
- id: create-images-manifests-input
231+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
232+
env:
233+
BUILT_IMAGES_OUTPUT: ${{ needs.build-original-tag.outputs.built-images }}
234+
with:
235+
script: |
236+
const builtImages = JSON.parse(process.env.BUILT_IMAGES_OUTPUT);
237+
238+
const imageName = "application";
239+
const originalImage = builtImages[imageName];
240+
if (!originalImage) {
241+
throw new Error(`Missing "${imageName}" entry in "built-images" output`);
242+
}
243+
244+
// Build manifest-clone input: source = existing 1.0.0-rc.0 tag, destination = 1.0.0 tag.
245+
const cloneInput = {
246+
[imageName]: {
247+
...originalImage,
248+
tags: ["1.0.0"],
249+
images: [`${originalImage.registry}/${originalImage.repository}:1.0.0-rc.0`],
250+
"multi-platform": true,
251+
},
252+
};
253+
254+
core.setOutput("built-images", JSON.stringify(cloneInput));
255+
256+
- id: clone-tag
257+
uses: hoverkraft-tech/ci-github-container/actions/docker/create-images-manifests@5396e1258d209f9af18e55da8692361508e3338c # 0.36.2
258+
with:
259+
oci-registry: ghcr.io
260+
oci-registry-username: ${{ github.repository_owner }}
261+
oci-registry-password: ${{ secrets.GITHUB_TOKEN }}
262+
built-images: ${{ steps.create-images-manifests-input.outputs.built-images }}
263+
```
264+
182265
<!-- examples:end -->
183266
184267
<!--

0 commit comments

Comments
 (0)