diff --git a/__tests__/buildx/buildx.test.ts b/__tests__/buildx/buildx.test.ts index 113a742..d62e1a1 100644 --- a/__tests__/buildx/buildx.test.ts +++ b/__tests__/buildx/buildx.test.ts @@ -24,7 +24,7 @@ import {Buildx} from '../../src/buildx/buildx'; import {Context} from '../../src/context'; import {Exec} from '../../src/exec'; -import {Cert} from '../../src/types/buildx/buildx'; +import {Cert, LocalState} from '../../src/types/buildx/buildx'; const fixturesDir = path.join(__dirname, '..', 'fixtures'); // prettier-ignore @@ -250,19 +250,70 @@ describe('resolveCertsDriverOpts', () => { }); }); +describe('localState', () => { + // prettier-ignore + test.each([ + [ + 'default/default/ij71n3ubmhck85d03zdvye5nr', + { + LocalPath: '/home/crazymax/github/docker_org/buildx', + DockerfilePath: '/home/crazymax/github/docker_org/buildx/Dockerfile' + } as LocalState, + ], + [ + 'default/default/7pnnqpgacnqq98oa1a1h5sz6t', + { + LocalPath: 'https://github.com/docker/actions-toolkit.git#:__tests__/fixtures', + DockerfilePath: 'hello.Dockerfile' + } as LocalState, + ], + [ + 'default/default/84p2qpgacnqq98oa1a1h5sz6t', + { + LocalPath: 'https://github.com/docker/actions-toolkit.git#:__tests__/fixtures', + DockerfilePath: '-' + } as LocalState, + ], + [ + 'default/default/a5s9rlg9cnqq98oa1a1h5sz6t', + { + LocalPath: '-', + DockerfilePath: '' + } as LocalState, + ], + [ + 'default/default/aav2ix4nw5eky66fw045dkylr', + { + LocalPath: 'https://github.com/docker/buildx.git', + DockerfilePath: '' + } as LocalState, + ], + [ + 'default/default/w38vcd5fo5cfvfyig77qjec0v', + { + LocalPath: '/home/crazy/hello', + DockerfilePath: '-' + } as LocalState, + ] + ])('given %p', async (ref: string, expected: LocalState) => { + const localState = Buildx.localState(path.join(fixturesDir, 'buildx-refs'), ref); + expect(localState).toEqual(expected); + }); +}); + describe('refs', () => { it('returns all refs', async () => { const refs = Buildx.refs({ dir: path.join(fixturesDir, 'buildx-refs') }); - expect(Object.keys(refs).length).toEqual(11); + expect(Object.keys(refs).length).toEqual(16); }); it('returns default builder refs', async () => { const refs = Buildx.refs({ dir: path.join(fixturesDir, 'buildx-refs'), builderName: 'default' }); - expect(Object.keys(refs).length).toEqual(8); + expect(Object.keys(refs).length).toEqual(13); }); it('returns foo builder refs', async () => { const refs = Buildx.refs({ @@ -281,6 +332,6 @@ describe('refs', () => { builderName: 'default', since: new Date('2024-01-10T00:00:00Z') }); - expect(Object.keys(refs).length).toEqual(5); + expect(Object.keys(refs).length).toEqual(10); }); }); diff --git a/__tests__/fixtures/buildx-refs/default/default/7pnnqpgacnqq98oa1a1h5sz6t b/__tests__/fixtures/buildx-refs/default/default/7pnnqpgacnqq98oa1a1h5sz6t new file mode 100644 index 0000000..863934c --- /dev/null +++ b/__tests__/fixtures/buildx-refs/default/default/7pnnqpgacnqq98oa1a1h5sz6t @@ -0,0 +1 @@ +{"LocalPath":"/home/crazy/foo/bar/https:/github.com/docker/actions-toolkit.git#:__tests__/fixtures","DockerfilePath":"/home/crazy/foo/bar/hello.Dockerfile"} diff --git a/__tests__/fixtures/buildx-refs/default/default/84p2qpgacnqq98oa1a1h5sz6t b/__tests__/fixtures/buildx-refs/default/default/84p2qpgacnqq98oa1a1h5sz6t new file mode 100644 index 0000000..2e3800b --- /dev/null +++ b/__tests__/fixtures/buildx-refs/default/default/84p2qpgacnqq98oa1a1h5sz6t @@ -0,0 +1 @@ +{"LocalPath":"/home/crazy/foo/bar/https:/github.com/docker/actions-toolkit.git#:__tests__/fixtures","DockerfilePath":"/home/crazy/foo/bar/-"} diff --git a/__tests__/fixtures/buildx-refs/default/default/a5s9rlg9cnqq98oa1a1h5sz6t b/__tests__/fixtures/buildx-refs/default/default/a5s9rlg9cnqq98oa1a1h5sz6t new file mode 100644 index 0000000..f5544ae --- /dev/null +++ b/__tests__/fixtures/buildx-refs/default/default/a5s9rlg9cnqq98oa1a1h5sz6t @@ -0,0 +1 @@ +{"LocalPath":"/home/crazy/foo/bar/-","DockerfilePath":""} diff --git a/__tests__/fixtures/buildx-refs/default/default/aav2ix4nw5eky66fw045dkylr b/__tests__/fixtures/buildx-refs/default/default/aav2ix4nw5eky66fw045dkylr new file mode 100644 index 0000000..79285e4 --- /dev/null +++ b/__tests__/fixtures/buildx-refs/default/default/aav2ix4nw5eky66fw045dkylr @@ -0,0 +1 @@ +{"LocalPath":"/home/crazy/foo/bar/https:/github.com/docker/buildx.git","DockerfilePath":""} diff --git a/__tests__/fixtures/buildx-refs/default/default/w38vcd5fo5cfvfyig77qjec0v b/__tests__/fixtures/buildx-refs/default/default/w38vcd5fo5cfvfyig77qjec0v new file mode 100644 index 0000000..8b13609 --- /dev/null +++ b/__tests__/fixtures/buildx-refs/default/default/w38vcd5fo5cfvfyig77qjec0v @@ -0,0 +1 @@ +{"LocalPath":"/home/crazy/hello","DockerfilePath":"/home/crazy/hello/-"} diff --git a/src/buildx/buildx.ts b/src/buildx/buildx.ts index 5820236..728d9dd 100644 --- a/src/buildx/buildx.ts +++ b/src/buildx/buildx.ts @@ -177,6 +177,54 @@ export class Buildx { return driverOpts; } + public static localState(dir: string, ref: string): LocalState { + const [builderName, nodeName, id] = ref.split('/'); + if (!builderName || !nodeName || !id) { + throw new Error(`Invalid build reference: ${ref}`); + } + const lsPath = path.join(dir, builderName, nodeName, id); + if (!fs.existsSync(lsPath)) { + throw new Error(`Local state not found in ${lsPath}`); + } + return Buildx.fixLocalState(JSON.parse(fs.readFileSync(lsPath, 'utf8'))); + } + + // https://github.com/docker/buildx/pull/2560 + private static fixLocalState(ls: LocalState): LocalState { + const fnTrimToValidContext = function (inp: string): [string, string, boolean] { + const match = inp.match(/(.*)(https?:\/{1,2}\S+|ssh:\/\/\S+|git:\/\/\S+)/i); + if (match && match.length == 3) { + const trimed = match[1]; + let url = match[2]; + if (url.startsWith('https:/') && !url.startsWith('https://')) { + url = url.replace('https:/', 'https://'); + } + if (url.startsWith('http:/') && !url.startsWith('http://')) { + url = url.replace('http:/', 'http://'); + } + if (url.startsWith('ssh:/') && !url.startsWith('ssh://')) { + url = url.replace('https:/', 'ssh://'); + } + if (url.startsWith('git:/') && !url.startsWith('git://')) { + url = url.replace('https:/', 'git://'); + } + return [url, trimed, true]; + } + return [inp, '', false]; + }; + + const [contextPath, trimedPath, isURL] = fnTrimToValidContext(ls.LocalPath); + if (isURL) { + ls.LocalPath = contextPath; + if (ls.DockerfilePath.indexOf(trimedPath) === 0) { + ls.DockerfilePath = ls.DockerfilePath.substring(trimedPath.length); + } + } + ls.LocalPath = ls.LocalPath.endsWith('/-') ? '-' : ls.LocalPath; + ls.DockerfilePath = ls.DockerfilePath.endsWith('/-') ? '-' : ls.DockerfilePath; + return ls; + } + public static refs(opts: LocalRefsOpts, refs: LocalRefsResponse = {}): LocalRefsResponse { const {dir, builderName, nodeName, since} = opts; @@ -210,7 +258,7 @@ export class Buildx { if (since && stat.mtime < since) { continue; } - const localState = JSON.parse(fs.readFileSync(filePath, 'utf8')); + const localState = Buildx.fixLocalState(JSON.parse(fs.readFileSync(filePath, 'utf8'))); const ref = `${builderName}/${nodeName}/${file}`; refs[ref] = localState; }