matrix subaction

Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax
2025-07-06 02:23:32 +02:00
parent 6de75d5ad2
commit 68cf998b48
6 changed files with 322 additions and 54 deletions

BIN
.github/subaction-matrix.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -25,75 +25,66 @@ on:
- 'test/**'
jobs:
list-targets-group:
list-targets:
runs-on: ubuntu-latest
steps:
strategy:
fail-fast: false
matrix:
include:
-
name: Checkout
uses: actions/checkout@v5
testdir: group
-
name: Matrix gen
id: gen
uses: ./subaction/list-targets
with:
workdir: ./test/group
-
name: Check targets
uses: actions/github-script@v7
with:
script: |
const targets = `${{ steps.gen.outputs.targets }}`;
if (!targets) {
core.setFailed('No targets generated');
}
core.info(`targets=${targets}`);
list-targets-group-matrix:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v5
-
name: Matrix gen
id: gen
uses: ./subaction/list-targets
with:
workdir: ./test/group-matrix
testdir: group-matrix
target: validate
-
name: Check targets
uses: actions/github-script@v7
with:
script: |
const targets = `${{ steps.gen.outputs.targets }}`;
if (!targets) {
core.setFailed('No targets generated');
}
core.info(`targets=${targets}`);
list-targets-multi-files:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v5
-
name: Matrix gen
id: gen
uses: ./subaction/list-targets
with:
workdir: ./test/multi-files
testdir: multi-files
files: |
docker-bake.json
docker-bake.hcl
steps:
-
name: Check targets
uses: actions/github-script@v7
name: Checkout
uses: actions/checkout@v5
-
name: Matrix gen
id: gen
uses: ./subaction/list-targets
with:
script: |
const targets = `${{ steps.gen.outputs.targets }}`;
if (!targets) {
core.setFailed('No targets generated');
}
core.info(`targets=${targets}`);
workdir: ./test/${{ matrix.testdir }}
files: ${{ matrix.files }}
target: ${{ matrix.target }}
matrix:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
-
testdir: group
-
testdir: group-matrix
target: validate
-
testdir: group-with-platform
target: validate
-
testdir: group-with-platform
target: validate
fields: platforms
-
testdir: group-with-platform
target: validate
fields: platforms,dockerfile
steps:
-
name: Checkout
uses: actions/checkout@v5
-
name: Matrix gen
id: gen
uses: ./subaction/matrix
with:
workdir: ./test/${{ matrix.testdir }}
target: ${{ matrix.target }}
fields: ${{ matrix.fields }}

View File

