2022-09-22 02:48:11 +02:00
|
|
|
import * as fs from 'fs';
|
2020-08-18 17:40:31 +02:00
|
|
|
import * as os from 'os';
|
|
|
|
import * as path from 'path';
|
2022-09-22 02:48:11 +02:00
|
|
|
import * as auth from './auth';
|
2020-08-18 17:40:31 +02:00
|
|
|
import * as buildx from './buildx';
|
2020-09-03 16:23:15 +02:00
|
|
|
import * as context from './context';
|
2022-04-17 17:22:03 +02:00
|
|
|
import * as docker from './docker';
|
2020-08-18 17:40:31 +02:00
|
|
|
import * as stateHelper from './state-helper';
|
2021-07-02 07:02:22 +02:00
|
|
|
import * as util from './util';
|
2021-06-23 16:11:52 +02:00
|
|
|
import * as core from '@actions/core';
|
|
|
|
import * as exec from '@actions/exec';
|
2020-08-18 17:40:31 +02:00
|
|
|
|
|
|
|
async function run(): Promise<void> {
|
|
|
|
try {
|
2020-09-03 16:23:15 +02:00
|
|
|
const inputs: context.Inputs = await context.getInputs();
|
2020-08-18 17:40:31 +02:00
|
|
|
const dockerConfigHome: string = process.env.DOCKER_CONFIG || path.join(os.homedir(), '.docker');
|
|
|
|
|
2022-04-17 17:22:03 +02:00
|
|
|
// standalone if docker cli not available
|
|
|
|
const standalone = !(await docker.isAvailable());
|
|
|
|
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();
|
|
|
|
|
2021-07-02 07:02:22 +02:00
|
|
|
if (util.isValidUrl(inputs.version)) {
|
2022-04-17 17:22:03 +02:00
|
|
|
if (standalone) {
|
|
|
|
throw new Error(`Cannot build from source without the Docker CLI`);
|
|
|
|
}
|
2021-07-02 07:02:22 +02:00
|
|
|
core.startGroup(`Build and install buildx`);
|
2022-04-17 17:22:03 +02:00
|
|
|
await buildx.build(inputs.version, dockerConfigHome, standalone);
|
2021-07-02 07:02:22 +02:00
|
|
|
core.endGroup();
|
2022-04-17 17:22:03 +02:00
|
|
|
} else if (!(await buildx.isAvailable(standalone)) || inputs.version) {
|
2021-07-02 07:02:22 +02:00
|
|
|
core.startGroup(`Download and install buildx`);
|
2022-04-17 17:22:03 +02:00
|
|
|
await buildx.install(inputs.version || 'latest', standalone ? context.tmpDir() : dockerConfigHome, standalone);
|
2020-10-20 22:29:53 +02:00
|
|
|
core.endGroup();
|
2020-08-18 17:40:31 +02:00
|
|
|
}
|
|
|
|
|
2022-04-17 17:22:03 +02:00
|
|
|
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
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-10-12 11:30:30 +02:00
|
|
|
core.setOutput('name', inputs.name);
|
2022-09-19 11:36:58 +02:00
|
|
|
stateHelper.setBuilderName(inputs.name);
|
2020-08-18 17:40:31 +02:00
|
|
|
|
2022-09-19 11:36:58 +02:00
|
|
|
const credsdir = path.join(dockerConfigHome, 'buildx', 'creds', inputs.name);
|
2022-09-22 02:48:11 +02:00
|
|
|
fs.mkdirSync(credsdir, {recursive: true});
|
|
|
|
stateHelper.setCredsDir(credsdir);
|
|
|
|
|
2020-09-03 16:23:15 +02:00
|
|
|
if (inputs.driver !== 'docker') {
|
2021-04-02 01:19:14 +02:00
|
|
|
core.startGroup(`Creating a new builder instance`);
|
2022-09-22 02:48:11 +02:00
|
|
|
const authOpts = auth.setCredentials(credsdir, 0, inputs.driver, inputs.endpoint);
|
|
|
|
if (authOpts.length > 0) {
|
|
|
|
inputs.driverOpts = [...inputs.driverOpts, ...authOpts];
|
|
|
|
}
|
2022-09-19 11:36:58 +02:00
|
|
|
const createCmd = buildx.getCommand(await context.getCreateArgs(inputs, buildxVersion), standalone);
|
2022-04-17 17:22:03 +02:00
|
|
|
await exec.exec(createCmd.commandLine, createCmd.args);
|
2020-10-20 22:29:53 +02:00
|
|
|
core.endGroup();
|
2020-08-27 02:41:25 +02:00
|
|
|
}
|
2020-08-18 17:40:31 +02:00
|
|
|
|
2022-09-19 11:36:58 +02:00
|
|
|
core.startGroup(`Booting builder`);
|
|
|
|
const inspectCmd = buildx.getCommand(await context.getInspectArgs(inputs, buildxVersion), standalone);
|
|
|
|
await exec.exec(inspectCmd.commandLine, inspectCmd.args);
|
|
|
|
core.endGroup();
|
|
|
|
|
2020-09-03 16:23:15 +02:00
|
|
|
if (inputs.install) {
|
2022-04-17 17:22:03 +02:00
|
|
|
if (standalone) {
|
|
|
|
throw new Error(`Cannot set buildx as default builder without the Docker CLI`);
|
|
|
|
}
|
2021-04-02 01:19:14 +02:00
|
|
|
core.startGroup(`Setting buildx as default builder`);
|
2020-08-18 17:40:31 +02:00
|
|
|
await exec.exec('docker', ['buildx', 'install']);
|
2020-10-20 22:29:53 +02:00
|
|
|
core.endGroup();
|
2020-08-18 17:40:31 +02:00
|
|
|
}
|
|
|
|
|
2021-04-23 18:14:38 +02:00
|
|
|
core.startGroup(`Inspect builder`);
|
2022-09-19 11:36:58 +02:00
|
|
|
const builder = await buildx.inspect(inputs.name, standalone);
|
2022-09-18 02:24:38 +02:00
|
|
|
const firstNode = builder.nodes[0];
|
2021-04-23 18:14:38 +02:00
|
|
|
core.info(JSON.stringify(builder, undefined, 2));
|
2022-10-12 11:30:30 +02:00
|
|
|
core.setOutput('driver', builder.driver);
|
|
|
|
core.setOutput('platforms', firstNode.platforms);
|
|
|
|
core.setOutput('nodes', JSON.stringify(builder.nodes, undefined, 2));
|
|
|
|
core.setOutput('endpoint', firstNode.endpoint); // TODO: deprecated, to be removed in a later version
|
|
|
|
core.setOutput('status', firstNode.status); // TODO: deprecated, to be removed in a later version
|
|
|
|
core.setOutput('flags', firstNode['buildkitd-flags']); // TODO: deprecated, to be removed in a later version
|
2020-10-20 22:29:53 +02:00
|
|
|
core.endGroup();
|
2021-04-23 22:08:40 +02:00
|
|
|
|
2022-09-18 02:24:38 +02:00
|
|
|
if (!standalone && builder.driver == 'docker-container') {
|
|
|
|
stateHelper.setContainerName(`buildx_buildkit_${firstNode.name}`);
|
2021-04-28 18:08:43 +02:00
|
|
|
core.startGroup(`BuildKit version`);
|
2022-09-18 02:24:38 +02:00
|
|
|
for (const node of builder.nodes) {
|
|
|
|
const bkvers = await buildx.getBuildKitVersion(`buildx_buildkit_${node.name}`);
|
|
|
|
core.info(`${node.name}: ${bkvers}`);
|
|
|
|
}
|
2021-04-28 18:08:43 +02:00
|
|
|
core.endGroup();
|
2021-04-23 22:08:40 +02:00
|
|
|
}
|
2022-09-18 02:24:38 +02:00
|
|
|
if (core.isDebug() || firstNode['buildkitd-flags']?.includes('--debug')) {
|
2021-04-23 22:08:40 +02:00
|
|
|
stateHelper.setDebug('true');
|
|
|
|
}
|
2020-08-18 17:40:31 +02:00
|
|
|
} catch (error) {
|
|
|
|
core.setFailed(error.message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function cleanup(): Promise<void> {
|
2021-04-23 22:08:40 +02:00
|
|
|
if (stateHelper.IsDebug && stateHelper.containerName.length > 0) {
|
|
|
|
core.startGroup(`BuildKit container logs`);
|
2021-06-23 16:11:52 +02:00
|
|
|
await exec
|
|
|
|
.getExecOutput('docker', ['logs', `${stateHelper.containerName}`], {
|
|
|
|
ignoreReturnCode: true
|
|
|
|
})
|
|
|
|
.then(res => {
|
|
|
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
|
|
core.warning(res.stderr.trim());
|
|
|
|
}
|
|
|
|
});
|
2021-04-23 22:08:40 +02:00
|
|
|
core.endGroup();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stateHelper.builderName.length > 0) {
|
|
|
|
core.startGroup(`Removing builder`);
|
2022-04-17 17:22:03 +02:00
|
|
|
const rmCmd = buildx.getCommand(['rm', stateHelper.builderName], /true/i.test(stateHelper.standalone));
|
2021-06-23 16:11:52 +02:00
|
|
|
await exec
|
2022-04-17 17:22:03 +02:00
|
|
|
.getExecOutput(rmCmd.commandLine, rmCmd.args, {
|
2021-06-23 16:11:52 +02:00
|
|
|
ignoreReturnCode: true
|
|
|
|
})
|
|
|
|
.then(res => {
|
|
|
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
|
|
core.warning(res.stderr.trim());
|
|
|
|
}
|
|
|
|
});
|
2021-04-23 22:08:40 +02:00
|
|
|
core.endGroup();
|
2020-08-18 17:40:31 +02:00
|
|
|
}
|
2022-09-22 02:48:11 +02:00
|
|
|
|
|
|
|
if (stateHelper.credsDir.length > 0 && fs.existsSync(stateHelper.credsDir)) {
|
|
|
|
core.info(`Cleaning up credentials`);
|
2022-10-12 12:05:06 +02:00
|
|
|
fs.rmSync(stateHelper.credsDir, {recursive: true});
|
2022-09-22 02:48:11 +02:00
|
|
|
}
|
2020-08-18 17:40:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!stateHelper.IsPost) {
|
|
|
|
run();
|
|
|
|
} else {
|
|
|
|
cleanup();
|
|
|
|
}
|