Compare commits

...

43 Commits

Author SHA1 Message Date
CrazyMax
f78f708678 Merge pull request #57 from crazy-max/fix-docker-context
Some checks failed
publish / publish (push) Has been cancelled
docker: fix context command
2023-02-25 17:50:03 +01:00
CrazyMax
6fe7d54029 docker: fix context command
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-25 16:40:35 +01:00
CrazyMax
1cc5fc87fb Merge pull request #56 from crazy-max/docker-context
Some checks failed
publish / publish (push) Has been cancelled
docker: context method
2023-02-25 12:24:04 +01:00
CrazyMax
97e647fdd0 docker: context method
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-25 12:20:06 +01:00
CrazyMax
e08fc168a1 Merge pull request #54 from crazy-max/fix-node
builder: fix breaking change on node fields
2023-02-25 12:06:41 +01:00
CrazyMax
9128f56258 builder: fix breaking change on node fields
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-24 19:41:10 +01:00
CrazyMax
2e59ae7030 Merge pull request #53 from crazy-max/docker-io
Some checks failed
publish / publish (push) Has been cancelled
docker: check command using actions/io module
2023-02-21 08:46:20 +01:00
CrazyMax
99487d6986 docker: check command using actions/io module
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-21 08:40:27 +01:00
CrazyMax
3d9ec9f02d Merge pull request #52 from crazy-max/index
run function to handle GitHub Action main and post runs
2023-02-21 08:21:59 +01:00
CrazyMax
f2b1224b00 run function to handle GitHub Action main and post runs
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-21 08:18:56 +01:00
CrazyMax
1383a2bcaf Merge pull request #51 from crazy-max/fix-docker-exporter
Some checks failed
publish / publish (push) Has been cancelled
buildx: fix docker exporter check
2023-02-20 10:28:01 +01:00
CrazyMax
1acd6c2fc0 buildx: fix docker exporter check
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-20 10:25:50 +01:00
CrazyMax
d153cfaf3c Merge pull request #50 from crazy-max/github-throw-runtime-token
github: throw if runtime token invalid
2023-02-20 10:17:13 +01:00
CrazyMax
d09114e0c5 Merge pull request #49 from crazy-max/buildx-version
buildx: fix version method
2023-02-20 10:17:01 +01:00
CrazyMax
c3aa7f205d github: throw if runtime token invalid
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-20 10:14:11 +01:00
CrazyMax
62f8c6bef6 buildkit: fix debug logs for versionSatisfies
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-20 10:13:04 +01:00
CrazyMax
a9ce06b57e docker: do not set undefined args for checking availability
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-20 10:13:04 +01:00
CrazyMax
cb6ca3829f buildx: fix version method
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-20 09:59:44 +01:00
CrazyMax
1098847fe7 Merge pull request #48 from crazy-max/exec
Exec class
2023-02-20 09:21:41 +01:00
CrazyMax
35a8193474 Exec class
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-20 09:18:53 +01:00
CrazyMax
2915834633 Merge pull request #47 from crazy-max/context-static
make Context static
2023-02-20 07:27:00 +01:00
CrazyMax
a0e8f0bf18 make Context static
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-20 07:24:32 +01:00
CrazyMax
580aee99c0 Merge pull request #46 from crazy-max/buildx-split-install
Some checks failed
publish / publish (push) Has been cancelled
buildx: split install from download and build methods
2023-02-19 03:39:55 +01:00
CrazyMax
89ecd37681 buildx: info logs on install
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-19 03:34:30 +01:00
CrazyMax
139fb39ab0 buildx: split install from download and build methods
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-19 03:25:07 +01:00
CrazyMax
67957d8c7a Merge pull request #45 from crazy-max/docker-fix
docker: various fixes
2023-02-19 02:57:48 +01:00
CrazyMax
768df5fbf4 buildx: debug logs in isAvailable method
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-19 02:54:07 +01:00
CrazyMax
e9db81b6a1 docker: fix printVersion and printInfo
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-19 02:54:06 +01:00
CrazyMax
cd825ae548 docker: remove singleton
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-19 02:54:06 +01:00
CrazyMax
28c11a1819 Merge pull request #44 from crazy-max/cleanup
chore: remove path sep conversion
2023-02-19 01:52:35 +01:00
CrazyMax
ed087e5b0d chore: remove path sep conversion
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-19 00:59:04 +01:00
CrazyMax
2038d87306 Merge pull request #43 from crazy-max/fix-standalone
Some checks failed
publish / publish (push) Has been cancelled
fix buildx standalone and check for docker availability
2023-02-18 10:15:26 +01:00
CrazyMax
252c717cc3 fix buildx standalone and check for docker availability
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-18 10:09:41 +01:00
CrazyMax
9b338b58a7 toolkit: docker property not needed
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-18 10:08:21 +01:00
CrazyMax
abe37ab72b Merge pull request #42 from crazy-max/buildkit-fix-version
Some checks failed
publish / publish (push) Has been cancelled
buildkit: use node info to retrieve version
2023-02-18 07:34:55 +01:00
CrazyMax
b3a30a9e32 Merge pull request #41 from crazy-max/fix-docker
docker: fix instance
2023-02-18 07:32:33 +01:00
CrazyMax
31e915c017 buildkit: use node info to retrieve version
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-18 07:31:21 +01:00
CrazyMax
05bbe49fe1 toolkit: add docker
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-18 07:06:29 +01:00
CrazyMax
c80fedbbae docker: fix instance
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-18 07:06:20 +01:00
CrazyMax
2c60cad840 Merge pull request #40 from crazy-max/debug
Some checks failed
publish / publish (push) Has been cancelled
some debug logs
2023-02-18 06:00:54 +01:00
CrazyMax
847887b312 some debug logs
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-18 04:36:32 +01:00
CrazyMax
d9984214c9 Merge pull request #39 from crazy-max/buildkit-ctn-prefix
buildx: make containerNamePrefix static and public
2023-02-18 02:20:37 +01:00
CrazyMax
33b4390bc2 buildx: make containerNamePrefix static and public
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-02-18 02:12:09 +01:00
28 changed files with 533 additions and 470 deletions

View File

@@ -39,7 +39,7 @@ $ npm install @docker/actions-toolkit
## Usage
```js
const { Toolkit } = require('@docker/actions-toolkit')
const { Toolkit } = require('@docker/actions-toolkit/lib/toolkit')
const toolkit = new Toolkit()
```

View File

@@ -15,11 +15,9 @@
*/
import {beforeEach, describe, expect, it, jest, test} from '@jest/globals';
import * as semver from 'semver';
import {BuildKit} from '../../src/buildkit/buildkit';
import {Builder} from '../../src/buildx/builder';
import {Context} from '../../src/context';
import {BuilderInfo} from '../../src/types/builder';
@@ -34,9 +32,9 @@ jest.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise<Bu
lastActivity: new Date('2023-01-16 09:45:23 +0000 UTC'),
nodes: [
{
buildkitVersion: 'v0.11.0',
buildkitdFlags: '--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
driverOpts: ['BUILDKIT_STEP_LOG_MAX_SIZE=10485760', 'BUILDKIT_STEP_LOG_MAX_SPEED=10485760', 'JAEGER_TRACE=localhost:6831', 'image=moby/buildkit:latest', 'network=host'],
buildkit: 'v0.11.0',
'buildkitd-flags': '--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
'driver-opts': ['BUILDKIT_STEP_LOG_MAX_SIZE=10485760', 'BUILDKIT_STEP_LOG_MAX_SPEED=10485760', 'JAEGER_TRACE=localhost:6831', 'image=moby/buildkit:latest', 'network=host'],
endpoint: 'unix:///var/run/docker.sock',
name: 'builder20',
platforms: 'linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6',
@@ -48,11 +46,11 @@ jest.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise<Bu
describe('getVersion', () => {
it('valid', async () => {
const buildkit = new BuildKit({
context: new Context()
});
const version = await buildkit.getVersion('builder2');
expect(semver.valid(version)).not.toBeNull();
const builder = new Builder();
const builderInfo = await builder.inspect('builder2');
const buildkit = new BuildKit();
const version = await buildkit.getVersion(builderInfo.nodes[0]);
expect(version).toBe('v0.11.0');
});
});
@@ -61,9 +59,7 @@ describe('satisfies', () => {
['builder2', '>=0.10.0', true],
['builder2', '>0.11.0', false]
])('given %p', async (builderName, range, expected) => {
const buildkit = new BuildKit({
context: new Context()
});
const buildkit = new BuildKit();
expect(await buildkit.versionSatisfies(builderName, range)).toBe(expected);
});
});

