Skip to content

Commit 624e16f

Browse files
authored
Merge pull request #307 from crazy-max/build-export
buildx: build history export
2 parents 7eb10a1 + ee84f2a commit 624e16f

File tree

7 files changed

+425
-0
lines changed

7 files changed

+425
-0
lines changed

.github/workflows/test.yml

+9
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,14 @@ jobs:
131131
with:
132132
version: ${{ env.BUILDX_VERSION }}
133133
driver: docker
134+
-
135+
name: Set up container builder
136+
if: startsWith(matrix.os, 'ubuntu')
137+
id: builder
138+
uses: docker/setup-buildx-action@v3
139+
with:
140+
version: ${{ env.BUILDX_VERSION }}
141+
use: false
134142
-
135143
name: Install
136144
run: yarn install
@@ -140,6 +148,7 @@ jobs:
140148
yarn test:itg-coverage --runTestsByPath __tests__/${{ matrix.test }} --coverageDirectory=./coverage
141149
env:
142150
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
151+
CTN_BUILDER_NAME: ${{ steps.builder.outputs.name }}
143152
-
144153
name: Check coverage
145154
run: |

__tests__/buildx/history.test.itg.ts

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/**
2+
* Copyright 2024 actions-toolkit authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {beforeEach, describe, expect, jest, test} from '@jest/globals';
18+
import * as fs from 'fs';
19+
import * as path from 'path';
20+
21+
import {Buildx} from '../../src/buildx/buildx';
22+
import {Bake} from '../../src/buildx/bake';
23+
import {Build} from '../../src/buildx/build';
24+
import {History} from '../../src/buildx/history';
25+
import {Exec} from '../../src/exec';
26+
27+
const fixturesDir = path.join(__dirname, '..', 'fixtures');
28+
29+
// prettier-ignore
30+
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-history-jest');
31+
32+
const maybe = !process.env.GITHUB_ACTIONS || (process.env.GITHUB_ACTIONS === 'true' && process.env.ImageOS && process.env.ImageOS.startsWith('ubuntu')) ? describe : describe.skip;
33+
34+
beforeEach(() => {
35+
jest.clearAllMocks();
36+
});
37+
38+
maybe('exportBuild', () => {
39+
// prettier-ignore
40+
test.each([
41+
[
42+
'single',
43+
[
44+
'build',
45+
'-f', path.join(fixturesDir, 'hello.Dockerfile'),
46+
fixturesDir
47+
],
48+
],
49+
[
50+
'multi-platform',
51+
[
52+
'build',
53+
'-f', path.join(fixturesDir, 'hello.Dockerfile'),
54+
'--platform', 'linux/amd64,linux/arm64',
55+
fixturesDir
56+
],
57+
]
58+
])('export build %p', async (_, bargs) => {
59+
const buildx = new Buildx();
60+
const build = new Build({buildx: buildx});
61+
62+
fs.mkdirSync(tmpDir, {recursive: true});
63+
await expect(
64+
(async () => {
65+
// prettier-ignore
66+
const buildCmd = await buildx.getCommand([
67+
'--builder', process.env.CTN_BUILDER_NAME ?? 'default',
68+
...bargs,
69+
'--metadata-file', build.getMetadataFilePath()
70+
]);
71+
await Exec.exec(buildCmd.command, buildCmd.args);
72+
})()
73+
).resolves.not.toThrow();
74+
75+
const metadata = build.resolveMetadata();
76+
expect(metadata).toBeDefined();
77+
const buildRef = build.resolveRef(metadata);
78+
expect(buildRef).toBeDefined();
79+
80+
const history = new History({buildx: buildx});
81+
const exportRes = await history.export({
82+
refs: [buildRef ?? '']
83+
});
84+
85+
expect(exportRes).toBeDefined();
86+
expect(exportRes?.dockerbuildFilename).toBeDefined();
87+
expect(exportRes?.dockerbuildSize).toBeDefined();
88+
expect(fs.existsSync(exportRes?.dockerbuildFilename)).toBe(true);
89+
});
90+
91+
// prettier-ignore
92+
test.each([
93+
[
94+
'single',
95+
[
96+
'bake',
97+
'-f', path.join(fixturesDir, 'hello-bake.hcl'),
98+
'hello'
99+
],
100+
],
101+
[
102+
'group',
103+
[
104+
'bake',
105+
'-f', path.join(fixturesDir, 'hello-bake.hcl'),
106+
'hello-all'
107+
],
108+
],
109+
[
110+
'matrix',
111+
[
112+
'bake',
113+
'-f', path.join(fixturesDir, 'hello-bake.hcl'),
114+
'hello-matrix'
115+
],
116+
]
117+
])('export bake build %p', async (_, bargs) => {
118+
const buildx = new Buildx();
119+
const bake = new Bake({buildx: buildx});
120+
121+
fs.mkdirSync(tmpDir, {recursive: true});
122+
await expect(
123+
(async () => {
124+
// prettier-ignore
125+
const buildCmd = await buildx.getCommand([
126+
'--builder', process.env.CTN_BUILDER_NAME ?? 'default',
127+
...bargs,
128+
'--metadata-file', bake.getMetadataFilePath()
129+
]);
130+
await Exec.exec(buildCmd.command, buildCmd.args, {
131+
cwd: fixturesDir
132+
});
133+
})()
134+
).resolves.not.toThrow();
135+
136+
const metadata = bake.resolveMetadata();
137+
expect(metadata).toBeDefined();
138+
const buildRefs = bake.resolveRefs(metadata);
139+
expect(buildRefs).toBeDefined();
140+
141+
const history = new History({buildx: buildx});
142+
const exportRes = await history.export({
143+
refs: buildRefs ?? []
144+
});
145+
146+
expect(exportRes).toBeDefined();
147+
expect(exportRes?.dockerbuildFilename).toBeDefined();
148+
expect(exportRes?.dockerbuildSize).toBeDefined();
149+
expect(fs.existsSync(exportRes?.dockerbuildFilename)).toBe(true);
150+
});
151+
});

__tests__/fixtures/hello-bake.hcl

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2024 actions-toolkit authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
target "hello" {
16+
dockerfile = "hello.Dockerfile"
17+
}
18+
19+
target "hello-bar" {
20+
dockerfile = "hello.Dockerfile"
21+
args = {
22+
NAME = "bar"
23+
}
24+
}
25+
26+
group "hello-all" {
27+
targets = ["hello", "hello-bar"]
28+
}
29+
30+
target "hello-matrix" {
31+
name = "matrix-${name}"
32+
matrix = {
33+
name = ["bar", "baz", "boo", "far", "faz", "foo", "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj"]
34+
}
35+
dockerfile = "hello.Dockerfile"
36+
args = {
37+
NAME = name
38+
}
39+
}

__tests__/fixtures/hello.Dockerfile

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# syntax=docker/dockerfile:1
2+
3+
# Copyright 2024 actions-toolkit authors
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
FROM busybox
18+
ARG NAME=foo
19+
ARG TARGETPLATFORM
20+
RUN echo "Hello $NAME from $TARGETPLATFORM"

jest.config.itg.ts

+15
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@
1414
* limitations under the License.
1515
*/
1616

17+
import fs from 'fs';
18+
import os from 'os';
19+
import path from 'path';
20+
21+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-actions-toolkit-'));
22+
23+
process.env = Object.assign({}, process.env, {
24+
TEMP: tmpDir,
25+
GITHUB_REPOSITORY: 'docker/actions-toolkit',
26+
RUNNER_TEMP: path.join(tmpDir, 'runner-temp'),
27+
RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache')
28+
}) as {
29+
[key: string]: string;
30+
};
31+
1732
module.exports = {
1833
clearMocks: true,
1934
testEnvironment: 'node',

0 commit comments

Comments
 (0)