Skip to content

Commit 88cf262

Browse files
Copilotneilime
andcommitted
feat: support structured OCI registry inputs
Co-authored-by: neilime <314088+neilime@users.noreply.github.com>
1 parent 120e726 commit 88cf262

8 files changed

Lines changed: 626 additions & 49 deletions

File tree

.github/workflows/__shared-ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ jobs:
5959
uses: ./.github/workflows/__test-workflow-docker-build-images-caching.yml
6060
secrets: inherit
6161

62+
test-workflow-docker-build-images-multi-registry:
63+
name: Test docker build images - Multi registry inputs
64+
needs: linter
65+
uses: ./.github/workflows/__test-workflow-docker-build-images-multi-registry.yml
66+
secrets: inherit
67+
6268
test-workflow-docker-build-images-platforms-and-signing:
6369
name: Test docker build images - Platforms and Signing
6470
needs: linter
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
---
2+
name: Test for "docker-build-images" workflow - Multi registry inputs
3+
run-name: Test for "docker-build-images" workflow - Multi registry inputs
4+
5+
on: # yamllint disable-line rule:truthy
6+
workflow_call:
7+
8+
permissions:
9+
contents: read
10+
issues: read
11+
packages: write
12+
pull-requests: read
13+
id-token: write
14+
15+
jobs:
16+
act-build-images-multi-registry:
17+
name: Act - Build images with structured registry inputs
18+
uses: ./.github/workflows/docker-build-images.yml
19+
secrets:
20+
oci-registry-password: |
21+
{"ghcr.io":"${{ secrets.GITHUB_TOKEN }}"}
22+
build-secret-github-app-key: ${{ secrets.CI_BOT_APP_PRIVATE_KEY }}
23+
with:
24+
cache-type: "registry"
25+
sign: false
26+
oci-registry: |
27+
{"pull":["docker.io","ghcr.io"],"push":"ghcr.io","cache":"ghcr.io"}
28+
oci-registry-username: |
29+
{"ghcr.io":"${{ github.repository_owner }}"}
30+
images: |
31+
[
32+
{
33+
"name": "test-multi-registry-inputs",
34+
"context": ".",
35+
"dockerfile": "./tests/application/Dockerfile",
36+
"build-args": { "BUILD_RUN_ID": "${{ github.run_id }}" },
37+
"target": "prod",
38+
"platforms": ["linux/amd64"]
39+
}
40+
]
41+
42+
assert-multi-registry:
43+
name: Assert - Build images with structured registry inputs
44+
needs: act-build-images-multi-registry
45+
runs-on: ubuntu-latest
46+
steps:
47+
- name: Login to GitHub Container Registry
48+
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
49+
with:
50+
registry: ghcr.io
51+
username: ${{ github.repository_owner }}
52+
password: ${{ github.token }}
53+
54+
- name: Assert built image output and pullability
55+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
56+
env:
57+
BUILT_IMAGES: ${{ needs.act-build-images-multi-registry.outputs.built-images }}
58+
EXPECTED_IMAGE: ghcr.io/${{ github.repository }}/test-multi-registry-inputs
59+
with:
60+
script: |
61+
const assert = require("assert");
62+
const sha = `${{ github.sha }}`;
63+
64+
const builtImages = JSON.parse(process.env.BUILT_IMAGES);
65+
const builtImage = builtImages["test-multi-registry-inputs"];
66+
67+
assert(builtImage, `"built-images" output does not contain "test-multi-registry-inputs" image`);
68+
assert.equal(builtImage.registry, "ghcr.io", `"registry" output is not valid`);
69+
assert.match(builtImage.digest, /^sha256:[0-9a-f]{64}$/, `"digest" output is not valid`);
70+
71+
const expectedTag = `${{ github.event_name }}` === "pull_request"
72+
? `pr-${{ github.event.pull_request.number }}-${sha.substring(0, 7)}`
73+
: `${{ github.ref_name }}`;
74+
75+
const expectedImage = `${process.env.EXPECTED_IMAGE}:${expectedTag}@${builtImage.digest}`;
76+
assert.equal(builtImage.images[0], expectedImage, `"image" output is not valid`);
77+
78+
await exec.exec("docker", ["pull", expectedImage]);
79+
80+
- name: Assert registry cache usage with structured inputs
81+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
82+
env:
83+
EXPECTED_CACHE_IMAGE: ghcr.io/${{ github.repository }}/test-multi-registry-inputs/cache
84+
EXPECTED_CACHE_TAG: ${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || github.ref_name }}
85+
with:
86+
script: |
87+
const cacheImage = `${process.env.EXPECTED_CACHE_IMAGE}:${process.env.EXPECTED_CACHE_TAG}-linux-amd64`;
88+
await exec.exec("docker", ["manifest", "inspect", cacheImage]);

.github/workflows/docker-build-images.md

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,15 @@ jobs:
7373
# Default: `["ubuntu-latest"]`
7474
runs-on: '["ubuntu-latest"]'
7575

76-
# OCI registry where to pull and push images
76+
# OCI registry configuration used to pull, push and cache images.
77+
# Accepts either a registry hostname string or a JSON object with
78+
# `default`, `pull`, `push` and `cache` keys.
7779
# Default: `ghcr.io`
7880
oci-registry: ghcr.io
7981