View File

@@ -24,16 +24,17 @@ import {Context} from '../../src/context';
const fixturesDir = path.join(__dirname, '..', 'fixtures');
// prettier-ignore
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildkit-config-jest').split(path.sep).join(path.posix.sep);
const tmpName = path.join(tmpDir, '.tmpname-jest').split(path.sep).join(path.posix.sep);
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildkit-config-jest');
const tmpName = path.join(tmpDir, '.tmpname-jest');
jest.spyOn(Context.prototype, 'tmpDir').mockImplementation((): string => {
jest.spyOn(Context, 'tmpDir').mockImplementation((): string => {
if (!fs.existsSync(tmpDir)) {
fs.mkdirSync(tmpDir, {recursive: true});
}
return tmpDir;
});
jest.spyOn(Context.prototype, 'tmpName').mockImplementation((): string => {
jest.spyOn(Context, 'tmpName').mockImplementation((): string => {
return tmpName;
});
@@ -50,7 +51,7 @@ describe('resolve', () => {
['debug = true', false, 'debug = true', null],
[`notfound.toml`, true, '', new Error('config file notfound.toml not found')],
[
`${path.join(fixturesDir, 'buildkitd.toml').split(path.sep).join(path.posix.sep)}`,
`${path.join(fixturesDir, 'buildkitd.toml')}`,
true,
`debug = true
[registry."docker.io"]
@@ -60,9 +61,7 @@ describe('resolve', () => {
]
])('given %p config', async (val, file, exValue, error: Error) => {
try {
const buildkit = new BuildKit({
context: new Context()
});
const buildkit = new BuildKit();
let config: string;
if (file) {
config = buildkit.config.resolveFromFile(val);

View File

@@ -19,7 +19,6 @@ import * as fs from 'fs';
import * as path from 'path';
import {Builder} from '../../src/buildx/builder';
import {Context} from '../../src/context';
import {BuilderInfo} from '../../src/types/builder';
@@ -36,9 +35,9 @@ jest.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise<Bu
lastActivity: new Date('2023-01-16 09:45:23 +0000 UTC'),
nodes: [
{
buildkitVersion: 'v0.11.0',
buildkitdFlags: '--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
driverOpts: ['BUILDKIT_STEP_LOG_MAX_SIZE=10485760', 'BUILDKIT_STEP_LOG_MAX_SPEED=10485760', 'JAEGER_TRACE=localhost:6831', 'image=moby/buildkit:latest', 'network=host'],
buildkit: 'v0.11.0',
'buildkitd-flags': '--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
'driver-opts': ['BUILDKIT_STEP_LOG_MAX_SIZE=10485760', 'BUILDKIT_STEP_LOG_MAX_SPEED=10485760', 'JAEGER_TRACE=localhost:6831', 'image=moby/buildkit:latest', 'network=host'],
endpoint: 'unix:///var/run/docker.sock',
name: 'builder20',
platforms: 'linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6',
@@ -50,9 +49,7 @@ jest.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise<Bu
describe('inspect', () => {
it('valid', async () => {
const builder = new Builder({
context: new Context()
});
const builder = new Builder();
const builderInfo = await builder.inspect('');
expect(builderInfo).not.toBeUndefined();
expect(builderInfo.name).not.toEqual('');
@@ -74,8 +71,8 @@ describe('parseInspect', () => {
"name": "builder-5cb467f7-0940-47e1-b94b-d51f54054d620",
"endpoint": "unix:///var/run/docker.sock",
"status": "running",
"buildkitdFlags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
"buildkitVersion": "v0.10.4",
"buildkitd-flags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
"buildkit": "v0.10.4",
"platforms": "linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/amd64/v4,linux/arm64,linux/riscv64,linux/386,linux/arm/v7,linux/arm/v6"
}
]
@@ -90,12 +87,12 @@ describe('parseInspect', () => {
{
"name": "builder-5f449644-ff29-48af-8344-abb0292d06730",
"endpoint": "unix:///var/run/docker.sock",
"driverOpts": [
"driver-opts": [
"image=moby/buildkit:latest"
],
"status": "running",
"buildkitdFlags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
"buildkitVersion": "v0.10.4",
"buildkitd-flags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
"buildkit": "v0.10.4",
"platforms": "linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/amd64/v4,linux/386"
}
]
@@ -110,13 +107,13 @@ describe('parseInspect', () => {
{
"name": "builder-9929e463-7954-4dc3-89cd-514cca29ff800",
"endpoint": "unix:///var/run/docker.sock",
"driverOpts": [
"driver-opts": [
"image=moby/buildkit:master",
"network=host"
],
"status": "running",
"buildkitdFlags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
"buildkitVersion": "3fab389",
"buildkitd-flags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
"buildkit": "3fab389",
"platforms": "linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/amd64/v4,linux/386"
}
]
@@ -132,7 +129,7 @@ describe('parseInspect', () => {
"name": "default",
"endpoint": "default",
"status": "running",
"buildkitVersion": "20.10.17",
"buildkit": "20.10.17",
"platforms": "linux/amd64,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6"
}
]
@@ -147,7 +144,7 @@ describe('parseInspect', () => {
{
"name": "aws_graviton2",
"endpoint": "tcp://1.23.45.67:1234",
"driverOpts": [
"driver-opts": [
"cert=/home/user/.certs/aws_graviton2/cert.pem",
"key=/home/user/.certs/aws_graviton2/key.pem",
"cacert=/home/user/.certs/aws_graviton2/ca.pem"
@@ -166,7 +163,7 @@ describe('parseInspect', () => {
"name": "builder-17cfff01-48d9-4c3d-9332-9992e308a5100",
"endpoint": "unix:///var/run/docker.sock",
"status": "running",
"buildkitdFlags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
"buildkitd-flags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
"platforms": "linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/386"
}
],
@@ -182,9 +179,9 @@ describe('parseInspect', () => {
"lastActivity": new Date("2023-01-16T09:45:23.000Z"),
"nodes": [
{
"buildkitVersion": "v0.11.0",
"buildkitdFlags": "--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
"driverOpts": [
"buildkit": "v0.11.0",
"buildkitd-flags": "--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
"driver-opts": [
"BUILDKIT_STEP_LOG_MAX_SIZE=10485760",
"BUILDKIT_STEP_LOG_MAX_SPEED=10485760",
"JAEGER_TRACE=localhost:6831",

View File

@@ -19,24 +19,25 @@ import * as fs from 'fs';
import * as path from 'path';
import * as rimraf from 'rimraf';
import * as semver from 'semver';
import * as exec from '@actions/exec';
import {Buildx} from '../../src/buildx/buildx';
import {Context} from '../../src/context';
import {Exec} from '../../src/exec';
import {Cert} from '../../src/types/buildx';
// prettier-ignore
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-jest').split(path.sep).join(path.posix.sep);
const tmpName = path.join(tmpDir, '.tmpname-jest').split(path.sep).join(path.posix.sep);
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-jest');
const tmpName = path.join(tmpDir, '.tmpname-jest');
jest.spyOn(Context.prototype, 'tmpDir').mockImplementation((): string => {
jest.spyOn(Context, 'tmpDir').mockImplementation((): string => {
if (!fs.existsSync(tmpDir)) {
fs.mkdirSync(tmpDir, {recursive: true});
}
return tmpDir;
});
jest.spyOn(Context.prototype, 'tmpName').mockImplementation((): string => {
jest.spyOn(Context, 'tmpName').mockImplementation((): string => {
return tmpName;
});
@@ -90,14 +91,11 @@ describe('certsDir', () => {
describe('isAvailable', () => {
it('docker cli', async () => {
const execSpy = jest.spyOn(exec, 'getExecOutput');
const execSpy = jest.spyOn(Exec, 'getExecOutput');
const buildx = new Buildx({
context: new Context(),
standalone: false
});
buildx.isAvailable().catch(() => {
// noop
});
await buildx.isAvailable();
// eslint-disable-next-line jest/no-standalone-expect
expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx'], {
silent: true,
@@ -105,14 +103,11 @@ describe('isAvailable', () => {
});
});
it('standalone', async () => {
const execSpy = jest.spyOn(exec, 'getExecOutput');
const execSpy = jest.spyOn(Exec, 'getExecOutput');
const buildx = new Buildx({
context: new Context(),
standalone: true
});
buildx.isAvailable().catch(() => {
// noop
});
await buildx.isAvailable();
// eslint-disable-next-line jest/no-standalone-expect
expect(execSpy).toHaveBeenCalledWith(`buildx`, [], {
silent: true,
@@ -122,13 +117,12 @@ describe('isAvailable', () => {
});
describe('printInspect', () => {
it('prints builder2 instance', () => {
const execSpy = jest.spyOn(exec, 'exec');
it('prints builder2 instance', async () => {
const execSpy = jest.spyOn(Exec, 'exec');
const buildx = new Buildx({
context: new Context(),
standalone: true
});
buildx.printInspect('builder2').catch(() => {
await buildx.printInspect('builder2').catch(() => {
// noop
});
expect(execSpy).toHaveBeenCalledWith(`buildx`, ['inspect', 'builder2'], {
@@ -138,24 +132,22 @@ describe('printInspect', () => {
});
describe('printVersion', () => {
it('docker cli', () => {
const execSpy = jest.spyOn(exec, 'exec');
it('docker cli', async () => {
const execSpy = jest.spyOn(Exec, 'exec');
const buildx = new Buildx({
context: new Context(),
standalone: false
});
buildx.printVersion();
await buildx.printVersion();
expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx', 'version'], {
failOnStdErr: false
});
});
it('standalone', () => {
const execSpy = jest.spyOn(exec, 'exec');
it('standalone', async () => {
const execSpy = jest.spyOn(Exec, 'exec');
const buildx = new Buildx({
context: new Context(),
standalone: true
});
buildx.printVersion();
await buildx.printVersion();
expect(execSpy).toHaveBeenCalledWith(`buildx`, ['version'], {
failOnStdErr: false
});
@@ -164,10 +156,8 @@ describe('printVersion', () => {
describe('version', () => {
it('valid', async () => {
const buildx = new Buildx({
context: new Context()
});
expect(semver.valid(await buildx.version)).not.toBeUndefined();
const buildx = new Buildx();
expect(semver.valid(await buildx.version())).not.toBeUndefined();
});
});
@@ -188,9 +178,7 @@ describe('versionSatisfies', () => {
['bda4882a65349ca359216b135896bddc1d92461c', '>0.1.0', false],
['f117971', '>0.6.0', true]
])('given %p', async (version, range, expected) => {
const buildx = new Buildx({
context: new Context()
});
const buildx = new Buildx();
expect(await buildx.versionSatisfies(range, version)).toBe(expected);
});
});

View File

@@ -25,20 +25,21 @@ import {Inputs} from '../../src/buildx/inputs';
const fixturesDir = path.join(__dirname, '..', 'fixtures');
// prettier-ignore
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-inputs-jest').split(path.sep).join(path.posix.sep);
const tmpName = path.join(tmpDir, '.tmpname-jest').split(path.sep).join(path.posix.sep);
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-inputs-jest');
const tmpName = path.join(tmpDir, '.tmpname-jest');
const metadata = `{
"containerimage.config.digest": "sha256:059b68a595b22564a1cbc167af369349fdc2ecc1f7bc092c2235cbf601a795fd",
"containerimage.digest": "sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c"
}`;
jest.spyOn(Context.prototype, 'tmpDir').mockImplementation((): string => {
jest.spyOn(Context, 'tmpDir').mockImplementation((): string => {
if (!fs.existsSync(tmpDir)) {
fs.mkdirSync(tmpDir, {recursive: true});
}
return tmpDir;
});
jest.spyOn(Context.prototype, 'tmpName').mockImplementation((): string => {
jest.spyOn(Context, 'tmpName').mockImplementation((): string => {
return tmpName;
});
@@ -52,9 +53,7 @@ afterEach(() => {
describe('resolveBuildImageID', () => {
it('matches', async () => {
const buildx = new Buildx({
context: new Context()
});
const buildx = new Buildx();
const imageID = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9';
const imageIDFile = buildx.inputs.getBuildImageIDFilePath();
await fs.writeFileSync(imageIDFile, imageID);
@@ -65,9 +64,7 @@ describe('resolveBuildImageID', () => {
describe('resolveBuildMetadata', () => {
it('matches', async () => {
const buildx = new Buildx({
context: new Context()
});
const buildx = new Buildx();
const metadataFile = buildx.inputs.getBuildMetadataFilePath();
await fs.writeFileSync(metadataFile, metadata);
const expected = buildx.inputs.resolveBuildMetadata();
@@ -77,9 +74,7 @@ describe('resolveBuildMetadata', () => {
describe('resolveDigest', () => {
it('matches', async () => {
const buildx = new Buildx({
context: new Context()
});
const buildx = new Buildx();
const metadataFile = buildx.inputs.getBuildMetadataFilePath();
await fs.writeFileSync(metadataFile, metadata);
const expected = buildx.inputs.resolveDigest();
@@ -129,9 +124,7 @@ describe('getProvenanceInput', () => {
],
])('given input %p', async (input: string, expected: string) => {
await setInput('provenance', input);
const buildx = new Buildx({
context: new Context()
});
const buildx = new Buildx();
expect(buildx.inputs.getProvenanceInput('provenance')).toEqual(expected);
});
});
@@ -160,9 +153,7 @@ describe('resolveProvenanceAttrs', () => {
'builder-id=https://github.com/docker/actions-toolkit/actions/runs/123'
],
])('given %p', async (input: string, expected: string) => {
const buildx = new Buildx({
context: new Context()
});
const buildx = new Buildx();
expect(buildx.inputs.resolveProvenanceAttrs(input)).toEqual(expected);
});
});
@@ -175,13 +166,11 @@ describe('resolveBuildSecret', () => {
['aaaaaaaa', false, '', '', new Error('aaaaaaaa is not a valid secret')],
['aaaaaaaa=', false, '', '', new Error('aaaaaaaa= is not a valid secret')],
['=bbbbbbb', false, '', '', new Error('=bbbbbbb is not a valid secret')],
[`foo=${path.join(fixturesDir, 'secret.txt').split(path.sep).join(path.posix.sep)}`, true, 'foo', 'bar', null],
[`foo=${path.join(fixturesDir, 'secret.txt')}`, true, 'foo', 'bar', null],
[`notfound=secret`, true, '', '', new Error('secret file secret not found')]
])('given %p key and %p secret', async (kvp: string, file: boolean, exKey: string, exValue: string, error: Error) => {
try {
const buildx = new Buildx({
context: new Context()
});
const buildx = new Buildx();
let secret: string;
if (file) {
secret = buildx.inputs.resolveBuildSecretFile(kvp);
@@ -239,6 +228,8 @@ describe('hasDockerExporter', () => {
[['type=docker', 'type=tar,dest=/tmp/image.tar'], true, undefined],
[['"type=tar","dest=/tmp/image.tar"'], false, undefined],
[['" type= local" , dest=./release-out'], false, undefined],
[['type=docker'], true, false],
[['type=docker'], true, true],
[['.'], true, true],
])('given %p returns %p', async (exporters: Array<string>, expected: boolean, load: boolean | undefined) => {
expect(Inputs.hasDockerExporter(exporters, load)).toEqual(expected);

View File

@@ -23,7 +23,7 @@ import osm = require('os');
import {Install} from '../../src/buildx/install';
// prettier-ignore
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-jest').split(path.sep).join(path.posix.sep);
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-jest');
beforeEach(() => {
jest.clearAllMocks();
@@ -43,7 +43,14 @@ describe('download', () => {
])(
'acquires %p of buildx (standalone: %p)', async (version, standalone) => {
const install = new Install({standalone: standalone});
const buildxBin = await install.download(version, tmpDir);
const toolPath = await install.download(version);
expect(fs.existsSync(toolPath)).toBe(true);
let buildxBin: string;
if (standalone) {
buildxBin = await install.installStandalone(toolPath, tmpDir);
} else {
buildxBin = await install.installPlugin(toolPath, tmpDir);
}
expect(fs.existsSync(buildxBin)).toBe(true);
},
100000
@@ -65,7 +72,7 @@ describe('download', () => {
jest.spyOn(osm, 'platform').mockImplementation(() => os);
jest.spyOn(osm, 'arch').mockImplementation(() => arch);
const install = new Install();
const buildxBin = await install.download('latest', tmpDir);
const buildxBin = await install.download('latest');
expect(fs.existsSync(buildxBin)).toBe(true);
},
100000
@@ -82,14 +89,18 @@ describe('build', () => {
// eslint-disable-next-line jest/no-disabled-tests
it.skip('builds refs/pull/648/head', async () => {
const install = new Install();
const buildxBin = await install.build('https://github.com/docker/buildx.git#refs/pull/648/head', tmpDir);
const toolPath = await install.build('https://github.com/docker/buildx.git#refs/pull/648/head');
expect(fs.existsSync(toolPath)).toBe(true);
const buildxBin = await install.installStandalone(toolPath, tmpDir);
expect(fs.existsSync(buildxBin)).toBe(true);
}, 100000);
// eslint-disable-next-line jest/no-disabled-tests
it.skip('builds 67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', async () => {
const install = new Install();
const buildxBin = await install.build('https://github.com/docker/buildx.git#67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', tmpDir);
const toolPath = await install.build('https://github.com/docker/buildx.git#67bd6f4dc82a9cd96f34133dab3f6f7af803bb14');
expect(fs.existsSync(toolPath)).toBe(true);
const buildxBin = await install.installPlugin(toolPath, tmpDir);
expect(fs.existsSync(buildxBin)).toBe(true);
}, 100000);
});

View File

@@ -22,16 +22,17 @@ import {describe, expect, jest, it, beforeEach, afterEach} from '@jest/globals';
import {Context} from '../src/context';
// prettier-ignore
const tmpDir = path.join(process.env.TEMP || '/tmp', 'context-jest').split(path.sep).join(path.posix.sep);
const tmpName = path.join(tmpDir, '.tmpname-jest').split(path.sep).join(path.posix.sep);
const tmpDir = path.join(process.env.TEMP || '/tmp', 'context-jest');
const tmpName = path.join(tmpDir, '.tmpname-jest');
jest.spyOn(Context.prototype, 'tmpDir').mockImplementation((): string => {
jest.spyOn(Context, 'tmpDir').mockImplementation((): string => {
if (!fs.existsSync(tmpDir)) {
fs.mkdirSync(tmpDir, {recursive: true});
}
return tmpDir;
});
jest.spyOn(Context.prototype, 'tmpName').mockImplementation((): string => {
jest.spyOn(Context, 'tmpName').mockImplementation((): string => {
return tmpName;
});
@@ -43,16 +44,20 @@ afterEach(() => {
rimraf.sync(tmpDir);
});
describe('gitRef', () => {
it('returns refs/heads/master', async () => {
expect(Context.gitRef()).toEqual('refs/heads/master');
});
});
describe('gitContext', () => {
it('returns refs/heads/master', async () => {
const context = new Context();
expect(context.buildGitContext).toEqual('https://github.com/docker/actions-toolkit.git#refs/heads/master');
expect(Context.gitContext()).toEqual('https://github.com/docker/actions-toolkit.git#refs/heads/master');
});
});
describe('provenanceBuilderID', () => {
it('returns 123', async () => {
const context = new Context();
expect(context.provenanceBuilderID).toEqual('https://github.com/docker/actions-toolkit/actions/runs/123');
expect(Context.provenanceBuilderID()).toEqual('https://github.com/docker/actions-toolkit/actions/runs/123');
});
});

View File

@@ -15,11 +15,12 @@
*/
import {afterEach, beforeEach, describe, expect, it, jest} from '@jest/globals';
import * as exec from '@actions/exec';
import path from 'path';
import * as io from '@actions/io';
import osm = require('os');
import {Docker} from '../src/docker';
import {Exec} from '../src/exec';
beforeEach(() => {
jest.clearAllMocks();
@@ -48,55 +49,43 @@ describe('configDir', () => {
});
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
it('cli', async () => {
const ioWhichSpy = jest.spyOn(io, 'which');
await Docker.isAvailable();
expect(ioWhichSpy).toHaveBeenCalledTimes(1);
expect(ioWhichSpy).toHaveBeenCalledWith('docker', true);
});
});
describe('context', () => {
it('call docker context show', async () => {
const execSpy = jest.spyOn(Exec, 'getExecOutput');
await Docker.context().catch(() => {
// noop
});
expect(execSpy).toHaveBeenCalledWith(`docker`, ['context', 'inspect', '--format', '{{.Name}}'], {
ignoreReturnCode: true,
silent: true
});
});
});
describe('printVersion', () => {
it('docker cli', () => {
const execSpy = jest.spyOn(exec, 'exec');
Docker.printVersion(false).catch(() => {
it('call docker version', async () => {
const execSpy = jest.spyOn(Exec, 'exec');
await Docker.printVersion().catch(() => {
// noop
});
expect(execSpy).toHaveBeenCalledWith(`docker`, ['version'], {
failOnStdErr: false
});
});
it('standalone', () => {
const execSpy = jest.spyOn(exec, 'exec');
Docker.printVersion(true).catch(() => {
// noop
});
expect(execSpy).not.toHaveBeenCalledWith(`docker`, ['version'], {
failOnStdErr: false
});
expect(execSpy).toHaveBeenCalledWith(`docker`, ['version']);
});
});
describe('printInfo', () => {
it('docker cli', () => {
const execSpy = jest.spyOn(exec, 'exec');
Docker.printInfo(false).catch(() => {
it('call docker info', async () => {
const execSpy = jest.spyOn(Exec, 'exec');
await Docker.printInfo().catch(() => {
// noop
});
expect(execSpy).toHaveBeenCalledWith(`docker`, ['info'], {
failOnStdErr: false
});
});
it('standalone', () => {
const execSpy = jest.spyOn(exec, 'exec');
Docker.printInfo(true).catch(() => {
// noop
});
expect(execSpy).not.toHaveBeenCalledWith(`docker`, ['info'], {
failOnStdErr: false
});
expect(execSpy).toHaveBeenCalledWith(`docker`, ['info']);
});
});

51
__tests__/exec.test.ts Normal file
View File

@@ -0,0 +1,51 @@
/**
* Copyright 2023 actions-toolkit authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {beforeEach, describe, expect, it, jest} from '@jest/globals';
import {Exec} from '../src/exec';
beforeEach(() => {
jest.clearAllMocks();
});
describe('exec', () => {
it('returns docker version', async () => {
const execSpy = jest.spyOn(Exec, 'exec');
await Exec.exec('docker', ['version'], {
ignoreReturnCode: true,
silent: true
});
expect(execSpy).toHaveBeenCalledWith(`docker`, ['version'], {
ignoreReturnCode: true,
silent: true
});
});
});
describe('getExecOutput', () => {
it('returns docker version', async () => {
const execSpy = jest.spyOn(Exec, 'getExecOutput');
await Exec.getExecOutput('docker', ['version'], {
ignoreReturnCode: true,
silent: true
});
expect(execSpy).toHaveBeenCalledWith(`docker`, ['version'], {
ignoreReturnCode: true,
silent: true
});
});
});

View File

@@ -130,18 +130,12 @@ describe('printActionsRuntimeTokenACs', () => {
process.env = originalEnv;
});
it('empty', async () => {
const warnSpy = jest.spyOn(core, 'warning');
process.env.ACTIONS_RUNTIME_TOKEN = '';
await GitHub.printActionsRuntimeTokenACs();
expect(warnSpy).toHaveBeenCalledTimes(1);
expect(warnSpy).toHaveBeenCalledWith(`ACTIONS_RUNTIME_TOKEN not set`);
await expect(GitHub.printActionsRuntimeTokenACs()).rejects.toThrowError(new Error('ACTIONS_RUNTIME_TOKEN not set'));
});
it('malformed', async () => {
const warnSpy = jest.spyOn(core, 'warning');
process.env.ACTIONS_RUNTIME_TOKEN = 'foo';
await GitHub.printActionsRuntimeTokenACs();
expect(warnSpy).toHaveBeenCalledTimes(1);
expect(warnSpy).toHaveBeenCalledWith(`Cannot parse Actions Runtime Token: Invalid token specified: Cannot read properties of undefined (reading 'replace')`);
await expect(GitHub.printActionsRuntimeTokenACs()).rejects.toThrowError(new Error("Cannot parse GitHub Actions Runtime Token: Invalid token specified: Cannot read properties of undefined (reading 'replace')"));
});
it('refs/heads/master', async () => {
const infoSpy = jest.spyOn(core, 'info');

View File

@@ -18,13 +18,13 @@ import fs from 'fs';
import os from 'os';
import path from 'path';
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-actions-toolkit-')).split(path.sep).join(path.posix.sep);
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-actions-toolkit-'));
process.env = Object.assign({}, process.env, {
TEMP: tmpDir,
GITHUB_REPOSITORY: 'docker/actions-toolkit',
RUNNER_TEMP: path.join(tmpDir, 'runner-temp').split(path.sep).join(path.posix.sep),
RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache').split(path.sep).join(path.posix.sep)
RUNNER_TEMP: path.join(tmpDir, 'runner-temp'),
RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache')
}) as {
[key: string]: string;
};
@@ -41,7 +41,7 @@ module.exports = {
moduleNameMapper: {
'^csv-parse/sync': '<rootDir>/node_modules/csv-parse/dist/cjs/sync.cjs'
},
collectCoverageFrom: ['src/**/{!(toolkit.ts),}.ts'],
collectCoverageFrom: ['src/**/{!(index.ts),}.ts'],
coveragePathIgnorePatterns: ['lib/', 'node_modules/', '__mocks__/', '__tests__/'],
verbose: true
};

View File

@@ -28,8 +28,8 @@
"author": "Docker Inc.",
"license": "Apache-2.0",
"packageManager": "yarn@3.3.1",
"main": "lib/toolkit.js",
"types": "lib/toolkit.d.ts",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"directories": {
"lib": "lib",
"test": "__tests__"
@@ -46,6 +46,7 @@
"@actions/exec": "^1.1.1",
"@actions/github": "^5.1.1",
"@actions/http-client": "^2.0.1",
"@actions/io": "^1.1.2",
"@actions/tool-cache": "^2.0.1",
"csv-parse": "^5.3.5",
"jwt-decode": "^3.1.2",

View File

@@ -15,95 +15,82 @@
*/
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import * as semver from 'semver';
import {Context} from '../context';
import {Buildx} from '../buildx/buildx';
import {Builder} from '../buildx/builder';
import {Config} from './config';
import {Exec} from '../exec';
import {BuilderInfo} from '../types/builder';
import {BuilderInfo, NodeInfo} from '../types/builder';
export interface BuildKitOpts {
context: Context;
buildx?: Buildx;
}
export class BuildKit {
private readonly context: Context;
private readonly buildx: Buildx;
private containerNamePrefix = 'buildx_buildkit_';
public readonly config: Config;
constructor(opts: BuildKitOpts) {
this.context = opts.context;
this.config = new Config(this.context);
this.buildx =
opts?.buildx ||
new Buildx({
context: this.context
});
constructor(opts?: BuildKitOpts) {
this.config = new Config();
this.buildx = opts?.buildx || new Buildx();
}
public async getVersion(builderName: string): Promise<string | undefined> {
const builderInfo = await this.getBuilderInfo(builderName);
if (builderInfo.nodes.length == 0) {
// a builder always have on node, should not happen.
return undefined;
}
// TODO: get version for all nodes
const node = builderInfo.nodes[0];
if (!node.buildkitVersion && node.name) {
public async getVersion(node: NodeInfo): Promise<string | undefined> {
if (!node.buildkit && node.name) {
try {
return await this.getVersionWithinImage(node.name);
} catch (e) {
core.warning(e);
}
}
return node.buildkitVersion;
return node.buildkit;
}
private async getVersionWithinImage(nodeName: string): Promise<string> {
return exec
.getExecOutput(`docker`, ['inspect', '--format', '{{.Config.Image}}', `${this.containerNamePrefix}${nodeName}`], {
ignoreReturnCode: true,
silent: true
})
.then(bkitimage => {
if (bkitimage.exitCode == 0 && bkitimage.stdout.length > 0) {
return exec
.getExecOutput(`docker`, ['run', '--rm', bkitimage.stdout.trim(), '--version'], {
ignoreReturnCode: true,
silent: true
})
.then(bkitversion => {
if (bkitversion.exitCode == 0 && bkitversion.stdout.length > 0) {
return `${bkitimage.stdout.trim()} => ${bkitversion.stdout.trim()}`;
} else if (bkitversion.stderr.length > 0) {
throw new Error(bkitimage.stderr.trim());
}
return bkitversion.stdout.trim();
});
} else if (bkitimage.stderr.length > 0) {
throw new Error(bkitimage.stderr.trim());
}
return bkitimage.stdout.trim();
});
core.debug(`BuildKit.getVersionWithinImage nodeName: ${nodeName}`);
return Exec.getExecOutput(`docker`, ['inspect', '--format', '{{.Config.Image}}', `${Buildx.containerNamePrefix}${nodeName}`], {
ignoreReturnCode: true,
silent: true
}).then(bkitimage => {
if (bkitimage.exitCode == 0 && bkitimage.stdout.length > 0) {
core.debug(`BuildKit.getVersionWithinImage image: ${bkitimage.stdout.trim()}`);
return Exec.getExecOutput(`docker`, ['run', '--rm', bkitimage.stdout.trim(), '--version'], {
ignoreReturnCode: true,
silent: true
}).then(bkitversion => {
if (bkitversion.exitCode == 0 && bkitversion.stdout.length > 0) {
return `${bkitimage.stdout.trim()} => ${bkitversion.stdout.trim()}`;
} else if (bkitversion.stderr.length > 0) {
throw new Error(bkitimage.stderr.trim());
}
return bkitversion.stdout.trim();
});
} else if (bkitimage.stderr.length > 0) {
throw new Error(bkitimage.stderr.trim());
}
return bkitimage.stdout.trim();
});
}
public async versionSatisfies(builderName: string, range: string): Promise<boolean> {
const builderInfo = await this.getBuilderInfo(builderName);
public async versionSatisfies(builderName: string, range: string, builderInfo?: BuilderInfo): Promise<boolean> {
if (!builderInfo) {
builderInfo = await new Builder({buildx: this.buildx}).inspect(builderName);
}
for (const node of builderInfo.nodes) {
let bkversion = node.buildkitVersion;
let bkversion = node.buildkit;
core.debug(`BuildKit.versionSatisfies ${bkversion}: ${range}`);
if (!bkversion) {
try {
bkversion = await this.getVersionWithinImage(node.name || '');
} catch (e) {
core.debug(`BuildKit.versionSatisfies ${node.name}: can't get version`);
return false;
}
}
core.debug(`BuildKit.versionSatisfies ${node.name}: version ${bkversion}`);
// BuildKit version reported by moby is in the format of `v0.11.0-moby`
if (builderInfo.driver == 'docker' && !bkversion.endsWith('-moby')) {
return false;
@@ -114,12 +101,4 @@ export class BuildKit {
}
return true;
}
private async getBuilderInfo(name: string): Promise<BuilderInfo> {
const builder = new Builder({
context: this.context,
buildx: this.buildx
});
return builder.inspect(name);
}
}

View File

@@ -19,12 +19,6 @@ import fs from 'fs';
import {Context} from '../context';
export class Config {
private readonly context: Context;
constructor(context: Context) {
this.context = context;
}
public resolveFromString(s: string): string {
return this.resolve(s, false);
}
@@ -40,7 +34,7 @@ export class Config {
}
s = fs.readFileSync(s, {encoding: 'utf-8'});
}
const configFile = this.context.tmpName({tmpdir: this.context.tmpDir()});
const configFile = Context.tmpName({tmpdir: Context.tmpDir()});
fs.writeFileSync(configFile, s);
return configFile;
}

View File

@@ -14,44 +14,33 @@
* limitations under the License.
*/
import * as exec from '@actions/exec';
import {Buildx} from './buildx';
import {Context} from '../context';
import {Exec} from '../exec';
import {BuilderInfo, NodeInfo} from '../types/builder';
export interface BuilderOpts {
context: Context;
buildx?: Buildx;
}
export class Builder {
private readonly context: Context;
private readonly buildx: Buildx;
constructor(opts: BuilderOpts) {
this.context = opts.context;
this.buildx =
opts?.buildx ||
new Buildx({
context: this.context
});
constructor(opts?: BuilderOpts) {
this.buildx = opts?.buildx || new Buildx();
}
public async inspect(name: string): Promise<BuilderInfo> {
const cmd = this.buildx.getCommand(['inspect', name]);
return await exec
.getExecOutput(cmd.command, cmd.args, {
ignoreReturnCode: true,
silent: true
})
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(res.stderr.trim());
}
return Builder.parseInspect(res.stdout);
});
const cmd = await this.buildx.getCommand(['inspect', name]);
return await Exec.getExecOutput(cmd.command, cmd.args, {
ignoreReturnCode: true,
silent: true
}).then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(res.stderr.trim());
}
return Builder.parseInspect(res.stdout);
});
}
public static parseInspect(data: string): BuilderInfo {
@@ -91,7 +80,7 @@ export class Builder {
break;
}
case 'driver options': {
node.driverOpts = (value.match(/(\w+)="([^"]*)"/g) || []).map(v => v.replace(/^(.*)="(.*)"$/g, '$1=$2'));
node['driver-opts'] = (value.match(/(\w+)="([^"]*)"/g) || []).map(v => v.replace(/^(.*)="(.*)"$/g, '$1=$2'));
break;
}
case 'status': {
@@ -99,11 +88,11 @@ export class Builder {
break;
}
case 'flags': {
node.buildkitdFlags = value;
node['buildkitd-flags'] = value;
break;
}
case 'buildkit': {
node.buildkitVersion = value;
node.buildkit = value;
break;
}
case 'platforms': {

View File

@@ -16,31 +16,33 @@
import fs from 'fs';
import path from 'path';
import * as exec from '@actions/exec';
import * as core from '@actions/core';
import * as semver from 'semver';
import {Docker} from '../docker';
import {Context} from '../context';
import {Exec} from '../exec';
import {Inputs} from './inputs';
import {Cert} from '../types/buildx';
export interface BuildxOpts {
context: Context;
standalone?: boolean;
}
export class Buildx {
private readonly context: Context;
private _version: string | undefined;
private _version: string;
private _versionOnce: boolean;
private readonly _standalone: boolean | undefined;
public readonly inputs: Inputs;
public readonly standalone: boolean;
constructor(opts: BuildxOpts) {
this.context = opts.context;
this.inputs = new Inputs(this.context);
this.standalone = opts?.standalone ?? !Docker.isAvailable;
public static readonly containerNamePrefix = 'buildx_buildkit_';
constructor(opts?: BuildxOpts) {
this._standalone = opts?.standalone;
this._version = '';
this._versionOnce = false;
this.inputs = new Inputs();
}
static get configDir(): string {
@@ -51,62 +53,71 @@ export class Buildx {
return path.join(Buildx.configDir, 'certs');
}
public getCommand(args: Array<string>) {
public async isStandalone(): Promise<boolean> {
const standalone = this._standalone ?? !(await Docker.isAvailable());
core.debug(`Buildx.isStandalone: ${standalone}`);
return standalone;
}
public async getCommand(args: Array<string>) {
const standalone = await this.isStandalone();
return {
command: this.standalone ? 'buildx' : 'docker',
args: this.standalone ? args : ['buildx', ...args]
command: standalone ? 'buildx' : 'docker',
args: standalone ? args : ['buildx', ...args]
};
}
public async isAvailable(): Promise<boolean> {
const cmd = this.getCommand([]);
return await exec
.getExecOutput(cmd.command, cmd.args, {
ignoreReturnCode: true,
silent: true
})
const cmd = await this.getCommand([]);
const ok: boolean = await Exec.getExecOutput(cmd.command, cmd.args, {
ignoreReturnCode: true,
silent: true
})
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
core.debug(`Buildx.isAvailable cmd err: ${res.stderr}`);
return false;
}
return res.exitCode == 0;
})
// eslint-disable-next-line @typescript-eslint/no-unused-vars
.catch(error => {
core.debug(`Buildx.isAvailable error: ${error}`);
return false;
});
core.debug(`Buildx.isAvailable: ${ok}`);
return ok;
}
public async printInspect(name: string): Promise<void> {
const cmd = this.getCommand(['inspect', name]);
await exec.exec(cmd.command, cmd.args, {
const cmd = await this.getCommand(['inspect', name]);
await Exec.exec(cmd.command, cmd.args, {
failOnStdErr: false
});
}
get version() {
return (async () => {
if (!this._version) {
const cmd = this.getCommand(['version']);
this._version = await exec
.getExecOutput(cmd.command, cmd.args, {
ignoreReturnCode: true,
silent: true
})
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(res.stderr.trim());
}
return Buildx.parseVersion(res.stdout.trim());
});
}
public async version(): Promise<string> {
if (this._versionOnce) {
return this._version;
})();
}
this._versionOnce = true;
const cmd = await this.getCommand(['version']);
this._version = await Exec.getExecOutput(cmd.command, cmd.args, {
ignoreReturnCode: true,
silent: true
}).then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(res.stderr.trim());
}
return Buildx.parseVersion(res.stdout.trim());
});
return this._version;
}
public async printVersion() {
const cmd = this.getCommand(['version']);
await exec.exec(cmd.command, cmd.args, {
const cmd = await this.getCommand(['version']);
await Exec.exec(cmd.command, cmd.args, {
failOnStdErr: false
});
}
@@ -120,11 +131,14 @@ export class Buildx {
}
public async versionSatisfies(range: string, version?: string): Promise<boolean> {
const ver = version ?? (await this.version);
const ver = version ?? (await this.version());
if (!ver) {
core.debug(`Buildx.versionSatisfies false: undefined version`);
return false;
}
return semver.satisfies(ver, range) || /^[0-9a-f]{7}$/.exec(ver) !== null;
const res = semver.satisfies(ver, range) || /^[0-9a-f]{7}$/.exec(ver) !== null;
core.debug(`Buildx.versionSatisfies ${ver} statisfies ${range}: ${res}`);
return res;
}
public static resolveCertsDriverOpts(driver: string, endpoint: string, cert: Cert): Array<string> {

View File

@@ -22,18 +22,12 @@ import {parse} from 'csv-parse/sync';
import {Context} from '../context';
export class Inputs {
private readonly context: Context;
constructor(context: Context) {
this.context = context;
}
public getBuildImageIDFilePath(): string {
return path.join(this.context.tmpDir(), 'iidfile').split(path.sep).join(path.posix.sep);
return path.join(Context.tmpDir(), 'iidfile');
}
public getBuildMetadataFilePath(): string {
return path.join(this.context.tmpDir(), 'metadata-file').split(path.sep).join(path.posix.sep);
return path.join(Context.tmpDir(), 'metadata-file');
}
public resolveBuildImageID(): string | undefined {
@@ -89,7 +83,7 @@ export class Inputs {
}
value = fs.readFileSync(value, {encoding: 'utf-8'});
}
const secretFile = this.context.tmpName({tmpdir: this.context.tmpDir()});
const secretFile = Context.tmpName({tmpdir: Context.tmpDir()});
fs.writeFileSync(secretFile, value);
return `id=${key},src=${secretFile}`;
}
@@ -100,9 +94,8 @@ export class Inputs {
// if input is not set returns empty string
return input;
}
const builderID = this.context.provenanceBuilderID;
try {
return core.getBooleanInput(name) ? `builder-id=${builderID}` : 'false';
return core.getBooleanInput(name) ? `builder-id=${Context.provenanceBuilderID()}` : 'false';
} catch (err) {
// not a valid boolean, so we assume it's a string
return this.resolveProvenanceAttrs(input);
@@ -111,7 +104,7 @@ export class Inputs {
public resolveProvenanceAttrs(input: string): string {
if (!input) {
return `builder-id=${this.context.provenanceBuilderID}`;
return `builder-id=${Context.provenanceBuilderID()}`;
}
// parse attributes from input
const fields = parse(input, {
@@ -129,7 +122,7 @@ export class Inputs {
}
}
// if not add builder-id attribute
return `${input},builder-id=${this.context.provenanceBuilderID}`;
return `${input},builder-id=${Context.provenanceBuilderID()}`;
}
public static hasLocalExporter(exporters: string[]): boolean {
@@ -141,7 +134,7 @@ export class Inputs {
}
public static hasDockerExporter(exporters: string[], load?: boolean): boolean {
return load ?? Inputs.hasExporterType('docker', exporters);
return load || Inputs.hasExporterType('docker', exporters);
}
public static hasExporterType(name: string, exporters: string[]): boolean {

View File

@@ -18,7 +18,6 @@ import fs from 'fs';
import os from 'os';
import path from 'path';
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import * as httpm from '@actions/http-client';
import * as tc from '@actions/tool-cache';
import * as semver from 'semver';
@@ -26,28 +25,27 @@ import * as util from 'util';
import {Buildx} from './buildx';
import {Context} from '../context';
import {Exec} from '../exec';
import {Docker} from '../docker';
import {Git} from '../git';
import {GitHubRelease} from '../types/github';
export interface InstallOpts {
context?: Context;
standalone?: boolean;
}
export class Install {
private readonly context: Context;
private readonly standalone: boolean;
private readonly _standalone: boolean | undefined;
constructor(opts?: InstallOpts) {
this.context = opts?.context || new Context();
this.standalone = opts?.standalone ?? !Docker.isAvailable;
this._standalone = opts?.standalone;
}
public async download(version: string, dest?: string): Promise<string> {
public async download(version: string): Promise<string> {
const release: GitHubRelease = await Install.getRelease(version);
const fversion = release.tag_name.replace(/^v+|v+$/g, '');
core.debug(`Install.download version: ${fversion}`);
let toolPath: string;
toolPath = tc.find('buildx', fversion, this.platform());
@@ -58,15 +56,12 @@ export class Install {
}
toolPath = await this.fetchBinary(fversion);
}
core.debug(`Install.download toolPath: ${toolPath}`);
dest = dest || (this.standalone ? this.context.tmpDir() : Docker.configDir);
if (this.standalone) {
return this.setStandalone(toolPath, dest);
}
return this.setPlugin(toolPath, dest);
return toolPath;
}
public async build(gitContext: string, dest?: string): Promise<string> {
public async build(gitContext: string): Promise<string> {
// eslint-disable-next-line prefer-const
let [repo, ref] = gitContext.split('#');
if (ref.length == 0) {
@@ -80,64 +75,29 @@ export class Install {
} else {
vspec = await Git.getRemoteSha(repo, ref);
}
core.debug(`Tool version spec ${vspec}`);
core.debug(`Install.build: tool version spec ${vspec}`);
let toolPath: string;
toolPath = tc.find('buildx', vspec);
if (!toolPath) {
const outputDir = path.join(this.context.tmpDir(), 'build-cache').split(path.sep).join(path.posix.sep);
const outputDir = path.join(Context.tmpDir(), 'build-cache');
const buildCmd = await this.buildCommand(gitContext, outputDir);
toolPath = await exec
.getExecOutput(buildCmd.command, buildCmd.args, {
ignoreReturnCode: true
})
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
core.warning(res.stderr.trim());
}
return tc.cacheFile(`${outputDir}/buildx`, os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx', 'buildx', vspec);
});
toolPath = await Exec.getExecOutput(buildCmd.command, buildCmd.args, {
ignoreReturnCode: true
}).then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
core.warning(res.stderr.trim());
}
return tc.cacheFile(`${outputDir}/buildx`, os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx', 'buildx', vspec);
});
}
dest = dest || Docker.configDir;
if (this.standalone) {
return this.setStandalone(toolPath, dest);
}
return this.setPlugin(toolPath, dest);
return toolPath;
}
private async buildCommand(gitContext: string, outputDir: string): Promise<{args: Array<string>; command: string}> {
const buildxStandaloneFound = await new Buildx({context: this.context, standalone: true}).isAvailable();
const buildxPluginFound = await new Buildx({context: this.context, standalone: false}).isAvailable();
let buildStandalone = false;
if (this.standalone && buildxStandaloneFound) {
core.debug(`Buildx standalone found, build with it`);
buildStandalone = true;
} else if (!this.standalone && buildxPluginFound) {
core.debug(`Buildx plugin found, build with it`);
buildStandalone = false;
} else if (buildxStandaloneFound) {
core.debug(`Buildx plugin not found, but standalone found so trying to build with it`);
buildStandalone = true;
} else if (buildxPluginFound) {
core.debug(`Buildx standalone not found, but plugin found so trying to build with it`);
buildStandalone = false;
} else {
throw new Error(`Neither buildx standalone or plugin have been found to build from ref ${gitContext}`);
}
//prettier-ignore
return new Buildx({context: this.context, standalone: buildStandalone}).getCommand([
'build',
'--target', 'binaries',
'--build-arg', 'BUILDKIT_CONTEXT_KEEP_GIT_DIR=1',
'--output', `type=local,dest=${outputDir}`,
gitContext
]);
}
private async setStandalone(toolPath: string, dest: string): Promise<string> {
public async installStandalone(toolPath: string, dest?: string): Promise<string> {
core.info('Standalone mode');
dest = dest || Context.tmpDir();
const toolBinPath = path.join(toolPath, os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx');
const binDir = path.join(dest, 'bin');
if (!fs.existsSync(binDir)) {
@@ -146,12 +106,20 @@ export class Install {
const filename: string = os.platform() == 'win32' ? 'buildx.exe' : 'buildx';
const buildxPath: string = path.join(binDir, filename);
fs.copyFileSync(toolBinPath, buildxPath);
core.info('Fixing perms');
fs.chmodSync(buildxPath, '0755');
core.addPath(binDir);
core.info('Added Buildx to PATH');
core.info(`Binary path: ${buildxPath}`);
return buildxPath;
}
private async setPlugin(toolPath: string, dest: string): Promise<string> {
public async installPlugin(toolPath: string, dest?: string): Promise<string> {
core.info('Docker plugin mode');
dest = dest || Docker.configDir;
const toolBinPath = path.join(toolPath, os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx');
const pluginsDir: string = path.join(dest, 'cli-plugins');
if (!fs.existsSync(pluginsDir)) {
@@ -160,16 +128,57 @@ export class Install {
const filename: string = os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx';
const pluginPath: string = path.join(pluginsDir, filename);
fs.copyFileSync(toolBinPath, pluginPath);
core.info('Fixing perms');
fs.chmodSync(pluginPath, '0755');
core.info(`Plugin path: ${pluginPath}`);
return pluginPath;
}
private async buildCommand(gitContext: string, outputDir: string): Promise<{args: Array<string>; command: string}> {
const buildxStandaloneFound = await new Buildx({standalone: true}).isAvailable();
const buildxPluginFound = await new Buildx({standalone: false}).isAvailable();
let buildStandalone = false;
if ((await this.isStandalone()) && buildxStandaloneFound) {
core.debug(`Install.buildCommand: Buildx standalone found, build with it`);
buildStandalone = true;
} else if (!(await this.isStandalone()) && buildxPluginFound) {
core.debug(`Install.buildCommand: Buildx plugin found, build with it`);
buildStandalone = false;
} else if (buildxStandaloneFound) {
core.debug(`Install.buildCommand: Buildx plugin not found, but standalone found so trying to build with it`);
buildStandalone = true;
} else if (buildxPluginFound) {
core.debug(`Install.buildCommand: Buildx standalone not found, but plugin found so trying to build with it`);
buildStandalone = false;
} else {
throw new Error(`Neither buildx standalone or plugin have been found to build from ref ${gitContext}`);
}
//prettier-ignore
return await new Buildx({standalone: buildStandalone}).getCommand([
'build',
'--target', 'binaries',
'--build-arg', 'BUILDKIT_CONTEXT_KEEP_GIT_DIR=1',
'--output', `type=local,dest=${outputDir}`,
gitContext
]);
}
private async isStandalone(): Promise<boolean> {
const standalone = this._standalone ?? !(await Docker.isAvailable());
core.debug(`Install.isStandalone: ${standalone}`);
return standalone;
}
private async fetchBinary(version: string): Promise<string> {
const targetFile: string = os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx';
const downloadURL = util.format('https://github.com/docker/buildx/releases/download/v%s/%s', version, this.filename(version));
core.info(`Downloading ${downloadURL}`);
const downloadPath = await tc.downloadTool(downloadURL);
core.debug(`downloadURL: ${downloadURL}`);
core.debug(`downloadPath: ${downloadPath}`);
core.debug(`Install.fetchBinary downloadPath: ${downloadPath}`);
return await tc.cacheFile(downloadPath, targetFile, 'buildx', version);
}

View File

@@ -23,29 +23,32 @@ import * as github from '@actions/github';
import {GitHub} from './github';
export class Context {
public gitRef: string;
public buildGitContext: string;
public provenanceBuilderID: string;
private static readonly _tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-actions-toolkit-'));
private readonly _tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-actions-toolkit-')).split(path.sep).join(path.posix.sep);
constructor() {
this.gitRef = github.context.ref;
if (github.context.sha && this.gitRef && !this.gitRef.startsWith('refs/')) {
this.gitRef = `refs/heads/${github.context.ref}`;
}
if (github.context.sha && !this.gitRef.startsWith(`refs/pull/`)) {
this.gitRef = github.context.sha;
}
this.buildGitContext = `${GitHub.serverURL}/${github.context.repo.owner}/${github.context.repo.repo}.git#${this.gitRef}`;
this.provenanceBuilderID = `${GitHub.serverURL}/${github.context.repo.owner}/${github.context.repo.repo}/actions/runs/${github.context.runId}`;
public static tmpDir(): string {
return Context._tmpDir;
}
public tmpDir(): string {
return this._tmpDir;
}
public tmpName(options?: tmp.TmpNameOptions): string {
public static tmpName(options?: tmp.TmpNameOptions): string {
return tmp.tmpNameSync(options);
}
public static gitRef(): string {
let gitRef = github.context.ref;
if (github.context.sha && gitRef && !gitRef.startsWith('refs/')) {
gitRef = `refs/heads/${github.context.ref}`;
}
if (github.context.sha && !gitRef.startsWith(`refs/pull/`)) {
gitRef = github.context.sha;
}
return gitRef;
}
public static gitContext(): string {
return `${GitHub.serverURL}/${github.context.repo.owner}/${github.context.repo.repo}.git#${Context.gitRef()}`;
}
public static provenanceBuilderID(): string {
return `${GitHub.serverURL}/${github.context.repo.owner}/${github.context.repo.repo}/actions/runs/${github.context.runId}`;
}
}

View File

@@ -16,51 +16,49 @@
import os from 'os';
import path from 'path';
import * as exec from '@actions/exec';
import * as core from '@actions/core';
import * as io from '@actions/io';
import {Exec} from './exec';
export class Docker {
static get configDir(): string {
return process.env.DOCKER_CONFIG || path.join(os.homedir(), '.docker');
}
static get isAvailable(): boolean {
let dockerAvailable = false;
exec
.getExecOutput('docker', undefined, {
ignoreReturnCode: true,
silent: true
})
public static async isAvailable(): Promise<boolean> {
return await io
.which('docker', true)
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
dockerAvailable = false;
} else {
dockerAvailable = res.exitCode == 0;
}
core.debug(`Docker.isAvailable ok: ${res}`);
return true;
})
// eslint-disable-next-line @typescript-eslint/no-unused-vars
.catch(error => {
dockerAvailable = false;
core.debug(`Docker.isAvailable error: ${error}`);
return false;
});
return dockerAvailable;
}
public static async printVersion(standalone?: boolean) {
const noDocker = standalone ?? !Docker.isAvailable;
if (noDocker) {
return;
public static async context(name?: string): Promise<string> {
const args = ['context', 'inspect', '--format', '{{.Name}}'];
if (name) {
args.push(name);
}
await exec.exec('docker', ['version'], {
failOnStdErr: false
return await Exec.getExecOutput(`docker`, args, {
ignoreReturnCode: true,
silent: true
}).then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(res.stderr);
}
return res.stdout.trim();
});
}
public static async printInfo(standalone?: boolean) {
const noDocker = standalone ?? !Docker.isAvailable;
if (noDocker) {
return;
}
await exec.exec('docker', ['info'], {
failOnStdErr: false
});
public static async printVersion(): Promise<void> {
await Exec.exec('docker', ['version']);
}
public static async printInfo(): Promise<void> {
await Exec.exec('docker', ['info']);
}
}

31
src/exec.ts Normal file
View File

@@ -0,0 +1,31 @@
/**
* Copyright 2023 actions-toolkit authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import {ExecOptions, ExecOutput} from '@actions/exec';
export class Exec {
public static async exec(commandLine: string, args?: string[], options?: ExecOptions): Promise<number> {
core.debug(`Exec.exec: ${commandLine} ${args?.join(' ')}`);
return exec.exec(commandLine, args, options);
}
public static async getExecOutput(commandLine: string, args?: string[], options?: ExecOptions): Promise<ExecOutput> {
core.debug(`Exec.getExecOutput: ${commandLine} ${args?.join(' ')}`);
return exec.getExecOutput(commandLine, args, options);
}
}

View File

@@ -14,24 +14,22 @@
* limitations under the License.
*/
import * as exec from '@actions/exec';
import {Exec} from './exec';
export class Git {
public static async getRemoteSha(repo: string, ref: string): Promise<string> {
return await exec
.getExecOutput(`git`, ['ls-remote', repo, ref], {
ignoreReturnCode: true,
silent: true
})
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(res.stderr);
}
const [rsha] = res.stdout.trim().split(/[\s\t]/);
if (rsha.length == 0) {
throw new Error(`Cannot find remote ref for ${repo}#${ref}`);
}
return rsha;
});
return await Exec.getExecOutput(`git`, ['ls-remote', repo, ref], {
ignoreReturnCode: true,
silent: true
}).then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(res.stderr);
}
const [rsha] = res.stdout.trim().split(/[\s\t]/);
if (rsha.length == 0) {
throw new Error(`Cannot find remote ref for ${repo}#${ref}`);
}
return rsha;
});
}
}

View File

@@ -59,12 +59,10 @@ export class GitHub {
try {
jwt = GitHub.actionsRuntimeToken;
} catch (e) {
core.warning(`Cannot parse Actions Runtime Token: ${e.message}`);
return;
throw new Error(`Cannot parse GitHub Actions Runtime Token: ${e.message}`);
}
if (!jwt) {
core.warning(`ACTIONS_RUNTIME_TOKEN not set`);
return;
throw new Error(`ACTIONS_RUNTIME_TOKEN not set`);
}
try {
<Array<GitHubActionsRuntimeTokenAC>>JSON.parse(`${jwt.ac}`).forEach(ac => {
@@ -85,7 +83,7 @@ export class GitHub {
core.info(`${ac.Scope}: ${permission}`);
});
} catch (e) {
core.warning(`Cannot parse Actions Runtime Token Access Controls: ${e.message}`);
throw new Error(`Cannot parse GitHub Actions Runtime Token ACs: ${e.message}`);
}
}
}

42
src/index.ts Normal file
View File

@@ -0,0 +1,42 @@
/**
* Copyright 2023 actions-toolkit authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as core from '@actions/core';
const isPost = !!process.env['STATE_isPost'];
if (!isPost) {
core.saveState('isPost', 'true');
}
/**
* Runs a GitHub Action.
* Output will be streamed to the live console.
*
* @param main runs the defined function.
* @param post runs the defined function at the end of the job if set.
* @returns Promise<void>
*/
export async function run(main: () => Promise<void>, post?: () => Promise<void>): Promise<void> {
if (!isPost) {
try {
await main();
} catch (e) {
core.setFailed(e.message);
}
} else if (post) {
await post();
}
}

View File

@@ -14,7 +14,6 @@
* limitations under the License.
*/
import {Context} from './context';
import {Buildx} from './buildx/buildx';
import {Install} from './buildx/install';
import {Builder} from './buildx/builder';
@@ -30,7 +29,6 @@ export interface ToolkitOpts {
}
export class Toolkit {
public context: Context;
public github: GitHub;
public buildx: Buildx;
public buildxInstall: Install;
@@ -38,11 +36,10 @@ export class Toolkit {
public buildkit: BuildKit;
constructor(opts: ToolkitOpts = {}) {
this.context = new Context();
this.github = new GitHub({token: opts.githubToken});
this.buildx = new Buildx({context: this.context});
this.buildxInstall = new Install({context: this.context, standalone: this.buildx.standalone});
this.builder = new Builder({context: this.context, buildx: this.buildx});
this.buildkit = new BuildKit({context: this.context, buildx: this.buildx});
this.buildx = new Buildx();
this.buildxInstall = new Install();
this.builder = new Builder({buildx: this.buildx});
this.buildkit = new BuildKit({buildx: this.buildx});
}
}

View File

@@ -21,16 +21,6 @@ export interface BuilderInfo {
nodes: NodeInfo[];
}
export interface NodeInfo {
name?: string;
endpoint?: string;
driverOpts?: Array<string>;
status?: string;
buildkitdFlags?: string;
buildkitVersion?: string;
platforms?: string;
}
export interface Node {
name?: string;
endpoint?: string;
@@ -38,3 +28,8 @@ export interface Node {
'buildkitd-flags'?: string;
platforms?: string;
}
export interface NodeInfo extends Node {
status?: string;
buildkit?: string;
}

View File

@@ -52,7 +52,7 @@ __metadata:
languageName: node
linkType: hard
"@actions/io@npm:^1.1.1":
"@actions/io@npm:^1.1.1, @actions/io@npm:^1.1.2":
version: 1.1.2
resolution: "@actions/io@npm:1.1.2"
checksum: 3c6583c4557abf6c95e9cfc9b6377045e65ba2c5dd4863f4feedd6be9daf4f6b60e588ab0151d5626b5f8320a37f05b8d44ab5c329b8c19f65be31b0616e1464
@@ -766,6 +766,7 @@ __metadata:
"@actions/exec": ^1.1.1
"@actions/github": ^5.1.1
"@actions/http-client": ^2.0.1
"@actions/io": ^1.1.2
"@actions/tool-cache": ^2.0.1
"@types/csv-parse": ^1.2.2
"@types/node": ^16.18.11