support standalone mode and display version
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									2a6fbda6d8
								
							
						
					
					
						commit
						3472856dd9
					
				
							
								
								
									
										34
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								README.md
									
									
									
									
									
								
							@ -24,6 +24,7 @@ ___
 | 
				
			|||||||
  * [BuildKit daemon configuration](#buildkit-daemon-configuration)
 | 
					  * [BuildKit daemon configuration](#buildkit-daemon-configuration)
 | 
				
			||||||
    * [Registry mirror](#registry-mirror)
 | 
					    * [Registry mirror](#registry-mirror)
 | 
				
			||||||
    * [Max parallelism](#max-parallelism)
 | 
					    * [Max parallelism](#max-parallelism)
 | 
				
			||||||
 | 
					  * [Standalone mode](#standalone-mode)
 | 
				
			||||||
* [Customizing](#customizing)
 | 
					* [Customizing](#customizing)
 | 
				
			||||||
  * [inputs](#inputs)
 | 
					  * [inputs](#inputs)
 | 
				
			||||||
  * [outputs](#outputs)
 | 
					  * [outputs](#outputs)
 | 
				
			||||||
@ -180,6 +181,33 @@ jobs:
 | 
				
			|||||||
          config: .github/buildkitd.toml
 | 
					          config: .github/buildkitd.toml
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Standalone mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you don't have the Docker CLI installed on the GitHub Runner, buildx binary
 | 
				
			||||||
 | 
					is invoked directly, instead of calling it as a docker plugin. This can be
 | 
				
			||||||
 | 
					useful if you want to use the `kubernetes` driver in your self-hosted runner:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```yaml
 | 
				
			||||||
 | 
					name: ci
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					on:
 | 
				
			||||||
 | 
					  push:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  buildx:
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      -
 | 
				
			||||||
 | 
					        name: Set up Docker Buildx
 | 
				
			||||||
 | 
					        uses: docker/setup-buildx-action@v1
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          driver: kubernetes
 | 
				
			||||||
 | 
					      -
 | 
				
			||||||
 | 
					        name: Build
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          buildx build .
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Customizing
 | 
					## Customizing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### inputs
 | 
					### inputs
 | 
				
			||||||
@ -195,10 +223,10 @@ Following inputs can be used as `step.with` keys
 | 
				
			|||||||
| `install`          | Bool    | Sets up `docker build` command as an alias to `docker buildx` (default `false`) |
 | 
					| `install`          | Bool    | Sets up `docker build` command as an alias to `docker buildx` (default `false`) |
 | 
				
			||||||
| `use`              | Bool    | Switch to this builder instance (default `true`) |
 | 
					| `use`              | Bool    | Switch to this builder instance (default `true`) |
 | 
				
			||||||
| `endpoint`         | String  | [Optional address for docker socket](https://github.com/docker/buildx/blob/master/docs/reference/buildx_create.md#description) or context from `docker context ls` |
 | 
					| `endpoint`         | String  | [Optional address for docker socket](https://github.com/docker/buildx/blob/master/docs/reference/buildx_create.md#description) or context from `docker context ls` |
 | 
				
			||||||
| `config`           | String  | [BuildKit config file](https://github.com/docker/buildx/blob/master/docs/reference/buildx_create.md#config) |
 | 
					| `config`¹          | String  | [BuildKit config file](https://github.com/docker/buildx/blob/master/docs/reference/buildx_create.md#config) |
 | 
				
			||||||
| `config-inline`    | String  | Same as `config` but inline |
 | 
					| `config-inline`¹   | String  | Same as `config` but inline |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> `config` and `config-inline` are mutually exclusive.
 | 
					> * ¹ `config` and `config-inline` are mutually exclusive
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> `CSV` type must be a newline-delimited string
 | 
					> `CSV` type must be a newline-delimited string
 | 
				
			||||||
> ```yaml
 | 
					> ```yaml
 | 
				
			||||||
 | 
				
			|||||||
@ -32,6 +32,17 @@ describe('isAvailable', () => {
 | 
				
			|||||||
  });
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('isAvailable standalone', () => {
 | 
				
			||||||
 | 
					  const execSpy = jest.spyOn(exec, 'getExecOutput');
 | 
				
			||||||
 | 
					  buildx.isAvailable(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // eslint-disable-next-line jest/no-standalone-expect
 | 
				
			||||||
 | 
					  expect(execSpy).toHaveBeenCalledWith(`buildx`, [], {
 | 
				
			||||||
 | 
					    silent: true,
 | 
				
			||||||
 | 
					    ignoreReturnCode: true
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('getVersion', () => {
 | 
					describe('getVersion', () => {
 | 
				
			||||||
  it('valid', async () => {
 | 
					  it('valid', async () => {
 | 
				
			||||||
    const version = await buildx.getVersion();
 | 
					    const version = await buildx.getVersion();
 | 
				
			||||||
@ -75,29 +86,32 @@ describe('build', () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // eslint-disable-next-line jest/no-disabled-tests
 | 
					  // eslint-disable-next-line jest/no-disabled-tests
 | 
				
			||||||
  it.skip('builds refs/pull/648/head', async () => {
 | 
					  it.skip('builds refs/pull/648/head', async () => {
 | 
				
			||||||
    const buildxBin = await buildx.build('https://github.com/docker/buildx.git#refs/pull/648/head', tmpDir);
 | 
					    const buildxBin = await buildx.build('https://github.com/docker/buildx.git#refs/pull/648/head', tmpDir, false);
 | 
				
			||||||
    expect(fs.existsSync(buildxBin)).toBe(true);
 | 
					    expect(fs.existsSync(buildxBin)).toBe(true);
 | 
				
			||||||
  }, 100000);
 | 
					  }, 100000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // eslint-disable-next-line jest/no-disabled-tests
 | 
					  // eslint-disable-next-line jest/no-disabled-tests
 | 
				
			||||||
  it.skip('builds 67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', async () => {
 | 
					  it.skip('builds 67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', async () => {
 | 
				
			||||||
    const buildxBin = await buildx.build('https://github.com/docker/buildx.git#67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', tmpDir);
 | 
					    const buildxBin = await buildx.build('https://github.com/docker/buildx.git#67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', tmpDir, false);
 | 
				
			||||||
    expect(fs.existsSync(buildxBin)).toBe(true);
 | 
					    expect(fs.existsSync(buildxBin)).toBe(true);
 | 
				
			||||||
  }, 100000);
 | 
					  }, 100000);
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('install', () => {
 | 
					describe('install', () => {
 | 
				
			||||||
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-buildx-'));
 | 
					  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-buildx-'));
 | 
				
			||||||
 | 
					  test.each([
 | 
				
			||||||
  it('acquires v0.4.1 version of buildx', async () => {
 | 
					    ['v0.4.1', false],
 | 
				
			||||||
    const buildxBin = await buildx.install('v0.4.1', tmpDir);
 | 
					    ['latest', false],
 | 
				
			||||||
 | 
					    ['v0.4.1', true],
 | 
				
			||||||
 | 
					    ['latest', true]
 | 
				
			||||||
 | 
					  ])(
 | 
				
			||||||
 | 
					    'acquires %p of buildx (standalone: %p)',
 | 
				
			||||||
 | 
					    async (version, standalone) => {
 | 
				
			||||||
 | 
					      const buildxBin = await buildx.install(version, tmpDir, standalone);
 | 
				
			||||||
      expect(fs.existsSync(buildxBin)).toBe(true);
 | 
					      expect(fs.existsSync(buildxBin)).toBe(true);
 | 
				
			||||||
  }, 100000);
 | 
					    },
 | 
				
			||||||
 | 
					    100000
 | 
				
			||||||
  it('acquires latest version of buildx', async () => {
 | 
					  );
 | 
				
			||||||
    const buildxBin = await buildx.install('latest', tmpDir);
 | 
					 | 
				
			||||||
    expect(fs.existsSync(buildxBin)).toBe(true);
 | 
					 | 
				
			||||||
  }, 100000);
 | 
					 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('getConfig', () => {
 | 
					describe('getConfig', () => {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										16
									
								
								__tests__/docker.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								__tests__/docker.test.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					import {describe, expect, it, jest} from '@jest/globals';
 | 
				
			||||||
 | 
					import * as docker from '../src/docker';
 | 
				
			||||||
 | 
					import * as exec from '@actions/exec';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('isAvailable', () => {
 | 
				
			||||||
 | 
					  it('cli', () => {
 | 
				
			||||||
 | 
					    const execSpy = jest.spyOn(exec, 'getExecOutput');
 | 
				
			||||||
 | 
					    docker.isAvailable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // eslint-disable-next-line jest/no-standalone-expect
 | 
				
			||||||
 | 
					    expect(execSpy).toHaveBeenCalledWith(`docker`, undefined, {
 | 
				
			||||||
 | 
					      silent: true,
 | 
				
			||||||
 | 
					      ignoreReturnCode: true
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										4
									
								
								dist/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								dist/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/index.js.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/index.js.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -41,9 +41,10 @@ export async function getConfig(s: string, file: boolean): Promise<string> {
 | 
				
			|||||||
  return configFile;
 | 
					  return configFile;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export async function isAvailable(): Promise<boolean> {
 | 
					export async function isAvailable(standalone?: boolean): Promise<boolean> {
 | 
				
			||||||
 | 
					  const cmd = getCommand([], standalone);
 | 
				
			||||||
  return await exec
 | 
					  return await exec
 | 
				
			||||||
    .getExecOutput('docker', ['buildx'], {
 | 
					    .getExecOutput(cmd.commandLine, cmd.args, {
 | 
				
			||||||
      ignoreReturnCode: true,
 | 
					      ignoreReturnCode: true,
 | 
				
			||||||
      silent: true
 | 
					      silent: true
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
@ -52,12 +53,17 @@ export async function isAvailable(): Promise<boolean> {
 | 
				
			|||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return res.exitCode == 0;
 | 
					      return res.exitCode == 0;
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | 
				
			||||||
 | 
					    .catch(error => {
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export async function getVersion(): Promise<string> {
 | 
					export async function getVersion(standalone?: boolean): Promise<string> {
 | 
				
			||||||
 | 
					  const cmd = getCommand(['version'], standalone);
 | 
				
			||||||
  return await exec
 | 
					  return await exec
 | 
				
			||||||
    .getExecOutput('docker', ['buildx', 'version'], {
 | 
					    .getExecOutput(cmd.commandLine, cmd.args, {
 | 
				
			||||||
      ignoreReturnCode: true,
 | 
					      ignoreReturnCode: true,
 | 
				
			||||||
      silent: true
 | 
					      silent: true
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
@ -81,9 +87,10 @@ export function satisfies(version: string, range: string): boolean {
 | 
				
			|||||||
  return semver.satisfies(version, range) || /^[0-9a-f]{7}$/.exec(version) !== null;
 | 
					  return semver.satisfies(version, range) || /^[0-9a-f]{7}$/.exec(version) !== null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export async function inspect(name: string): Promise<Builder> {
 | 
					export async function inspect(name: string, standalone?: boolean): Promise<Builder> {
 | 
				
			||||||
 | 
					  const cmd = getCommand(['inspect', name], standalone);
 | 
				
			||||||
  return await exec
 | 
					  return await exec
 | 
				
			||||||
    .getExecOutput(`docker`, ['buildx', 'inspect', name], {
 | 
					    .getExecOutput(cmd.commandLine, cmd.args, {
 | 
				
			||||||
      ignoreReturnCode: true,
 | 
					      ignoreReturnCode: true,
 | 
				
			||||||
      silent: true
 | 
					      silent: true
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
@ -133,7 +140,7 @@ export async function inspect(name: string): Promise<Builder> {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export async function build(inputBuildRef: string, dockerConfigHome: string): Promise<string> {
 | 
					export async function build(inputBuildRef: string, dest: string, standalone: boolean): Promise<string> {
 | 
				
			||||||
  // eslint-disable-next-line prefer-const
 | 
					  // eslint-disable-next-line prefer-const
 | 
				
			||||||
  let [repo, ref] = inputBuildRef.split('#');
 | 
					  let [repo, ref] = inputBuildRef.split('#');
 | 
				
			||||||
  if (ref.length == 0) {
 | 
					  if (ref.length == 0) {
 | 
				
			||||||
@ -152,8 +159,27 @@ export async function build(inputBuildRef: string, dockerConfigHome: string): Pr
 | 
				
			|||||||
  toolPath = tc.find('buildx', vspec);
 | 
					  toolPath = tc.find('buildx', vspec);
 | 
				
			||||||
  if (!toolPath) {
 | 
					  if (!toolPath) {
 | 
				
			||||||
    const outFolder = path.join(context.tmpDir(), 'out').split(path.sep).join(path.posix.sep);
 | 
					    const outFolder = path.join(context.tmpDir(), 'out').split(path.sep).join(path.posix.sep);
 | 
				
			||||||
 | 
					    let buildWithStandalone = false;
 | 
				
			||||||
 | 
					    const standaloneFound = await isAvailable(true);
 | 
				
			||||||
 | 
					    const pluginFound = await isAvailable(false);
 | 
				
			||||||
 | 
					    if (standalone && standaloneFound) {
 | 
				
			||||||
 | 
					      core.debug(`Buildx standalone found, build with it`);
 | 
				
			||||||
 | 
					      buildWithStandalone = true;
 | 
				
			||||||
 | 
					    } else if (!standalone && pluginFound) {
 | 
				
			||||||
 | 
					      core.debug(`Buildx plugin found, build with it`);
 | 
				
			||||||
 | 
					      buildWithStandalone = false;
 | 
				
			||||||
 | 
					    } else if (standaloneFound) {
 | 
				
			||||||
 | 
					      core.debug(`Buildx plugin not found, but standalone found so trying to build with it`);
 | 
				
			||||||
 | 
					      buildWithStandalone = true;
 | 
				
			||||||
 | 
					    } else if (pluginFound) {
 | 
				
			||||||
 | 
					      core.debug(`Buildx standalone not found, but plugin found so trying to build with it`);
 | 
				
			||||||
 | 
					      buildWithStandalone = false;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      throw new Error(`Neither buildx standalone or plugin have been found to build from ref`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const buildCmd = getCommand(['build', '--target', 'binaries', '--build-arg', 'BUILDKIT_CONTEXT_KEEP_GIT_DIR=1', '--output', `type=local,dest=${outFolder}`, inputBuildRef], buildWithStandalone);
 | 
				
			||||||
    toolPath = await exec
 | 
					    toolPath = await exec
 | 
				
			||||||
      .getExecOutput('docker', ['buildx', 'build', '--target', 'binaries', '--build-arg', 'BUILDKIT_CONTEXT_KEEP_GIT_DIR=1', '--output', `type=local,dest=${outFolder}`, inputBuildRef], {
 | 
					      .getExecOutput(buildCmd.commandLine, buildCmd.args, {
 | 
				
			||||||
        ignoreReturnCode: true
 | 
					        ignoreReturnCode: true
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      .then(res => {
 | 
					      .then(res => {
 | 
				
			||||||
@ -164,10 +190,13 @@ export async function build(inputBuildRef: string, dockerConfigHome: string): Pr
 | 
				
			|||||||
      });
 | 
					      });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return setPlugin(toolPath, dockerConfigHome);
 | 
					  if (standalone) {
 | 
				
			||||||
 | 
					    return setStandalone(toolPath, dest);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return setPlugin(toolPath, dest);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export async function install(inputVersion: string, dockerConfigHome: string): Promise<string> {
 | 
					export async function install(inputVersion: string, dest: string, standalone: boolean): Promise<string> {
 | 
				
			||||||
  const release: github.GitHubRelease | null = await github.getRelease(inputVersion);
 | 
					  const release: github.GitHubRelease | null = await github.getRelease(inputVersion);
 | 
				
			||||||
  if (!release) {
 | 
					  if (!release) {
 | 
				
			||||||
    throw new Error(`Cannot find buildx ${inputVersion} release`);
 | 
					    throw new Error(`Cannot find buildx ${inputVersion} release`);
 | 
				
			||||||
@ -185,10 +214,40 @@ export async function install(inputVersion: string, dockerConfigHome: string): P
 | 
				
			|||||||
    toolPath = await download(version);
 | 
					    toolPath = await download(version);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return setPlugin(toolPath, dockerConfigHome);
 | 
					  if (standalone) {
 | 
				
			||||||
 | 
					    return setStandalone(toolPath, dest);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return setPlugin(toolPath, dest);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function setStandalone(toolPath: string, dest: string): Promise<string> {
 | 
				
			||||||
 | 
					  core.info('Standalone mode');
 | 
				
			||||||
 | 
					  const toolBinPath = path.join(toolPath, context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const binDir = path.join(dest, 'bin');
 | 
				
			||||||
 | 
					  core.debug(`Bin dir is ${binDir}`);
 | 
				
			||||||
 | 
					  if (!fs.existsSync(binDir)) {
 | 
				
			||||||
 | 
					    fs.mkdirSync(binDir, {recursive: true});
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const filename: string = context.osPlat == 'win32' ? 'buildx.exe' : 'buildx';
 | 
				
			||||||
 | 
					  const buildxPath: string = path.join(binDir, filename);
 | 
				
			||||||
 | 
					  core.debug(`Bin path is ${buildxPath}`);
 | 
				
			||||||
 | 
					  fs.copyFileSync(toolBinPath, buildxPath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  core.info('Fixing perms');
 | 
				
			||||||
 | 
					  fs.chmodSync(buildxPath, '0755');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  core.addPath(binDir);
 | 
				
			||||||
 | 
					  core.info('Added buildx to the path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return buildxPath;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function setPlugin(toolPath: string, dockerConfigHome: string): Promise<string> {
 | 
					async function setPlugin(toolPath: string, dockerConfigHome: string): Promise<string> {
 | 
				
			||||||
 | 
					  core.info('Docker plugin mode');
 | 
				
			||||||
 | 
					  const toolBinPath = path.join(toolPath, context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const pluginsDir: string = path.join(dockerConfigHome, 'cli-plugins');
 | 
					  const pluginsDir: string = path.join(dockerConfigHome, 'cli-plugins');
 | 
				
			||||||
  core.debug(`Plugins dir is ${pluginsDir}`);
 | 
					  core.debug(`Plugins dir is ${pluginsDir}`);
 | 
				
			||||||
  if (!fs.existsSync(pluginsDir)) {
 | 
					  if (!fs.existsSync(pluginsDir)) {
 | 
				
			||||||
@ -198,7 +257,7 @@ async function setPlugin(toolPath: string, dockerConfigHome: string): Promise<st
 | 
				
			|||||||
  const filename: string = context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx';
 | 
					  const filename: string = context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx';
 | 
				
			||||||
  const pluginPath: string = path.join(pluginsDir, filename);
 | 
					  const pluginPath: string = path.join(pluginsDir, filename);
 | 
				
			||||||
  core.debug(`Plugin path is ${pluginPath}`);
 | 
					  core.debug(`Plugin path is ${pluginPath}`);
 | 
				
			||||||
  fs.copyFileSync(path.join(toolPath, filename), pluginPath);
 | 
					  fs.copyFileSync(toolBinPath, pluginPath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  core.info('Fixing perms');
 | 
					  core.info('Fixing perms');
 | 
				
			||||||
  fs.chmodSync(pluginPath, '0755');
 | 
					  fs.chmodSync(pluginPath, '0755');
 | 
				
			||||||
@ -269,3 +328,10 @@ export async function getBuildKitVersion(containerID: string): Promise<string> {
 | 
				
			|||||||
      return bkitimage.stdout.trim();
 | 
					      return bkitimage.stdout.trim();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function getCommand(args: Array<string>, standalone?: boolean) {
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    commandLine: standalone ? 'buildx' : 'docker',
 | 
				
			||||||
 | 
					    args: standalone ? args : ['buildx', ...args]
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										19
									
								
								src/docker.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/docker.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					import * as exec from '@actions/exec';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function isAvailable(): Promise<boolean> {
 | 
				
			||||||
 | 
					  return await exec
 | 
				
			||||||
 | 
					    .getExecOutput('docker', undefined, {
 | 
				
			||||||
 | 
					      ignoreReturnCode: true,
 | 
				
			||||||
 | 
					      silent: true
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .then(res => {
 | 
				
			||||||
 | 
					      if (res.stderr.length > 0 && res.exitCode != 0) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return res.exitCode == 0;
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | 
				
			||||||
 | 
					    .catch(error => {
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										65
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										65
									
								
								src/main.ts
									
									
									
									
									
								
							@ -3,6 +3,7 @@ import * as path from 'path';
 | 
				
			|||||||
import * as uuid from 'uuid';
 | 
					import * as uuid from 'uuid';
 | 
				
			||||||
import * as buildx from './buildx';
 | 
					import * as buildx from './buildx';
 | 
				
			||||||
import * as context from './context';
 | 
					import * as context from './context';
 | 
				
			||||||
 | 
					import * as docker from './docker';
 | 
				
			||||||
import * as stateHelper from './state-helper';
 | 
					import * as stateHelper from './state-helper';
 | 
				
			||||||
import * as util from './util';
 | 
					import * as util from './util';
 | 
				
			||||||
import * as core from '@actions/core';
 | 
					import * as core from '@actions/core';
 | 
				
			||||||
@ -10,32 +11,54 @@ import * as exec from '@actions/exec';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
async function run(): Promise<void> {
 | 
					async function run(): Promise<void> {
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    core.startGroup(`Docker info`);
 | 
					 | 
				
			||||||
    await exec.exec('docker', ['version']);
 | 
					 | 
				
			||||||
    await exec.exec('docker', ['info']);
 | 
					 | 
				
			||||||
    core.endGroup();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const inputs: context.Inputs = await context.getInputs();
 | 
					    const inputs: context.Inputs = await context.getInputs();
 | 
				
			||||||
    const dockerConfigHome: string = process.env.DOCKER_CONFIG || path.join(os.homedir(), '.docker');
 | 
					    const dockerConfigHome: string = process.env.DOCKER_CONFIG || path.join(os.homedir(), '.docker');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (util.isValidUrl(inputs.version)) {
 | 
					    // standalone if docker cli not available
 | 
				
			||||||
      core.startGroup(`Build and install buildx`);
 | 
					    const standalone = !(await docker.isAvailable());
 | 
				
			||||||
      await buildx.build(inputs.version, dockerConfigHome);
 | 
					    stateHelper.setStandalone(standalone);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    core.startGroup(`Docker info`);
 | 
				
			||||||
 | 
					    if (standalone) {
 | 
				
			||||||
 | 
					      core.info(`Docker info skipped in standalone mode`);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      await exec.exec('docker', ['version'], {
 | 
				
			||||||
 | 
					        failOnStdErr: false
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      await exec.exec('docker', ['info'], {
 | 
				
			||||||
 | 
					        failOnStdErr: false
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    core.endGroup();
 | 
					    core.endGroup();
 | 
				
			||||||
    } else if (!(await buildx.isAvailable()) || inputs.version) {
 | 
					
 | 
				
			||||||
 | 
					    if (util.isValidUrl(inputs.version)) {
 | 
				
			||||||
 | 
					      if (standalone) {
 | 
				
			||||||
 | 
					        throw new Error(`Cannot build from source without the Docker CLI`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      core.startGroup(`Build and install buildx`);
 | 
				
			||||||
 | 
					      await buildx.build(inputs.version, dockerConfigHome, standalone);
 | 
				
			||||||
 | 
					      core.endGroup();
 | 
				
			||||||
 | 
					    } else if (!(await buildx.isAvailable(standalone)) || inputs.version) {
 | 
				
			||||||
      core.startGroup(`Download and install buildx`);
 | 
					      core.startGroup(`Download and install buildx`);
 | 
				
			||||||
      await buildx.install(inputs.version || 'latest', dockerConfigHome);
 | 
					      await buildx.install(inputs.version || 'latest', standalone ? context.tmpDir() : dockerConfigHome, standalone);
 | 
				
			||||||
      core.endGroup();
 | 
					      core.endGroup();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const buildxVersion = await buildx.getVersion();
 | 
					    const buildxVersion = await buildx.getVersion(standalone);
 | 
				
			||||||
 | 
					    await core.group(`Buildx version`, async () => {
 | 
				
			||||||
 | 
					      const versionCmd = buildx.getCommand(['version'], standalone);
 | 
				
			||||||
 | 
					      await exec.exec(versionCmd.commandLine, versionCmd.args, {
 | 
				
			||||||
 | 
					        failOnStdErr: false
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const builderName: string = inputs.driver == 'docker' ? 'default' : `builder-${uuid.v4()}`;
 | 
					    const builderName: string = inputs.driver == 'docker' ? 'default' : `builder-${uuid.v4()}`;
 | 
				
			||||||
    context.setOutput('name', builderName);
 | 
					    context.setOutput('name', builderName);
 | 
				
			||||||
    stateHelper.setBuilderName(builderName);
 | 
					    stateHelper.setBuilderName(builderName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (inputs.driver !== 'docker') {
 | 
					    if (inputs.driver !== 'docker') {
 | 
				
			||||||
      core.startGroup(`Creating a new builder instance`);
 | 
					      core.startGroup(`Creating a new builder instance`);
 | 
				
			||||||
      const createArgs: Array<string> = ['buildx', 'create', '--name', builderName, '--driver', inputs.driver];
 | 
					      const createArgs: Array<string> = ['create', '--name', builderName, '--driver', inputs.driver];
 | 
				
			||||||
      if (buildx.satisfies(buildxVersion, '>=0.3.0')) {
 | 
					      if (buildx.satisfies(buildxVersion, '>=0.3.0')) {
 | 
				
			||||||
        await context.asyncForEach(inputs.driverOpts, async driverOpt => {
 | 
					        await context.asyncForEach(inputs.driverOpts, async driverOpt => {
 | 
				
			||||||
          createArgs.push('--driver-opt', driverOpt);
 | 
					          createArgs.push('--driver-opt', driverOpt);
 | 
				
			||||||
@ -55,26 +78,31 @@ async function run(): Promise<void> {
 | 
				
			|||||||
      } else if (inputs.configInline) {
 | 
					      } else if (inputs.configInline) {
 | 
				
			||||||
        createArgs.push('--config', await buildx.getConfigInline(inputs.configInline));
 | 
					        createArgs.push('--config', await buildx.getConfigInline(inputs.configInline));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      await exec.exec('docker', createArgs);
 | 
					      const createCmd = buildx.getCommand(createArgs, standalone);
 | 
				
			||||||
 | 
					      await exec.exec(createCmd.commandLine, createCmd.args);
 | 
				
			||||||
      core.endGroup();
 | 
					      core.endGroup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      core.startGroup(`Booting builder`);
 | 
					      core.startGroup(`Booting builder`);
 | 
				
			||||||
      const bootstrapArgs: Array<string> = ['buildx', 'inspect', '--bootstrap'];
 | 
					      const bootstrapArgs: Array<string> = ['inspect', '--bootstrap'];
 | 
				
			||||||
      if (buildx.satisfies(buildxVersion, '>=0.4.0')) {
 | 
					      if (buildx.satisfies(buildxVersion, '>=0.4.0')) {
 | 
				
			||||||
        bootstrapArgs.push('--builder', builderName);
 | 
					        bootstrapArgs.push('--builder', builderName);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      await exec.exec('docker', bootstrapArgs);
 | 
					      const bootstrapCmd = buildx.getCommand(bootstrapArgs, standalone);
 | 
				
			||||||
 | 
					      await exec.exec(bootstrapCmd.commandLine, bootstrapCmd.args);
 | 
				
			||||||
      core.endGroup();
 | 
					      core.endGroup();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (inputs.install) {
 | 
					    if (inputs.install) {
 | 
				
			||||||
 | 
					      if (standalone) {
 | 
				
			||||||
 | 
					        throw new Error(`Cannot set buildx as default builder without the Docker CLI`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      core.startGroup(`Setting buildx as default builder`);
 | 
					      core.startGroup(`Setting buildx as default builder`);
 | 
				
			||||||
      await exec.exec('docker', ['buildx', 'install']);
 | 
					      await exec.exec('docker', ['buildx', 'install']);
 | 
				
			||||||
      core.endGroup();
 | 
					      core.endGroup();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    core.startGroup(`Inspect builder`);
 | 
					    core.startGroup(`Inspect builder`);
 | 
				
			||||||
    const builder = await buildx.inspect(builderName);
 | 
					    const builder = await buildx.inspect(builderName, standalone);
 | 
				
			||||||
    core.info(JSON.stringify(builder, undefined, 2));
 | 
					    core.info(JSON.stringify(builder, undefined, 2));
 | 
				
			||||||
    context.setOutput('driver', builder.driver);
 | 
					    context.setOutput('driver', builder.driver);
 | 
				
			||||||
    context.setOutput('endpoint', builder.node_endpoint);
 | 
					    context.setOutput('endpoint', builder.node_endpoint);
 | 
				
			||||||
@ -83,7 +111,7 @@ async function run(): Promise<void> {
 | 
				
			|||||||
    context.setOutput('platforms', builder.node_platforms);
 | 
					    context.setOutput('platforms', builder.node_platforms);
 | 
				
			||||||
    core.endGroup();
 | 
					    core.endGroup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (inputs.driver == 'docker-container') {
 | 
					    if (!standalone && inputs.driver == 'docker-container') {
 | 
				
			||||||
      stateHelper.setContainerName(`buildx_buildkit_${builder.node_name}`);
 | 
					      stateHelper.setContainerName(`buildx_buildkit_${builder.node_name}`);
 | 
				
			||||||
      core.startGroup(`BuildKit version`);
 | 
					      core.startGroup(`BuildKit version`);
 | 
				
			||||||
      core.info(await buildx.getBuildKitVersion(`buildx_buildkit_${builder.node_name}`));
 | 
					      core.info(await buildx.getBuildKitVersion(`buildx_buildkit_${builder.node_name}`));
 | 
				
			||||||
@ -114,8 +142,9 @@ async function cleanup(): Promise<void> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  if (stateHelper.builderName.length > 0) {
 | 
					  if (stateHelper.builderName.length > 0) {
 | 
				
			||||||
    core.startGroup(`Removing builder`);
 | 
					    core.startGroup(`Removing builder`);
 | 
				
			||||||
 | 
					    const rmCmd = buildx.getCommand(['rm', stateHelper.builderName], /true/i.test(stateHelper.standalone));
 | 
				
			||||||
    await exec
 | 
					    await exec
 | 
				
			||||||
      .getExecOutput('docker', ['buildx', 'rm', `${stateHelper.builderName}`], {
 | 
					      .getExecOutput(rmCmd.commandLine, rmCmd.args, {
 | 
				
			||||||
        ignoreReturnCode: true
 | 
					        ignoreReturnCode: true
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      .then(res => {
 | 
					      .then(res => {
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@ import * as core from '@actions/core';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export const IsPost = !!process.env['STATE_isPost'];
 | 
					export const IsPost = !!process.env['STATE_isPost'];
 | 
				
			||||||
export const IsDebug = !!process.env['STATE_isDebug'];
 | 
					export const IsDebug = !!process.env['STATE_isDebug'];
 | 
				
			||||||
 | 
					export const standalone = process.env['STATE_standalone'] || '';
 | 
				
			||||||
export const builderName = process.env['STATE_builderName'] || '';
 | 
					export const builderName = process.env['STATE_builderName'] || '';
 | 
				
			||||||
export const containerName = process.env['STATE_containerName'] || '';
 | 
					export const containerName = process.env['STATE_containerName'] || '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -9,6 +10,10 @@ export function setDebug(debug: string) {
 | 
				
			|||||||
  core.saveState('isDebug', debug);
 | 
					  core.saveState('isDebug', debug);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function setStandalone(standalone: boolean) {
 | 
				
			||||||
 | 
					  core.saveState('standalone', standalone);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function setBuilderName(builderName: string) {
 | 
					export function setBuilderName(builderName: string) {
 | 
				
			||||||
  core.saveState('builderName', builderName);
 | 
					  core.saveState('builderName', builderName);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user