From 8b13d483f2ca37dd930328edb2eea2c32832ba99 Mon Sep 17 00:00:00 2001
From: CrazyMax <crazy-max@users.noreply.github.com>
Date: Fri, 3 Mar 2023 11:56:21 +0100
Subject: [PATCH] cleanup input to remove builder and temp files

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
---
 .github/workflows/ci.yml  | 18 ++++++++++++++++++
 README.md                 | 27 ++++++++++++++-------------
 __tests__/context.test.ts | 39 ++++++++++++++++++++++++++++++++-------
 action.yml                |  4 ++++
 src/context.ts            |  4 +++-
 src/main.ts               |  9 +++++++--
 src/state-helper.ts       |  7 ++++++-
 7 files changed, 84 insertions(+), 24 deletions(-)

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<string, string>([
         ['install', 'false'],
         ['use', 'true'],
+        ['cleanup', 'true'],
       ]),
       [
         'create',
@@ -41,10 +44,12 @@ describe('getCreateArgs', () => {
     ],
     [
       1,
+      'v0.10.3',
       new Map<string, string>([
         ['driver', 'docker'],
         ['install', 'false'],
         ['use', 'true'],
+        ['cleanup', 'true'],
       ]),
       [
         'create',
@@ -56,10 +61,12 @@ describe('getCreateArgs', () => {
     ],
     [
       2,
+      'v0.10.3',
       new Map<string, string>([
         ['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<string, string>([
         ['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<string, string>([
         ['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<string, string>([
         ['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<string, string>([
         ['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<string, string>, expected: Array<string>) => {
+    '[%d] given buildx %s and %p as inputs, returns %p',
+    async (num: number, buildxVersion: string, inputs: Map<string, string>, expected: Array<string>) => {
       inputs.forEach((value: string, name: string) => {
         setInput(name, value);
       });
+      const toolkit = new Toolkit();
+      jest.spyOn(Buildx.prototype, 'version').mockImplementation(async (): Promise<string> => {
+        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<string, string>([
         ['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<string, string>, node: Node, expected: Array<string>) => {
+    '[%d] given buildx %s and %p as inputs, returns %p',
+    async (num: number, buildxVersion: string, inputs: Map<string, string>, node: Node, expected: Array<string>) => {
       inputs.forEach((value: string, name: string) => {
         setInput(name, value);
       });
+      const toolkit = new Toolkit();
+      jest.spyOn(Buildx.prototype, 'version').mockImplementation(async (): Promise<string> => {
+        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<Inputs> {
@@ -35,7 +36,8 @@ export async function getInputs(): Promise<Inputs> {
     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);
+}