2022-09-22 08:48:11 +08:00
|
|
|
import * as fs from 'fs';
|
2023-02-19 09:12:29 +08:00
|
|
|
import * as yaml from 'js-yaml';
|
2021-06-23 22:11:52 +08:00
|
|
|
import * as core from '@actions/core';
|
2023-02-19 09:12:29 +08:00
|
|
|
import * as actionsToolkit from '@docker/actions-toolkit';
|
2024-07-04 05:10:05 +08:00
|
|
|
|
2023-02-19 09:12:29 +08:00
|
|
|
import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx';
|
2023-03-10 07:05:22 +08:00
|
|
|
import {Builder} from '@docker/actions-toolkit/lib/buildx/builder';
|
2023-03-09 02:12:49 +08:00
|
|
|
import {Docker} from '@docker/actions-toolkit/lib/docker/docker';
|
2024-04-12 18:09:07 +08:00
|
|
|
import {Exec} from '@docker/actions-toolkit/lib/exec';
|
2023-02-19 09:12:29 +08:00
|
|
|
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit';
|
|
|
|
import {Util} from '@docker/actions-toolkit/lib/util';
|
2024-07-04 05:10:05 +08:00
|
|
|
|
|
|
|
import {Node} from '@docker/actions-toolkit/lib/types/buildx/builder';
|
2023-02-19 09:12:29 +08:00
|
|
|
|
|
|
|
import * as context from './context';
|
|
|
|
import * as stateHelper from './state-helper';
|
2020-08-18 23:40:31 +08:00
|
|
|
|
2023-02-19 09:12:29 +08:00
|
|
|
actionsToolkit.run(
|
|
|
|
// main
|
|
|
|
async () => {
|
2020-09-03 22:23:15 +08:00
|
|
|
const inputs: context.Inputs = await context.getInputs();
|
2023-03-03 18:56:21 +08:00
|
|
|
stateHelper.setCleanup(inputs.cleanup);
|
2020-08-18 23:40:31 +08:00
|
|
|
|
2023-03-03 18:56:21 +08:00
|
|
|
const toolkit = new Toolkit();
|
2023-02-19 09:12:29 +08:00
|
|
|
const standalone = await toolkit.buildx.isStandalone();
|
2022-04-17 23:22:03 +08:00
|
|
|
stateHelper.setStandalone(standalone);
|
|
|
|
|
2023-02-19 09:12:29 +08:00
|
|
|
await core.group(`Docker info`, async () => {
|
|
|
|
try {
|
|
|
|
await Docker.printVersion();
|
|
|
|
await Docker.printInfo();
|
|
|
|
} catch (e) {
|
|
|
|
core.info(e.message);
|
|
|
|
}
|
|
|
|
});
|
2022-04-17 23:22:03 +08:00
|
|
|
|
2023-02-19 09:12:29 +08:00
|
|
|
let toolPath;
|
2023-04-17 08:59:25 +08:00
|
|
|
if (Util.isValidRef(inputs.version)) {
|
2022-04-17 23:22:03 +08:00
|
|
|
if (standalone) {
|
|
|
|
throw new Error(`Cannot build from source without the Docker CLI`);
|
|
|
|
}
|
2023-02-19 09:12:29 +08:00
|
|
|
await core.group(`Build buildx from source`, async () => {
|
2024-02-23 17:51:47 +08:00
|
|
|
toolPath = await toolkit.buildxInstall.build(inputs.version, !inputs.cacheBinary);
|
2023-02-19 09:12:29 +08:00
|
|
|
});
|
|
|
|
} else if (!(await toolkit.buildx.isAvailable()) || inputs.version) {
|
|
|
|
await core.group(`Download buildx from GitHub Releases`, async () => {
|
2024-02-23 17:51:47 +08:00
|
|
|
toolPath = await toolkit.buildxInstall.download(inputs.version || 'latest', !inputs.cacheBinary);
|
2023-02-19 09:12:29 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
if (toolPath) {
|
|
|
|
await core.group(`Install buildx`, async () => {
|
|
|
|
if (standalone) {
|
|
|
|
await toolkit.buildxInstall.installStandalone(toolPath);
|
|
|
|
} else {
|
|
|
|
await toolkit.buildxInstall.installPlugin(toolPath);
|
|
|
|
}
|
|
|
|
});
|
2020-08-18 23:40:31 +08:00
|
|
|
}
|
|
|
|
|
2022-04-17 23:22:03 +08:00
|
|
|
await core.group(`Buildx version`, async () => {
|
2023-02-19 09:12:29 +08:00
|
|
|
await toolkit.buildx.printVersion();
|
2022-04-17 23:22:03 +08:00
|
|
|
});
|
|
|
|
|
2022-10-12 17:30:30 +08:00
|
|
|
core.setOutput('name', inputs.name);
|
2022-09-19 17:36:58 +08:00
|
|
|
stateHelper.setBuilderName(inputs.name);
|
2023-03-03 20:46:26 +08:00
|
|
|
stateHelper.setBuilderDriver(inputs.driver);
|
2020-08-18 23:40:31 +08:00
|
|
|
|
2023-02-19 09:12:29 +08:00
|
|
|
fs.mkdirSync(Buildx.certsDir, {recursive: true});
|
|
|
|
stateHelper.setCertsDir(Buildx.certsDir);
|
2022-09-22 08:48:11 +08:00
|
|
|
|
2020-09-03 22:23:15 +08:00
|
|
|
if (inputs.driver !== 'docker') {
|
2023-02-19 09:12:29 +08:00
|
|
|
await core.group(`Creating a new builder instance`, async () => {
|
|
|
|
const certsDriverOpts = Buildx.resolveCertsDriverOpts(inputs.driver, inputs.endpoint, {
|
|
|
|
cacert: process.env[`${context.builderNodeEnvPrefix}_0_AUTH_TLS_CACERT`],
|
|
|
|
cert: process.env[`${context.builderNodeEnvPrefix}_0_AUTH_TLS_CERT`],
|
|
|
|
key: process.env[`${context.builderNodeEnvPrefix}_0_AUTH_TLS_KEY`]
|
|
|
|
});
|
|
|
|
if (certsDriverOpts.length > 0) {
|
|
|
|
inputs.driverOpts = [...inputs.driverOpts, ...certsDriverOpts];
|
|
|
|
}
|
|
|
|
const createCmd = await toolkit.buildx.getCommand(await context.getCreateArgs(inputs, toolkit));
|
2024-04-12 18:09:07 +08:00
|
|
|
await Exec.getExecOutput(createCmd.command, createCmd.args, {
|
|
|
|
ignoreReturnCode: true
|
|
|
|
}).then(res => {
|
|
|
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
|
|
throw new Error(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
|
|
|
}
|
|
|
|
});
|
2023-02-19 09:12:29 +08:00
|
|
|
});
|
2020-08-27 08:41:25 +08:00
|
|
|
}
|
2020-08-18 23:40:31 +08:00
|
|
|
|
2022-09-19 17:34:47 +08:00
|
|
|
if (inputs.append) {
|
2023-02-19 09:12:29 +08:00
|
|
|
await core.group(`Appending node(s) to builder`, async () => {
|
|
|
|
let nodeIndex = 1;
|
|
|
|
const nodes = yaml.load(inputs.append) as Node[];
|
|
|
|
for (const node of nodes) {
|
|
|
|
const certsDriverOpts = Buildx.resolveCertsDriverOpts(inputs.driver, `${node.endpoint}`, {
|
|
|
|
cacert: process.env[`${context.builderNodeEnvPrefix}_${nodeIndex}_AUTH_TLS_CACERT`],
|
|
|
|
cert: process.env[`${context.builderNodeEnvPrefix}_${nodeIndex}_AUTH_TLS_CERT`],
|
|
|
|
key: process.env[`${context.builderNodeEnvPrefix}_${nodeIndex}_AUTH_TLS_KEY`]
|
|
|
|
});
|
|
|
|
if (certsDriverOpts.length > 0) {
|
|
|
|
node['driver-opts'] = [...(node['driver-opts'] || []), ...certsDriverOpts];
|
|
|
|
}
|
|
|
|
const appendCmd = await toolkit.buildx.getCommand(await context.getAppendArgs(inputs, node, toolkit));
|
2024-04-12 18:09:07 +08:00
|
|
|
await Exec.getExecOutput(appendCmd.command, appendCmd.args, {
|
|
|
|
ignoreReturnCode: true
|
|
|
|
}).then(res => {
|
|
|
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
|
|
throw new Error(`Failed to append node ${node.name}: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
|
|
|
|
}
|
|
|
|
});
|
2023-02-19 09:12:29 +08:00
|
|
|
nodeIndex++;
|
2022-09-19 17:34:47 +08:00
|
|
|
}
|
2023-02-19 09:12:29 +08:00
|
|
|
});
|
2022-09-19 17:34:47 +08:00
|
|
|
}
|
|
|
|
|
2023-02-19 09:12:29 +08:00
|
|
|
await core.group(`Booting builder`, async () => {
|
|
|
|
const inspectCmd = await toolkit.buildx.getCommand(await context.getInspectArgs(inputs, toolkit));
|
2024-04-12 18:09:07 +08:00
|
|
|
await Exec.getExecOutput(inspectCmd.command, inspectCmd.args, {
|
|
|
|
ignoreReturnCode: true
|
|
|
|
}).then(res => {
|
|
|
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
|
|
throw new Error(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
|
|
|
}
|
|
|
|
});
|
2023-02-19 09:12:29 +08:00
|
|
|
});
|
2022-09-19 17:36:58 +08:00
|
|
|
|
2020-09-03 22:23:15 +08:00
|
|
|
if (inputs.install) {
|
2022-04-17 23:22:03 +08:00
|
|
|
if (standalone) {
|
|
|
|
throw new Error(`Cannot set buildx as default builder without the Docker CLI`);
|
|
|
|
}
|
2023-02-19 09:12:29 +08:00
|
|
|
await core.group(`Setting buildx as default builder`, async () => {
|
|
|
|
const installCmd = await toolkit.buildx.getCommand(['install']);
|
2024-04-12 18:09:07 +08:00
|
|
|
await Exec.getExecOutput(installCmd.command, installCmd.args, {
|
|
|
|
ignoreReturnCode: true
|
|
|
|
}).then(res => {
|
|
|
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
|
|
throw new Error(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
|
|
|
}
|
|
|
|
});
|
2023-02-19 09:12:29 +08:00
|
|
|
});
|
2020-08-18 23:40:31 +08:00
|
|
|
}
|
|
|
|
|
2023-02-19 09:12:29 +08:00
|
|
|
const builderInspect = await toolkit.builder.inspect(inputs.name);
|
|
|
|
const firstNode = builderInspect.nodes[0];
|
|
|
|
|
|
|
|
await core.group(`Inspect builder`, async () => {
|
|
|
|
const reducedPlatforms: Array<string> = [];
|
|
|
|
for (const node of builderInspect.nodes) {
|
|
|
|
for (const platform of node.platforms?.split(',') || []) {
|
|
|
|
if (reducedPlatforms.indexOf(platform) > -1) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
reducedPlatforms.push(platform);
|
2022-09-19 17:34:47 +08:00
|
|
|
}
|
2022-09-18 08:24:38 +08:00
|
|
|
}
|
2023-02-19 09:12:29 +08:00
|
|
|
core.info(JSON.stringify(builderInspect, undefined, 2));
|
|
|
|
core.setOutput('driver', builderInspect.driver);
|
|
|
|
core.setOutput('platforms', reducedPlatforms.join(','));
|
|
|
|
core.setOutput('nodes', JSON.stringify(builderInspect.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
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!standalone && builderInspect.driver == 'docker-container') {
|
|
|
|
stateHelper.setContainerName(`${Buildx.containerNamePrefix}${firstNode.name}`);
|
|
|
|
await core.group(`BuildKit version`, async () => {
|
|
|
|
for (const node of builderInspect.nodes) {
|
|
|
|
const buildkitVersion = await toolkit.buildkit.getVersion(node);
|
|
|
|
core.info(`${node.name}: ${buildkitVersion}`);
|
|
|
|
}
|
|
|
|
});
|
2021-04-24 04:08:40 +08:00
|
|
|
}
|
2022-09-18 08:24:38 +08:00
|
|
|
if (core.isDebug() || firstNode['buildkitd-flags']?.includes('--debug')) {
|
2021-04-24 04:08:40 +08:00
|
|
|
stateHelper.setDebug('true');
|
|
|
|
}
|
2023-02-19 09:12:29 +08:00
|
|
|
},
|
|
|
|
// post
|
|
|
|
async () => {
|
|
|
|
if (stateHelper.IsDebug && stateHelper.containerName.length > 0) {
|
|
|
|
await core.group(`BuildKit container logs`, async () => {
|
2024-04-12 18:09:07 +08:00
|
|
|
await Exec.getExecOutput('docker', ['logs', `${stateHelper.containerName}`], {
|
|
|
|
ignoreReturnCode: true
|
|
|
|
}).then(res => {
|
|
|
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
|
|
core.warning(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
|
|
|
}
|
|
|
|
});
|
2021-06-23 22:11:52 +08:00
|
|
|
});
|
2023-02-19 09:12:29 +08:00
|
|
|
}
|
2021-04-24 04:08:40 +08:00
|
|
|
|
2023-03-03 18:56:21 +08:00
|
|
|
if (!stateHelper.cleanup) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-03-03 20:46:26 +08:00
|
|
|
if (stateHelper.builderDriver != 'docker' && stateHelper.builderName.length > 0) {
|
2023-02-19 09:12:29 +08:00
|
|
|
await core.group(`Removing builder`, async () => {
|
2023-03-03 18:56:21 +08:00
|
|
|
const buildx = new Buildx({standalone: stateHelper.standalone});
|
2023-03-10 07:05:22 +08:00
|
|
|
const builder = new Builder({buildx: buildx});
|
|
|
|
if (await builder.exists(stateHelper.builderName)) {
|
|
|
|
const rmCmd = await buildx.getCommand(['rm', stateHelper.builderName]);
|
2024-04-12 18:09:07 +08:00
|
|
|
await Exec.getExecOutput(rmCmd.command, rmCmd.args, {
|
|
|
|
ignoreReturnCode: true
|
|
|
|
}).then(res => {
|
|
|
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
|
|
core.warning(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
|
|
|
}
|
|
|
|
});
|
2023-03-10 07:05:22 +08:00
|
|
|
} else {
|
|
|
|
core.info(`${stateHelper.builderName} does not exist`);
|
|
|
|
}
|
2021-06-23 22:11:52 +08:00
|
|
|
});
|
2023-02-19 09:12:29 +08:00
|
|
|
}
|
2022-09-22 08:48:11 +08:00
|
|
|
|
2023-02-19 09:12:29 +08:00
|
|
|
if (stateHelper.certsDir.length > 0 && fs.existsSync(stateHelper.certsDir)) {
|
|
|
|
await core.group(`Cleaning up certificates`, async () => {
|
|
|
|
fs.rmSync(stateHelper.certsDir, {recursive: true});
|
|
|
|
});
|
|
|
|
}
|
2022-09-22 08:48:11 +08:00
|
|
|
}
|
2023-02-19 09:12:29 +08:00
|
|
|
);
|