Compare commits
33 Commits
v0.1.0-bet
...
v0.1.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1383a2bcaf | ||
|
|
1acd6c2fc0 | ||
|
|
d153cfaf3c | ||
|
|
d09114e0c5 | ||
|
|
c3aa7f205d | ||
|
|
62f8c6bef6 | ||
|
|
a9ce06b57e | ||
|
|
cb6ca3829f | ||
|
|
1098847fe7 | ||
|
|
35a8193474 | ||
|
|
2915834633 | ||
|
|
a0e8f0bf18 | ||
|
|
580aee99c0 | ||
|
|
89ecd37681 | ||
|
|
139fb39ab0 | ||
|
|
67957d8c7a | ||
|
|
768df5fbf4 | ||
|
|
e9db81b6a1 | ||
|
|
cd825ae548 | ||
|
|
28c11a1819 | ||
|
|
ed087e5b0d | ||
|
|
2038d87306 | ||
|
|
252c717cc3 | ||
|
|
9b338b58a7 | ||
|
|
abe37ab72b | ||
|
|
b3a30a9e32 | ||
|
|
31e915c017 | ||
|
|
05bbe49fe1 | ||
|
|
c80fedbbae | ||
|
|
2c60cad840 | ||
|
|
847887b312 | ||
|
|
d9984214c9 | ||
|
|
33b4390bc2 |
@@ -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';
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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('');
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
|
||||
import {afterEach, beforeEach, describe, expect, it, jest} from '@jest/globals';
|
||||
import * as exec from '@actions/exec';
|
||||
import path from 'path';
|
||||
import osm = require('os');
|
||||
|
||||
import {Docker} from '../src/docker';
|
||||
import {Exec} from '../src/exec';
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
@@ -48,11 +48,11 @@ describe('configDir', () => {
|
||||
});
|
||||
|
||||
describe('isAvailable', () => {
|
||||
it('cli', () => {
|
||||
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||
Docker.isAvailable;
|
||||
it('cli', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'getExecOutput');
|
||||
await Docker.isAvailable();
|
||||
// eslint-disable-next-line jest/no-standalone-expect
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, undefined, {
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, [], {
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
});
|
||||
@@ -60,43 +60,21 @@ describe('isAvailable', () => {
|
||||
});
|
||||
|
||||
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
51
__tests__/exec.test.ts
Normal 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
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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');
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -15,46 +15,30 @@
|
||||
*/
|
||||
|
||||
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];
|
||||
public async getVersion(node: NodeInfo): Promise<string | undefined> {
|
||||
if (!node.buildkitVersion && node.name) {
|
||||
try {
|
||||
return await this.getVersionWithinImage(node.name);
|
||||
@@ -66,44 +50,47 @@ export class 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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,51 +16,40 @@
|
||||
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import * as exec from '@actions/exec';
|
||||
import * as core from '@actions/core';
|
||||
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> {
|
||||
const ok: boolean = await Exec.getExecOutput('docker', [], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
dockerAvailable = false;
|
||||
} else {
|
||||
dockerAvailable = res.exitCode == 0;
|
||||
core.debug(`Docker.isAvailable cmd err: ${res.stderr}`);
|
||||
return false;
|
||||
}
|
||||
return res.exitCode == 0;
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.catch(error => {
|
||||
dockerAvailable = false;
|
||||
core.debug(`Docker.isAvailable error: ${error}`);
|
||||
return false;
|
||||
});
|
||||
return dockerAvailable;
|
||||
|
||||
core.debug(`Docker.isAvailable: ${ok}`);
|
||||
return ok;
|
||||
}
|
||||
|
||||
public static async printVersion(standalone?: boolean) {
|
||||
const noDocker = standalone ?? !Docker.isAvailable;
|
||||
if (noDocker) {
|
||||
return;
|
||||
}
|
||||
await exec.exec('docker', ['version'], {
|
||||
failOnStdErr: false
|
||||
});
|
||||
public static async printVersion(): Promise<void> {
|
||||
await Exec.exec('docker', ['version']);
|
||||
}
|
||||
|
||||
public static async printInfo(standalone?: boolean) {
|
||||
const noDocker = standalone ?? !Docker.isAvailable;
|
||||
if (noDocker) {
|
||||
return;
|
||||
}
|
||||
await exec.exec('docker', ['info'], {
|
||||
failOnStdErr: false
|
||||
});
|
||||
public static async printInfo(): Promise<void> {
|
||||
await Exec.exec('docker', ['info']);
|
||||
}
|
||||
}
|
||||
|
||||
31
src/exec.ts
Normal file
31
src/exec.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
30
src/git.ts
30
src/git.ts
@@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user