80-
# Username used to log against the OCI registry.
82+
# Username configuration used to log against OCI registries.
83+
# Accepts either a single username string or a JSON object keyed by registry hostname.
84+
# JSON object can also define `default` as a fallback username.
8185
# See https://github.com/docker/login-action#usage.
8286
#
8387
# Default: `${{ github.repository_owner }}`
@@ -165,8 +169,10 @@ jobs:
165169
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ----------- | -------------------------------- |
166170
| **`runs-on`** | Runner to use. JSON array of runners. | **false** | **string** | `["ubuntu-latest"]` |
167171
| | See <https://docs.github.com/en/actions/using-jobs/choosing-the-runner-for-a-job>. | | | |
168-
| **`oci-registry`** | OCI registry where to pull and push images | **false** | **string** | `ghcr.io` |
169-
| **`oci-registry-username`** | Username used to log against the OCI registry. | **false** | **string** | `${{ github.repository_owner }}` |
172+
| **`oci-registry`** | OCI registry configuration used to pull, push and cache images. | **false** | **string** | `ghcr.io` |
173+
| | Accepts a single registry hostname or a JSON object with `default`, `pull`, `push` and `cache` keys. | | | |
174+
| **`oci-registry-username`** | Username configuration used to log against OCI registries. | **false** | **string** | `${{ github.repository_owner }}` |
175+
| | Accepts a single username or a JSON object keyed by registry hostname, with optional `default`. | | | |
170176
| | See <https://github.com/docker/login-action#usage>. | | | |
171177
| **`images`** | Images to build parameters. | **true** | **string** | - |
172178
| | JSON array of objects. | | | |
@@ -193,17 +199,46 @@ jobs:
193199

194200
## Secrets
195201

196-
| **Secret** | **Description** | **Required** |
197-
| --------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------ |
198-
| **`oci-registry-password`** | Password or GitHub token (`packages:read` and `packages:write` scopes) used to log against the OCI registry. | **true** |
199-
| | See <https://github.com/docker/login-action#usage>. | |
200-
| **`build-secrets`** | List of secrets to expose to the build. | **false** |
201-
| | See <https://docs.docker.com/build/ci/github-actions/secrets/>. | |
202-
| **`build-secret-github-app-key`** | GitHub App private key to generate GitHub token to be passed as build secret env. | **false** |
203-
| | See <https://github.com/actions/create-github-app-token>. | |
202+
| **Secret** | **Description** | **Required** |
203+
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------ |
204+
| **`oci-registry-password`** | Password or GitHub token (`packages:read` and `packages:write` scopes) configuration used to log against OCI registries. | **true** |
205+
| | Accepts a single password/token or a JSON object keyed by registry hostname, with optional `default`. | |
206+
| | See <https://github.com/docker/login-action#usage>. | |
207+
| **`build-secrets`** | List of secrets to expose to the build. | **false** |
208+
| | See <https://docs.docker.com/build/ci/github-actions/secrets/>. | |
209+
| **`build-secret-github-app-key`** | GitHub App private key to generate GitHub token to be passed as build secret env. | **false** |
210+
| | See <https://github.com/actions/create-github-app-token>. | |
204211

205212
<!-- secrets:end -->
206213

214+
## Multiple registries
215+
216+
The legacy single-registry format still works:
217+
218+
```yaml
219+
with:
220+
oci-registry: ghcr.io
221+
oci-registry-username: ${{ github.repository_owner }}
222+
secrets:
223+
oci-registry-password: ${{ github.token }}
224+
```
225+
226+
To configure distinct pull, push and cache registries, pass JSON objects:
227+
228+
```yaml
229+
with:
230+
oci-registry: |
231+
{"pull":["docker.io","ghcr.io"],"push":"ghcr.io","cache":"ghcr.io"}
232+
oci-registry-username: |
233+
{"ghcr.io":"${{ github.repository_owner }}"}
234+
secrets:
235+
oci-registry-password: |
236+
{"ghcr.io":"${{ github.token }}"}
237+
```
238+
239+
Registry credentials are resolved by hostname, then by the optional `default` entry when present.
240+
Optional pull registries without credentials are skipped, which is useful for public registries such as Docker Hub.
241+
207242
### Images entry parameters
208243

209244
| **Parameter** | **Description** | **Default** | **Required** |

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,22 @@ on: # yamllint disable-line rule:truthy
1515
default: '["ubuntu-latest"]'
1616
required: false
1717
oci-registry:
18-
description: "OCI registry where to pull and push images"
18+
description: |
19+
OCI registry configuration used to pull, push and cache images.
20+
Accepts either a registry hostname string (legacy format) or a JSON object.
21+
JSON object keys:
22+
- `default`: fallback registry for unspecified operations
23+
- `pull`: string or array of registries to authenticate for pulls
24+
- `push`: registry used for published images
25+
- `cache`: registry used when `cache-type` is `registry`
1926
type: string
2027
default: "ghcr.io"
2128
required: false
2229
oci-registry-username:
2330
description: |
24-
Username used to log against the OCI registry.
31+
Username configuration used to log against OCI registries.
32+
Accepts either a single username string (legacy format) or a JSON object keyed by registry hostname.
33+
JSON object can also define `default` as a fallback username.
2534
See https://github.com/docker/login-action#usage.
2635
type: string
2736
default: ${{ github.repository_owner }}
@@ -103,7 +112,9 @@ on: # yamllint disable-line rule:truthy
103112
secrets:
104113
oci-registry-password:
105114
description: |
106-
Password or GitHub token (`packages:read` and `packages:write` scopes) used to log against the OCI registry.
115+
Password or GitHub token (`packages:read` and `packages:write` scopes) configuration used to log against OCI registries.
116+
Accepts either a single password/token string (legacy format) or a JSON object keyed by registry hostname.
117+
JSON object can also define `default` as a fallback password/token.
107118
See https://github.com/docker/login-action#usage.
108119
required: true
109120
build-secrets:

0 commit comments

Comments
 (0)