diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3a5b3ae..3b178b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -481,3 +481,21 @@ jobs: uses: ./ with: driver: docker + + cleanup: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + cleanup: + - true + - false + steps: + - + name: Checkout + uses: actions/checkout@v3 + - + name: Set up Docker Buildx + uses: ./ + with: + cleanup: ${{ matrix.cleanup }} diff --git a/README.md b/README.md index 6ae6d7e..b69ec0a 100644 --- a/README.md +++ b/README.md @@ -85,19 +85,20 @@ Following inputs can be used as `step.with` keys: > platforms: linux/amd64,linux/arm64 > ``` -| Name | Type | Description | -|-------------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `version` | String | [Buildx](https://github.com/docker/buildx) version. (eg. `v0.3.0`, `latest`, `https://github.com/docker/buildx.git#master`) | -| `driver` | String | Sets the [builder driver](https://docs.docker.com/engine/reference/commandline/buildx_create/#driver) to be used (default `docker-container`) | -| `driver-opts` | List | List of additional [driver-specific options](https://docs.docker.com/engine/reference/commandline/buildx_create/#driver-opt) (eg. `image=moby/buildkit:master`) | -| `buildkitd-flags` | String | [Flags for buildkitd](https://docs.docker.com/engine/reference/commandline/buildx_create/#buildkitd-flags) daemon (since [buildx v0.3.0](https://github.com/docker/buildx/releases/tag/v0.3.0)) | -| `install` | Bool | Sets up `docker build` command as an alias to `docker buildx` (default `false`) | -| `use` | Bool | Switch to this builder instance (default `true`) | -| `endpoint` | String | [Optional address for docker socket](https://docs.docker.com/engine/reference/commandline/buildx_create/#description) or context from `docker context ls` | -| `platforms` | List/CSV | Fixed [platforms](https://docs.docker.com/engine/reference/commandline/buildx_create/#platform) for current node. If not empty, values take priority over the detected ones. | -| `config`¹ | String | [BuildKit config file](https://docs.docker.com/engine/reference/commandline/buildx_create/#config) | -| `config-inline`¹ | String | Same as `config` but inline | -| `append` | YAML | [Append additional nodes](docs/advanced/append-nodes.md) to the builder | +| Name | Type | Default | Description | +|-------------------|----------|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `version` | String | | [Buildx](https://github.com/docker/buildx) version. (eg. `v0.3.0`, `latest`, `https://github.com/docker/buildx.git#master`) | +| `driver` | String | `docker-container` | Sets the [builder driver](https://docs.docker.com/engine/reference/commandline/buildx_create/#driver) to be used | +| `driver-opts` | List | | List of additional [driver-specific options](https://docs.docker.com/engine/reference/commandline/buildx_create/#driver-opt) (eg. `image=moby/buildkit:master`) | +| `buildkitd-flags` | String | | [Flags for buildkitd](https://docs.docker.com/engine/reference/commandline/buildx_create/#buildkitd-flags) daemon | +| `install` | Bool | `false` | Sets up `docker build` command as an alias to `docker buildx` | +| `use` | Bool | `true` | Switch to this builder instance | +| `endpoint` | String | | [Optional address for docker socket](https://docs.docker.com/engine/reference/commandline/buildx_create/#description) or context from `docker context ls` | +| `platforms` | List/CSV | | Fixed [platforms](https://docs.docker.com/engine/reference/commandline/buildx_create/#platform) for current node. If not empty, values take priority over the detected ones. | +| `config`¹ | String | | [BuildKit config file](https://docs.docker.com/engine/reference/commandline/buildx_create/#config) | +| `config-inline`¹ | String | | Same as `config` but inline | +| `append` | YAML | | [Append additional nodes](docs/advanced/append-nodes.md) to the builder | +| `cleanup` | Bool | `true` | Cleanup temp files and remove builder at the end of a job | > * ¹ `config` and `config-inline` are mutually exclusive diff --git a/__tests__/context.test.ts b/__tests__/context.test.ts index b63d070..9f33f81 100644 --- a/__tests__/context.test.ts +++ b/__tests__/context.test.ts @@ -1,5 +1,6 @@ import {beforeEach, describe, expect, jest, test} from '@jest/globals'; import * as uuid from 'uuid'; +import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx'; import {Docker} from '@docker/actions-toolkit/lib/docker'; import {Toolkit} from '@docker/actions-toolkit/lib/toolkit'; import {Node} from '@docker/actions-toolkit/lib/types/builder'; @@ -27,9 +28,11 @@ describe('getCreateArgs', () => { test.each([ [ 0, + 'v0.10.3', new Map([ ['install', 'false'], ['use', 'true'], + ['cleanup', 'true'], ]), [ 'create', @@ -41,10 +44,12 @@ describe('getCreateArgs', () => { ], [ 1, + 'v0.10.3', new Map([ ['driver', 'docker'], ['install', 'false'], ['use', 'true'], + ['cleanup', 'true'], ]), [ 'create', @@ -56,10 +61,12 @@ describe('getCreateArgs', () => { ], [ 2, + 'v0.10.3', new Map([ ['install', 'false'], ['use', 'false'], ['driver-opts', 'image=moby/buildkit:master\nnetwork=host'], + ['cleanup', 'true'], ]), [ 'create', @@ -72,11 +79,13 @@ describe('getCreateArgs', () => { ], [ 3, + 'v0.10.3', new Map([ ['driver', 'remote'], ['endpoint', 'tls://foo:1234'], ['install', 'false'], ['use', 'true'], + ['cleanup', 'true'], ]), [ 'create', @@ -88,12 +97,14 @@ describe('getCreateArgs', () => { ], [ 4, + 'v0.10.3', new Map([ ['driver', 'remote'], ['platforms', 'linux/arm64,linux/arm/v7'], ['endpoint', 'tls://foo:1234'], ['install', 'false'], ['use', 'true'], + ['cleanup', 'true'], ]), [ 'create', @@ -106,10 +117,12 @@ describe('getCreateArgs', () => { ], [ 5, + 'v0.10.3', new Map([ ['install', 'false'], ['use', 'false'], ['driver-opts', `"env.no_proxy=localhost,127.0.0.1,.mydomain"`], + ['cleanup', 'true'], ]), [ 'create', @@ -121,10 +134,12 @@ describe('getCreateArgs', () => { ], [ 6, + 'v0.10.3', new Map([ ['install', 'false'], ['use', 'false'], ['platforms', 'linux/amd64\n"linux/arm64,linux/arm/v7"'], + ['cleanup', 'true'], ]), [ 'create', @@ -133,15 +148,19 @@ describe('getCreateArgs', () => { '--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host', '--platform', 'linux/amd64,linux/arm64,linux/arm/v7' ] - ], + ] ])( - '[%d] given %p as inputs, returns %p', - async (num: number, inputs: Map, expected: Array) => { + '[%d] given buildx %s and %p as inputs, returns %p', + async (num: number, buildxVersion: string, inputs: Map, expected: Array) => { inputs.forEach((value: string, name: string) => { setInput(name, value); }); + const toolkit = new Toolkit(); + jest.spyOn(Buildx.prototype, 'version').mockImplementation(async (): Promise => { + return buildxVersion; + }); const inp = await context.getInputs(); - const res = await context.getCreateArgs(inp, new Toolkit()); + const res = await context.getCreateArgs(inp, toolkit); expect(res).toEqual(expected); } ); @@ -161,9 +180,11 @@ describe('getAppendArgs', () => { test.each([ [ 0, + 'v0.10.3', new Map([ ['install', 'false'], ['use', 'true'], + ['cleanup', 'true'], ]), { "name": "aws_graviton2", @@ -186,13 +207,17 @@ describe('getAppendArgs', () => { ] ] ])( - '[%d] given %p as inputs, returns %p', - async (num: number, inputs: Map, node: Node, expected: Array) => { + '[%d] given buildx %s and %p as inputs, returns %p', + async (num: number, buildxVersion: string, inputs: Map, node: Node, expected: Array) => { inputs.forEach((value: string, name: string) => { setInput(name, value); }); + const toolkit = new Toolkit(); + jest.spyOn(Buildx.prototype, 'version').mockImplementation(async (): Promise => { + return buildxVersion; + }); const inp = await context.getInputs(); - const res = await context.getAppendArgs(inp, node, new Toolkit()); + const res = await context.getAppendArgs(inp, node, toolkit); expect(res).toEqual(expected); } ); diff --git a/action.yml b/action.yml index 885679e..9fa815c 100644 --- a/action.yml +++ b/action.yml @@ -44,6 +44,10 @@ inputs: append: description: 'Append additional nodes to the builder' required: false + cleanup: + description: 'Cleanup temp files and remove builder at the end of a job' + default: 'true' + required: false outputs: name: diff --git a/src/context.ts b/src/context.ts index 583d8ba..d1f983a 100644 --- a/src/context.ts +++ b/src/context.ts @@ -20,6 +20,7 @@ export interface Inputs { config: string; configInline: string; append: string; + cleanup: boolean; } export async function getInputs(): Promise { @@ -35,7 +36,8 @@ export async function getInputs(): Promise { endpoint: core.getInput('endpoint'), config: core.getInput('config'), configInline: core.getInput('config-inline'), - append: core.getInput('append') + append: core.getInput('append'), + cleanup: core.getBooleanInput('cleanup') }; } diff --git a/src/main.ts b/src/main.ts index c5cae20..e697225 100644 --- a/src/main.ts +++ b/src/main.ts @@ -16,8 +16,9 @@ actionsToolkit.run( // main async () => { const inputs: context.Inputs = await context.getInputs(); - const toolkit = new Toolkit(); + stateHelper.setCleanup(inputs.cleanup); + const toolkit = new Toolkit(); const standalone = await toolkit.buildx.isStandalone(); stateHelper.setStandalone(standalone); @@ -164,9 +165,13 @@ actionsToolkit.run( }); } + if (!stateHelper.cleanup) { + return; + } + if (stateHelper.builderName.length > 0) { await core.group(`Removing builder`, async () => { - const buildx = new Buildx({standalone: /true/i.test(stateHelper.standalone)}); + const buildx = new Buildx({standalone: stateHelper.standalone}); const rmCmd = await buildx.getCommand(['rm', stateHelper.builderName]); await exec .getExecOutput(rmCmd.command, rmCmd.args, { diff --git a/src/state-helper.ts b/src/state-helper.ts index b347be8..294c02b 100644 --- a/src/state-helper.ts +++ b/src/state-helper.ts @@ -1,10 +1,11 @@ import * as core from '@actions/core'; export const IsDebug = !!process.env['STATE_isDebug']; -export const standalone = process.env['STATE_standalone'] || ''; +export const standalone = /true/i.test(process.env['STATE_standalone'] || ''); export const builderName = process.env['STATE_builderName'] || ''; export const containerName = process.env['STATE_containerName'] || ''; export const certsDir = process.env['STATE_certsDir'] || ''; +export const cleanup = /true/i.test(process.env['STATE_cleanup'] || ''); export function setDebug(debug: string) { core.saveState('isDebug', debug); @@ -25,3 +26,7 @@ export function setContainerName(containerName: string) { export function setCertsDir(certsDir: string) { core.saveState('certsDir', certsDir); } + +export function setCleanup(cleanup: boolean) { + core.saveState('cleanup', cleanup); +}