diff --git a/__tests__/context.test.ts b/__tests__/context.test.ts index 5fb156c2..075bc37e 100644 --- a/__tests__/context.test.ts +++ b/__tests__/context.test.ts @@ -1,7 +1,8 @@ -import {beforeEach, describe, expect, it, jest} from '@jest/globals'; +import {beforeEach, describe, expect, it, jest, test} from '@jest/globals'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; +import * as uuid from 'uuid'; import * as context from '../src/context'; const tmpdir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-setup-buildx-')).split(path.sep).join(path.posix.sep); @@ -13,6 +14,95 @@ jest.spyOn(context, 'tmpNameSync').mockImplementation((): string => { return path.join(tmpdir, '.tmpname').split(path.sep).join(path.posix.sep); }); +jest.mock('uuid'); +jest.spyOn(uuid, 'v4').mockReturnValue('9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'); + +describe('getCreateArgs', () => { + beforeEach(() => { + process.env = Object.keys(process.env).reduce((object, key) => { + if (!key.startsWith('INPUT_')) { + object[key] = process.env[key]; + } + return object; + }, {}); + }); + + // prettier-ignore + test.each([ + [ + 0, + new Map([ + ['install', 'false'], + ['use', 'true'], + ]), + [ + 'create', + '--name', 'builder-9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d', + '--driver', 'docker-container', + '--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host', + '--use' + ] + ], + [ + 1, + new Map([ + ['driver', 'docker'], + ['install', 'false'], + ['use', 'true'], + ]), + [ + 'create', + '--name', 'default', + '--driver', 'docker', + '--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host', + '--use' + ] + ], + [ + 2, + new Map([ + ['install', 'false'], + ['use', 'false'], + ['driver-opts', 'image=moby/buildkit:master\nnetwork=host'], + ]), + [ + 'create', + '--name', 'builder-9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d', + '--driver', 'docker-container', + '--driver-opt', 'image=moby/buildkit:master', + '--driver-opt', 'network=host', + '--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host' + ] + ], + [ + 3, + new Map([ + ['driver', 'remote'], + ['endpoint', 'tls://foo:1234'], + ['install', 'false'], + ['use', 'true'], + ]), + [ + 'create', + '--name', 'builder-9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d', + '--driver', 'remote', + '--use', + 'tls://foo:1234' + ] + ], + ])( + '[%d] given %p as inputs, returns %p', + async (num: number, inputs: Map, expected: Array) => { + inputs.forEach((value: string, name: string) => { + setInput(name, value); + }); + const inp = await context.getInputs(); + const res = await context.getCreateArgs(inp, '0.9.0'); + expect(res).toEqual(expected); + } + ); +}); + describe('getInputList', () => { it('handles single line correctly', async () => { await setInput('foo', 'bar'); diff --git a/src/context.ts b/src/context.ts index 046e726b..3e92e492 100644 --- a/src/context.ts +++ b/src/context.ts @@ -2,6 +2,8 @@ import fs from 'fs'; import * as os from 'os'; import path from 'path'; import * as tmp from 'tmp'; +import * as uuid from 'uuid'; +import * as buildx from './buildx'; import * as core from '@actions/core'; import {issueCommand} from '@actions/core/lib/command'; @@ -22,6 +24,7 @@ export function tmpNameSync(options?: tmp.TmpNameOptions): string { export interface Inputs { version: string; + name: string; driver: string; driverOpts: string[]; buildkitdFlags: string; @@ -35,6 +38,7 @@ export interface Inputs { export async function getInputs(): Promise { return { version: core.getInput('version'), + name: getBuilderName(core.getInput('driver') || 'docker-container'), driver: core.getInput('driver') || 'docker-container', driverOpts: await getInputList('driver-opts', true), buildkitdFlags: core.getInput('buildkitd-flags') || '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host', @@ -46,6 +50,44 @@ export async function getInputs(): Promise { }; } +export function getBuilderName(driver: string): string { + return driver == 'docker' ? 'default' : `builder-${uuid.v4()}`; +} + +export async function getCreateArgs(inputs: Inputs, buildxVersion: string): Promise> { + const args: Array = ['create', '--name', inputs.name, '--driver', inputs.driver]; + if (buildx.satisfies(buildxVersion, '>=0.3.0')) { + await asyncForEach(inputs.driverOpts, async driverOpt => { + args.push('--driver-opt', driverOpt); + }); + if (inputs.driver != 'remote' && inputs.buildkitdFlags) { + args.push('--buildkitd-flags', inputs.buildkitdFlags); + } + } + if (inputs.use) { + args.push('--use'); + } + if (inputs.driver != 'remote') { + if (inputs.config) { + args.push('--config', await buildx.getConfigFile(inputs.config)); + } else if (inputs.configInline) { + args.push('--config', await buildx.getConfigInline(inputs.configInline)); + } + } + if (inputs.endpoint) { + args.push(inputs.endpoint); + } + return args; +} + +export async function getInspectArgs(inputs: Inputs, buildxVersion: string): Promise> { + const args: Array = ['inspect', '--bootstrap']; + if (buildx.satisfies(buildxVersion, '>=0.4.0')) { + args.push('--builder', inputs.name); + } + return args; +} + export async function getInputList(name: string, ignoreComma?: boolean): Promise { const items = core.getInput(name); if (items == '') { diff --git a/src/main.ts b/src/main.ts index a0d4f6ba..04c33ea7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,7 +1,6 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -import * as uuid from 'uuid'; import * as auth from './auth'; import * as buildx from './buildx'; import * as context from './context'; @@ -54,11 +53,10 @@ async function run(): Promise { }); }); - const builderName: string = inputs.driver == 'docker' ? 'default' : `builder-${uuid.v4()}`; - context.setOutput('name', builderName); - stateHelper.setBuilderName(builderName); + context.setOutput('name', inputs.name); + stateHelper.setBuilderName(inputs.name); - const credsdir = path.join(dockerConfigHome, 'buildx', 'creds', builderName); + const credsdir = path.join(dockerConfigHome, 'buildx', 'creds', inputs.name); fs.mkdirSync(credsdir, {recursive: true}); stateHelper.setCredsDir(credsdir); @@ -68,42 +66,16 @@ async function run(): Promise { if (authOpts.length > 0) { inputs.driverOpts = [...inputs.driverOpts, ...authOpts]; } - const createArgs: Array = ['create', '--name', builderName, '--driver', inputs.driver]; - if (buildx.satisfies(buildxVersion, '>=0.3.0')) { - await context.asyncForEach(inputs.driverOpts, async driverOpt => { - createArgs.push('--driver-opt', driverOpt); - }); - if (inputs.driver != 'remote' && inputs.buildkitdFlags) { - createArgs.push('--buildkitd-flags', inputs.buildkitdFlags); - } - } - if (inputs.use) { - createArgs.push('--use'); - } - if (inputs.endpoint) { - createArgs.push(inputs.endpoint); - } - if (inputs.driver != 'remote') { - if (inputs.config) { - createArgs.push('--config', await buildx.getConfigFile(inputs.config)); - } else if (inputs.configInline) { - createArgs.push('--config', await buildx.getConfigInline(inputs.configInline)); - } - } - const createCmd = buildx.getCommand(createArgs, standalone); + const createCmd = buildx.getCommand(await context.getCreateArgs(inputs, buildxVersion), standalone); await exec.exec(createCmd.commandLine, createCmd.args); core.endGroup(); - - core.startGroup(`Booting builder`); - const bootstrapArgs: Array = ['inspect', '--bootstrap']; - if (buildx.satisfies(buildxVersion, '>=0.4.0')) { - bootstrapArgs.push('--builder', builderName); - } - const bootstrapCmd = buildx.getCommand(bootstrapArgs, standalone); - await exec.exec(bootstrapCmd.commandLine, bootstrapCmd.args); - core.endGroup(); } + core.startGroup(`Booting builder`); + const inspectCmd = buildx.getCommand(await context.getInspectArgs(inputs, buildxVersion), standalone); + await exec.exec(inspectCmd.commandLine, inspectCmd.args); + core.endGroup(); + if (inputs.install) { if (standalone) { throw new Error(`Cannot set buildx as default builder without the Docker CLI`); @@ -114,7 +86,7 @@ async function run(): Promise { } core.startGroup(`Inspect builder`); - const builder = await buildx.inspect(builderName, standalone); + const builder = await buildx.inspect(inputs.name, standalone); const firstNode = builder.nodes[0]; core.info(JSON.stringify(builder, undefined, 2)); context.setOutput('driver', builder.driver);