@@ -22,7 +22,7 @@ ___
* [outputs](#outputs)
* [environment variables](#environment-variables)
* [Subactions](#subactions)
* [`list-targets`](subaction/list-targets)
* [`matrix`](subaction/matrix)
* [Contributing](#contributing)
## Usage
@@ -234,7 +234,7 @@ The following outputs are available
## Subactions
* [`list-targets`](subaction/list-targets)
* [`matrix`](subaction/matrix)
## Contributing

140
subaction/matrix/README.md Normal file
View File

@@ -0,0 +1,140 @@
## About
This subaction generates a multi-dimension matrix that can be used in a [GitHub matrix](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix)
through the [`include` property](https://docs.github.com/en/actions/how-tos/writing-workflows/choosing-what-your-workflow-does/running-variations-of-jobs-in-a-workflow#expanding-or-adding-matrix-configurations)
so you can distribute your builds across multiple runners.
![Screenshot](../../.github/subaction-matrix.png)
___
* [Usage](#usage)
* [Customizing](#customizing)
* [inputs](#inputs)
* [outputs](#outputs)
## Usage
### List targets
```hcl
# docker-bake.hcl
group "validate" {
targets = ["lint", "doctoc"]
}
target "lint" {
target = "lint"
}
target "doctoc" {
target = "doctoc"
}
```
```yaml
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.generate.outputs.matrix }}
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Generate matrix
id: generate
uses: docker/bake-action/subaction/matrix@v6
with:
target: validate
validate:
runs-on: ubuntu-latest
needs:
- prepare
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(needs.prepare.outputs.matrix) }}
steps:
-
name: Validate
uses: docker/bake-action@v6
with:
targets: ${{ matrix.target }}
```
### Platforms split
```hcl
# docker-bake.hcl
target "lint" {
dockerfile = "./hack/dockerfiles/lint.Dockerfile"
output = ["type=cacheonly"]
platforms = [
"darwin/amd64",
"darwin/arm64",
"linux/amd64",
"linux/arm64",
"linux/s390x",
"linux/ppc64le",
"linux/riscv64",
"windows/amd64",
"windows/arm64"
]
}
```
```yaml
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.generate.outputs.matrix }}
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Generate matrix
id: generate
uses: docker/bake-action/subaction/matrix@v6
with:
target: lint
fields: platforms
lint:
runs-on: ${{ startsWith(matrix.platforms, 'linux/arm') && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
needs:
- prepare
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(needs.prepare.outputs.matrix) }}
steps:
-
name: Lint
uses: docker/bake-action@v6
with:
targets: ${{ matrix.target }}
set: |
*.platform=${{ matrix.platforms }}
```
## Customizing
### inputs
| Name | Type | Description |
|-----------|----------|------------------------------------------------------------------------------------------------|
| `workdir` | String | Working directory to use (defaults to `.`) |
| `files` | List/CSV | List of [bake definition files](https://docs.docker.com/build/customize/bake/file-definition/) |
| `target` | String | The target to use within the bake file |
| `fields` | String | List of extra fields to include in the matrix |
### outputs
| Name | Type | Description |
|----------|------|----------------------|
| `matrix` | JSON | Matrix configuration |

101
subaction/matrix/action.yml Normal file
View File

@@ -0,0 +1,101 @@
# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions
name: 'Matrix'
description: 'Generate a matrix from a Bake definition to help distributing builds in your workflow'
inputs:
workdir:
description: Working directory
default: '.'
required: false
files:
description: List of Bake files
required: false
target:
description: Bake target
required: false
fields:
description: List of extra fields to include in the matrix
required: false
outputs:
matrix:
description: Matrix configuration
value: ${{ steps.generate.outputs.includes }}
runs:
using: composite
steps:
-
name: Generate
id: generate
uses: actions/github-script@v7
env:
INPUT_WORKDIR: ${{ inputs.workdir }}
INPUT_FILES: ${{ inputs.files }}
INPUT_TARGET: ${{ inputs.target }}
INPUT_FIELDS: ${{ inputs.fields }}
with:
script: |
function getInputList(name) {
return core.getInput(name) ? core.getInput(name).split(/[\r?\n,]+/).filter(x => x !== '') : [];
}
const workdir = core.getInput('workdir');
const files = getInputList('files');
const target = core.getInput('target');
const fields = getInputList('fields');
let def = {};
await core.group(`Parsing definition`, async () => {
let args = ['buildx', 'bake'];
for (const file of files) {
args.push('--file', file);
}
if (target) {
args.push(target);
}
args.push('--print');
const res = await exec.getExecOutput('docker', args, {
ignoreReturnCode: true,
silent: true,
cwd: workdir
});
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(res.stderr);
}
def = JSON.parse(res.stdout.trim());
core.info(JSON.stringify(def, null, 2));
});
await core.group(`Generating matrix`, async () => {
const result = [];
for (const targetName of Object.keys(def.target)) {
const target = def.target[targetName];
const entry = { target: targetName };
if (fields.length === 0) {
result.push({ ...entry });
continue;
}
let fieldFound = false;
Object.keys(target).forEach(field => {
if (fields.includes(field)) {
fieldFound = true;
const value = target[field];
if (Array.isArray(value)) {
value.forEach((v) => {
entry[field] = v;
result.push({ ...entry });
});
} else {
entry[field] = value;
result.push({ ...entry });
}
}
});
if (!fieldFound) {
result.push({ ...entry });
}
}
core.info(JSON.stringify(result, null, 2));
core.setOutput('includes', JSON.stringify(result));
});

View File

@@ -0,0 +1,36 @@
group "validate" {
targets = ["lint", "lint-gopls", "validate-vendor", "validate-docs"]
}
target "lint" {
dockerfile = "./hack/dockerfiles/lint.Dockerfile"
output = ["type=cacheonly"]
platforms = [
"darwin/amd64",
"darwin/arm64",
"linux/amd64",
"linux/arm64",
"linux/s390x",
"linux/ppc64le",
"linux/riscv64",
"windows/amd64",
"windows/arm64"
]
}
target "lint-gopls" {
inherits = ["lint"]
target = "gopls-analyze"
}
target "validate-vendor" {
dockerfile = "./hack/dockerfiles/vendor.Dockerfile"
target = "validate"
output = ["type=cacheonly"]
}
target "validate-docs" {
dockerfile = "./hack/dockerfiles/docs.Dockerfile"
target = "validate"
output = ["type=cacheonly"]
}