Compare commits
527 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6df98c1aad | ||
|
|
a9bd3f5b6b | ||
|
|
f7a8b21610 | ||
|
|
8177e153d6 | ||
|
|
a14ead6486 | ||
|
|
f9de623b1d | ||
|
|
202104bf16 | ||
|
|
b6b4cf170e | ||
|
|
311ae1dacc | ||
|
|
163d33a2bd | ||
|
|
d283be916f | ||
|
|
ffc7d98a98 | ||
|
|
d36bef4156 | ||
|
|
300c014384 | ||
|
|
b641895e8b | ||
|
|
4db21c4b43 | ||
|
|
8d807b6902 | ||
|
|
99e6b01d39 | ||
|
|
23208073ee | ||
|
|
2264b5ac72 | ||
|
|
d5247558ad | ||
|
|
e5ef18078d | ||
|
|
517914fc72 | ||
|
|
4c7e849bb4 | ||
|
|
ce0d3d5cf1 | ||
|
|
90311d5c08 | ||
|
|
d908ffcd2c | ||
|
|
3bd6acf499 | ||
|
|
5b4c1ac025 | ||
|
|
e49e07d23e | ||
|
|
b4c8e1a503 | ||
|
|
1510b1d394 | ||
|
|
214e644835 | ||
|
|
d7a84a5d46 | ||
|
|
61967435c1 | ||
|
|
78ca5b7f21 | ||
|
|
cc344864cb | ||
|
|
c70efab546 | ||
|
|
55a2181286 | ||
|
|
846cac2aa2 | ||
|
|
83d63d1cf1 | ||
|
|
931b62d64f | ||
|
|
16ecd76490 | ||
|
|
b26af9f868 | ||
|
|
ff35e30b01 | ||
|
|
200e43c426 | ||
|
|
2cb2c5573f | ||
|
|
f2de331691 | ||
|
|
27254cb337 | ||
|
|
c8df3474bd | ||
|
|
fe9937dd36 | ||
|
|
8785275da1 | ||
|
|
7bd4fed6bc | ||
|
|
18fbe0cb64 | ||
|
|
7360d08bf9 | ||
|
|
644587f0d1 | ||
|
|
3a7b0a6080 | ||
|
|
2e70a0cac6 | ||
|
|
e600fe266c | ||
|
|
52d663521a | ||
|
|
dceb603792 | ||
|
|
77b8d647eb | ||
|
|
630b180101 | ||
|
|
2e536e4a37 | ||
|
|
40f2a14d95 | ||
|
|
9853314413 | ||
|
|
f2e65ab473 | ||
|
|
e130c40c84 | ||
|
|
bbf0a8d268 | ||
|
|
4ce8a708c9 | ||
|
|
6f66565779 | ||
|
|
504af69bd9 | ||
|
|
f3734ee134 | ||
|
|
4183444df2 | ||
|
|
a5466523c1 | ||
|
|
e0007fb5cd | ||
|
|
c330895cef | ||
|
|
e7017a21b8 | ||
|
|
b56d9771d7 | ||
|
|
680ab5bdf1 | ||
|
|
5ea53e0090 | ||
|
|
b5ae9ccb69 | ||
|
|
8c81eef9ff | ||
|
|
6668cc52b7 | ||
|
|
58b2ef7640 | ||
|
|
d791e46ccd | ||
|
|
1cb547a599 | ||
|
|
b61fc5ff9c | ||
|
|
eb3bf3055e | ||
|
|
6c6fdffd44 | ||
|
|
edcf239f49 | ||
|
|
e26a82d0aa | ||
|
|
3162c096bd | ||
|
|
0da8b903ef | ||
|
|
953dc3bb00 | ||
|
|
f27d52d6b7 | ||
|
|
5c3fc146af | ||
|
|
ef2bd7607f | ||
|
|
6352d92e3f | ||
|
|
a39cb53a8a | ||
|
|
9b811fbceb | ||
|
|
7b876a9e95 | ||
|
|
fd2f683a14 | ||
|
|
5205f4197c | ||
|
|
c76674dd4a | ||
|
|
8471422135 | ||
|
|
e266e3e984 | ||
|
|
1b7201d572 | ||
|
|
6983a397f4 | ||
|
|
81e959d041 | ||
|
|
475cefa34e | ||
|
|
c14688a151 | ||
|
|
dde9860104 | ||
|
|
ee6e7bbd95 | ||
|
|
fe58cc26f5 | ||
|
|
1bf4b58db1 | ||
|
|
82d10009f7 | ||
|
|
bf985d0056 | ||
|
|
129955ee04 | ||
|
|
6d74aad91b | ||
|
|
24546185f6 | ||
|
|
1b5c574732 | ||
|
|
2ace0cd1f7 | ||
|
|
33d4b448ac | ||
|
|
ee91773603 | ||
|
|
5186ba6fdf | ||
|
|
1309d2023e | ||
|
|
6a4479ebc2 | ||
|
|
cd9f97a8c5 | ||
|
|
65f5b77696 | ||
|
|
9ba5af418c | ||
|
|
93ae2ded04 | ||
|
|
15788e8b93 | ||
|
|
92053e1988 | ||
|
|
6d856fd53e | ||
|
|
e67313ac6d | ||
|
|
881230f4b0 | ||
|
|
6fb52d2a23 | ||
|
|
2941f52b66 | ||
|
|
760d0c2369 | ||
|
|
d344961874 | ||
|
|
5958c823ef | ||
|
|
a033bb70cd | ||
|
|
8f8c0bb7ec | ||
|
|
0903e498a4 | ||
|
|
1e903f84b6 | ||
|
|
3a2e4a89a6 | ||
|
|
b3dc87c0e0 | ||
|
|
bd1955c564 | ||
|
|
956acbf3c6 | ||
|
|
ea36deec7f | ||
|
|
9d829e4f4a | ||
|
|
66c00b9bbd | ||
|
|
448f9ac218 | ||
|
|
624e16fb7c | ||
|
|
ee84f2ac79 | ||
|
|
7eb10a1871 | ||
|
|
27a4b44e2c | ||
|
|
75c874dd62 | ||
|
|
c94131a9e9 | ||
|
|
ec0a6e279b | ||
|
|
e0dd35a21c | ||
|
|
b25aadfb15 | ||
|
|
70f40871ae | ||
|
|
61d2e66416 | ||
|
|
c425c1b90c | ||
|
|
4a832ddb12 | ||
|
|
adf692bdc3 | ||
|
|
022c68391f | ||
|
|
eea3ac78bc | ||
|
|
76526d71ff | ||
|
|
4078ffc721 | ||
|
|
ffa2fadd58 | ||
|
|
53d4eba877 | ||
|
|
2c7c8d2118 | ||
|
|
4e56c9c296 | ||
|
|
ae20b6fb50 | ||
|
|
a99525f2f1 | ||
|
|
5820a0ba86 | ||
|
|
62e3923775 | ||
|
|
a459c7c911 | ||
|
|
4c3e9b6acf | ||
|
|
139c4c71de | ||
|
|
4383056550 | ||
|
|
40802f0aa9 | ||
|
|
8f9d3a3d14 | ||
|
|
e41efdd2aa | ||
|
|
33688c4ac8 | ||
|
|
f549f7954e | ||
|
|
5bbaf90158 | ||
|
|
00abdc0e59 | ||
|
|
0f39343265 | ||
|
|
97b80719d2 | ||
|
|
e03b1899b0 | ||
|
|
aece826a8c | ||
|
|
e6bbe6fe93 | ||
|
|
7621606be3 | ||
|
|
4ebe781891 | ||
|
|
a783f79a57 | ||
|
|
8d18a4a3a8 | ||
|
|
045a9c213c | ||
|
|
db0a36131e | ||
|
|
8d4d79eeb7 | ||
|
|
d44748420a | ||
|
|
b4e58da038 | ||
|
|
db6f070033 | ||
|
|
f35cc699c5 | ||
|
|
be6d9ea002 | ||
|
|
579376516d | ||
|
|
3c3a909fe3 | ||
|
|
53bcd3e6fe | ||
|
|
c6f16e945f | ||
|
|
06acacde0e | ||
|
|
2bba1c12c1 | ||
|
|
ad54dd379e | ||
|
|
a40fd9420f | ||
|
|
4d8bd68c1c | ||
|
|
43d331f793 | ||
|
|
fc4dae47b6 | ||
|
|
aa0228d826 | ||
|
|
02007009cc | ||
|
|
329c1c75cf | ||
|
|
056cded622 | ||
|
|
c47291c3a8 | ||
|
|
b73c694210 | ||
|
|
84b6763d80 | ||
|
|
10b5647a43 | ||
|
|
18e4452bac | ||
|
|
eb5663273f | ||
|
|
0bd3773680 | ||
|
|
f6cafdfce1 | ||
|
|
416c2914df | ||
|
|
341bae465f | ||
|
|
264a0eec2a | ||
|
|
545f7cd6ea | ||
|
|
de2888af87 | ||
|
|
43f61228ec | ||
|
|
8d1d731562 | ||
|
|
5706b95a7f | ||
|
|
5d8b7b4828 | ||
|
|
48e339fd34 | ||
|
|
41cae83741 | ||
|
|
d58f77be10 | ||
|
|
a24f5c12ca | ||
|
|
e73765a5ce | ||
|
|
cd14c5b580 | ||
|
|
9b446bf084 | ||
|
|
cbcf885731 | ||
|
|
5fba0d0374 | ||
|
|
d0e492964d | ||
|
|
e1fa386cb5 | ||
|
|
3401826b29 | ||
|
|
90c8d29f29 | ||
|
|
22e390c8ba | ||
|
|
70d3d9ae67 | ||
|
|
9436c6ca61 | ||
|
|
225d61b701 | ||
|
|
5dacef0ba8 | ||
|
|
26887092dc | ||
|
|
8dc7edb368 | ||
|
|
5879437e96 | ||
|
|
1c0d7a58fd | ||
|
|
e6c7da2fcd | ||
|
|
a98aa046a8 | ||
|
|
63adf44466 | ||
|
|
7fb507050a | ||
|
|
8e9a04559b | ||
|
|
224d7ab315 | ||
|
|
755c685d84 | ||
|
|
7d8b4dc669 | ||
|
|
cae64f370a | ||
|
|
7ed7bac5eb | ||
|
|
d86f59520c | ||
|
|
e1439ff231 | ||
|
|
cbb7546c52 | ||
|
|
05a9e511a8 | ||
|
|
8125540486 | ||
|
|
aff5040515 | ||
|
|
30cd573d15 | ||
|
|
3653f3bca9 | ||
|
|
250b2120b4 | ||
|
|
7ea6ed7dab | ||
|
|
3344f7b1c8 | ||
|
|
619687375a | ||
|
|
cbc244c2f4 | ||
|
|
f1c76199be | ||
|
|
b0d1226bb6 | ||
|
|
039e7f9c6e | ||
|
|
048d6c3fbe | ||
|
|
59a3548fbb | ||
|
|
c1429fefa4 | ||
|
|
1274cd2848 | ||
|
|
48394d7948 | ||
|
|
aebb2a6f58 | ||
|
|
dff5cd7e88 | ||
|
|
7e4d49d3be | ||
|
|
dee5356ab8 | ||
|
|
2267dad53e | ||
|
|
666b19e915 | ||
|
|
a5975adf41 | ||
|
|
3f7d7f75b5 | ||
|
|
299d4131fa | ||
|
|
ab1052f7e0 | ||
|
|
bf4bc3c036 | ||
|
|
49a22f7a3e | ||
|
|
03b8464ee3 | ||
|
|
0a1d2c2307 | ||
|
|
0adac517e3 | ||
|
|
012b121eb5 | ||
|
|
11cc7c697d | ||
|
|
0721cb2aa9 | ||
|
|
26949f5f39 | ||
|
|
32b78e4566 | ||
|
|
2d240ca0fc | ||
|
|
8c09071628 | ||
|
|
a9fec88f7a | ||
|
|
066518ecec | ||
|
|
d63347f68f | ||
|
|
9282d3e13b | ||
|
|
d240b3146a | ||
|
|
7063f758ae | ||
|
|
ad2fe8539c | ||
|
|
5d0a08a448 | ||
|
|
66f17c25e3 | ||
|
|
bf9adbe540 | ||
|
|
f2a56cda90 | ||
|
|
a60fe56754 | ||
|
|
9c42213ecc | ||
|
|
2e9fde295e | ||
|
|
942777afdc | ||
|
|
d468250481 | ||
|
|
8854de97ed | ||
|
|
666e090b82 | ||
|
|
f04fa19563 | ||
|
|
f8b8b5b18d | ||
|
|
f92cc3db0b | ||
|
|
032e16cf73 | ||
|
|
a6a71daf88 | ||
|
|
e298150fd7 | ||
|
|
a99fb34091 | ||
|
|
3a20771080 | ||
|
|
5430d017a5 | ||
|
|
e3bdf20325 | ||
|
|
f8ca396f63 | ||
|
|
603112bbed | ||
|
|
31a5828eff | ||
|
|
b3bb7713d9 | ||
|
|
6273173795 | ||
|
|
5fd725469f | ||
|
|
7929028d80 | ||
|
|
4995997eed | ||
|
|
348446a8d6 | ||
|
|
c8a1b7a531 | ||
|
|
911d146f5f | ||
|
|
0cc3169aa7 | ||
|
|
1de2911b5e | ||
|
|
9e9fc490d2 | ||
|
|
a45afd3161 | ||
|
|
7d829c430b | ||
|
|
ddc04994d9 | ||
|
|
b613f395b8 | ||
|
|
9e405d775a | ||
|
|
248fc44d7e | ||
|
|
e907622be4 | ||
|
|
5bc270dc53 | ||
|
|
c1ecc4b621 | ||
|
|
0a04d5661f | ||
|
|
252cfd570c | ||
|
|
2f97829cfc | ||
|
|
ea541ecec7 | ||
|
|
64a550a5dc | ||
|
|
73bb35d328 | ||
|
|
97573bff9a | ||
|
|
cef4c16170 | ||
|
|
3281ef2a12 | ||
|
|
03b93c3aee | ||
|
|
f8909e3265 | ||
|
|
624fee6e10 | ||
|
|
e927ebb09c | ||
|
|
5250fc63c3 | ||
|
|
77c591b46c | ||
|
|
602235dcce | ||
|
|
3ca52c06b2 | ||
|
|
7c2659dc5d | ||
|
|
307731cacb | ||
|
|
81355687c2 | ||
|
|
cca99038ee | ||
|
|
24a9fd8152 | ||
|
|
53e9f24dd0 | ||
|
|
b525cd9de8 | ||
|
|
21a7def1e9 | ||
|
|
243e746a8d | ||
|
|
b212b3b35e | ||
|
|
191def3857 | ||
|
|
0e5f8a766a | ||
|
|
a625c7487f | ||
|
|
e8569c2d9b | ||
|
|
7b1a9e4e34 | ||
|
|
8b3ff1beb0 | ||
|
|
35555f7a24 | ||
|
|
5562309585 | ||
|
|
2848275bb4 | ||
|
|
48c7d682b4 | ||
|
|
04d1940f48 | ||
|
|
6af9ce25af | ||
|
|
1e2ed9bcf1 | ||
|
|
3e8e9fc046 | ||
|
|
663d108e8d | ||
|
|
2629338e09 | ||
|
|
7a01b3e2a4 | ||
|
|
c363216f0d | ||
|
|
0ebe5d1c2f | ||
|
|
6d03d1708d | ||
|
|
d6753812df | ||
|
|
3f7939e71c | ||
|
|
584493d659 | ||
|
|
dd4311c75e | ||
|
|
b91698741e | ||
|
|
36e5638636 | ||
|
|
d852953482 | ||
|
|
9bb2a9fe23 | ||
|
|
f4fdb6a9f8 | ||
|
|
558d76d017 | ||
|
|
f3dd07df13 | ||
|
|
0455460f6f | ||
|
|
f5c9bb7acd | ||
|
|
9d75f8f839 | ||
|
|
b86f723512 | ||
|
|
d3d7271f87 | ||
|
|
fddef161c1 | ||
|
|
e75930a3a6 | ||
|
|
bd5e1d1bab | ||
|
|
354737b4fc | ||
|
|
eea8c07dcc | ||
|
|
f08154f2c4 | ||
|
|
aae835e4b4 | ||
|
|
6f9aedec5e | ||
|
|
78cfd0384b | ||
|
|
d5f67f772e | ||
|
|
cb4777c2a5 | ||
|
|
80845a187b | ||
|
|
66e22ce5a5 | ||
|
|
7b63a1220d | ||
|
|
59715cf565 | ||
|
|
e8cb844045 | ||
|
|
a00c49179b | ||
|
|
dc2c313f17 | ||
|
|
c73f530a0e | ||
|
|
66fff011ac | ||
|
|
c4085cc810 | ||
|
|
79d8877773 | ||
|
|
95ac6338f1 | ||
|
|
7b72d5977b | ||
|
|
2ad0e2331e | ||
|
|
f2d14e7769 | ||
|
|
33dc7b6ecb | ||
|
|
6bf3dcef73 | ||
|
|
31d5e42cc0 | ||
|
|
32e2a6bf6f | ||
|
|
c8d666e020 | ||
|
|
49ed594253 | ||
|
|
144df6eecc | ||
|
|
c3e31dcc03 | ||
|
|
0f8ae202d6 | ||
|
|
c674e727ec | ||
|
|
a72977ca69 | ||
|
|
a6558f6584 | ||
|
|
6a8f167e10 | ||
|
|
19f5e39cc1 | ||
|
|
945af30d0c | ||
|
|
24a56dbe42 | ||
|
|
4e8d894523 | ||
|
|
5b15c952e9 | ||
|
|
9822f1ac09 | ||
|
|
b9121242ac | ||
|
|
c759388ee4 | ||
|
|
dfcd13e51e | ||
|
|
2be3d9389c | ||
|
|
541f8784ed | ||
|
|
4abccc4c6a | ||
|
|
fcc92b092b | ||
|
|
6e043aee71 | ||
|
|
7a37a260aa | ||
|
|
1534dfad1b | ||
|
|
08e669e7d5 | ||
|
|
83d366eb65 | ||
|
|
5b760c8b3a | ||
|
|
674ee4994a | ||
|
|
a56ca8f880 | ||
|
|
b833243795 | ||
|
|
823d1cfce9 | ||
|
|
97bc88d30b | ||
|
|
ed4441e704 | ||
|
|
7a4b2122b2 | ||
|
|
959fb2fd2e | ||
|
|
2c0d9d0c4e | ||
|
|
3199bce461 | ||
|
|
f1593e3aa2 | ||
|
|
db5c712dec | ||
|
|
fd97af130e | ||
|
|
ec700a3813 | ||
|
|
324e807d2e | ||
|
|
8e45354f0c | ||
|
|
906aacf7ff | ||
|
|
1d9f94872d | ||
|
|
b99f9ec3ef | ||
|
|
8d02bad9a9 | ||
|
|
c1edd0b5e3 | ||
|
|
70c0e12f74 | ||
|
|
ddcd63c92a | ||
|
|
0e5fc3661a | ||
|
|
3d49d98580 | ||
|
|
ca519e1aa8 | ||
|
|
b13ef76b5e | ||
|
|
2043356c92 | ||
|
|
84371bb189 | ||
|
|
ad6e71b881 | ||
|
|
e47142d45b | ||
|
|
e79f79bcd9 | ||
|
|
ab02f62089 | ||
|
|
8cef70fefb | ||
|
|
321a028303 | ||
|
|
80eaf0972b | ||
|
|
101a44b0a7 | ||
|
|
22cc0b6c27 | ||
|
|
21fdfc52c4 | ||
|
|
eebb677d5a |
@@ -1,12 +1,13 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true,
|
||||
"es2021": true,
|
||||
"es6": true,
|
||||
"mocha": true,
|
||||
"jest": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:import/errors",
|
||||
"plugin:import/typescript", // this is needed to allow importing typescript files from JS
|
||||
@@ -16,7 +17,7 @@
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"ecmaVersion": 2023,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": [
|
||||
@@ -27,7 +28,7 @@
|
||||
"rules": {
|
||||
"import/no-unresolved": [
|
||||
"error", {
|
||||
"ignore": ["csv-parse/sync"]
|
||||
"ignore": ["csv-parse/sync", "@octokit/openapi-types"]
|
||||
}
|
||||
],
|
||||
"jest/no-disabled-tests": 0
|
||||
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,2 +1,3 @@
|
||||
/.yarn/releases/** binary
|
||||
/.yarn/plugins/** binary
|
||||
/__tests__/fixtures/oci-archive/** binary
|
||||
|
||||
535
.github/buildx-lab-releases.json
vendored
Normal file
535
.github/buildx-lab-releases.json
vendored
Normal file
@@ -0,0 +1,535 @@
|
||||
{
|
||||
"latest": {
|
||||
"id": 161492089,
|
||||
"tag_name": "v0.15.1-desktop.1",
|
||||
"html_url": "https://github.com/docker/buildx-desktop/releases/tag/v0.15.1-desktop.1",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v6",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v7",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-ppc64le",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-riscv64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-s390x",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.15.1-desktop.1": {
|
||||
"id": 161492089,
|
||||
"tag_name": "v0.15.1-desktop.1",
|
||||
"html_url": "https://github.com/docker/buildx-desktop/releases/tag/v0.15.1-desktop.1",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v6",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v7",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-ppc64le",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-riscv64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-s390x",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.15.0-desktop.1": {
|
||||
"id": 160473592,
|
||||
"tag_name": "v0.15.0-desktop.1",
|
||||
"html_url": "https://github.com/docker/buildx-desktop/releases/tag/v0.15.0-desktop.1",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.darwin-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.darwin-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-arm-v6",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-arm-v7",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-ppc64le",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-riscv64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-s390x",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/buildx-v0.15.0-desktop.1.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.15.0-desktop.1/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.14.1-desktop.1": {
|
||||
"id": 157588052,
|
||||
"tag_name": "v0.14.1-desktop.1",
|
||||
"html_url": "https://github.com/docker/buildx-desktop/releases/tag/v0.14.1-desktop.1",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.darwin-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.darwin-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-arm-v6",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-arm-v7",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-ppc64le",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-riscv64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-s390x",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/buildx-v0.14.1-desktop.1.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.14.0-desktop.1": {
|
||||
"id": 155523887,
|
||||
"tag_name": "v0.14.0-desktop.1",
|
||||
"html_url": "https://github.com/docker/buildx-desktop/releases/tag/v0.14.0-desktop.1",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.darwin-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.darwin-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-arm-v6",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-arm-v7",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-ppc64le",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-riscv64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-s390x",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/buildx-v0.14.0-desktop.1.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.14.0-desktop.1/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.13.1-desktop-preview.2": {
|
||||
"id": 151417247,
|
||||
"tag_name": "v0.13.1-desktop-preview.2",
|
||||
"html_url": "https://github.com/docker/buildx-desktop/releases/tag/v0.13.1-desktop-preview.2",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.darwin-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.darwin-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-arm-v6",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-arm-v7",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-ppc64le",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-riscv64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-s390x",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/buildx-v0.13.1-desktop-preview.2.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.13.1-desktop-preview.2/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.12.1-desktop.4": {
|
||||
"id": 137689487,
|
||||
"tag_name": "v0.12.1-desktop.4",
|
||||
"html_url": "https://github.com/docker/buildx-desktop/releases/tag/v0.12.1-desktop.4",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.darwin-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.darwin-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-arm-v6",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-arm-v7",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-ppc64le",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-riscv64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-s390x",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/buildx-v0.12.1-desktop.4.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.4/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.12.1-desktop.3": {
|
||||
"id": 137560191,
|
||||
"tag_name": "v0.12.1-desktop.3",
|
||||
"html_url": "https://github.com/docker/buildx-desktop/releases/tag/v0.12.1-desktop.3",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.darwin-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.darwin-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-arm-v6",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-arm-v7",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-ppc64le",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-riscv64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-s390x",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/buildx-v0.12.1-desktop.3.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.1-desktop.3/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.12.0-desktop.2": {
|
||||
"id": 132264953,
|
||||
"tag_name": "v0.12.0-desktop.2",
|
||||
"html_url": "https://github.com/docker/buildx-desktop/releases/tag/v0.12.0-desktop.2",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.darwin-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.darwin-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-arm-v6",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-arm-v7",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-ppc64le",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-riscv64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-s390x",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/buildx-v0.12.0-desktop.2.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.2/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.12.0-desktop.1": {
|
||||
"id": 130699107,
|
||||
"tag_name": "v0.12.0-desktop.1",
|
||||
"html_url": "https://github.com/docker/buildx-desktop/releases/tag/v0.12.0-desktop.1",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.darwin-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.darwin-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-arm-v6",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-arm-v7",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-ppc64le",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-riscv64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-s390x",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/buildx-v0.12.0-desktop.1.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.12.0-desktop.1/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.11.2-desktop.5": {
|
||||
"id": 123496811,
|
||||
"tag_name": "v0.11.2-desktop.5",
|
||||
"html_url": "https://github.com/docker/buildx-desktop/releases/tag/v0.11.2-desktop.5",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.darwin-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.darwin-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-arm-v6",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-arm-v7",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-ppc64le",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-riscv64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-s390x",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/buildx-v0.11.2-desktop.5.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.5/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.11.2-desktop.4": {
|
||||
"id": 119399782,
|
||||
"tag_name": "v0.11.2-desktop.4",
|
||||
"html_url": "https://github.com/docker/buildx-desktop/releases/tag/v0.11.2-desktop.4",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.darwin-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.darwin-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-arm-v6",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-arm-v7",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-ppc64le",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-riscv64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-s390x",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/buildx-v0.11.2-desktop.4.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.4/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.11.2-desktop.2": {
|
||||
"id": 118213369,
|
||||
"tag_name": "v0.11.2-desktop.2",
|
||||
"html_url": "https://github.com/docker/buildx-desktop/releases/tag/v0.11.2-desktop.2",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.darwin-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.darwin-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-amd64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-arm-v6",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-arm-v7",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-arm64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-ppc64le",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-riscv64",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-s390x",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/buildx-v0.11.2-desktop.2.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx-desktop/releases/download/v0.11.2-desktop.2/checksums.txt"
|
||||
]
|
||||
}
|
||||
}
|
||||
1017
.github/buildx-releases.json
vendored
1017
.github/buildx-releases.json
vendored
File diff suppressed because it is too large
Load Diff
5
.github/dependabot.yml
vendored
5
.github/dependabot.yml
vendored
@@ -11,8 +11,13 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
versioning-strategy: "increase"
|
||||
allow:
|
||||
- dependency-type: "production"
|
||||
ignore:
|
||||
- # we want to match the same version as the one used by @actions/artifact
|
||||
# https://github.com/actions/toolkit/blob/ae38557bb0dba824cdda26ce787bd6b66cf07a83/packages/artifact/package.json#L46
|
||||
dependency-name: "@azure/storage-blob"
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "bot"
|
||||
|
||||
276
.github/docker-releases.json
vendored
276
.github/docker-releases.json
vendored
@@ -1,8 +1,278 @@
|
||||
{
|
||||
"latest": {
|
||||
"id": 104366762,
|
||||
"tag_name": "v24.0.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.2",
|
||||
"id": 163311279,
|
||||
"tag_name": "v27.0.3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v27.0.3",
|
||||
"assets": []
|
||||
},
|
||||
"v27.0.3": {
|
||||
"id": 163311279,
|
||||
"tag_name": "v27.0.3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v27.0.3",
|
||||
"assets": []
|
||||
},
|
||||
"v27.0.2": {
|
||||
"id": 162600493,
|
||||
"tag_name": "v27.0.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v27.0.2",
|
||||
"assets": []
|
||||
},
|
||||
"v27.0.1": {
|
||||
"id": 162009909,
|
||||
"tag_name": "v27.0.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v27.0.1",
|
||||
"assets": []
|
||||
},
|
||||
"v27.0.1-rc.1": {
|
||||
"id": 161457618,
|
||||
"tag_name": "v27.0.1-rc.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v27.0.1-rc.1",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.13": {
|
||||
"id": 161533551,
|
||||
"tag_name": "v23.0.13",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.13",
|
||||
"assets": []
|
||||
},
|
||||
"v27.0.0-rc.2": {
|
||||
"id": 160534078,
|
||||
"tag_name": "v27.0.0-rc.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v27.0.0-rc.2",
|
||||
"assets": []
|
||||
},
|
||||
"v27.0.0-rc.1": {
|
||||
"id": 160112985,
|
||||
"tag_name": "v27.0.0-rc.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v27.0.0-rc.1",
|
||||
"assets": []
|
||||
},
|
||||
"v26.1.4": {
|
||||
"id": 159031384,
|
||||
"tag_name": "v26.1.4",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v26.1.4",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.12": {
|
||||
"id": 158038616,
|
||||
"tag_name": "v23.0.12",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.12",
|
||||
"assets": []
|
||||
},
|
||||
"v26.1.3": {
|
||||
"id": 155867714,
|
||||
"tag_name": "v26.1.3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v26.1.3",
|
||||
"assets": []
|
||||
},
|
||||
"v26.1.2": {
|
||||
"id": 154733361,
|
||||
"tag_name": "v26.1.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v26.1.2",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.11": {
|
||||
"id": 154425437,
|
||||
"tag_name": "v23.0.11",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.11",
|
||||
"assets": []
|
||||
},
|
||||
"v26.1.1": {
|
||||
"id": 153294610,
|
||||
"tag_name": "v26.1.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v26.1.1",
|
||||
"assets": []
|
||||
},
|
||||
"v26.1.0": {
|
||||
"id": 149919896,
|
||||
"tag_name": "v26.1.0",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v26.1.0",
|
||||
"assets": []
|
||||
},
|
||||
"v26.0.2": {
|
||||
"id": 151768426,
|
||||
"tag_name": "v26.0.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v26.0.2",
|
||||
"assets": []
|
||||
},
|
||||
"v26.0.1": {
|
||||
"id": 149921469,
|
||||
"tag_name": "v26.0.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v26.0.1",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.10": {
|
||||
"id": 147776752,
|
||||
"tag_name": "v23.0.10",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.10",
|
||||
"assets": []
|
||||
},
|
||||
"v26.0.0": {
|
||||
"id": 145844215,
|
||||
"tag_name": "v26.0.0",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v26.0.0",
|
||||
"assets": []
|
||||
},
|
||||
"v26.0.0-rc3": {
|
||||
"id": 146688910,
|
||||
"tag_name": "v26.0.0-rc3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v26.0.0-rc3",
|
||||
"assets": []
|
||||
},
|
||||
"v25.0.5": {
|
||||
"id": 147202747,
|
||||
"tag_name": "v25.0.5",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v25.0.5",
|
||||
"assets": []
|
||||
},
|
||||
"v26.0.0-rc2": {
|
||||
"id": 144926580,
|
||||
"tag_name": "v26.0.0-rc2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v26.0.0-rc2",
|
||||
"assets": []
|
||||
},
|
||||
"v25.0.4": {
|
||||
"id": 144022554,
|
||||
"tag_name": "v25.0.4",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v25.0.4",
|
||||
"assets": []
|
||||
},
|
||||
"v26.0.0-rc1": {
|
||||
"id": 142822675,
|
||||
"tag_name": "v26.0.0-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v26.0.0-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v25.0.3": {
|
||||
"id": 140187402,
|
||||
"tag_name": "v25.0.3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v25.0.3",
|
||||
"assets": []
|
||||
},
|
||||
"v25.0.2": {
|
||||
"id": 139426676,
|
||||
"tag_name": "v25.0.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v25.0.2",
|
||||
"assets": []
|
||||
},
|
||||
"v24.0.9": {
|
||||
"id": 139508924,
|
||||
"tag_name": "v24.0.9",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.9",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.9": {
|
||||
"id": 139233691,
|
||||
"tag_name": "v23.0.9",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.9",
|
||||
"assets": []
|
||||
},
|
||||
"v24.0.8": {
|
||||
"id": 138593185,
|
||||
"tag_name": "v24.0.8",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.8",
|
||||
"assets": []
|
||||
},
|
||||
"v25.0.1": {
|
||||
"id": 138305010,
|
||||
"tag_name": "v25.0.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v25.0.1",
|
||||
"assets": []
|
||||
},
|
||||
"v25.0.0": {
|
||||
"id": 137711983,
|
||||
"tag_name": "v25.0.0",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v25.0.0",
|
||||
"assets": []
|
||||
},
|
||||
"v25.0.0-rc.3": {
|
||||
"id": 137464931,
|
||||
"tag_name": "v25.0.0-rc.3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v25.0.0-rc.3",
|
||||
"assets": []
|
||||
},
|
||||
"v25.0.0-rc.2": {
|
||||
"id": 136912066,
|
||||
"tag_name": "v25.0.0-rc.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v25.0.0-rc.2",
|
||||
"assets": []
|
||||
},
|
||||
"v25.0.0-rc.1": {
|
||||
"id": 135904442,
|
||||
"tag_name": "v25.0.0-rc.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v25.0.0-rc.1",
|
||||
"assets": []
|
||||
},
|
||||
"v25.0.0-beta.3": {
|
||||
"id": 134782996,
|
||||
"tag_name": "v25.0.0-beta.3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v25.0.0-beta.3",
|
||||
"assets": []
|
||||
},
|
||||
"v25.0.0-beta.2": {
|
||||
"id": 133659834,
|
||||
"tag_name": "v25.0.0-beta.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v25.0.0-beta.2",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.8": {
|
||||
"id": 132317923,
|
||||
"tag_name": "v23.0.8",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.8",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.27": {
|
||||
"id": 132318746,
|
||||
"tag_name": "v20.10.27",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.27",
|
||||
"assets": []
|
||||
},
|
||||
"v25.0.0-beta.1": {
|
||||
"id": 129244747,
|
||||
"tag_name": "v25.0.0-beta.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v25.0.0-beta.1",
|
||||
"assets": []
|
||||
},
|
||||
"v24.0.7": {
|
||||
"id": 126933125,
|
||||
"tag_name": "v24.0.7",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.7",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.7": {
|
||||
"id": 122845906,
|
||||
"tag_name": "v23.0.7",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.7",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.26": {
|
||||
"id": 122843129,
|
||||
"tag_name": "v20.10.26",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.26",
|
||||
"assets": []
|
||||
},
|
||||
"v24.0.6": {
|
||||
"id": 120021175,
|
||||
"tag_name": "v24.0.6",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.6",
|
||||
"assets": []
|
||||
},
|
||||
"v24.0.5": {
|
||||
"id": 113348684,
|
||||
"tag_name": "v24.0.5",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.5",
|
||||
"assets": []
|
||||
},
|
||||
"v24.0.4": {
|
||||
"id": 111464537,
|
||||
"tag_name": "v24.0.4",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.4",
|
||||
"assets": []
|
||||
},
|
||||
"v24.0.3": {
|
||||
"id": 111300256,
|
||||
"tag_name": "v24.0.3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.3",
|
||||
"assets": []
|
||||
},
|
||||
"v24.0.2": {
|
||||
|
||||
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -18,9 +18,9 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@v3
|
||||
uses: docker/bake-action@v5
|
||||
with:
|
||||
targets: build
|
||||
|
||||
58
.github/workflows/buildx-lab-releases-json.yml
vendored
Normal file
58
.github/workflows/buildx-lab-releases-json.yml
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
name: buildx-lab-releases-json
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 */12 * * *'
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/buildx-lab-releases-json.yml'
|
||||
|
||||
jobs:
|
||||
generate:
|
||||
uses: crazy-max/.github/.github/workflows/releases-json.yml@fa6141aedf23596fb8bdcceab9cce8dadaa31bd9
|
||||
with:
|
||||
repository: docker/buildx-desktop
|
||||
artifact_name: buildx-lab-releases-json
|
||||
filename: buildx-lab-releases.json
|
||||
secrets: inherit
|
||||
|
||||
open-pr:
|
||||
runs-on: ubuntu-22.04
|
||||
if: github.event_name != 'pull_request'
|
||||
needs:
|
||||
- generate
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Download
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: buildx-lab-releases-json
|
||||
path: .github
|
||||
-
|
||||
name: Commit changes
|
||||
run: |
|
||||
git add -A .
|
||||
-
|
||||
name: Create PR
|
||||
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0
|
||||
with:
|
||||
base: main
|
||||
branch: bot/buildx-lab-releases-json
|
||||
commit-message: "github: update .github/buildx-lab-releases.json"
|
||||
signoff: true
|
||||
delete-branch: true
|
||||
title: "Update `.github/buildx-lab-releases.json`"
|
||||
body: |
|
||||
Update `.github/buildx-lab-releases.json` to keep in sync with [https://github.com/docker/buildx-desktop](https://github.com/docker/buildx-desktop).
|
||||
draft: false
|
||||
12
.github/workflows/buildx-releases-json.yml
vendored
12
.github/workflows/buildx-releases-json.yml
vendored
@@ -12,12 +12,12 @@ on:
|
||||
branches:
|
||||
- 'main'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '.github/*-releases.json'
|
||||
paths:
|
||||
- '.github/workflows/buildx-releases-json.yml'
|
||||
|
||||
jobs:
|
||||
generate:
|
||||
uses: crazy-max/.github/.github/workflows/releases-json.yml@6dc31870ca6c4f8489bf5a408ab38fae60f47eec
|
||||
uses: crazy-max/.github/.github/workflows/releases-json.yml@fa6141aedf23596fb8bdcceab9cce8dadaa31bd9
|
||||
with:
|
||||
repository: docker/buildx
|
||||
artifact_name: buildx-releases-json
|
||||
@@ -32,10 +32,10 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Download
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: buildx-releases-json
|
||||
path: .github
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
git add -A .
|
||||
-
|
||||
name: Create PR
|
||||
uses: peter-evans/create-pull-request@284f54f989303d2699d373481a0cfa13ad5a6666
|
||||
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0
|
||||
with:
|
||||
base: main
|
||||
branch: bot/buildx-releases-json
|
||||
|
||||
46
.github/workflows/codeql.yml
vendored
Normal file
46
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
name: codeql
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
env:
|
||||
NODE_VERSION: 20
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Enable corepack
|
||||
run: |
|
||||
corepack enable
|
||||
yarn --version
|
||||
-
|
||||
name: Set up Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
-
|
||||
name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: javascript-typescript
|
||||
-
|
||||
name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
-
|
||||
name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:javascript-typescript"
|
||||
12
.github/workflows/docker-releases-json.yml
vendored
12
.github/workflows/docker-releases-json.yml
vendored
@@ -12,12 +12,12 @@ on:
|
||||
branches:
|
||||
- 'main'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '.github/*-releases.json'
|
||||
paths:
|
||||
- '.github/workflows/docker-releases-json.yml'
|
||||
|
||||
jobs:
|
||||
generate:
|
||||
uses: crazy-max/.github/.github/workflows/releases-json.yml@6dc31870ca6c4f8489bf5a408ab38fae60f47eec
|
||||
uses: crazy-max/.github/.github/workflows/releases-json.yml@fa6141aedf23596fb8bdcceab9cce8dadaa31bd9
|
||||
with:
|
||||
repository: moby/moby
|
||||
artifact_name: docker-releases-json
|
||||
@@ -32,10 +32,10 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Download
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: docker-releases-json
|
||||
path: .github
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
git add -A .
|
||||
-
|
||||
name: Create PR
|
||||
uses: peter-evans/create-pull-request@284f54f989303d2699d373481a0cfa13ad5a6666
|
||||
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0
|
||||
with:
|
||||
base: main
|
||||
branch: bot/docker-releases-json
|
||||
|
||||
6
.github/workflows/publish.yml
vendored
6
.github/workflows/publish.yml
vendored
@@ -15,13 +15,13 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Publish
|
||||
uses: docker/bake-action@v3
|
||||
uses: docker/bake-action@v5
|
||||
with:
|
||||
targets: publish
|
||||
env:
|
||||
|
||||
97
.github/workflows/test.yml
vendored
97
.github/workflows/test.yml
vendored
@@ -13,26 +13,42 @@ on:
|
||||
paths-ignore:
|
||||
- '.github/*-releases.json'
|
||||
|
||||
env:
|
||||
NODE_VERSION: "20"
|
||||
BUILDX_VERSION: "v0.16.1"
|
||||
BUILDKIT_IMAGE: "moby/buildkit:v0.15.0"
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Test
|
||||
uses: docker/bake-action@v3
|
||||
uses: docker/bake-action@v5
|
||||
with:
|
||||
targets: test-coverage
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
-
|
||||
name: Check coverage
|
||||
run: |
|
||||
if [ -f ./coverage/clover.xml ] && [ ! -f ./coverage/allSkipped.txt ]; then
|
||||
echo "RUN_CODECOV=true" >> $GITHUB_ENV
|
||||
else
|
||||
echo "RUN_CODECOV=false" >> $GITHUB_ENV
|
||||
fi
|
||||
shell: bash
|
||||
-
|
||||
name: Upload coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
uses: codecov/codecov-action@v4
|
||||
if: env.RUN_CODECOV == 'true'
|
||||
with:
|
||||
file: ./coverage/clover.xml
|
||||
flags: unit
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
prepare-itg:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -41,12 +57,17 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Enable corepack
|
||||
run: |
|
||||
corepack enable
|
||||
yarn --version
|
||||
-
|
||||
name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: 'yarn'
|
||||
-
|
||||
name: Install
|
||||
@@ -75,34 +96,76 @@ jobs:
|
||||
test: ${{ fromJson(needs.prepare-itg.outputs.matrix) }}
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
#- macos-14 # no virt: https://github.com/docker/actions-toolkit/issues/317
|
||||
- macos-13
|
||||
- macos-12
|
||||
- windows-latest
|
||||
exclude:
|
||||
- os: macos-latest
|
||||
test: buildx/bake.test.itg.ts
|
||||
- os: windows-latest
|
||||
test: buildx/bake.test.itg.ts
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Expose GitHub Runtime
|
||||
uses: crazy-max/ghaction-github-runtime@v3
|
||||
-
|
||||
# FIXME: Needs to setup node twice on Windows due to a bug with runner
|
||||
name: Setup Node
|
||||
if: startsWith(matrix.os, 'windows')
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
-
|
||||
name: Enable corepack
|
||||
run: |
|
||||
corepack enable
|
||||
yarn --version
|
||||
-
|
||||
name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: 'yarn'
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
if: startsWith(matrix.os, 'ubuntu')
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.BUILDX_VERSION }}
|
||||
driver: docker
|
||||
-
|
||||
name: Set up container builder
|
||||
if: startsWith(matrix.os, 'ubuntu')
|
||||
id: builder
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.BUILDKIT_IMAGE }}
|
||||
use: false
|
||||
-
|
||||
name: Install
|
||||
run: yarn install
|
||||
-
|
||||
name: Test
|
||||
run: yarn test:itg-coverage --runTestsByPath __tests__/${{ matrix.test }} --coverageDirectory=./coverage
|
||||
run: |
|
||||
yarn test:itg-coverage --runTestsByPath __tests__/${{ matrix.test }} --coverageDirectory=./coverage
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CTN_BUILDER_NAME: ${{ steps.builder.outputs.name }}
|
||||
TEST_FOR_SUMMARY: ${{ secrets.TEST_FOR_SUMMARY }}
|
||||
-
|
||||
name: Check coverage
|
||||
run: |
|
||||
if [ -f ./coverage/clover.xml ] && [ ! -f ./coverage/allSkipped.txt ]; then
|
||||
echo "RUN_CODECOV=true" >> $GITHUB_ENV
|
||||
else
|
||||
echo "RUN_CODECOV=false" >> $GITHUB_ENV
|
||||
fi
|
||||
shell: bash
|
||||
-
|
||||
name: Upload coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
uses: codecov/codecov-action@v4
|
||||
if: env.RUN_CODECOV == 'true'
|
||||
with:
|
||||
file: ./coverage/clover.xml
|
||||
flags: itg
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
6
.github/workflows/validate.yml
vendored
6
.github/workflows/validate.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Matrix
|
||||
id: targets
|
||||
@@ -39,9 +39,9 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Validate
|
||||
uses: docker/bake-action@v3
|
||||
uses: docker/bake-action@v5
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
3
.github/workflows/virtual-env.yml
vendored
3
.github/workflows/virtual-env.yml
vendored
@@ -21,6 +21,7 @@ jobs:
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- ubuntu-24.04
|
||||
- ubuntu-22.04
|
||||
- ubuntu-20.04
|
||||
steps:
|
||||
@@ -42,7 +43,7 @@ jobs:
|
||||
-
|
||||
name: Docker daemon conf
|
||||
run: |
|
||||
cat /etc/docker/daemon.json
|
||||
cat /etc/docker/daemon.json || true
|
||||
-
|
||||
name: Docker info
|
||||
run: docker info
|
||||
|
||||
222
.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
vendored
222
.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
vendored
File diff suppressed because one or more lines are too long
823
.yarn/releases/yarn-3.3.1.cjs
vendored
823
.yarn/releases/yarn-3.3.1.cjs
vendored
File diff suppressed because one or more lines are too long
13
.yarnrc.yml
13
.yarnrc.yml
@@ -1,16 +1,15 @@
|
||||
nodeLinker: node-modules
|
||||
|
||||
npmAuthToken: "${NODE_AUTH_TOKEN:-fallback}"
|
||||
|
||||
logFilters:
|
||||
# https://yarnpkg.com/advanced/error-codes
|
||||
- code: YN0013
|
||||
level: discard
|
||||
- code: YN0019
|
||||
level: discard
|
||||
- code: YN0076
|
||||
level: discard
|
||||
|
||||
nodeLinker: node-modules
|
||||
|
||||
npmAuthToken: "${NODE_AUTH_TOKEN:-fallback}"
|
||||
|
||||
plugins:
|
||||
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
|
||||
spec: "@yarnpkg/plugin-interactive-tools"
|
||||
|
||||
yarnPath: .yarn/releases/yarn-3.3.1.cjs
|
||||
|
||||
@@ -22,7 +22,8 @@ export const context = {
|
||||
repo: 'actions-toolkit'
|
||||
},
|
||||
ref: 'refs/heads/master',
|
||||
runId: 123,
|
||||
runId: 2188748038,
|
||||
runNumber: 15,
|
||||
payload: {
|
||||
after: '860c1904a1ce19322e91ac35af1ab07466440c37',
|
||||
base_ref: null,
|
||||
|
||||
@@ -14,16 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {beforeEach, describe, expect, it, jest, test} from '@jest/globals';
|
||||
import {describe, expect, it, jest, test} from '@jest/globals';
|
||||
|
||||
import {BuildKit} from '../../src/buildkit/buildkit';
|
||||
import {Builder} from '../../src/buildx/builder';
|
||||
|
||||
import {BuilderInfo} from '../../src/types/builder';
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
import {BuilderInfo} from '../../src/types/buildx/builder';
|
||||
|
||||
jest.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise<BuilderInfo> => {
|
||||
return {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {describe, expect, jest, test, beforeEach, afterEach} from '@jest/globals';
|
||||
import {describe, expect, jest, test, afterEach} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as rimraf from 'rimraf';
|
||||
@@ -38,10 +38,6 @@ jest.spyOn(Context, 'tmpName').mockImplementation((): string => {
|
||||
return tmpName;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
rimraf.sync(tmpDir);
|
||||
});
|
||||
|
||||
344
__tests__/buildkit/git.test.ts
Normal file
344
__tests__/buildkit/git.test.ts
Normal file
@@ -0,0 +1,344 @@
|
||||
/**
|
||||
* Copyright 2024 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, jest, test} from '@jest/globals';
|
||||
|
||||
import {Git} from '../../src/buildkit/git';
|
||||
|
||||
import {GitRef, GitURL} from '../../src/types/buildkit/git';
|
||||
|
||||
beforeEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('parseURL', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
'http://github.com/moby/buildkit',
|
||||
{
|
||||
scheme: 'http',
|
||||
host: 'github.com',
|
||||
path: '/moby/buildkit'
|
||||
} as GitURL,
|
||||
false
|
||||
],
|
||||
[
|
||||
'https://github.com/moby/buildkit',
|
||||
{
|
||||
scheme: 'https',
|
||||
host: 'github.com',
|
||||
path: '/moby/buildkit'
|
||||
} as GitURL,
|
||||
false
|
||||
],
|
||||
[
|
||||
'http://github.com/moby/buildkit#v1.0.0',
|
||||
{
|
||||
scheme: 'http',
|
||||
host: 'github.com',
|
||||
path: '/moby/buildkit',
|
||||
fragment: {
|
||||
ref: 'v1.0.0',
|
||||
}
|
||||
} as GitURL,
|
||||
false
|
||||
],
|
||||
[
|
||||
'http://github.com/moby/buildkit#v1.0.0:subdir',
|
||||
{
|
||||
scheme: 'http',
|
||||
host: 'github.com',
|
||||
path: '/moby/buildkit',
|
||||
fragment: {
|
||||
ref: 'v1.0.0',
|
||||
subdir: 'subdir'
|
||||
}
|
||||
} as GitURL,
|
||||
false
|
||||
],
|
||||
[
|
||||
'http://foo:bar@github.com/moby/buildkit#v1.0.0',
|
||||
{
|
||||
scheme: 'http',
|
||||
host: 'github.com',
|
||||
path: '/moby/buildkit',
|
||||
fragment: {
|
||||
ref: 'v1.0.0',
|
||||
},
|
||||
user: {
|
||||
username: 'foo',
|
||||
password: 'bar',
|
||||
passwordSet: true
|
||||
}
|
||||
} as GitURL,
|
||||
false
|
||||
],
|
||||
[
|
||||
'ssh://git@github.com/moby/buildkit.git',
|
||||
{
|
||||
scheme: 'ssh',
|
||||
host: 'github.com',
|
||||
path: '/moby/buildkit.git',
|
||||
user: {
|
||||
username: 'git',
|
||||
password: '',
|
||||
passwordSet: false
|
||||
}
|
||||
} as GitURL,
|
||||
false
|
||||
],
|
||||
[
|
||||
'ssh://git@github.com:22/moby/buildkit.git',
|
||||
{
|
||||
scheme: 'ssh',
|
||||
host: 'github.com:22',
|
||||
path: '/moby/buildkit.git',
|
||||
user: {
|
||||
username: 'git',
|
||||
password: '',
|
||||
passwordSet: false
|
||||
}
|
||||
} as GitURL,
|
||||
false
|
||||
],
|
||||
// TODO: handle SCP-style URLs
|
||||
// [
|
||||
// 'git@github.com:moby/buildkit.git',
|
||||
// {
|
||||
// scheme: 'ssh',
|
||||
// host: 'github.com:22',
|
||||
// path: 'moby/buildkit.git',
|
||||
// user: {
|
||||
// username: 'git',
|
||||
// password: '',
|
||||
// passwordSet: false
|
||||
// }
|
||||
// } as GitURL,
|
||||
// false
|
||||
// ],
|
||||
[
|
||||
'ssh://root@subdomain.example.hostname:2222/root/my/really/weird/path/foo.git',
|
||||
{
|
||||
scheme: 'ssh',
|
||||
host: 'subdomain.example.hostname:2222',
|
||||
path: '/root/my/really/weird/path/foo.git',
|
||||
user: {
|
||||
username: 'root',
|
||||
password: '',
|
||||
passwordSet: false
|
||||
}
|
||||
} as GitURL,
|
||||
false
|
||||
],
|
||||
[
|
||||
'git://host.xz:1234/path/to/repo.git',
|
||||
{
|
||||
scheme: 'git',
|
||||
host: 'host.xz:1234',
|
||||
path: '/path/to/repo.git',
|
||||
} as GitURL,
|
||||
false
|
||||
],
|
||||
[
|
||||
'ssh://someuser@192.168.0.123:456/~/repo-in-my-home-dir.git',
|
||||
{
|
||||
scheme: 'ssh',
|
||||
host: '192.168.0.123:456',
|
||||
path: '/~/repo-in-my-home-dir.git',
|
||||
user: {
|
||||
username: 'someuser',
|
||||
password: '',
|
||||
passwordSet: false
|
||||
}
|
||||
} as GitURL,
|
||||
false
|
||||
],
|
||||
[
|
||||
'httpx://github.com/moby/buildkit',
|
||||
{} as GitURL,
|
||||
true
|
||||
],
|
||||
[
|
||||
'HTTP://github.com/moby/buildkit',
|
||||
{
|
||||
scheme: 'http',
|
||||
host: 'github.com',
|
||||
path: '/moby/buildkit'
|
||||
} as GitURL,
|
||||
false
|
||||
],
|
||||
])('given %p', async (ref: string, expected: GitURL, expectedErr: boolean) => {
|
||||
try {
|
||||
const got = Git.parseURL(ref);
|
||||
expect(got.scheme).toEqual(expected.scheme);
|
||||
expect(got.host).toEqual(expected.host);
|
||||
expect(got.path).toEqual(expected.path);
|
||||
expect(got.fragment).toEqual(expected.fragment);
|
||||
expect(got.user?.username).toEqual(expected.user?.username);
|
||||
expect(got.user?.password).toEqual(expected.user?.password);
|
||||
expect(got.user?.passwordSet).toEqual(expected.user?.passwordSet);
|
||||
} catch (err) {
|
||||
if (!expectedErr) {
|
||||
console.log(err);
|
||||
}
|
||||
// eslint-disable-next-line jest/no-conditional-expect
|
||||
expect(expectedErr).toBeTruthy();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseRef', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
'https://example.com/',
|
||||
undefined
|
||||
],
|
||||
[
|
||||
'https://example.com/foo',
|
||||
undefined
|
||||
],
|
||||
[
|
||||
'https://example.com/foo.git',
|
||||
{
|
||||
remote: 'https://example.com/foo.git',
|
||||
shortName: 'foo'
|
||||
} as GitRef
|
||||
],
|
||||
[
|
||||
'https://example.com/foo.git#deadbeef',
|
||||
{
|
||||
remote: 'https://example.com/foo.git',
|
||||
shortName: 'foo',
|
||||
commit: 'deadbeef'
|
||||
} as GitRef
|
||||
],
|
||||
[
|
||||
'https://example.com/foo.git#release/1.2',
|
||||
{
|
||||
remote: 'https://example.com/foo.git',
|
||||
shortName: 'foo',
|
||||
commit: 'release/1.2'
|
||||
} as GitRef
|
||||
],
|
||||
[
|
||||
'https://example.com/foo.git/',
|
||||
undefined
|
||||
],
|
||||
[
|
||||
'https://example.com/foo.git.bar',
|
||||
undefined
|
||||
],
|
||||
[
|
||||
'git://example.com/foo',
|
||||
{
|
||||
remote: 'git://example.com/foo',
|
||||
shortName: 'foo',
|
||||
unencryptedTCP: true
|
||||
} as GitRef
|
||||
],
|
||||
[
|
||||
'github.com/moby/buildkit',
|
||||
{
|
||||
remote: 'github.com/moby/buildkit',
|
||||
shortName: 'buildkit',
|
||||
indistinguishableFromLocal: true
|
||||
} as GitRef
|
||||
],
|
||||
[
|
||||
'custom.xyz/moby/buildkit.git',
|
||||
undefined
|
||||
],
|
||||
[
|
||||
'https://github.com/moby/buildkit',
|
||||
undefined
|
||||
],
|
||||
[
|
||||
'https://github.com/moby/buildkit.git',
|
||||
{
|
||||
remote: 'https://github.com/moby/buildkit.git',
|
||||
shortName: 'buildkit',
|
||||
} as GitRef
|
||||
],
|
||||
[
|
||||
'https://foo:bar@github.com/moby/buildkit.git',
|
||||
{
|
||||
remote: 'https://foo:bar@github.com/moby/buildkit.git',
|
||||
shortName: 'buildkit',
|
||||
} as GitRef
|
||||
],
|
||||
// TODO handle SCP-style URLs
|
||||
// [
|
||||
// 'git@github.com:moby/buildkit',
|
||||
// {
|
||||
// remote: 'git@github.com:moby/buildkit',
|
||||
// shortName: 'buildkit',
|
||||
// } as GitRef
|
||||
// ],
|
||||
// [
|
||||
// 'git@github.com:moby/buildkit.git',
|
||||
// {
|
||||
// remote: 'git@github.com:moby/buildkit',
|
||||
// shortName: 'buildkit',
|
||||
// } as GitRef
|
||||
// ],
|
||||
// [
|
||||
// 'git@bitbucket.org:atlassianlabs/atlassian-docker.git',
|
||||
// {
|
||||
// remote: 'git@bitbucket.org:atlassianlabs/atlassian-docker.git',
|
||||
// shortName: 'atlassian-docker',
|
||||
// } as GitRef
|
||||
// ],
|
||||
[
|
||||
'https://github.com/foo/bar.git#baz/qux:quux/quuz',
|
||||
{
|
||||
remote: 'https://github.com/foo/bar.git',
|
||||
shortName: 'bar',
|
||||
commit: 'baz/qux',
|
||||
subDir: 'quux/quuz',
|
||||
} as GitRef
|
||||
],
|
||||
[
|
||||
'https://github.com/docker/docker.git#:myfolder',
|
||||
{
|
||||
remote: 'https://github.com/docker/docker.git',
|
||||
shortName: 'docker',
|
||||
subDir: 'myfolder',
|
||||
commit: ''
|
||||
} as GitRef
|
||||
],
|
||||
[
|
||||
'./.git',
|
||||
undefined
|
||||
],
|
||||
[
|
||||
'.git',
|
||||
undefined
|
||||
],
|
||||
])('given %p', async (ref: string, expected: GitRef | undefined) => {
|
||||
try {
|
||||
const got = Git.parseRef(ref);
|
||||
expect(got).toEqual(expected);
|
||||
} catch (err) {
|
||||
if (expected) {
|
||||
console.log(err);
|
||||
}
|
||||
// eslint-disable-next-line jest/no-conditional-expect
|
||||
expect(expected).toBeUndefined();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -14,30 +14,45 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {beforeEach, describe, expect, jest, test} from '@jest/globals';
|
||||
import {describe, expect, test} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import {Bake} from '../../src/buildx/bake';
|
||||
import {BakeDefinition} from '../../src/types/bake';
|
||||
import {BakeDefinition} from '../../src/types/buildx/bake';
|
||||
|
||||
const fixturesDir = path.join(__dirname, '..', 'fixtures');
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
const maybe = !process.env.GITHUB_ACTIONS || (process.env.GITHUB_ACTIONS === 'true' && process.env.ImageOS && process.env.ImageOS.startsWith('ubuntu')) ? describe : describe.skip;
|
||||
|
||||
describe('parseDefinitions', () => {
|
||||
maybe('getDefinition', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
['https://github.com/docker/buildx.git#v0.10.4'],
|
||||
'https://github.com/docker/buildx.git#v0.10.4',
|
||||
['binaries-cross'],
|
||||
path.join(fixturesDir, 'bake-buildx-0.10.4-binaries-cross.json')
|
||||
]
|
||||
])('given %p', async (sources: string[], targets: string[], out: string) => {
|
||||
path.join(fixturesDir, 'bake-buildx-0.10.4-binaries-cross.json'),
|
||||
false,
|
||||
],
|
||||
// TODO: uncomment this test case when we have access to the private repo using an access token
|
||||
// [
|
||||
// 'https://github.com/docker/test-docker-action.git#remote-private',
|
||||
// ['default'],
|
||||
// path.join(fixturesDir, 'bake-test-docker-action-remote-private.json'),
|
||||
// true,
|
||||
// ]
|
||||
])('given %p', async (source: string, targets: string[], out: string, auth) => {
|
||||
const gitAuthToken = process.env.GITHUB_TOKEN || '';
|
||||
if (auth && !gitAuthToken) {
|
||||
console.log(`Git auth token not available, skipping test`);
|
||||
return;
|
||||
}
|
||||
const bake = new Bake();
|
||||
const expectedDef = <BakeDefinition>JSON.parse(fs.readFileSync(out, {encoding: 'utf-8'}).trim())
|
||||
expect(await bake.parseDefinitions(sources, targets)).toEqual(expectedDef);
|
||||
expect(await bake.getDefinition({
|
||||
source: source,
|
||||
targets: targets,
|
||||
githubToken: gitAuthToken,
|
||||
})).toEqual(expectedDef);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,44 +14,94 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {beforeEach, describe, expect, jest, test} from '@jest/globals';
|
||||
import {afterEach, describe, expect, it, jest, test} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as rimraf from 'rimraf';
|
||||
|
||||
import {Bake} from '../../src/buildx/bake';
|
||||
import {BakeDefinition} from '../../src/types/bake';
|
||||
import {Context} from '../../src/context';
|
||||
|
||||
import {ExecOptions} from '@actions/exec';
|
||||
import {BakeDefinition} from '../../src/types/buildx/bake';
|
||||
import {BuildMetadata} from '../../src/types/buildx/build';
|
||||
|
||||
const fixturesDir = path.join(__dirname, '..', 'fixtures');
|
||||
// prettier-ignore
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-inputs-jest');
|
||||
const tmpName = path.join(tmpDir, '.tmpname-jest');
|
||||
const metadata: BuildMetadata = {
|
||||
app: {
|
||||
'buildx.build.ref': 'default/default/7frbdw1fmfozgtqavghowsepk'
|
||||
},
|
||||
db: {
|
||||
'buildx.build.ref': 'default/default/onic7g2axylf56rxetob7qruy'
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.spyOn(Context, 'tmpDir').mockImplementation((): string => {
|
||||
if (!fs.existsSync(tmpDir)) {
|
||||
fs.mkdirSync(tmpDir, {recursive: true});
|
||||
}
|
||||
return tmpDir;
|
||||
});
|
||||
|
||||
describe('parseDefinitions', () => {
|
||||
jest.spyOn(Context, 'tmpName').mockImplementation((): string => {
|
||||
return tmpName;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
rimraf.sync(tmpDir);
|
||||
});
|
||||
|
||||
describe('resolveMetadata', () => {
|
||||
it('matches', async () => {
|
||||
const bake = new Bake();
|
||||
fs.writeFileSync(bake.getMetadataFilePath(), JSON.stringify(metadata));
|
||||
expect(bake.resolveMetadata()).toEqual(metadata as BuildMetadata);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRefs', () => {
|
||||
it('matches', async () => {
|
||||
const bake = new Bake();
|
||||
fs.writeFileSync(bake.getMetadataFilePath(), JSON.stringify(metadata));
|
||||
expect(bake.resolveRefs()).toEqual(['default/default/7frbdw1fmfozgtqavghowsepk', 'default/default/onic7g2axylf56rxetob7qruy']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDefinition', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
[path.join(fixturesDir, 'bake-01.hcl')],
|
||||
['validate'],
|
||||
[],
|
||||
{silent: true},
|
||||
path.join(fixturesDir, 'bake-01-validate.json')
|
||||
],
|
||||
[
|
||||
[path.join(fixturesDir, 'bake-02.hcl')],
|
||||
['build'],
|
||||
[],
|
||||
undefined,
|
||||
path.join(fixturesDir, 'bake-02-build.json')
|
||||
],
|
||||
[
|
||||
[path.join(fixturesDir, 'bake-01.hcl')],
|
||||
['image'],
|
||||
['*.output=type=docker', '*.platform=linux/amd64'],
|
||||
undefined,
|
||||
path.join(fixturesDir, 'bake-01-overrides.json')
|
||||
]
|
||||
])('given %p', async (sources: string[], targets: string[], overrides: string[], out: string) => {
|
||||
])('given %p', async (files: string[], targets: string[], overrides: string[], execOptions: ExecOptions | undefined, out: string) => {
|
||||
const bake = new Bake();
|
||||
const expectedDef = <BakeDefinition>JSON.parse(fs.readFileSync(out, {encoding: 'utf-8'}).trim())
|
||||
expect(await bake.parseDefinitions(sources, targets, overrides)).toEqual(expectedDef);
|
||||
expect(await bake.getDefinition({
|
||||
files: files,
|
||||
targets: targets,
|
||||
overrides: overrides
|
||||
}, execOptions)).toEqual(expectedDef);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -20,16 +20,13 @@ import * as path from 'path';
|
||||
import * as rimraf from 'rimraf';
|
||||
|
||||
import {Context} from '../../src/context';
|
||||
import {Inputs} from '../../src/buildx/inputs';
|
||||
import {Build} from '../../src/buildx/build';
|
||||
|
||||
const fixturesDir = path.join(__dirname, '..', 'fixtures');
|
||||
// prettier-ignore
|
||||
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"
|
||||
}`;
|
||||
const metadata = JSON.parse(fs.readFileSync(path.join(fixturesDir, 'metadata.json'), 'utf-8'));
|
||||
|
||||
jest.spyOn(Context, 'tmpDir').mockImplementation((): string => {
|
||||
if (!fs.existsSync(tmpDir)) {
|
||||
@@ -42,39 +39,62 @@ jest.spyOn(Context, 'tmpName').mockImplementation((): string => {
|
||||
return tmpName;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
rimraf.sync(tmpDir);
|
||||
});
|
||||
|
||||
describe('resolveBuildImageID', () => {
|
||||
describe('resolveImageID', () => {
|
||||
it('matches', async () => {
|
||||
const imageID = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9';
|
||||
const imageIDFile = Inputs.getBuildImageIDFilePath();
|
||||
await fs.writeFileSync(imageIDFile, imageID);
|
||||
const expected = Inputs.resolveBuildImageID();
|
||||
expect(expected).toEqual(imageID);
|
||||
const build = new Build();
|
||||
fs.writeFileSync(build.getImageIDFilePath(), imageID);
|
||||
expect(build.resolveImageID()).toEqual(imageID);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveBuildMetadata', () => {
|
||||
describe('resolveMetadata', () => {
|
||||
it('matches', async () => {
|
||||
const metadataFile = Inputs.getBuildMetadataFilePath();
|
||||
await fs.writeFileSync(metadataFile, metadata);
|
||||
const expected = Inputs.resolveBuildMetadata();
|
||||
expect(expected).toEqual(metadata);
|
||||
const build = new Build();
|
||||
fs.writeFileSync(build.getMetadataFilePath(), JSON.stringify(metadata));
|
||||
expect(build.resolveMetadata()).toEqual(metadata);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRef', () => {
|
||||
it('matches', async () => {
|
||||
const build = new Build();
|
||||
fs.writeFileSync(build.getMetadataFilePath(), JSON.stringify(metadata));
|
||||
expect(build.resolveRef()).toEqual('default/default/n6ibcp9b2pw108rrz7ywdznvo');
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveProvenance', () => {
|
||||
it('matches', async () => {
|
||||
const build = new Build();
|
||||
fs.writeFileSync(build.getMetadataFilePath(), JSON.stringify(metadata));
|
||||
const provenance = build.resolveProvenance();
|
||||
expect(provenance).toBeDefined();
|
||||
expect(provenance?.buildType).toEqual('https://mobyproject.org/buildkit@v1');
|
||||
expect(provenance?.materials).toBeDefined();
|
||||
expect(provenance?.materials?.length).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveWarnings', () => {
|
||||
it('matches', async () => {
|
||||
const build = new Build();
|
||||
fs.writeFileSync(build.getMetadataFilePath(), JSON.stringify(metadata));
|
||||
const warnings = build.resolveWarnings();
|
||||
expect(warnings).toBeDefined();
|
||||
expect(warnings?.length).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveDigest', () => {
|
||||
it('matches', async () => {
|
||||
const metadataFile = Inputs.getBuildMetadataFilePath();
|
||||
await fs.writeFileSync(metadataFile, metadata);
|
||||
const expected = Inputs.resolveDigest();
|
||||
expect(expected).toEqual('sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c');
|
||||
const build = new Build();
|
||||
fs.writeFileSync(build.getMetadataFilePath(), JSON.stringify(metadata));
|
||||
expect(build.resolveDigest()).toEqual('sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -92,7 +112,7 @@ describe('getProvenanceInput', () => {
|
||||
test.each([
|
||||
[
|
||||
'true',
|
||||
'builder-id=https://github.com/docker/actions-toolkit/actions/runs/123'
|
||||
'builder-id=https://github.com/docker/actions-toolkit/actions/runs/2188748038/attempts/2'
|
||||
],
|
||||
[
|
||||
'false',
|
||||
@@ -100,11 +120,11 @@ describe('getProvenanceInput', () => {
|
||||
],
|
||||
[
|
||||
'mode=min',
|
||||
'mode=min,builder-id=https://github.com/docker/actions-toolkit/actions/runs/123'
|
||||
'mode=min,builder-id=https://github.com/docker/actions-toolkit/actions/runs/2188748038/attempts/2'
|
||||
],
|
||||
[
|
||||
'mode=max',
|
||||
'mode=max,builder-id=https://github.com/docker/actions-toolkit/actions/runs/123'
|
||||
'mode=max,builder-id=https://github.com/docker/actions-toolkit/actions/runs/2188748038/attempts/2'
|
||||
],
|
||||
[
|
||||
'builder-id=foo',
|
||||
@@ -119,8 +139,8 @@ describe('getProvenanceInput', () => {
|
||||
''
|
||||
],
|
||||
])('given input %p', async (input: string, expected: string) => {
|
||||
await setInput('provenance', input);
|
||||
expect(Inputs.getProvenanceInput('provenance')).toEqual(expected);
|
||||
setInput('provenance', input);
|
||||
expect(Build.getProvenanceInput('provenance')).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -129,11 +149,11 @@ describe('resolveProvenanceAttrs', () => {
|
||||
test.each([
|
||||
[
|
||||
'mode=min',
|
||||
'mode=min,builder-id=https://github.com/docker/actions-toolkit/actions/runs/123'
|
||||
'mode=min,builder-id=https://github.com/docker/actions-toolkit/actions/runs/2188748038/attempts/2'
|
||||
],
|
||||
[
|
||||
'mode=max',
|
||||
'mode=max,builder-id=https://github.com/docker/actions-toolkit/actions/runs/123'
|
||||
'mode=max,builder-id=https://github.com/docker/actions-toolkit/actions/runs/2188748038/attempts/2'
|
||||
],
|
||||
[
|
||||
'builder-id=foo',
|
||||
@@ -145,14 +165,14 @@ describe('resolveProvenanceAttrs', () => {
|
||||
],
|
||||
[
|
||||
'',
|
||||
'builder-id=https://github.com/docker/actions-toolkit/actions/runs/123'
|
||||
'builder-id=https://github.com/docker/actions-toolkit/actions/runs/2188748038/attempts/2'
|
||||
],
|
||||
])('given %p', async (input: string, expected: string) => {
|
||||
expect(Inputs.resolveProvenanceAttrs(input)).toEqual(expected);
|
||||
expect(Build.resolveProvenanceAttrs(input)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveBuildSecret', () => {
|
||||
describe('resolveSecret', () => {
|
||||
test.each([
|
||||
['A_SECRET=abcdef0123456789', false, 'A_SECRET', 'abcdef0123456789', null],
|
||||
['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789', false, 'GIT_AUTH_TOKEN', 'abcdefghijklmno=0123456789', null],
|
||||
@@ -166,9 +186,9 @@ describe('resolveBuildSecret', () => {
|
||||
try {
|
||||
let secret: string;
|
||||
if (file) {
|
||||
secret = Inputs.resolveBuildSecretFile(kvp);
|
||||
secret = Build.resolveSecretFile(kvp);
|
||||
} else {
|
||||
secret = Inputs.resolveBuildSecretString(kvp);
|
||||
secret = Build.resolveSecretString(kvp);
|
||||
}
|
||||
expect(secret).toEqual(`id=${exKey},src=${tmpName}`);
|
||||
expect(fs.readFileSync(tmpName, 'utf-8')).toEqual(exValue);
|
||||
@@ -185,8 +205,8 @@ describe('resolveBuildSecret', () => {
|
||||
['FOO=bar=baz', 'FOO', 'bar=baz', null]
|
||||
])('given %p key and %p env', async (kvp: string, exKey: string, exValue: string, error: Error | null) => {
|
||||
try {
|
||||
const secret = Inputs.resolveBuildSecretEnv(kvp);
|
||||
expect(secret).toEqual(`id=${exKey},env="${exValue}"`);
|
||||
const secret = Build.resolveSecretEnv(kvp);
|
||||
expect(secret).toEqual(`id=${exKey},env=${exValue}`);
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line jest/no-conditional-expect
|
||||
expect(e.message).toEqual(error?.message);
|
||||
@@ -194,6 +214,54 @@ describe('resolveBuildSecret', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveCacheToAttrs', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
'',
|
||||
undefined,
|
||||
''
|
||||
],
|
||||
[
|
||||
'user/app:cache',
|
||||
undefined,
|
||||
'user/app:cache'
|
||||
],
|
||||
[
|
||||
'type=inline',
|
||||
undefined,
|
||||
'type=inline'
|
||||
],
|
||||
[
|
||||
'type=gha',
|
||||
undefined,
|
||||
'type=gha,repository=docker/actions-toolkit',
|
||||
],
|
||||
[
|
||||
'type=gha,mode=max',
|
||||
undefined,
|
||||
'type=gha,mode=max,repository=docker/actions-toolkit',
|
||||
],
|
||||
[
|
||||
'type=gha,mode=max',
|
||||
'abcd1234',
|
||||
'type=gha,mode=max,repository=docker/actions-toolkit,ghtoken=abcd1234',
|
||||
],
|
||||
[
|
||||
'type=gha,repository=foo/bar,mode=max',
|
||||
undefined,
|
||||
'type=gha,repository=foo/bar,mode=max',
|
||||
],
|
||||
[
|
||||
'type=gha,repository=foo/bar,mode=max',
|
||||
'abcd1234',
|
||||
'type=gha,repository=foo/bar,mode=max,ghtoken=abcd1234',
|
||||
],
|
||||
])('given %p', async (input: string, githubToken: string | undefined, expected: string) => {
|
||||
expect(Build.resolveCacheToAttrs(input, githubToken)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasLocalExporter', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
@@ -206,7 +274,7 @@ describe('hasLocalExporter', () => {
|
||||
[['" type= local" , dest=./release-out'], true],
|
||||
[['.'], true]
|
||||
])('given %p returns %p', async (exporters: Array<string>, expected: boolean) => {
|
||||
expect(Inputs.hasLocalExporter(exporters)).toEqual(expected);
|
||||
expect(Build.hasLocalExporter(exporters)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -222,7 +290,7 @@ describe('hasTarExporter', () => {
|
||||
[['" type= local" , dest=./release-out'], false],
|
||||
[['.'], false]
|
||||
])('given %p returns %p', async (exporters: Array<string>, expected: boolean) => {
|
||||
expect(Inputs.hasTarExporter(exporters)).toEqual(expected);
|
||||
expect(Build.hasTarExporter(exporters)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -240,7 +308,42 @@ describe('hasDockerExporter', () => {
|
||||
[['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);
|
||||
expect(Build.hasDockerExporter(exporters, load)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasAttestationType', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
['type=provenance,mode=min', 'provenance', true],
|
||||
['type=sbom,true', 'sbom', true],
|
||||
['type=foo,bar', 'provenance', false],
|
||||
])('given %p for %p returns %p', async (attrs: string, name: string, expected: boolean) => {
|
||||
expect(Build.hasAttestationType(name, attrs)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveAttestationAttrs', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
'type=provenance,mode=min',
|
||||
'type=provenance,mode=min'
|
||||
],
|
||||
[
|
||||
'type=provenance,true',
|
||||
'type=provenance,disabled=false'
|
||||
],
|
||||
[
|
||||
'type=provenance,false',
|
||||
'type=provenance,disabled=true'
|
||||
],
|
||||
[
|
||||
'',
|
||||
''
|
||||
],
|
||||
])('given %p', async (input: string, expected: string) => {
|
||||
expect(Build.resolveAttestationAttrs(input)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -250,7 +353,7 @@ describe('hasGitAuthTokenSecret', () => {
|
||||
[['A_SECRET=abcdef0123456789'], false],
|
||||
[['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789'], true],
|
||||
])('given %p secret', async (kvp: Array<string>, expected: boolean) => {
|
||||
expect(Inputs.hasGitAuthTokenSecret(kvp)).toBe(expected);
|
||||
expect(Build.hasGitAuthTokenSecret(kvp)).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,21 +14,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {beforeEach, describe, expect, it, jest, test} from '@jest/globals';
|
||||
import {describe, expect, it, jest, test} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import {Builder} from '../../src/buildx/builder';
|
||||
import {Exec} from '../../src/exec';
|
||||
|
||||
import {BuilderInfo} from '../../src/types/builder';
|
||||
import {BuilderInfo} from '../../src/types/buildx/builder';
|
||||
|
||||
const fixturesDir = path.join(__dirname, '..', 'fixtures');
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
jest.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise<BuilderInfo> => {
|
||||
return {
|
||||
name: 'builder2',
|
||||
@@ -210,7 +206,254 @@ describe('parseInspect', () => {
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
'inspect8.txt',
|
||||
{
|
||||
"name": "builder-52aa0611-faf0-42ac-a940-461e4e287d68",
|
||||
"driver": "docker-container",
|
||||
"lastActivity": new Date("2023-06-13T13:52:31.000Z"),
|
||||
"nodes": [
|
||||
{
|
||||
"buildkit": "v0.11.6",
|
||||
"buildkitd-flags": "--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
|
||||
"driver-opts": [
|
||||
"image=moby/buildkit:buildx-stable-1",
|
||||
"network=host",
|
||||
],
|
||||
"endpoint": "unix:///var/run/docker.sock",
|
||||
"name": "builder-52aa0611-faf0-42ac-a940-461e4e287d680",
|
||||
"platforms": "linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/amd64/v4,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6",
|
||||
"status": "running",
|
||||
"labels": {
|
||||
"org.mobyproject.buildkit.worker.executor": "oci",
|
||||
"org.mobyproject.buildkit.worker.hostname": "fv-az572-38",
|
||||
"org.mobyproject.buildkit.worker.network": "host",
|
||||
"org.mobyproject.buildkit.worker.oci.process-mode": "sandbox",
|
||||
"org.mobyproject.buildkit.worker.selinux.enabled": "false",
|
||||
"org.mobyproject.buildkit.worker.snapshotter": "overlayfs",
|
||||
},
|
||||
"gcPolicy": [
|
||||
{
|
||||
"all": false,
|
||||
"filter": [
|
||||
"type==source.local",
|
||||
"type==exec.cachemount",
|
||||
"type==source.git.checkout"
|
||||
],
|
||||
"keepDuration": "48h0m0s",
|
||||
"keepBytes": "488.3MiB",
|
||||
},
|
||||
{
|
||||
"all": false,
|
||||
"keepDuration": "1440h0m0s",
|
||||
"keepBytes": "8.382GiB",
|
||||
},
|
||||
{
|
||||
"all": false,
|
||||
"keepBytes": "8.382GiB",
|
||||
},
|
||||
{
|
||||
"all": true,
|
||||
"keepBytes": "8.382GiB",
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
[
|
||||
'inspect9.txt',
|
||||
{
|
||||
"name": "default",
|
||||
"driver": "docker",
|
||||
"lastActivity": new Date("2023-06-13T18:13:43.000Z"),
|
||||
"nodes": [
|
||||
{
|
||||
"buildkit": "v0.11.7-0.20230525183624-798ad6b0ce9f",
|
||||
"endpoint": "default",
|
||||
"name": "default",
|
||||
"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",
|
||||
"status": "running",
|
||||
"gcPolicy": [
|
||||
{
|
||||
"all": true,
|
||||
"keepBytes": "100GiB",
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
[
|
||||
'inspect10.txt',
|
||||
{
|
||||
"name": "remote-builder",
|
||||
"driver": "remote",
|
||||
"lastActivity": new Date("2023-04-20T12:47:49.000Z"),
|
||||
"nodes": [
|
||||
{
|
||||
"name": "remote-builder0",
|
||||
"endpoint": "docker-container://buildx_buildkit_dk-remote-builder0",
|
||||
"status": "inactive"
|
||||
},
|
||||
{
|
||||
"name": "aws_graviton2",
|
||||
"endpoint": "tcp://10.0.0.1:1234",
|
||||
"driver-opts": [
|
||||
"cacert=/home/user/.certs/aws_graviton2/ca.pem",
|
||||
"cert=/home/user/.certs/aws_graviton2/cert.pem",
|
||||
"key=/home/user/.certs/aws_graviton2/key.pem"
|
||||
],
|
||||
"status": "running",
|
||||
"buildkit": "v0.11.6",
|
||||
"platforms": "darwin/arm64,linux/arm64,linux/arm/v5,linux/arm/v6,linux/arm/v7,windows/arm64",
|
||||
"labels": {
|
||||
"org.mobyproject.buildkit.worker.executor": "oci",
|
||||
"org.mobyproject.buildkit.worker.hostname": "77ebc22e2d82",
|
||||
"org.mobyproject.buildkit.worker.network": "host",
|
||||
"org.mobyproject.buildkit.worker.oci.process-mode": "sandbox",
|
||||
"org.mobyproject.buildkit.worker.selinux.enabled": "false",
|
||||
"org.mobyproject.buildkit.worker.snapshotter": "overlayfs"
|
||||
},
|
||||
"gcPolicy": [
|
||||
{
|
||||
"all": false,
|
||||
"filter": [
|
||||
"type==source.local",
|
||||
"type==exec.cachemount",
|
||||
"type==source.git.checkout"
|
||||
],
|
||||
"keepDuration": "48h0m0s",
|
||||
"keepBytes": "488.3MiB"
|
||||
},
|
||||
{
|
||||
"all": false,
|
||||
"keepDuration": "1440h0m0s",
|
||||
"keepBytes": "23.28GiB"
|
||||
},
|
||||
{
|
||||
"all": false,
|
||||
"keepBytes": "23.28GiB"
|
||||
},
|
||||
{
|
||||
"all": true,
|
||||
"keepBytes": "23.28GiB"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "linuxone_s390x",
|
||||
"endpoint": "tcp://10.0.0.2:1234",
|
||||
"driver-opts": [
|
||||
"cacert=/home/user/.certs/linuxone_s390x/ca.pem",
|
||||
"cert=/home/user/.certs/linuxone_s390x/cert.pem",
|
||||
"key=/home/user/.certs/linuxone_s390x/key.pem"
|
||||
],
|
||||
"status": "running",
|
||||
"buildkit": "v0.11.6",
|
||||
"platforms": "linux/s390x",
|
||||
"labels": {
|
||||
"org.mobyproject.buildkit.worker.executor": "oci",
|
||||
"org.mobyproject.buildkit.worker.hostname": "9d0d62a96818",
|
||||
"org.mobyproject.buildkit.worker.network": "host",
|
||||
"org.mobyproject.buildkit.worker.oci.process-mode": "sandbox",
|
||||
"org.mobyproject.buildkit.worker.selinux.enabled": "false",
|
||||
"org.mobyproject.buildkit.worker.snapshotter": "overlayfs"
|
||||
},
|
||||
"gcPolicy": [
|
||||
{
|
||||
"all": false,
|
||||
"keepBytes": "488.3MiB",
|
||||
"filter": [
|
||||
"type==source.local",
|
||||
"type==exec.cachemount",
|
||||
"type==source.git.checkout"
|
||||
],
|
||||
"keepDuration": "48h0m0s"
|
||||
},
|
||||
{
|
||||
"all": false,
|
||||
"keepDuration": "1440h0m0s",
|
||||
"keepBytes": "9.313GiB"
|
||||
},
|
||||
{
|
||||
"all": false,
|
||||
"keepBytes": "9.313GiB"
|
||||
},
|
||||
{
|
||||
"all": true,
|
||||
"keepBytes": "9.313GiB"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
}
|
||||
],
|
||||
[
|
||||
'inspect11.txt',
|
||||
{
|
||||
"name": "builder",
|
||||
"driver": "docker-container",
|
||||
"lastActivity": new Date("2024-03-01T14:25:03.000Z"),
|
||||
"nodes": [
|
||||
{
|
||||
"buildkit": "37657a1",
|
||||
"buildkitd-flags": "--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host --allow-insecure-entitlement=network.host",
|
||||
"driver-opts": [
|
||||
"env.JAEGER_TRACE=localhost:6831",
|
||||
"image=moby/buildkit:master",
|
||||
"network=host",
|
||||
"env.BUILDKIT_STEP_LOG_MAX_SIZE=10485760",
|
||||
"env.BUILDKIT_STEP_LOG_MAX_SPEED=10485760",
|
||||
],
|
||||
"endpoint": "unix:///var/run/docker.sock",
|
||||
"name": "builder0",
|
||||
"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",
|
||||
"status": "running",
|
||||
"features": {
|
||||
"Cache export": true,
|
||||
"Docker exporter": true,
|
||||
"Multi-platform build": true,
|
||||
"OCI exporter": true,
|
||||
},
|
||||
"labels": {
|
||||
"org.mobyproject.buildkit.worker.executor": "oci",
|
||||
"org.mobyproject.buildkit.worker.hostname": "docker-desktop",
|
||||
"org.mobyproject.buildkit.worker.network": "host",
|
||||
"org.mobyproject.buildkit.worker.oci.process-mode": "sandbox",
|
||||
"org.mobyproject.buildkit.worker.selinux.enabled": "false",
|
||||
"org.mobyproject.buildkit.worker.snapshotter": "overlayfs",
|
||||
},
|
||||
"gcPolicy": [
|
||||
{
|
||||
"all": false,
|
||||
"filter": [
|
||||
"type==source.local",
|
||||
"type==exec.cachemount",
|
||||
"type==source.git.checkout"
|
||||
],
|
||||
"keepDuration": "48h0m0s",
|
||||
"keepBytes": "488.3MiB",
|
||||
},
|
||||
{
|
||||
"all": false,
|
||||
"keepDuration": "1440h0m0s",
|
||||
"keepBytes": "94.06GiB",
|
||||
},
|
||||
{
|
||||
"all": false,
|
||||
"keepBytes": "94.06GiB",
|
||||
},
|
||||
{
|
||||
"all": true,
|
||||
"keepBytes": "94.06GiB",
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
])('given %p', async (inspectFile, expected) => {
|
||||
expect(await Builder.parseInspect(fs.readFileSync(path.join(fixturesDir, inspectFile)).toString())).toEqual(expected);
|
||||
});
|
||||
|
||||
@@ -24,8 +24,9 @@ import {Buildx} from '../../src/buildx/buildx';
|
||||
import {Context} from '../../src/context';
|
||||
import {Exec} from '../../src/exec';
|
||||
|
||||
import {Cert} from '../../src/types/buildx';
|
||||
import {Cert, LocalState} from '../../src/types/buildx/buildx';
|
||||
|
||||
const fixturesDir = path.join(__dirname, '..', 'fixtures');
|
||||
// prettier-ignore
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-jest');
|
||||
const tmpName = path.join(tmpDir, '.tmpname-jest');
|
||||
@@ -41,10 +42,6 @@ jest.spyOn(Context, 'tmpName').mockImplementation((): string => {
|
||||
return tmpName;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
rimraf.sync(tmpDir);
|
||||
});
|
||||
@@ -116,21 +113,6 @@ describe('isAvailable', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('printInspect', () => {
|
||||
it('prints builder2 instance', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'exec');
|
||||
const buildx = new Buildx({
|
||||
standalone: true
|
||||
});
|
||||
await buildx.printInspect('builder2').catch(() => {
|
||||
// noop
|
||||
});
|
||||
expect(execSpy).toHaveBeenCalledWith(`buildx`, ['inspect', 'builder2'], {
|
||||
failOnStdErr: false
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('printVersion', () => {
|
||||
it('docker cli', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'exec');
|
||||
@@ -267,3 +249,96 @@ 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/dfsz8r57a98zf789pmlyzqp3n',
|
||||
{
|
||||
LocalPath: 'https://github.com/docker/actions-toolkit.git#:__tests__/fixtures',
|
||||
DockerfilePath: 'hello.Dockerfile'
|
||||
} as LocalState,
|
||||
],
|
||||
[
|
||||
'default/default/w38vcd5fo5cfvfyig77qjec0v',
|
||||
{
|
||||
LocalPath: '/home/crazy/hello',
|
||||
DockerfilePath: '-'
|
||||
} as LocalState,
|
||||
]
|
||||
])('given %p', async (ref: string, expected: LocalState) => {
|
||||
const localState = Buildx.localState(ref, path.join(fixturesDir, 'buildx-refs'));
|
||||
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(17);
|
||||
});
|
||||
it('returns default builder refs', async () => {
|
||||
const refs = Buildx.refs({
|
||||
dir: path.join(fixturesDir, 'buildx-refs'),
|
||||
builderName: 'default'
|
||||
});
|
||||
expect(Object.keys(refs).length).toEqual(14);
|
||||
});
|
||||
it('returns foo builder refs', async () => {
|
||||
const refs = Buildx.refs({
|
||||
dir: path.join(fixturesDir, 'buildx-refs'),
|
||||
builderName: 'foo'
|
||||
});
|
||||
expect(Object.keys(refs).length).toEqual(3);
|
||||
});
|
||||
it('returns default builder refs since', async () => {
|
||||
const mdate = new Date('2023-09-05T00:00:00Z');
|
||||
fs.utimesSync(path.join(fixturesDir, 'buildx-refs', 'default', 'default', '36dix0eiv9evr61vrwzn32w7q'), mdate, mdate);
|
||||
fs.utimesSync(path.join(fixturesDir, 'buildx-refs', 'default', 'default', '49p5r8und2konke5pmlyzqp3n'), mdate, mdate);
|
||||
fs.utimesSync(path.join(fixturesDir, 'buildx-refs', 'default', 'default', 'a8zqzhhv5yiazm396jobsgdw2'), mdate, mdate);
|
||||
const refs = Buildx.refs({
|
||||
dir: path.join(fixturesDir, 'buildx-refs'),
|
||||
builderName: 'default',
|
||||
since: new Date('2024-01-10T00:00:00Z')
|
||||
});
|
||||
expect(Object.keys(refs).length).toEqual(11);
|
||||
});
|
||||
});
|
||||
|
||||
198
__tests__/buildx/history.test.itg.ts
Normal file
198
__tests__/buildx/history.test.itg.ts
Normal file
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* Copyright 2024 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 {afterEach, beforeEach, describe, expect, it, jest, test} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import {Buildx} from '../../src/buildx/buildx';
|
||||
import {Bake} from '../../src/buildx/bake';
|
||||
import {Build} from '../../src/buildx/build';
|
||||
import {History} from '../../src/buildx/history';
|
||||
import {Exec} from '../../src/exec';
|
||||
|
||||
const fixturesDir = path.join(__dirname, '..', 'fixtures');
|
||||
|
||||
// prettier-ignore
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-history-jest');
|
||||
|
||||
const maybe = !process.env.GITHUB_ACTIONS || (process.env.GITHUB_ACTIONS === 'true' && process.env.ImageOS && process.env.ImageOS.startsWith('ubuntu')) ? describe : describe.skip;
|
||||
|
||||
maybe('exportBuild', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
'single',
|
||||
[
|
||||
'build',
|
||||
'-f', path.join(fixturesDir, 'hello.Dockerfile'),
|
||||
fixturesDir
|
||||
],
|
||||
],
|
||||
[
|
||||
'multi-platform',
|
||||
[
|
||||
'build',
|
||||
'-f', path.join(fixturesDir, 'hello.Dockerfile'),
|
||||
'--platform', 'linux/amd64,linux/arm64',
|
||||
fixturesDir
|
||||
],
|
||||
]
|
||||
])('export build %p', async (_, bargs) => {
|
||||
const buildx = new Buildx();
|
||||
const build = new Build({buildx: buildx});
|
||||
|
||||
fs.mkdirSync(tmpDir, {recursive: true});
|
||||
await expect(
|
||||
(async () => {
|
||||
// prettier-ignore
|
||||
const buildCmd = await buildx.getCommand([
|
||||
'--builder', process.env.CTN_BUILDER_NAME ?? 'default',
|
||||
...bargs,
|
||||
'--metadata-file', build.getMetadataFilePath()
|
||||
]);
|
||||
await Exec.exec(buildCmd.command, buildCmd.args);
|
||||
})()
|
||||
).resolves.not.toThrow();
|
||||
|
||||
const metadata = build.resolveMetadata();
|
||||
expect(metadata).toBeDefined();
|
||||
const buildRef = build.resolveRef(metadata);
|
||||
expect(buildRef).toBeDefined();
|
||||
|
||||
const history = new History({buildx: buildx});
|
||||
const exportRes = await history.export({
|
||||
refs: [buildRef ?? '']
|
||||
});
|
||||
|
||||
expect(exportRes).toBeDefined();
|
||||
expect(exportRes?.dockerbuildFilename).toBeDefined();
|
||||
expect(exportRes?.dockerbuildSize).toBeDefined();
|
||||
expect(fs.existsSync(exportRes?.dockerbuildFilename)).toBe(true);
|
||||
expect(exportRes?.summaries).toBeDefined();
|
||||
});
|
||||
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
'single',
|
||||
[
|
||||
'bake',
|
||||
'-f', path.join(fixturesDir, 'hello-bake.hcl'),
|
||||
'hello'
|
||||
],
|
||||
],
|
||||
[
|
||||
'group',
|
||||
[
|
||||
'bake',
|
||||
'-f', path.join(fixturesDir, 'hello-bake.hcl'),
|
||||
'hello-all'
|
||||
],
|
||||
],
|
||||
[
|
||||
'matrix',
|
||||
[
|
||||
'bake',
|
||||
'-f', path.join(fixturesDir, 'hello-bake.hcl'),
|
||||
'hello-matrix'
|
||||
],
|
||||
]
|
||||
])('export bake build %p', async (_, bargs) => {
|
||||
const buildx = new Buildx();
|
||||
const bake = new Bake({buildx: buildx});
|
||||
|
||||
fs.mkdirSync(tmpDir, {recursive: true});
|
||||
await expect(
|
||||
(async () => {
|
||||
// prettier-ignore
|
||||
const buildCmd = await buildx.getCommand([
|
||||
'--builder', process.env.CTN_BUILDER_NAME ?? 'default',
|
||||
...bargs,
|
||||
'--metadata-file', bake.getMetadataFilePath()
|
||||
]);
|
||||
await Exec.exec(buildCmd.command, buildCmd.args, {
|
||||
cwd: fixturesDir
|
||||
});
|
||||
})()
|
||||
).resolves.not.toThrow();
|
||||
|
||||
const metadata = bake.resolveMetadata();
|
||||
expect(metadata).toBeDefined();
|
||||
const buildRefs = bake.resolveRefs(metadata);
|
||||
expect(buildRefs).toBeDefined();
|
||||
|
||||
const history = new History({buildx: buildx});
|
||||
const exportRes = await history.export({
|
||||
refs: buildRefs ?? []
|
||||
});
|
||||
|
||||
expect(exportRes).toBeDefined();
|
||||
expect(exportRes?.dockerbuildFilename).toBeDefined();
|
||||
expect(exportRes?.dockerbuildSize).toBeDefined();
|
||||
expect(fs.existsSync(exportRes?.dockerbuildFilename)).toBe(true);
|
||||
expect(exportRes?.summaries).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
maybe('exportBuild custom image', () => {
|
||||
const originalEnv = process.env;
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
process.env = {
|
||||
...originalEnv,
|
||||
DOCKER_BUILD_EXPORT_BUILD_IMAGE: 'docker.io/dockereng/export-build:0.2.2'
|
||||
};
|
||||
});
|
||||
afterEach(() => {
|
||||
process.env = originalEnv;
|
||||
});
|
||||
|
||||
it('with custom image', async () => {
|
||||
const buildx = new Buildx();
|
||||
const build = new Build({buildx: buildx});
|
||||
|
||||
fs.mkdirSync(tmpDir, {recursive: true});
|
||||
await expect(
|
||||
(async () => {
|
||||
// prettier-ignore
|
||||
const buildCmd = await buildx.getCommand([
|
||||
'--builder', process.env.CTN_BUILDER_NAME ?? 'default',
|
||||
'build', '-f', path.join(fixturesDir, 'hello.Dockerfile'),
|
||||
'--metadata-file', build.getMetadataFilePath(),
|
||||
fixturesDir
|
||||
]);
|
||||
await Exec.exec(buildCmd.command, buildCmd.args);
|
||||
})()
|
||||
).resolves.not.toThrow();
|
||||
|
||||
const metadata = build.resolveMetadata();
|
||||
expect(metadata).toBeDefined();
|
||||
const buildRef = build.resolveRef(metadata);
|
||||
expect(buildRef).toBeDefined();
|
||||
|
||||
const history = new History({buildx: buildx});
|
||||
const exportRes = await history.export({
|
||||
refs: [buildRef ?? '']
|
||||
});
|
||||
|
||||
expect(exportRes).toBeDefined();
|
||||
expect(exportRes?.dockerbuildFilename).toBeDefined();
|
||||
expect(exportRes?.dockerbuildSize).toBeDefined();
|
||||
expect(fs.existsSync(exportRes?.dockerbuildFilename)).toBe(true);
|
||||
expect(exportRes?.summaries).toBeDefined();
|
||||
});
|
||||
});
|
||||
42
__tests__/buildx/install.test.itg.ts
Normal file
42
__tests__/buildx/install.test.itg.ts
Normal 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 {describe, expect, test} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
|
||||
import {Install} from '../../src/buildx/install';
|
||||
|
||||
const maybe = !process.env.GITHUB_ACTIONS || (process.env.GITHUB_ACTIONS === 'true' && process.env.ImageOS && process.env.ImageOS.startsWith('ubuntu')) ? describe : describe.skip;
|
||||
|
||||
maybe('download', () => {
|
||||
// prettier-ignore
|
||||
test.each(['latest'])(
|
||||
'install docker %s', async (version) => {
|
||||
await expect((async () => {
|
||||
const install = new Install({
|
||||
standalone: true
|
||||
});
|
||||
const toolPath = await install.download(version);
|
||||
if (!fs.existsSync(toolPath)) {
|
||||
throw new Error('toolPath does not exist');
|
||||
}
|
||||
const binPath = await install.installStandalone(toolPath);
|
||||
if (!fs.existsSync(binPath)) {
|
||||
throw new Error('binPath does not exist');
|
||||
}
|
||||
})()).resolves.not.toThrow();
|
||||
}, 60000);
|
||||
});
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {describe, expect, it, jest, test, beforeEach, afterEach} from '@jest/globals';
|
||||
import {describe, expect, it, jest, test, afterEach} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as rimraf from 'rimraf';
|
||||
@@ -25,10 +25,6 @@ import {Install} from '../../src/buildx/install';
|
||||
// prettier-ignore
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-jest');
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
rimraf.sync(tmpDir);
|
||||
});
|
||||
@@ -36,9 +32,8 @@ afterEach(function () {
|
||||
describe('download', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
['v0.9.1', false],
|
||||
['latest', false],
|
||||
['v0.9.1', true],
|
||||
['v0.9.0', false],
|
||||
['v0.10.5', true],
|
||||
['latest', true]
|
||||
])(
|
||||
'acquires %p of buildx (standalone: %p)', async (version, standalone) => {
|
||||
@@ -56,6 +51,29 @@ describe('download', () => {
|
||||
100000
|
||||
);
|
||||
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
// following versions are already cached to htc from previous test cases
|
||||
['v0.9.0'],
|
||||
['v0.10.5'],
|
||||
])(
|
||||
'acquires %p of buildx with cache', async (version) => {
|
||||
const install = new Install({standalone: false});
|
||||
const toolPath = await install.download(version);
|
||||
expect(fs.existsSync(toolPath)).toBe(true);
|
||||
});
|
||||
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
['v0.11.2'],
|
||||
['v0.12.0'],
|
||||
])(
|
||||
'acquires %p of buildx without cache', async (version) => {
|
||||
const install = new Install({standalone: false});
|
||||
const toolPath = await install.download(version, true);
|
||||
expect(fs.existsSync(toolPath)).toBe(true);
|
||||
});
|
||||
|
||||
// TODO: add tests for arm
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
@@ -77,12 +95,6 @@ describe('download', () => {
|
||||
},
|
||||
100000
|
||||
);
|
||||
|
||||
it('returns latest buildx GitHub release', async () => {
|
||||
const release = await Install.getRelease('latest');
|
||||
expect(release).not.toBeNull();
|
||||
expect(release?.tag_name).not.toEqual('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('build', () => {
|
||||
@@ -105,30 +117,72 @@ describe('build', () => {
|
||||
}, 100000);
|
||||
});
|
||||
|
||||
describe('getDownloadVersion', () => {
|
||||
it('returns official latest download version', async () => {
|
||||
const version = await Install.getDownloadVersion('latest');
|
||||
expect(version.key).toEqual('official');
|
||||
expect(version.version).toEqual('latest');
|
||||
expect(version.downloadURL).toEqual('https://github.com/docker/buildx/releases/download/v%s/%s');
|
||||
expect(version.releasesURL).toEqual('https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/buildx-releases.json');
|
||||
});
|
||||
|
||||
it('returns official v0.10.1 download version', async () => {
|
||||
const version = await Install.getDownloadVersion('v0.10.1');
|
||||
expect(version.key).toEqual('official');
|
||||
expect(version.version).toEqual('v0.10.1');
|
||||
expect(version.downloadURL).toEqual('https://github.com/docker/buildx/releases/download/v%s/%s');
|
||||
expect(version.releasesURL).toEqual('https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/buildx-releases.json');
|
||||
});
|
||||
|
||||
it('returns lab latest download version', async () => {
|
||||
const version = await Install.getDownloadVersion('lab:latest');
|
||||
expect(version.key).toEqual('lab');
|
||||
expect(version.version).toEqual('latest');
|
||||
expect(version.downloadURL).toEqual('https://github.com/docker/buildx-desktop/releases/download/v%s/%s');
|
||||
expect(version.releasesURL).toEqual('https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/buildx-lab-releases.json');
|
||||
});
|
||||
|
||||
it('returns lab v0.11.2-desktop.2 download version', async () => {
|
||||
const version = await Install.getDownloadVersion('lab:v0.11.2-desktop.2');
|
||||
expect(version.key).toEqual('lab');
|
||||
expect(version.version).toEqual('v0.11.2-desktop.2');
|
||||
expect(version.downloadURL).toEqual('https://github.com/docker/buildx-desktop/releases/download/v%s/%s');
|
||||
expect(version.releasesURL).toEqual('https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/buildx-lab-releases.json');
|
||||
});
|
||||
|
||||
it('unknown repo', async () => {
|
||||
await expect(Install.getDownloadVersion('foo:bar')).rejects.toThrow(new Error('Cannot find buildx version for foo:bar'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('getRelease', () => {
|
||||
it('returns latest buildx GitHub release', async () => {
|
||||
const release = await Install.getRelease('latest');
|
||||
it('returns latest official GitHub release', async () => {
|
||||
const version = await Install.getDownloadVersion('latest');
|
||||
const release = await Install.getRelease(version);
|
||||
expect(release).not.toBeNull();
|
||||
expect(release?.tag_name).not.toEqual('');
|
||||
});
|
||||
|
||||
it('returns v0.10.1 buildx GitHub release', async () => {
|
||||
const release = await Install.getRelease('v0.10.1');
|
||||
it('returns v0.10.1 official GitHub release', async () => {
|
||||
const version = await Install.getDownloadVersion('v0.10.1');
|
||||
const release = await Install.getRelease(version);
|
||||
expect(release).not.toBeNull();
|
||||
expect(release?.id).toEqual(90346950);
|
||||
expect(release?.tag_name).toEqual('v0.10.1');
|
||||
expect(release?.html_url).toEqual('https://github.com/docker/buildx/releases/tag/v0.10.1');
|
||||
});
|
||||
|
||||
it('returns v0.2.2 buildx GitHub release', async () => {
|
||||
const release = await Install.getRelease('v0.2.2');
|
||||
it('returns v0.11.2-desktop.2 lab GitHub release', async () => {
|
||||
const version = await Install.getDownloadVersion('lab:v0.11.2-desktop.2');
|
||||
const release = await Install.getRelease(version);
|
||||
expect(release).not.toBeNull();
|
||||
expect(release?.id).toEqual(17671545);
|
||||
expect(release?.tag_name).toEqual('v0.2.2');
|
||||
expect(release?.html_url).toEqual('https://github.com/docker/buildx/releases/tag/v0.2.2');
|
||||
expect(release?.id).toEqual(118213369);
|
||||
expect(release?.tag_name).toEqual('v0.11.2-desktop.2');
|
||||
expect(release?.html_url).toEqual('https://github.com/docker/buildx-desktop/releases/tag/v0.11.2-desktop.2');
|
||||
});
|
||||
|
||||
it('unknown release', async () => {
|
||||
await expect(Install.getRelease('foo')).rejects.toThrow(new Error('Cannot find Buildx release foo in https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/buildx-releases.json'));
|
||||
const version = await Install.getDownloadVersion('foo');
|
||||
await expect(Install.getRelease(version)).rejects.toThrow(new Error('Cannot find Buildx release foo in https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/buildx-releases.json'));
|
||||
});
|
||||
});
|
||||
|
||||
40
__tests__/cache.test.itg.ts
Normal file
40
__tests__/cache.test.itg.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright 2024 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 path from 'path';
|
||||
import {describe, expect, it} from '@jest/globals';
|
||||
|
||||
import {Cache} from '../src/cache';
|
||||
|
||||
// prettier-ignore
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'cache-jest');
|
||||
|
||||
const fixturesDir = path.join(__dirname, 'fixtures');
|
||||
|
||||
describe('cache', () => {
|
||||
it('github-repo', async () => {
|
||||
const r = (Math.random() + 1).toString(36).substring(7);
|
||||
const htcName = `cache-test-github-repo-${r}`;
|
||||
const c = new Cache({
|
||||
htcName: htcName,
|
||||
htcVersion: `v1.0.0+${r}`,
|
||||
baseCacheDir: path.join(tmpDir, '.cache-test'),
|
||||
cacheFile: 'github-repo.json'
|
||||
});
|
||||
expect(await c.save(path.join(fixturesDir, 'github-repo.json'))).not.toEqual('');
|
||||
expect(await c.find()).not.toEqual('');
|
||||
});
|
||||
});
|
||||
@@ -17,7 +17,7 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as rimraf from 'rimraf';
|
||||
import {describe, expect, jest, it, beforeEach, afterEach} from '@jest/globals';
|
||||
import {describe, expect, jest, it, afterEach} from '@jest/globals';
|
||||
|
||||
import {Context} from '../src/context';
|
||||
|
||||
@@ -36,10 +36,6 @@ jest.spyOn(Context, 'tmpName').mockImplementation((): string => {
|
||||
return tmpName;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
rimraf.sync(tmpDir);
|
||||
});
|
||||
@@ -55,9 +51,3 @@ describe('gitContext', () => {
|
||||
expect(Context.gitContext()).toEqual('https://github.com/docker/actions-toolkit.git#refs/heads/master');
|
||||
});
|
||||
});
|
||||
|
||||
describe('provenanceBuilderID', () => {
|
||||
it('returns 123', async () => {
|
||||
expect(Context.provenanceBuilderID()).toEqual('https://github.com/docker/actions-toolkit/actions/runs/123');
|
||||
});
|
||||
});
|
||||
|
||||
73
__tests__/docker/docker.test.itg.ts
Normal file
73
__tests__/docker/docker.test.itg.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright 2024 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 {describe, expect, it, test} from '@jest/globals';
|
||||
|
||||
import {Docker} from '../../src/docker/docker';
|
||||
|
||||
const maybe = !process.env.GITHUB_ACTIONS || (process.env.GITHUB_ACTIONS === 'true' && process.env.ImageOS && process.env.ImageOS.startsWith('ubuntu')) ? describe : describe.skip;
|
||||
|
||||
maybe('isDaemonRunning', () => {
|
||||
it('checks if daemon is running', async () => {
|
||||
expect(await Docker.isDaemonRunning()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
maybe('pull', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
'busybox',
|
||||
undefined,
|
||||
],
|
||||
[
|
||||
'busybox:1.36',
|
||||
undefined,
|
||||
],
|
||||
[
|
||||
'busybox@sha256:7ae8447f3a7f5bccaa765926f25fc038e425cf1b2be6748727bbea9a13102094',
|
||||
undefined,
|
||||
],
|
||||
[
|
||||
'doesnotexist:foo',
|
||||
`pull access denied for doesnotexist`,
|
||||
],
|
||||
])('pulling %p', async (image: string, err: string | undefined) => {
|
||||
try {
|
||||
await Docker.pull(image, true);
|
||||
if (err !== undefined) {
|
||||
throw new Error('Expected an error to be thrown');
|
||||
}
|
||||
} catch (e) {
|
||||
if (err === undefined) {
|
||||
throw new Error(`Expected no error, but got: ${e.message}`);
|
||||
}
|
||||
// eslint-disable-next-line jest/no-conditional-expect
|
||||
expect(e.message).toContain(err);
|
||||
}
|
||||
}, 600000);
|
||||
});
|
||||
|
||||
maybe('contextInspect', () => {
|
||||
it('inspect default context', async () => {
|
||||
const contextInfo = await Docker.contextInspect();
|
||||
expect(contextInfo).toBeDefined();
|
||||
console.log('contextInfo', contextInfo);
|
||||
expect(contextInfo?.Name).toBeDefined();
|
||||
expect(contextInfo?.Endpoints).toBeDefined();
|
||||
expect(Object.keys(contextInfo?.Endpoints).length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
@@ -22,19 +22,14 @@ import osm = require('os');
|
||||
import * as rimraf from 'rimraf';
|
||||
|
||||
import {Docker} from '../../src/docker/docker';
|
||||
import {Exec} from '../../src/exec';
|
||||
|
||||
import {ConfigFile} from '../../src/types/docker';
|
||||
import {ConfigFile} from '../../src/types/docker/docker';
|
||||
|
||||
const fixturesDir = path.join(__dirname, '..', 'fixtures');
|
||||
|
||||
// prettier-ignore
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'docker-jest');
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
rimraf.sync(tmpDir);
|
||||
});
|
||||
@@ -109,35 +104,132 @@ describe('isAvailable', () => {
|
||||
});
|
||||
});
|
||||
|
||||
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}}'], {
|
||||
describe('exec', () => {
|
||||
it('returns docker version', async () => {
|
||||
const execSpy = jest.spyOn(Docker, 'exec');
|
||||
await Docker.exec(['version'], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
});
|
||||
expect(execSpy).toHaveBeenCalledTimes(1);
|
||||
const callfunc = execSpy.mock.calls[0];
|
||||
expect(Object.keys(callfunc[1]?.env || {}).length).toBeGreaterThan(0);
|
||||
const env = callfunc[1]?.env;
|
||||
expect(env).toHaveProperty('DOCKER_CONTENT_TRUST');
|
||||
expect(env?.DOCKER_CONTENT_TRUST).toBe('false');
|
||||
if (callfunc[1]?.env) {
|
||||
// already checked env
|
||||
callfunc[1].env = undefined;
|
||||
}
|
||||
expect(callfunc).toEqual([
|
||||
['version'],
|
||||
{
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getExecOutput', () => {
|
||||
it('returns docker version', async () => {
|
||||
const execSpy = jest.spyOn(Docker, 'getExecOutput');
|
||||
await Docker.getExecOutput(['version'], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
});
|
||||
expect(execSpy).toHaveBeenCalledTimes(1);
|
||||
const callfunc = execSpy.mock.calls[0];
|
||||
expect(Object.keys(callfunc[1]?.env || {}).length).toBeGreaterThan(0);
|
||||
const env = callfunc[1]?.env;
|
||||
expect(env).toHaveProperty('DOCKER_CONTENT_TRUST');
|
||||
expect(env?.DOCKER_CONTENT_TRUST).toBe('false');
|
||||
if (callfunc[1]?.env) {
|
||||
// already checked env
|
||||
callfunc[1].env = undefined;
|
||||
}
|
||||
expect(callfunc).toEqual([
|
||||
['version'],
|
||||
{
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('context', () => {
|
||||
it('call docker context show', async () => {
|
||||
const execSpy = jest.spyOn(Docker, 'getExecOutput');
|
||||
await Docker.context().catch(() => {
|
||||
// noop
|
||||
});
|
||||
expect(execSpy).toHaveBeenCalledTimes(1);
|
||||
const callfunc = execSpy.mock.calls[0];
|
||||
if (callfunc && callfunc[1]) {
|
||||
// we don't want to check env opt
|
||||
callfunc[1].env = undefined;
|
||||
}
|
||||
expect(callfunc).toEqual([
|
||||
['context', 'inspect', '--format', '{{.Name}}'],
|
||||
{
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('contextInspect', () => {
|
||||
it('call docker context inspect', async () => {
|
||||
const execSpy = jest.spyOn(Docker, 'getExecOutput');
|
||||
await Docker.contextInspect('foo').catch(() => {
|
||||
// noop
|
||||
});
|
||||
expect(execSpy).toHaveBeenCalledTimes(1);
|
||||
const callfunc = execSpy.mock.calls[0];
|
||||
if (callfunc && callfunc[1]) {
|
||||
// we don't want to check env opt
|
||||
callfunc[1].env = undefined;
|
||||
}
|
||||
expect(callfunc).toEqual([
|
||||
['context', 'inspect', '--format=json', 'foo'],
|
||||
{
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('printVersion', () => {
|
||||
it('call docker version', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'exec');
|
||||
const execSpy = jest.spyOn(Docker, 'exec');
|
||||
await Docker.printVersion().catch(() => {
|
||||
// noop
|
||||
});
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['version']);
|
||||
expect(execSpy).toHaveBeenCalledTimes(1);
|
||||
const callfunc = execSpy.mock.calls[0];
|
||||
if (callfunc && callfunc[1]) {
|
||||
// we don't want to check env opt
|
||||
callfunc[1].env = undefined;
|
||||
}
|
||||
expect(callfunc).toEqual([['version']]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('printInfo', () => {
|
||||
it('call docker info', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'exec');
|
||||
const execSpy = jest.spyOn(Docker, 'exec');
|
||||
await Docker.printInfo().catch(() => {
|
||||
// noop
|
||||
});
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['info']);
|
||||
expect(execSpy).toHaveBeenCalledTimes(1);
|
||||
const callfunc = execSpy.mock.calls[0];
|
||||
if (callfunc && callfunc[1]) {
|
||||
// we don't want to check env opt
|
||||
callfunc[1].env = undefined;
|
||||
}
|
||||
expect(callfunc).toEqual([['info']]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,24 +15,49 @@
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
import {jest, describe, expect, test} from '@jest/globals';
|
||||
import {jest, describe, expect, test, beforeEach, afterEach} from '@jest/globals';
|
||||
|
||||
import {Install} from '../../src/docker/install';
|
||||
import {Docker} from '../../src/docker/docker';
|
||||
import {Exec} from '../../src/exec';
|
||||
|
||||
// prettier-ignore
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'docker-install-jest');
|
||||
|
||||
describe('install', () => {
|
||||
jest.retryTimes(2, {logErrorsBeforeRetry: true});
|
||||
const originalEnv = process.env;
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
process.env = {
|
||||
...originalEnv,
|
||||
LIMA_START_ARGS: '--cpus 4 --memory 8',
|
||||
LIMA_IMAGES: `x86_64:https://cloud.debian.org/images/cloud/bookworm/20231013-1532/debian-12-genericcloud-amd64-20231013-1532.qcow2@sha512:6b55e88b027c14da1b55c85a25a9f7069d4560a8fdb2d948c986a585db469728a06d2c528303e34bb62d8b2984def38fd9ddfc00965846ff6e05b01d6e883bfe
|
||||
aarch64:https://cloud.debian.org/images/cloud/bookworm/20231013-1532/debian-12-genericcloud-arm64-20231013-1532.qcow2`
|
||||
};
|
||||
});
|
||||
afterEach(() => {
|
||||
process.env = originalEnv;
|
||||
});
|
||||
// prettier-ignore
|
||||
test.each(['v23.0.0'])(
|
||||
test.each(['v26.1.4'])(
|
||||
'install docker %s', async (version) => {
|
||||
if (process.env.ImageOS && process.env.ImageOS.startsWith('ubuntu')) {
|
||||
// Remove containerd first on ubuntu runners to make sure it takes
|
||||
// ones packaged with docker
|
||||
await Exec.exec('sudo', ['apt-get', 'remove', '-y', 'containerd.io'], {
|
||||
env: Object.assign({}, process.env, {
|
||||
DEBIAN_FRONTEND: 'noninteractive'
|
||||
}) as {
|
||||
[key: string]: string;
|
||||
}
|
||||
});
|
||||
}
|
||||
await expect((async () => {
|
||||
const install = new Install({
|
||||
version: version,
|
||||
runDir: tmpDir,
|
||||
contextName: 'foo'
|
||||
contextName: 'foo',
|
||||
daemonConfig: `{"debug":true,"features":{"containerd-snapshotter":true}}`
|
||||
});
|
||||
await install.download();
|
||||
await install.install();
|
||||
@@ -40,5 +65,5 @@ describe('install', () => {
|
||||
await Docker.printInfo();
|
||||
await install.tearDown();
|
||||
})()).resolves.not.toThrow();
|
||||
});
|
||||
}, 1200000);
|
||||
});
|
||||
|
||||
@@ -25,10 +25,6 @@ import {Install} from '../../src/docker/install';
|
||||
// prettier-ignore
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'docker-install-jest');
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
rimraf.sync(tmpDir);
|
||||
});
|
||||
@@ -71,3 +67,32 @@ describe('getRelease', () => {
|
||||
await expect(Install.getRelease('foo')).rejects.toThrow(new Error('Cannot find Docker release foo in https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/docker-releases.json'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('limaImage', () => {
|
||||
const originalEnv = process.env;
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
process.env = {
|
||||
...originalEnv,
|
||||
LIMA_IMAGES: `x86_64:https://cloud-images.ubuntu.com/releases/23.10/release-20231011/ubuntu-23.10-server-cloudimg-amd64.img@sha256:f6529be56da3429a56e4f5ef202bf4958201bc63f8541e478caa6e8eb712e635
|
||||
aarch64:https://cloud-images.ubuntu.com/releases/23.10/release-20231011/ubuntu-23.10-server-cloudimg-arm64.img`
|
||||
};
|
||||
});
|
||||
afterEach(() => {
|
||||
process.env = originalEnv;
|
||||
});
|
||||
it('returns custom images', async () => {
|
||||
expect(Install.limaCustomImages()).toEqual([
|
||||
{
|
||||
location: 'https://cloud-images.ubuntu.com/releases/23.10/release-20231011/ubuntu-23.10-server-cloudimg-amd64.img',
|
||||
arch: 'x86_64',
|
||||
digest: 'sha256:f6529be56da3429a56e4f5ef202bf4958201bc63f8541e478caa6e8eb712e635'
|
||||
},
|
||||
{
|
||||
location: 'https://cloud-images.ubuntu.com/releases/23.10/release-20231011/ubuntu-23.10-server-cloudimg-arm64.img',
|
||||
arch: 'aarch64',
|
||||
digest: ''
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,17 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {describe, expect, jest, it, beforeEach} from '@jest/globals';
|
||||
import {describe, expect, jest, it} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import {DockerHub} from '../src/dockerhub';
|
||||
import {RepositoryResponse, RepositoryTagsResponse} from '../src/types/dockerhub';
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
import repoInfoFixture from './fixtures/dockerhub-repoinfo.json';
|
||||
import repoTagsFixture from './fixtures/dockerhub-repotags.json';
|
||||
import repoAllTagsFixture from './fixtures/dockerhub-repoalltags.json';
|
||||
|
||||
@@ -14,14 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {beforeEach, describe, expect, it, jest} from '@jest/globals';
|
||||
import {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');
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"target": {
|
||||
"default": {
|
||||
"context": "https://github.com/docker/test-docker-action.git#remote-private",
|
||||
"dockerfile": "Dockerfile",
|
||||
"tags": [
|
||||
"foo"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"Definition":"eyJncm91cCI6eyJkZWZhdWx0Ijp7InRhcmdldHMiOlsiZGV2Il19fSwidGFyZ2V0Ijp7ImRldiI6eyJjb250ZXh0IjoiLiIsImRvY2tlcmZpbGUiOiJEb2NrZXJmaWxlIiwiYXJncyI6eyJCVUlMREtJVF9DT05URVhUX0tFRVBfR0lUX0RJUiI6IjEiLCJERUZBVUxUX1BST0RVQ1RfTElDRU5TRSI6IiIsIkRPQ0tFUl9CVUlMRFRBR1MiOiIiLCJET0NLRVJfREVCVUciOiIiLCJET0NLRVJfTERGTEFHUyI6IiIsIkRPQ0tFUl9TVEFUSUMiOiIxIiwiUEFDS0FHRVJfTkFNRSI6IiIsIlBMQVRGT1JNIjoiIiwiUFJPRFVDVCI6IiIsIlNZU1RFTUQiOiJmYWxzZSIsIlZFUlNJT04iOiIifSwidGFncyI6WyJkb2NrZXItZGV2Il0sInRhcmdldCI6ImRldiIsIm91dHB1dCI6WyJ0eXBlPWRvY2tlciJdfX19","Targets":["dev"],"Refs":["vzxn0jxr44khtq7hc8drtzwjv"]}
|
||||
@@ -0,0 +1 @@
|
||||
{"LocalPath":"/home/crazymax/github/docker/docker-alpine-s6","DockerfilePath":""}
|
||||
@@ -0,0 +1 @@
|
||||
{"LocalPath":"/home/crazymax/github/docker_org/buildx","DockerfilePath":""}
|
||||
@@ -0,0 +1 @@
|
||||
{"LocalPath":"/home/crazy/foo/bar/https:/github.com/docker/actions-toolkit.git#:__tests__/fixtures","DockerfilePath":"/home/crazy/foo/bar/hello.Dockerfile"}
|
||||
@@ -0,0 +1 @@
|
||||
{"LocalPath":"/home/crazy/foo/bar/https:/github.com/docker/actions-toolkit.git#:__tests__/fixtures","DockerfilePath":"/home/crazy/foo/bar/-"}
|
||||
@@ -0,0 +1 @@
|
||||
{"LocalPath":"/home/crazy/foo/bar/-","DockerfilePath":""}
|
||||
@@ -0,0 +1 @@
|
||||
{"LocalPath":"/home/crazymax/github/docker_org/buildx","DockerfilePath":"/home/crazymax/github/docker_org/buildx/Dockerfile"}
|
||||
@@ -0,0 +1 @@
|
||||
{"LocalPath":"/home/crazy/foo/bar/https:/github.com/docker/buildx.git","DockerfilePath":""}
|
||||
@@ -0,0 +1 @@
|
||||
{"LocalPath":"https://github.com/docker/actions-toolkit.git#:__tests__/fixtures","DockerfilePath":"hello.Dockerfile"}
|
||||
@@ -0,0 +1 @@
|
||||
{"LocalPath":"/home/crazymax/github/docker_org/buildx","DockerfilePath":"/home/crazymax/github/docker_org/buildx/Dockerfile"}
|
||||
@@ -0,0 +1 @@
|
||||
{"LocalPath":"/home/crazymax/github/docker_org/buildx","DockerfilePath":""}
|
||||
@@ -0,0 +1 @@
|
||||
{"LocalPath":"/home/crazymax/github/docker_org/buildx","DockerfilePath":"/home/crazymax/github/docker_org/buildx/Dockerfile"}
|
||||
@@ -0,0 +1 @@
|
||||
{"LocalPath":"/home/crazymax/github/docker_org/buildx","DockerfilePath":""}
|
||||
@@ -0,0 +1 @@
|
||||
{"Target":"dev","LocalPath":"/home/crazymax/github/docker_org/docker","DockerfilePath":"/home/crazymax/github/docker_org/docker/Dockerfile","GroupRef":"1fugf958r4peyg86h6scim5t5"}
|
||||
@@ -0,0 +1 @@
|
||||
{"LocalPath":"/home/crazy/hello","DockerfilePath":"/home/crazy/hello/-"}
|
||||
@@ -0,0 +1 @@
|
||||
{"Target":"default","LocalPath":"/home/crazymax/github/docker_org/compose/.dev/47231","DockerfilePath":"/home/crazymax/github/docker_org/compose/.dev/47231/bad/Dockerfile"}
|
||||
@@ -0,0 +1 @@
|
||||
{"Target":"default","LocalPath":"/home/crazymax/github/docker_org/compose/.dev/47231","DockerfilePath":"/home/crazymax/github/docker_org/compose/.dev/47231/bad/Dockerfile"}
|
||||
@@ -0,0 +1 @@
|
||||
{"Target":"default","LocalPath":"/home/crazymax/github/docker_org/compose/.dev/47231","DockerfilePath":"/home/crazymax/github/docker_org/compose/.dev/47231/bad/Dockerfile"}
|
||||
39
__tests__/fixtures/hello-bake.hcl
Normal file
39
__tests__/fixtures/hello-bake.hcl
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
target "hello" {
|
||||
dockerfile = "hello.Dockerfile"
|
||||
}
|
||||
|
||||
target "hello-bar" {
|
||||
dockerfile = "hello.Dockerfile"
|
||||
args = {
|
||||
NAME = "bar"
|
||||
}
|
||||
}
|
||||
|
||||
group "hello-all" {
|
||||
targets = ["hello", "hello-bar"]
|
||||
}
|
||||
|
||||
target "hello-matrix" {
|
||||
name = "matrix-${name}"
|
||||
matrix = {
|
||||
name = ["bar", "baz", "boo", "far", "faz", "foo", "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj"]
|
||||
}
|
||||
dockerfile = "hello.Dockerfile"
|
||||
args = {
|
||||
NAME = name
|
||||
}
|
||||
}
|
||||
19
__tests__/fixtures/hello-err.Dockerfile
Normal file
19
__tests__/fixtures/hello-err.Dockerfile
Normal file
@@ -0,0 +1,19 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
# Copyright 2024 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.
|
||||
|
||||
FROM busybox:latest
|
||||
ARGGG NAME=foo
|
||||
RUN echo "hello $NAME"
|
||||
23
__tests__/fixtures/hello.Dockerfile
Normal file
23
__tests__/fixtures/hello.Dockerfile
Normal file
@@ -0,0 +1,23 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
# Copyright 2024 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.
|
||||
|
||||
FROM busybox AS build
|
||||
ARG NAME=foo
|
||||
ARG TARGETPLATFORM
|
||||
RUN echo "Hello $NAME from $TARGETPLATFORM" > foo
|
||||
|
||||
FROM scratch
|
||||
COPY --from=build /foo /
|
||||
67
__tests__/fixtures/inspect10.txt
Normal file
67
__tests__/fixtures/inspect10.txt
Normal file
@@ -0,0 +1,67 @@
|
||||
Name: remote-builder
|
||||
Driver: remote
|
||||
Last Activity: 2023-04-20 12:47:49 +0000 UTC
|
||||
|
||||
Nodes:
|
||||
Name: remote-builder0
|
||||
Endpoint: docker-container://buildx_buildkit_dk-remote-builder0
|
||||
Status: inactive
|
||||
Platforms:
|
||||
|
||||
Name: aws_graviton2
|
||||
Endpoint: tcp://10.0.0.1:1234
|
||||
Driver Options: cacert="/home/user/.certs/aws_graviton2/ca.pem" cert="/home/user/.certs/aws_graviton2/cert.pem" key="/home/user/.certs/aws_graviton2/key.pem"
|
||||
Status: running
|
||||
Buildkit: v0.11.6
|
||||
Platforms: darwin/arm64*, linux/arm64*, linux/arm/v5*, linux/arm/v6*, linux/arm/v7*, windows/arm64*
|
||||
Labels:
|
||||
org.mobyproject.buildkit.worker.executor: oci
|
||||
org.mobyproject.buildkit.worker.hostname: 77ebc22e2d82
|
||||
org.mobyproject.buildkit.worker.network: host
|
||||
org.mobyproject.buildkit.worker.oci.process-mode: sandbox
|
||||
org.mobyproject.buildkit.worker.selinux.enabled: false
|
||||
org.mobyproject.buildkit.worker.snapshotter: overlayfs
|
||||
GC Policy rule#0:
|
||||
All: false
|
||||
Filters: type==source.local,type==exec.cachemount,type==source.git.checkout
|
||||
Keep Duration: 48h0m0s
|
||||
Keep Bytes: 488.3MiB
|
||||
GC Policy rule#1:
|
||||
All: false
|
||||
Keep Duration: 1440h0m0s
|
||||
Keep Bytes: 23.28GiB
|
||||
GC Policy rule#2:
|
||||
All: false
|
||||
Keep Bytes: 23.28GiB
|
||||
GC Policy rule#3:
|
||||
All: true
|
||||
Keep Bytes: 23.28GiB
|
||||
|
||||
Name: linuxone_s390x
|
||||
Endpoint: tcp://10.0.0.2:1234
|
||||
Driver Options: cacert="/home/user/.certs/linuxone_s390x/ca.pem" cert="/home/user/.certs/linuxone_s390x/cert.pem" key="/home/user/.certs/linuxone_s390x/key.pem"
|
||||
Status: running
|
||||
Buildkit: v0.11.6
|
||||
Platforms: linux/s390x*
|
||||
Labels:
|
||||
org.mobyproject.buildkit.worker.executor: oci
|
||||
org.mobyproject.buildkit.worker.hostname: 9d0d62a96818
|
||||
org.mobyproject.buildkit.worker.network: host
|
||||
org.mobyproject.buildkit.worker.oci.process-mode: sandbox
|
||||
org.mobyproject.buildkit.worker.selinux.enabled: false
|
||||
org.mobyproject.buildkit.worker.snapshotter: overlayfs
|
||||
GC Policy rule#0:
|
||||
All: false
|
||||
Filters: type==source.local,type==exec.cachemount,type==source.git.checkout
|
||||
Keep Duration: 48h0m0s
|
||||
Keep Bytes: 488.3MiB
|
||||
GC Policy rule#1:
|
||||
All: false
|
||||
Keep Duration: 1440h0m0s
|
||||
Keep Bytes: 9.313GiB
|
||||
GC Policy rule#2:
|
||||
All: false
|
||||
Keep Bytes: 9.313GiB
|
||||
GC Policy rule#3:
|
||||
All: true
|
||||
Keep Bytes: 9.313GiB
|
||||
39
__tests__/fixtures/inspect11.txt
Normal file
39
__tests__/fixtures/inspect11.txt
Normal file
@@ -0,0 +1,39 @@
|
||||
Name: builder
|
||||
Driver: docker-container
|
||||
Last Activity: 2024-03-01 14:25:03 +0000 UTC
|
||||
|
||||
Nodes:
|
||||
Name: builder0
|
||||
Endpoint: unix:///var/run/docker.sock
|
||||
Driver Options: env.JAEGER_TRACE="localhost:6831" image="moby/buildkit:master" network="host" env.BUILDKIT_STEP_LOG_MAX_SIZE="10485760" env.BUILDKIT_STEP_LOG_MAX_SPEED="10485760"
|
||||
Status: running
|
||||
BuildKit daemon flags: --debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host --allow-insecure-entitlement=network.host
|
||||
BuildKit version: 37657a1
|
||||
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
|
||||
Features:
|
||||
Cache export: true
|
||||
Docker exporter: true
|
||||
Multi-platform build: true
|
||||
OCI exporter: true
|
||||
Labels:
|
||||
org.mobyproject.buildkit.worker.executor: oci
|
||||
org.mobyproject.buildkit.worker.hostname: docker-desktop
|
||||
org.mobyproject.buildkit.worker.network: host
|
||||
org.mobyproject.buildkit.worker.oci.process-mode: sandbox
|
||||
org.mobyproject.buildkit.worker.selinux.enabled: false
|
||||
org.mobyproject.buildkit.worker.snapshotter: overlayfs
|
||||
GC Policy rule#0:
|
||||
All: false
|
||||
Filters: type==source.local,type==exec.cachemount,type==source.git.checkout
|
||||
Keep Duration: 48h0m0s
|
||||
Keep Bytes: 488.3MiB
|
||||
GC Policy rule#1:
|
||||
All: false
|
||||
Keep Duration: 1440h0m0s
|
||||
Keep Bytes: 94.06GiB
|
||||
GC Policy rule#2:
|
||||
All: false
|
||||
Keep Bytes: 94.06GiB
|
||||
GC Policy rule#3:
|
||||
All: true
|
||||
Keep Bytes: 94.06GiB
|
||||
34
__tests__/fixtures/inspect8.txt
Normal file
34
__tests__/fixtures/inspect8.txt
Normal file
@@ -0,0 +1,34 @@
|
||||
Name: builder-52aa0611-faf0-42ac-a940-461e4e287d68
|
||||
Driver: docker-container
|
||||
Last Activity: 2023-06-13 13:52:31 +0000 UTC
|
||||
|
||||
Nodes:
|
||||
Name: builder-52aa0611-faf0-42ac-a940-461e4e287d680
|
||||
Endpoint: unix:///var/run/docker.sock
|
||||
Driver Options: image="moby/buildkit:buildx-stable-1" network="host"
|
||||
Status: running
|
||||
Flags: --debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host
|
||||
Buildkit: v0.11.6
|
||||
Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/amd64/v4, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
|
||||
Labels:
|
||||
org.mobyproject.buildkit.worker.executor: oci
|
||||
org.mobyproject.buildkit.worker.hostname: fv-az572-38
|
||||
org.mobyproject.buildkit.worker.network: host
|
||||
org.mobyproject.buildkit.worker.oci.process-mode: sandbox
|
||||
org.mobyproject.buildkit.worker.selinux.enabled: false
|
||||
org.mobyproject.buildkit.worker.snapshotter: overlayfs
|
||||
GC Policy rule#0:
|
||||
All: false
|
||||
Filters: type==source.local,type==exec.cachemount,type==source.git.checkout
|
||||
Keep Duration: 48h0m0s
|
||||
Keep Bytes: 488.3MiB
|
||||
GC Policy rule#1:
|
||||
All: false
|
||||
Keep Duration: 1440h0m0s
|
||||
Keep Bytes: 8.382GiB
|
||||
GC Policy rule#2:
|
||||
All: false
|
||||
Keep Bytes: 8.382GiB
|
||||
GC Policy rule#3:
|
||||
All: true
|
||||
Keep Bytes: 8.382GiB
|
||||
14
__tests__/fixtures/inspect9.txt
Normal file
14
__tests__/fixtures/inspect9.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
Name: default
|
||||
Driver: docker
|
||||
Last Activity: 2023-06-13 18:13:43 +0000 UTC
|
||||
|
||||
Nodes:
|
||||
Name: default
|
||||
Endpoint: default
|
||||
Status: running
|
||||
Buildkit: v0.11.7-0.20230525183624-798ad6b0ce9f
|
||||
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
|
||||
GC Policy rule#0:
|
||||
All: true
|
||||
Filters:
|
||||
Keep Bytes: 100GiB
|
||||
28
__tests__/fixtures/lint.Dockerfile
Normal file
28
__tests__/fixtures/lint.Dockerfile
Normal file
@@ -0,0 +1,28 @@
|
||||
# syntax=docker/dockerfile-upstream:master
|
||||
|
||||
# Copyright 2024 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.
|
||||
|
||||
frOM busybox as base
|
||||
cOpy lint.Dockerfile .
|
||||
|
||||
from scratch
|
||||
MAINTAINER moby@example.com
|
||||
COPy --from=base \
|
||||
/lint.Dockerfile \
|
||||
/
|
||||
|
||||
CMD [ "echo", "Hello, Norway!" ]
|
||||
CMD [ "echo", "Hello, Sweden!" ]
|
||||
ENTRYPOINT my-program start
|
||||
228
__tests__/fixtures/metadata.json
Normal file
228
__tests__/fixtures/metadata.json
Normal file
@@ -0,0 +1,228 @@
|
||||
{
|
||||
"buildx.build.provenance": {
|
||||
"buildType": "https://mobyproject.org/buildkit@v1",
|
||||
"materials": [
|
||||
{
|
||||
"uri": "pkg:docker/docker/dockerfile-upstream@master",
|
||||
"digest": {
|
||||
"sha256": "70433342168dafa34d11bd7236c3c3fcf448b90539733281711050808f32e835"
|
||||
}
|
||||
},
|
||||
{
|
||||
"uri": "pkg:docker/busybox@latest?platform=linux%2Famd64",
|
||||
"digest": {
|
||||
"sha256": "9ae97d36d26566ff84e8893c64a6dc4fe8ca6d1144bf5b87b2b85a32def253c7"
|
||||
}
|
||||
}
|
||||
],
|
||||
"invocation": {
|
||||
"configSource": {
|
||||
"entryPoint": "Dockerfile"
|
||||
},
|
||||
"parameters": {
|
||||
"frontend": "gateway.v0",
|
||||
"args": {
|
||||
"cmdline": "docker/dockerfile-upstream:master",
|
||||
"source": "docker/dockerfile-upstream:master"
|
||||
},
|
||||
"locals": [
|
||||
{
|
||||
"name": "context"
|
||||
},
|
||||
{
|
||||
"name": "dockerfile"
|
||||
}
|
||||
]
|
||||
},
|
||||
"environment": {
|
||||
"platform": "linux/amd64"
|
||||
}
|
||||
}
|
||||
},
|
||||
"buildx.build.ref": "default/default/n6ibcp9b2pw108rrz7ywdznvo",
|
||||
"buildx.build.warnings": [
|
||||
{
|
||||
"vertex": "sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0",
|
||||
"level": 1,
|
||||
"short": "Q29uc2lzdGVudEluc3RydWN0aW9uQ2FzaW5nOiBDb21tYW5kICdmck9NJyBzaG91bGQgYmUgY29uc2lzdGVudGx5IGNhc2VkIChsaW5lIDIp",
|
||||
"detail": [
|
||||
"SW5zdHJ1Y3Rpb25zIHNob3VsZCBiZSBpbiBjb25zaXN0ZW50IGNhc2luZyAoYWxsIGxvd2VyIG9yIGFsbCB1cHBlcik="
|
||||
],
|
||||
"url": "https://docs.docker.com/go/dockerfile/rule/consistent-instruction-casing/",
|
||||
"sourceInfo": {
|
||||
"filename": "Dockerfile",
|
||||
"data": "IyBzeW50YXg9ZG9ja2VyL2RvY2tlcmZpbGUtdXBzdHJlYW06bWFzdGVyCmZyT00gYnVzeWJveCBhcyBiYXNlCmNPcHkgRG9ja2VyZmlsZSAuCgpmcm9tIHNjcmF0Y2gKQ09QeSAtLWZyb209YmFzZSBcCiAgL0RvY2tlcmZpbGUgXAogIC8K",
|
||||
"definition": {
|
||||
"def": [
|
||||
"GsUBChJsb2NhbDovL2RvY2tlcmZpbGUSFAoMbG9jYWwuZGlmZmVyEgRub25lEkoKEWxvY2FsLmZvbGxvd3BhdGhzEjVbIkRvY2tlcmZpbGUiLCJEb2NrZXJmaWxlLmRvY2tlcmlnbm9yZSIsImRvY2tlcmZpbGUiXRIqCg1sb2NhbC5zZXNzaW9uEhkwN3A3MzJ6aGR4NXV1NnVsZDNzOGpteWo2EiEKE2xvY2FsLnNoYXJlZGtleWhpbnQSCmRvY2tlcmZpbGVaAA==",
|
||||
"CkkKR3NoYTI1Njo3YjQ3N2FjNWRkM2E0YzRkMjUyM2Y3ZjdmMjA0MDZiNjI2Mzk1ZGUwODJmNDRmZDVmZjk5NjMyM2VjODI1N2Qw"
|
||||
],
|
||||
"metadata": {
|
||||
"sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0": {
|
||||
"description": {
|
||||
"llb.customname": "[internal] load build definition from Dockerfile"
|
||||
},
|
||||
"caps": {
|
||||
"source.local": true,
|
||||
"source.local.followpaths": true,
|
||||
"source.local.sessionid": true,
|
||||
"source.local.sharedkeyhint": true
|
||||
}
|
||||
},
|
||||
"sha256:a06279dbe062a3b181c9b918abfaf37ca8106f1f9745b9d42356b3195b205cd1": {
|
||||
"caps": {
|
||||
"constraints": true,
|
||||
"meta.description": true,
|
||||
"platform": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"Source": {
|
||||
"locations": {
|
||||
"sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"language": "Dockerfile"
|
||||
},
|
||||
"range": [
|
||||
{
|
||||
"start": {
|
||||
"line": 2
|
||||
},
|
||||
"end": {
|
||||
"line": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"vertex": "sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0",
|
||||
"level": 1,
|
||||
"short": "Q29uc2lzdGVudEluc3RydWN0aW9uQ2FzaW5nOiBDb21tYW5kICdjT3B5JyBzaG91bGQgYmUgY29uc2lzdGVudGx5IGNhc2VkIChsaW5lIDMp",
|
||||
"detail": [
|
||||
"SW5zdHJ1Y3Rpb25zIHNob3VsZCBiZSBpbiBjb25zaXN0ZW50IGNhc2luZyAoYWxsIGxvd2VyIG9yIGFsbCB1cHBlcik="
|
||||
],
|
||||
"url": "https://docs.docker.com/go/dockerfile/rule/consistent-instruction-casing/",
|
||||
"sourceInfo": {
|
||||
"filename": "Dockerfile",
|
||||
"data": "IyBzeW50YXg9ZG9ja2VyL2RvY2tlcmZpbGUtdXBzdHJlYW06bWFzdGVyCmZyT00gYnVzeWJveCBhcyBiYXNlCmNPcHkgRG9ja2VyZmlsZSAuCgpmcm9tIHNjcmF0Y2gKQ09QeSAtLWZyb209YmFzZSBcCiAgL0RvY2tlcmZpbGUgXAogIC8K",
|
||||
"definition": {
|
||||
"def": [
|
||||
"GsUBChJsb2NhbDovL2RvY2tlcmZpbGUSFAoMbG9jYWwuZGlmZmVyEgRub25lEkoKEWxvY2FsLmZvbGxvd3BhdGhzEjVbIkRvY2tlcmZpbGUiLCJEb2NrZXJmaWxlLmRvY2tlcmlnbm9yZSIsImRvY2tlcmZpbGUiXRIqCg1sb2NhbC5zZXNzaW9uEhkwN3A3MzJ6aGR4NXV1NnVsZDNzOGpteWo2EiEKE2xvY2FsLnNoYXJlZGtleWhpbnQSCmRvY2tlcmZpbGVaAA==",
|
||||
"CkkKR3NoYTI1Njo3YjQ3N2FjNWRkM2E0YzRkMjUyM2Y3ZjdmMjA0MDZiNjI2Mzk1ZGUwODJmNDRmZDVmZjk5NjMyM2VjODI1N2Qw"
|
||||
],
|
||||
"metadata": {
|
||||
"sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0": {
|
||||
"description": {
|
||||
"llb.customname": "[internal] load build definition from Dockerfile"
|
||||
},
|
||||
"caps": {
|
||||
"source.local": true,
|
||||
"source.local.followpaths": true,
|
||||
"source.local.sessionid": true,
|
||||
"source.local.sharedkeyhint": true
|
||||
}
|
||||
},
|
||||
"sha256:a06279dbe062a3b181c9b918abfaf37ca8106f1f9745b9d42356b3195b205cd1": {
|
||||
"caps": {
|
||||
"constraints": true,
|
||||
"meta.description": true,
|
||||
"platform": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"Source": {
|
||||
"locations": {
|
||||
"sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"language": "Dockerfile"
|
||||
},
|
||||
"range": [
|
||||
{
|
||||
"start": {
|
||||
"line": 3
|
||||
},
|
||||
"end": {
|
||||
"line": 3
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"vertex": "sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0",
|
||||
"level": 1,
|
||||
"short": "Q29uc2lzdGVudEluc3RydWN0aW9uQ2FzaW5nOiBDb21tYW5kICdDT1B5JyBzaG91bGQgYmUgY29uc2lzdGVudGx5IGNhc2VkIChsaW5lIDYp",
|
||||
"detail": [
|
||||
"SW5zdHJ1Y3Rpb25zIHNob3VsZCBiZSBpbiBjb25zaXN0ZW50IGNhc2luZyAoYWxsIGxvd2VyIG9yIGFsbCB1cHBlcik="
|
||||
],
|
||||
"url": "https://docs.docker.com/go/dockerfile/rule/consistent-instruction-casing/",
|
||||
"sourceInfo": {
|
||||
"filename": "Dockerfile",
|
||||
"data": "IyBzeW50YXg9ZG9ja2VyL2RvY2tlcmZpbGUtdXBzdHJlYW06bWFzdGVyCmZyT00gYnVzeWJveCBhcyBiYXNlCmNPcHkgRG9ja2VyZmlsZSAuCgpmcm9tIHNjcmF0Y2gKQ09QeSAtLWZyb209YmFzZSBcCiAgL0RvY2tlcmZpbGUgXAogIC8K",
|
||||
"definition": {
|
||||
"def": [
|
||||
"GsUBChJsb2NhbDovL2RvY2tlcmZpbGUSFAoMbG9jYWwuZGlmZmVyEgRub25lEkoKEWxvY2FsLmZvbGxvd3BhdGhzEjVbIkRvY2tlcmZpbGUiLCJEb2NrZXJmaWxlLmRvY2tlcmlnbm9yZSIsImRvY2tlcmZpbGUiXRIqCg1sb2NhbC5zZXNzaW9uEhkwN3A3MzJ6aGR4NXV1NnVsZDNzOGpteWo2EiEKE2xvY2FsLnNoYXJlZGtleWhpbnQSCmRvY2tlcmZpbGVaAA==",
|
||||
"CkkKR3NoYTI1Njo3YjQ3N2FjNWRkM2E0YzRkMjUyM2Y3ZjdmMjA0MDZiNjI2Mzk1ZGUwODJmNDRmZDVmZjk5NjMyM2VjODI1N2Qw"
|
||||
],
|
||||
"metadata": {
|
||||
"sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0": {
|
||||
"description": {
|
||||
"llb.customname": "[internal] load build definition from Dockerfile"
|
||||
},
|
||||
"caps": {
|
||||
"source.local": true,
|
||||
"source.local.followpaths": true,
|
||||
"source.local.sessionid": true,
|
||||
"source.local.sharedkeyhint": true
|
||||
}
|
||||
},
|
||||
"sha256:a06279dbe062a3b181c9b918abfaf37ca8106f1f9745b9d42356b3195b205cd1": {
|
||||
"caps": {
|
||||
"constraints": true,
|
||||
"meta.description": true,
|
||||
"platform": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"Source": {
|
||||
"locations": {
|
||||
"sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"language": "Dockerfile"
|
||||
},
|
||||
"range": [
|
||||
{
|
||||
"start": {
|
||||
"line": 6
|
||||
},
|
||||
"end": {
|
||||
"line": 6
|
||||
}
|
||||
},
|
||||
{
|
||||
"start": {
|
||||
"line": 7
|
||||
},
|
||||
"end": {
|
||||
"line": 7
|
||||
}
|
||||
},
|
||||
{
|
||||
"start": {
|
||||
"line": 8
|
||||
},
|
||||
"end": {
|
||||
"line": 8
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"containerimage.config.digest": "sha256:059b68a595b22564a1cbc167f369349fdc2ecc1f7bc092c2235cbf601a795fd",
|
||||
"containerimage.digest": "sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c"
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
__tests__/fixtures/oci-archive/hello-oci-gzip.tar
Normal file
BIN
__tests__/fixtures/oci-archive/hello-oci-gzip.tar
Normal file
Binary file not shown.
BIN
__tests__/fixtures/oci-archive/hello-oci-multiplatform-gzip.tar
Normal file
BIN
__tests__/fixtures/oci-archive/hello-oci-multiplatform-gzip.tar
Normal file
Binary file not shown.
BIN
__tests__/fixtures/oci-archive/hello-oci-uncompressed.tar
Normal file
BIN
__tests__/fixtures/oci-archive/hello-oci-uncompressed.tar
Normal file
Binary file not shown.
BIN
__tests__/fixtures/oci-archive/hello-oci-zstd.tar
Normal file
BIN
__tests__/fixtures/oci-archive/hello-oci-zstd.tar
Normal file
Binary file not shown.
BIN
__tests__/fixtures/oci-archive/moby~buildkit~LWDOW6.dockerbuild
Normal file
BIN
__tests__/fixtures/oci-archive/moby~buildkit~LWDOW6.dockerbuild
Normal file
Binary file not shown.
@@ -21,7 +21,6 @@ import {Exec} from '../src/exec';
|
||||
import {ExecOutput} from '@actions/exec';
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
@@ -34,6 +33,9 @@ describe('context', () => {
|
||||
case 'git show --format=%H HEAD --quiet --':
|
||||
result = 'test-sha';
|
||||
break;
|
||||
case 'git branch --show-current':
|
||||
result = 'test';
|
||||
break;
|
||||
case 'git symbolic-ref HEAD':
|
||||
result = 'refs/heads/test';
|
||||
break;
|
||||
@@ -90,17 +92,146 @@ describe('remoteURL', () => {
|
||||
});
|
||||
|
||||
describe('ref', () => {
|
||||
it('have been called', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'getExecOutput');
|
||||
try {
|
||||
await Git.ref();
|
||||
} catch (err) {
|
||||
// noop
|
||||
}
|
||||
expect(execSpy).toHaveBeenCalledWith(`git`, ['symbolic-ref', 'HEAD'], {
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
it('returns mocked ref', async () => {
|
||||
jest.spyOn(Exec, 'getExecOutput').mockImplementation((cmd, args): Promise<ExecOutput> => {
|
||||
const fullCmd = `${cmd} ${args?.join(' ')}`;
|
||||
let result = '';
|
||||
switch (fullCmd) {
|
||||
case 'git branch --show-current':
|
||||
result = 'test';
|
||||
break;
|
||||
case 'git symbolic-ref HEAD':
|
||||
result = 'refs/heads/test';
|
||||
break;
|
||||
}
|
||||
return Promise.resolve({
|
||||
stdout: result,
|
||||
stderr: '',
|
||||
exitCode: 0
|
||||
});
|
||||
});
|
||||
|
||||
const ref = await Git.ref();
|
||||
|
||||
expect(ref).toEqual('refs/heads/test');
|
||||
});
|
||||
|
||||
it('returns mocked detached tag ref', async () => {
|
||||
jest.spyOn(Exec, 'getExecOutput').mockImplementation((cmd, args): Promise<ExecOutput> => {
|
||||
const fullCmd = `${cmd} ${args?.join(' ')}`;
|
||||
let result = '';
|
||||
switch (fullCmd) {
|
||||
case 'git branch --show-current':
|
||||
result = '';
|
||||
break;
|
||||
case 'git show -s --pretty=%D':
|
||||
result = 'HEAD, tag: 8.0.0';
|
||||
break;
|
||||
}
|
||||
return Promise.resolve({
|
||||
stdout: result,
|
||||
stderr: '',
|
||||
exitCode: 0
|
||||
});
|
||||
});
|
||||
|
||||
const ref = await Git.ref();
|
||||
|
||||
expect(ref).toEqual('refs/tags/8.0.0');
|
||||
});
|
||||
|
||||
it('returns mocked detached tag ref (shallow clone)', async () => {
|
||||
jest.spyOn(Exec, 'getExecOutput').mockImplementation((cmd, args): Promise<ExecOutput> => {
|
||||
const fullCmd = `${cmd} ${args?.join(' ')}`;
|
||||
let result = '';
|
||||
switch (fullCmd) {
|
||||
case 'git branch --show-current':
|
||||
result = '';
|
||||
break;
|
||||
case 'git show -s --pretty=%D':
|
||||
result = 'grafted, HEAD, tag: 8.0.0';
|
||||
break;
|
||||
}
|
||||
return Promise.resolve({
|
||||
stdout: result,
|
||||
stderr: '',
|
||||
exitCode: 0
|
||||
});
|
||||
});
|
||||
|
||||
const ref = await Git.ref();
|
||||
|
||||
expect(ref).toEqual('refs/tags/8.0.0');
|
||||
});
|
||||
|
||||
it('returns mocked detached pull request merge ref (shallow clone)', async () => {
|
||||
jest.spyOn(Exec, 'getExecOutput').mockImplementation((cmd, args): Promise<ExecOutput> => {
|
||||
const fullCmd = `${cmd} ${args?.join(' ')}`;
|
||||
let result = '';
|
||||
switch (fullCmd) {
|
||||
case 'git branch --show-current':
|
||||
result = '';
|
||||
break;
|
||||
case 'git show -s --pretty=%D':
|
||||
result = 'grafted, HEAD, pull/221/merge';
|
||||
break;
|
||||
}
|
||||
return Promise.resolve({
|
||||
stdout: result,
|
||||
stderr: '',
|
||||
exitCode: 0
|
||||
});
|
||||
});
|
||||
|
||||
const ref = await Git.ref();
|
||||
|
||||
expect(ref).toEqual('refs/pull/221/merge');
|
||||
});
|
||||
|
||||
it('should throws an error when detached HEAD ref is not supported', async () => {
|
||||
jest.spyOn(Exec, 'getExecOutput').mockImplementation((cmd, args): Promise<ExecOutput> => {
|
||||
const fullCmd = `${cmd} ${args?.join(' ')}`;
|
||||
let result = '';
|
||||
switch (fullCmd) {
|
||||
case 'git branch --show-current':
|
||||
result = '';
|
||||
break;
|
||||
case 'git show -s --pretty=%D':
|
||||
result = 'wrong, HEAD, tag: 8.0.0';
|
||||
break;
|
||||
}
|
||||
return Promise.resolve({
|
||||
stdout: result,
|
||||
stderr: '',
|
||||
exitCode: 0
|
||||
});
|
||||
});
|
||||
|
||||
await expect(Git.ref()).rejects.toThrow('Cannot find detached HEAD ref in "wrong, HEAD, tag: 8.0.0"');
|
||||
});
|
||||
|
||||
it('returns mocked detached branch ref', async () => {
|
||||
jest.spyOn(Exec, 'getExecOutput').mockImplementation((cmd, args): Promise<ExecOutput> => {
|
||||
const fullCmd = `${cmd} ${args?.join(' ')}`;
|
||||
let result = '';
|
||||
switch (fullCmd) {
|
||||
case 'git branch --show-current':
|
||||
result = '';
|
||||
break;
|
||||
case 'git show -s --pretty=%D':
|
||||
result = 'HEAD, origin/test, test';
|
||||
break;
|
||||
}
|
||||
return Promise.resolve({
|
||||
stdout: result,
|
||||
stderr: '',
|
||||
exitCode: 0
|
||||
});
|
||||
});
|
||||
|
||||
const ref = await Git.ref();
|
||||
|
||||
expect(ref).toEqual('refs/heads/test');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
334
__tests__/github.test.itg.ts
Normal file
334
__tests__/github.test.itg.ts
Normal file
@@ -0,0 +1,334 @@
|
||||
/**
|
||||
* Copyright 2024 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 {describe, expect, it, test} from '@jest/globals';
|
||||
import fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import {Buildx} from '../src/buildx/buildx';
|
||||
import {Bake} from '../src/buildx/bake';
|
||||
import {Build} from '../src/buildx/build';
|
||||
import {Exec} from '../src/exec';
|
||||
import {GitHub} from '../src/github';
|
||||
import {History} from '../src/buildx/history';
|
||||
|
||||
const fixturesDir = path.join(__dirname, 'fixtures');
|
||||
|
||||
// prettier-ignore
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'github-jest');
|
||||
|
||||
const maybe = !process.env.GITHUB_ACTIONS || (process.env.GITHUB_ACTIONS === 'true' && process.env.ImageOS && process.env.ImageOS.startsWith('ubuntu')) ? describe : describe.skip;
|
||||
|
||||
maybe('uploadArtifact', () => {
|
||||
it('uploads an artifact', async () => {
|
||||
const res = await GitHub.uploadArtifact({
|
||||
filename: path.join(fixturesDir, 'github-repo.json'),
|
||||
mimeType: 'application/json',
|
||||
retentionDays: 1
|
||||
});
|
||||
expect(res).toBeDefined();
|
||||
console.log('uploadArtifactResponse', res);
|
||||
expect(res?.url).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
maybe('writeBuildSummary', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
"single",
|
||||
[
|
||||
'build',
|
||||
'-f', path.join(fixturesDir, 'hello.Dockerfile'),
|
||||
fixturesDir
|
||||
],
|
||||
],
|
||||
[
|
||||
"multiplatform",
|
||||
[
|
||||
'build',
|
||||
'-f', path.join(fixturesDir, 'hello.Dockerfile'),
|
||||
'--platform', 'linux/amd64,linux/arm64',
|
||||
fixturesDir
|
||||
],
|
||||
]
|
||||
])('write build summary %p', async (_, bargs) => {
|
||||
const buildx = new Buildx();
|
||||
const build = new Build({buildx: buildx});
|
||||
|
||||
fs.mkdirSync(tmpDir, {recursive: true});
|
||||
await expect(
|
||||
(async () => {
|
||||
// prettier-ignore
|
||||
const buildCmd = await buildx.getCommand([
|
||||
'--builder', process.env.CTN_BUILDER_NAME ?? 'default',
|
||||
...bargs,
|
||||
'--metadata-file', build.getMetadataFilePath()
|
||||
]);
|
||||
await Exec.exec(buildCmd.command, buildCmd.args);
|
||||
})()
|
||||
).resolves.not.toThrow();
|
||||
|
||||
const metadata = build.resolveMetadata();
|
||||
expect(metadata).toBeDefined();
|
||||
const buildRef = build.resolveRef(metadata);
|
||||
expect(buildRef).toBeDefined();
|
||||
|
||||
const history = new History({buildx: buildx});
|
||||
const exportRes = await history.export({
|
||||
refs: [buildRef ?? '']
|
||||
});
|
||||
expect(exportRes).toBeDefined();
|
||||
expect(exportRes?.dockerbuildFilename).toBeDefined();
|
||||
expect(exportRes?.dockerbuildSize).toBeDefined();
|
||||
expect(exportRes?.summaries).toBeDefined();
|
||||
|
||||
const uploadRes = await GitHub.uploadArtifact({
|
||||
filename: exportRes?.dockerbuildFilename,
|
||||
mimeType: 'application/gzip',
|
||||
retentionDays: 1
|
||||
});
|
||||
expect(uploadRes).toBeDefined();
|
||||
expect(uploadRes?.url).toBeDefined();
|
||||
|
||||
await GitHub.writeBuildSummary({
|
||||
exportRes: exportRes,
|
||||
uploadRes: uploadRes,
|
||||
inputs: {
|
||||
context: fixturesDir,
|
||||
file: path.join(fixturesDir, 'hello.Dockerfile')
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
'single',
|
||||
path.join(fixturesDir, 'hello-bake.hcl'),
|
||||
'hello'
|
||||
],
|
||||
[
|
||||
'group',
|
||||
path.join(fixturesDir, 'hello-bake.hcl'),
|
||||
'hello-all'
|
||||
],
|
||||
[
|
||||
'matrix',
|
||||
path.join(fixturesDir, 'hello-bake.hcl'),
|
||||
'hello-matrix'
|
||||
]
|
||||
])('write bake summary %p', async (_, file, target) => {
|
||||
const buildx = new Buildx();
|
||||
const bake = new Bake({buildx: buildx});
|
||||
|
||||
fs.mkdirSync(tmpDir, {recursive: true});
|
||||
await expect(
|
||||
(async () => {
|
||||
// prettier-ignore
|
||||
const buildCmd = await buildx.getCommand([
|
||||
'--builder', process.env.CTN_BUILDER_NAME ?? 'default',
|
||||
'bake',
|
||||
'-f', file,
|
||||
target,
|
||||
'--metadata-file', bake.getMetadataFilePath()
|
||||
]);
|
||||
await Exec.exec(buildCmd.command, buildCmd.args, {
|
||||
cwd: fixturesDir
|
||||
});
|
||||
})()
|
||||
).resolves.not.toThrow();
|
||||
|
||||
const definition = await bake.getDefinition(
|
||||
{
|
||||
files: [file],
|
||||
targets: [target],
|
||||
},
|
||||
{
|
||||
cwd: fixturesDir
|
||||
}
|
||||
);
|
||||
|
||||
const metadata = bake.resolveMetadata();
|
||||
expect(metadata).toBeDefined();
|
||||
const buildRefs = bake.resolveRefs(metadata);
|
||||
expect(buildRefs).toBeDefined();
|
||||
|
||||
const history = new History({buildx: buildx});
|
||||
const exportRes = await history.export({
|
||||
refs: buildRefs ?? []
|
||||
});
|
||||
expect(exportRes).toBeDefined();
|
||||
expect(exportRes?.dockerbuildFilename).toBeDefined();
|
||||
expect(exportRes?.dockerbuildSize).toBeDefined();
|
||||
expect(exportRes?.summaries).toBeDefined();
|
||||
|
||||
const uploadRes = await GitHub.uploadArtifact({
|
||||
filename: exportRes?.dockerbuildFilename,
|
||||
mimeType: 'application/gzip',
|
||||
retentionDays: 1
|
||||
});
|
||||
expect(uploadRes).toBeDefined();
|
||||
expect(uploadRes?.url).toBeDefined();
|
||||
|
||||
await GitHub.writeBuildSummary({
|
||||
exportRes: exportRes,
|
||||
uploadRes: uploadRes,
|
||||
inputs: {
|
||||
files: path.join(fixturesDir, 'hello-bake.hcl')
|
||||
},
|
||||
bakeDefinition: definition
|
||||
});
|
||||
});
|
||||
|
||||
it('fails with dockerfile syntax issue', async () => {
|
||||
const startedTime = new Date();
|
||||
const buildx = new Buildx();
|
||||
const build = new Build({buildx: buildx});
|
||||
|
||||
fs.mkdirSync(tmpDir, {recursive: true});
|
||||
await expect(
|
||||
(async () => {
|
||||
// prettier-ignore
|
||||
const buildCmd = await buildx.getCommand([
|
||||
'--builder', process.env.CTN_BUILDER_NAME ?? 'default',
|
||||
'build',
|
||||
'-f', path.join(fixturesDir, 'hello-err.Dockerfile'),
|
||||
fixturesDir,
|
||||
'--metadata-file', build.getMetadataFilePath()
|
||||
]);
|
||||
await Exec.exec(buildCmd.command, buildCmd.args);
|
||||
})()
|
||||
).rejects.toThrow();
|
||||
|
||||
const refs = Buildx.refs({
|
||||
dir: Buildx.refsDir,
|
||||
builderName: process.env.CTN_BUILDER_NAME ?? 'default',
|
||||
since: startedTime
|
||||
});
|
||||
expect(refs).toBeDefined();
|
||||
expect(Object.keys(refs).length).toBeGreaterThan(0);
|
||||
|
||||
const history = new History({buildx: buildx});
|
||||
const exportRes = await history.export({
|
||||
refs: [Object.keys(refs)[0] ?? '']
|
||||
});
|
||||
expect(exportRes).toBeDefined();
|
||||
expect(exportRes?.dockerbuildFilename).toBeDefined();
|
||||
expect(exportRes?.dockerbuildSize).toBeDefined();
|
||||
expect(exportRes?.summaries).toBeDefined();
|
||||
|
||||
const uploadRes = await GitHub.uploadArtifact({
|
||||
filename: exportRes?.dockerbuildFilename,
|
||||
mimeType: 'application/gzip',
|
||||
retentionDays: 1
|
||||
});
|
||||
expect(uploadRes).toBeDefined();
|
||||
expect(uploadRes?.url).toBeDefined();
|
||||
|
||||
await GitHub.writeBuildSummary({
|
||||
exportRes: exportRes,
|
||||
uploadRes: uploadRes,
|
||||
inputs: {
|
||||
context: fixturesDir,
|
||||
file: path.join(fixturesDir, 'hello-err.Dockerfile')
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('without build record', async () => {
|
||||
const startedTime = new Date();
|
||||
const buildx = new Buildx();
|
||||
const build = new Build({buildx: buildx});
|
||||
|
||||
fs.mkdirSync(tmpDir, {recursive: true});
|
||||
await expect(
|
||||
(async () => {
|
||||
// prettier-ignore
|
||||
const buildCmd = await buildx.getCommand([
|
||||
'--builder', process.env.CTN_BUILDER_NAME ?? 'default',
|
||||
'build',
|
||||
'-f', path.join(fixturesDir, 'hello.Dockerfile'),
|
||||
fixturesDir,
|
||||
'--metadata-file', build.getMetadataFilePath()
|
||||
]);
|
||||
await Exec.exec(buildCmd.command, buildCmd.args);
|
||||
})()
|
||||
).resolves.not.toThrow();
|
||||
|
||||
const refs = Buildx.refs({
|
||||
dir: Buildx.refsDir,
|
||||
builderName: process.env.CTN_BUILDER_NAME ?? 'default',
|
||||
since: startedTime
|
||||
});
|
||||
expect(refs).toBeDefined();
|
||||
expect(Object.keys(refs).length).toBeGreaterThan(0);
|
||||
|
||||
const history = new History({buildx: buildx});
|
||||
const exportRes = await history.export({
|
||||
refs: [Object.keys(refs)[0] ?? '']
|
||||
});
|
||||
expect(exportRes).toBeDefined();
|
||||
expect(exportRes?.dockerbuildFilename).toBeDefined();
|
||||
expect(exportRes?.dockerbuildSize).toBeDefined();
|
||||
expect(exportRes?.summaries).toBeDefined();
|
||||
|
||||
await GitHub.writeBuildSummary({
|
||||
exportRes: exportRes,
|
||||
inputs: {
|
||||
context: fixturesDir,
|
||||
file: path.join(fixturesDir, 'hello.Dockerfile')
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
maybe('annotateBuildWarnings', () => {
|
||||
it('annoate lint issues', async () => {
|
||||
const buildx = new Buildx();
|
||||
const build = new Build({buildx: buildx});
|
||||
|
||||
fs.mkdirSync(tmpDir, {recursive: true});
|
||||
await expect(
|
||||
(async () => {
|
||||
// prettier-ignore
|
||||
const buildCmd = await buildx.getCommand([
|
||||
'--builder', process.env.CTN_BUILDER_NAME ?? 'default',
|
||||
'build',
|
||||
'-f', path.join(fixturesDir, 'lint.Dockerfile'),
|
||||
fixturesDir,
|
||||
'--metadata-file', build.getMetadataFilePath()
|
||||
]);
|
||||
await Exec.exec(buildCmd.command, buildCmd.args, {
|
||||
env: Object.assign({}, process.env, {
|
||||
BUILDX_METADATA_WARNINGS: 'true'
|
||||
}) as {
|
||||
[key: string]: string;
|
||||
}
|
||||
});
|
||||
})()
|
||||
).resolves.not.toThrow();
|
||||
|
||||
const metadata = build.resolveMetadata();
|
||||
expect(metadata).toBeDefined();
|
||||
const buildRef = build.resolveRef(metadata);
|
||||
expect(buildRef).toBeDefined();
|
||||
const buildWarnings = build.resolveWarnings(metadata);
|
||||
expect(buildWarnings).toBeDefined();
|
||||
|
||||
await GitHub.annotateBuildWarnings(path.join(fixturesDir, 'lint.Dockerfile'), buildWarnings);
|
||||
});
|
||||
});
|
||||
@@ -22,17 +22,13 @@ import * as core from '@actions/core';
|
||||
import {GitHub} from '../src/github';
|
||||
import {GitHubRepo} from '../src/types/github';
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
import repoFixture from './fixtures/github-repo.json';
|
||||
jest.spyOn(GitHub.prototype, 'repoData').mockImplementation((): Promise<GitHubRepo> => {
|
||||
return <Promise<GitHubRepo>>(repoFixture as unknown);
|
||||
});
|
||||
|
||||
describe('repoData', () => {
|
||||
it('returns GitHub repository', async () => {
|
||||
it('returns GitHub repo data', async () => {
|
||||
const github = new GitHub();
|
||||
expect((await github.repoData()).name).toEqual('Hello-World');
|
||||
});
|
||||
@@ -89,6 +85,21 @@ describe('apiURL', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('repository', () => {
|
||||
it('returns GitHub repository', async () => {
|
||||
expect(GitHub.repository).toEqual('docker/actions-toolkit');
|
||||
});
|
||||
});
|
||||
|
||||
describe('workflowRunURL', () => {
|
||||
it('returns 2188748038', async () => {
|
||||
expect(GitHub.workflowRunURL()).toEqual('https://github.com/docker/actions-toolkit/actions/runs/2188748038');
|
||||
});
|
||||
it('returns 2188748038 with attempts 2', async () => {
|
||||
expect(GitHub.workflowRunURL(true)).toEqual('https://github.com/docker/actions-toolkit/actions/runs/2188748038/attempts/2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('actionsRuntimeToken', () => {
|
||||
const originalEnv = process.env;
|
||||
beforeEach(() => {
|
||||
@@ -111,7 +122,10 @@ describe('actionsRuntimeToken', () => {
|
||||
}).toThrow();
|
||||
});
|
||||
it('fixture', async () => {
|
||||
process.env.ACTIONS_RUNTIME_TOKEN = fs.readFileSync(path.join(__dirname, 'fixtures', 'runtimeToken.txt')).toString().trim();
|
||||
process.env.ACTIONS_RUNTIME_TOKEN = fs
|
||||
.readFileSync(path.join(__dirname, 'fixtures', 'runtimeToken.txt'))
|
||||
.toString()
|
||||
.trim();
|
||||
const runtimeToken = GitHub.actionsRuntimeToken;
|
||||
expect(runtimeToken?.ac).toEqual('[{"Scope":"refs/heads/master","Permission":3}]');
|
||||
expect(runtimeToken?.iss).toEqual('vstoken.actions.githubusercontent.com');
|
||||
@@ -135,11 +149,14 @@ describe('printActionsRuntimeTokenACs', () => {
|
||||
});
|
||||
it('malformed', async () => {
|
||||
process.env.ACTIONS_RUNTIME_TOKEN = 'foo';
|
||||
await expect(GitHub.printActionsRuntimeTokenACs()).rejects.toThrow(new Error("Cannot parse GitHub Actions Runtime Token: Invalid token specified: Cannot read properties of undefined (reading 'replace')"));
|
||||
await expect(GitHub.printActionsRuntimeTokenACs()).rejects.toThrow(new Error('Cannot parse GitHub Actions Runtime Token: Invalid token specified: missing part #2'));
|
||||
});
|
||||
it('refs/heads/master', async () => {
|
||||
const infoSpy = jest.spyOn(core, 'info');
|
||||
process.env.ACTIONS_RUNTIME_TOKEN = fs.readFileSync(path.join(__dirname, 'fixtures', 'runtimeToken.txt')).toString().trim();
|
||||
process.env.ACTIONS_RUNTIME_TOKEN = fs
|
||||
.readFileSync(path.join(__dirname, 'fixtures', 'runtimeToken.txt'))
|
||||
.toString()
|
||||
.trim();
|
||||
await GitHub.printActionsRuntimeTokenACs();
|
||||
expect(infoSpy).toHaveBeenCalledTimes(1);
|
||||
expect(infoSpy).toHaveBeenCalledWith(`refs/heads/master: read/write`);
|
||||
|
||||
46
__tests__/oci/oci.test.ts
Normal file
46
__tests__/oci/oci.test.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright 2024 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 {afterEach, describe, expect, test} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import path from 'path';
|
||||
import * as rimraf from 'rimraf';
|
||||
|
||||
import {OCI} from '../../src/oci/oci';
|
||||
|
||||
const fixturesDir = path.join(__dirname, '..', 'fixtures');
|
||||
|
||||
// prettier-ignore
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'docker-jest');
|
||||
|
||||
afterEach(function () {
|
||||
rimraf.sync(tmpDir);
|
||||
});
|
||||
|
||||
describe('loadArchive', () => {
|
||||
// prettier-ignore
|
||||
test.each(fs.readdirSync(path.join(fixturesDir, 'oci-archive')).filter(file => {
|
||||
return fs.statSync(path.join(path.join(fixturesDir, 'oci-archive'), file)).isFile();
|
||||
}).map(filename => [filename]))('extracting %p', async (filename) => {
|
||||
const res = await OCI.loadArchive({
|
||||
file: path.join(fixturesDir, 'oci-archive', filename)
|
||||
});
|
||||
expect(res).toBeDefined();
|
||||
expect(res?.root.index).toBeDefined();
|
||||
expect(res?.root.layout).toBeDefined();
|
||||
// console.log(JSON.stringify(res, null, 2));
|
||||
});
|
||||
});
|
||||
30
__tests__/testResultsProcessor.ts
Normal file
30
__tests__/testResultsProcessor.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright 2024 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.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const fs = require('fs');
|
||||
|
||||
module.exports = results => {
|
||||
const allSkipped = results.testResults.every(result => {
|
||||
return result.skipped;
|
||||
});
|
||||
if (allSkipped) {
|
||||
console.log('All tests were skipped!');
|
||||
// create an empty file to signal that all tests were skipped for CI
|
||||
fs.closeSync(fs.openSync('./coverage/allSkipped.txt', 'w'));
|
||||
}
|
||||
return results;
|
||||
};
|
||||
@@ -14,16 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {beforeEach, describe, expect, it, jest, test} from '@jest/globals';
|
||||
import {describe, expect, it, test} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import {Util} from '../src/util';
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('getInputList', () => {
|
||||
it('single line correctly', async () => {
|
||||
await setInput('foo', 'bar');
|
||||
@@ -31,6 +27,12 @@ describe('getInputList', () => {
|
||||
expect(res).toEqual(['bar']);
|
||||
});
|
||||
|
||||
it('empty correctly', async () => {
|
||||
setInput('foo', '');
|
||||
const res = Util.getInputList('foo');
|
||||
expect(res).toEqual([]);
|
||||
});
|
||||
|
||||
it('multiline correctly', async () => {
|
||||
setInput('foo', 'bar\nbaz');
|
||||
const res = Util.getInputList('foo');
|
||||
@@ -191,6 +193,12 @@ ccccccccc`,
|
||||
'FOO=bar'
|
||||
]);
|
||||
});
|
||||
|
||||
it('keep quotes', async () => {
|
||||
const output = `type=image,"name=ghcr.io/nginxinc/nginx-unprivileged,docker.io/nginxinc/nginx-unprivileged",push-by-digest=true,name-canonical=true,push=true`;
|
||||
setInput('outputs', output);
|
||||
expect(Util.getInputList('outputs', {ignoreComma: true, quote: false})).toEqual([output]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('asyncForEach', () => {
|
||||
@@ -232,6 +240,182 @@ describe('isValidRef', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('trimPrefix', () => {
|
||||
test.each([
|
||||
['', 'abc', ''],
|
||||
['abc', 'a', 'bc'],
|
||||
['abc', 'ab', 'c'],
|
||||
['abc', '', 'abc'],
|
||||
['abc', '', 'abc'],
|
||||
['abc', 'd', 'abc'],
|
||||
['abc', 'abc', ''],
|
||||
['abc', 'abcd', 'abc'],
|
||||
['abcdabc', 'abc', 'dabc'],
|
||||
['abcabc', 'abc', 'abc'],
|
||||
['abcdabc', 'd', 'abcdabc']
|
||||
])('given %p', async (str, prefix, expected) => {
|
||||
expect(Util.trimPrefix(str, prefix)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('trimSuffix', () => {
|
||||
test.each([
|
||||
['', 'abc', ''],
|
||||
['abc', 'c', 'ab'],
|
||||
['abc', '', 'abc'],
|
||||
['abc', 'bc', 'a'],
|
||||
['abc', 'abc', ''],
|
||||
['abc', 'abcd', 'abc'],
|
||||
['abc', 'aabc', 'abc'],
|
||||
['abcdabc', 'abc', 'abcd'],
|
||||
['abcabc', 'abc', 'abc'],
|
||||
['abcdabc', 'd', 'abcdabc']
|
||||
])('given %p', async (str, suffix, expected) => {
|
||||
expect(Util.trimSuffix(str, suffix)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hash', () => {
|
||||
it('returns 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae', async () => {
|
||||
expect(Util.hash('foo')).toEqual('2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae');
|
||||
});
|
||||
});
|
||||
|
||||
// https://github.com/golang/go/blob/f6b93a4c358b28b350dd8fe1780c1f78e520c09c/src/strconv/atob_test.go#L36-L58
|
||||
describe('parseBool', () => {
|
||||
[
|
||||
{input: '', expected: false, throwsError: true},
|
||||
{input: 'asdf', expected: false, throwsError: true},
|
||||
{input: '0', expected: false, throwsError: false},
|
||||
{input: 'f', expected: false, throwsError: false},
|
||||
{input: 'F', expected: false, throwsError: false},
|
||||
{input: 'FALSE', expected: false, throwsError: false},
|
||||
{input: 'false', expected: false, throwsError: false},
|
||||
{input: 'False', expected: false, throwsError: false},
|
||||
{input: '1', expected: true, throwsError: false},
|
||||
{input: 't', expected: true, throwsError: false},
|
||||
{input: 'T', expected: true, throwsError: false},
|
||||
{input: 'TRUE', expected: true, throwsError: false},
|
||||
{input: 'true', expected: true, throwsError: false},
|
||||
{input: 'True', expected: true, throwsError: false}
|
||||
].forEach(({input, expected, throwsError}) => {
|
||||
test(`parseBool("${input}")`, () => {
|
||||
if (throwsError) {
|
||||
// eslint-disable-next-line jest/no-conditional-expect
|
||||
expect(() => Util.parseBool(input)).toThrow();
|
||||
} else {
|
||||
// eslint-disable-next-line jest/no-conditional-expect
|
||||
expect(Util.parseBool(input)).toBe(expected);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatFileSize', () => {
|
||||
test('should return "0 Bytes" when given 0 bytes', () => {
|
||||
expect(Util.formatFileSize(0)).toBe('0 Bytes');
|
||||
});
|
||||
test('should format bytes to KB correctly', () => {
|
||||
expect(Util.formatFileSize(1024)).toBe('1 KB');
|
||||
expect(Util.formatFileSize(2048)).toBe('2 KB');
|
||||
expect(Util.formatFileSize(1500)).toBe('1.46 KB');
|
||||
});
|
||||
test('should format bytes to MB correctly', () => {
|
||||
expect(Util.formatFileSize(1024 * 1024)).toBe('1 MB');
|
||||
expect(Util.formatFileSize(2.5 * 1024 * 1024)).toBe('2.5 MB');
|
||||
expect(Util.formatFileSize(3.8 * 1024 * 1024)).toBe('3.8 MB');
|
||||
});
|
||||
test('should format bytes to GB correctly', () => {
|
||||
expect(Util.formatFileSize(1024 * 1024 * 1024)).toBe('1 GB');
|
||||
expect(Util.formatFileSize(2.5 * 1024 * 1024 * 1024)).toBe('2.5 GB');
|
||||
expect(Util.formatFileSize(3.8 * 1024 * 1024 * 1024)).toBe('3.8 GB');
|
||||
});
|
||||
test('should format bytes to TB correctly', () => {
|
||||
expect(Util.formatFileSize(1024 * 1024 * 1024 * 1024)).toBe('1 TB');
|
||||
expect(Util.formatFileSize(2.5 * 1024 * 1024 * 1024 * 1024)).toBe('2.5 TB');
|
||||
expect(Util.formatFileSize(3.8 * 1024 * 1024 * 1024 * 1024)).toBe('3.8 TB');
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateRandomString', () => {
|
||||
it('should generate a random string of default length 10', async () => {
|
||||
const res = Util.generateRandomString();
|
||||
expect(typeof res).toBe('string');
|
||||
expect(res.length).toBe(10);
|
||||
expect(/^[0-9a-f]+$/i.test(res)).toBe(true);
|
||||
});
|
||||
it('should generate a random string of specified length', async () => {
|
||||
const length = 15;
|
||||
const res = Util.generateRandomString(length);
|
||||
expect(typeof res).toBe('string');
|
||||
expect(res.length).toBe(15);
|
||||
expect(/^[0-9a-f]+$/i.test(res)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('stringToUnicodeEntities', () => {
|
||||
it('should convert a string to Unicode entities', () => {
|
||||
const input = 'Hello, World!';
|
||||
const expected = 'Hello, World!';
|
||||
const result = Util.stringToUnicodeEntities(input);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
it('should handle an empty string', () => {
|
||||
const input = '';
|
||||
const expected = '';
|
||||
const result = Util.stringToUnicodeEntities(input);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
it('should handle special characters', () => {
|
||||
const input = '@#^&*()';
|
||||
const expected = '@#^&*()';
|
||||
const result = Util.stringToUnicodeEntities(input);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
it('should handle non-English characters', () => {
|
||||
const input = 'こんにちは';
|
||||
const expected = 'こんにちは';
|
||||
const result = Util.stringToUnicodeEntities(input);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('countLines', () => {
|
||||
it('counts total number of lines correctly', () => {
|
||||
const text = `This
|
||||
|
||||
is
|
||||
a
|
||||
sample
|
||||
|
||||
text
|
||||
with
|
||||
multiple
|
||||
lines`;
|
||||
|
||||
const result = Util.countLines(text);
|
||||
expect(result).toEqual(10); // Including empty lines
|
||||
});
|
||||
it('handles edge case with empty string', () => {
|
||||
const text = '';
|
||||
|
||||
const result = Util.countLines(text);
|
||||
expect(result).toEqual(1); // Empty string should have 1 line
|
||||
});
|
||||
it('handles edge case with single line', () => {
|
||||
const text = 'Single line text';
|
||||
|
||||
const result = Util.countLines(text);
|
||||
expect(result).toEqual(1); // Single line should have 1 line
|
||||
});
|
||||
it('handles multiple types of line breaks', () => {
|
||||
const text = `Line 1\r\nLine 2\rLine 3\nLine 4`;
|
||||
|
||||
const result = Util.countLines(text);
|
||||
expect(result).toEqual(4); // Different line break types should be counted correctly
|
||||
});
|
||||
});
|
||||
|
||||
// See: https://github.com/actions/toolkit/blob/a1b068ec31a042ff1e10a522d8fdf0b8869d53ca/packages/core/src/core.ts#L89
|
||||
function getInputName(name: string): string {
|
||||
return `INPUT_${name.replace(/ /g, '_').toUpperCase()}`;
|
||||
|
||||
@@ -14,14 +14,19 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
ARG NODE_VERSION=16
|
||||
ARG DOCKER_VERSION=20.10.22
|
||||
ARG BUILDX_VERSION=0.10.0
|
||||
ARG NODE_VERSION=20
|
||||
ARG DOCKER_VERSION=26.0.2
|
||||
ARG BUILDX_VERSION=0.16.1
|
||||
|
||||
FROM node:${NODE_VERSION}-alpine AS base
|
||||
RUN apk add --no-cache cpio findutils git
|
||||
RUN yarn config set --home enableTelemetry 0
|
||||
WORKDIR /src
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
--mount=type=cache,target=/src/.yarn/cache <<EOT
|
||||
corepack enable
|
||||
yarn --version
|
||||
yarn config set --home enableTelemetry 0
|
||||
EOT
|
||||
|
||||
FROM base AS deps
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
|
||||
@@ -14,8 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-actions-toolkit-'));
|
||||
|
||||
process.env = Object.assign({}, process.env, {
|
||||
TEMP: tmpDir,
|
||||
RUNNER_TEMP: path.join(tmpDir, 'runner-temp'),
|
||||
RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache')
|
||||
}) as {
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
clearMocks: true,
|
||||
testEnvironment: 'node',
|
||||
moduleFileExtensions: ['js', 'ts'],
|
||||
setupFiles: ['dotenv/config'],
|
||||
@@ -27,5 +40,6 @@ module.exports = {
|
||||
moduleNameMapper: {
|
||||
'^csv-parse/sync': '<rootDir>/node_modules/csv-parse/dist/cjs/sync.cjs'
|
||||
},
|
||||
testResultsProcessor: './__tests__/testResultsProcessor.ts',
|
||||
verbose: false
|
||||
};
|
||||
|
||||
@@ -23,6 +23,9 @@ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-actions-toolkit-'))
|
||||
process.env = Object.assign({}, process.env, {
|
||||
TEMP: tmpDir,
|
||||
GITHUB_REPOSITORY: 'docker/actions-toolkit',
|
||||
GITHUB_RUN_ATTEMPT: 2,
|
||||
GITHUB_RUN_ID: 2188748038,
|
||||
GITHUB_RUN_NUMBER: 15,
|
||||
RUNNER_TEMP: path.join(tmpDir, 'runner-temp'),
|
||||
RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache')
|
||||
}) as {
|
||||
@@ -43,5 +46,6 @@ module.exports = {
|
||||
},
|
||||
collectCoverageFrom: ['src/**/{!(index.ts),}.ts'],
|
||||
coveragePathIgnorePatterns: ['lib/', 'node_modules/', '__mocks__/', '__tests__/'],
|
||||
testResultsProcessor: './__tests__/testResultsProcessor.ts',
|
||||
verbose: true
|
||||
};
|
||||
|
||||
69
package.json
69
package.json
@@ -30,7 +30,7 @@
|
||||
],
|
||||
"author": "Docker Inc.",
|
||||
"license": "Apache-2.0",
|
||||
"packageManager": "yarn@3.3.1",
|
||||
"packageManager": "yarn@3.6.3",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"directories": {
|
||||
@@ -45,39 +45,50 @@
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.0",
|
||||
"@actions/artifact": "^2.1.8",
|
||||
"@actions/cache": "^3.2.4",
|
||||
"@actions/core": "^1.10.1",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/github": "^5.1.1",
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"@actions/io": "^1.1.2",
|
||||
"@actions/github": "^6.0.0",
|
||||
"@actions/http-client": "^2.2.1",
|
||||
"@actions/io": "^1.1.3",
|
||||
"@actions/tool-cache": "^2.0.1",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^7.2.1",
|
||||
"@azure/storage-blob": "^12.15.0",
|
||||
"@octokit/core": "^5.1.0",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^10.4.0",
|
||||
"async-retry": "^1.3.3",
|
||||
"csv-parse": "^5.4.0",
|
||||
"handlebars": "^4.7.7",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"semver": "^7.5.1",
|
||||
"tmp": "^0.2.1"
|
||||
"csv-parse": "^5.5.6",
|
||||
"gunzip-maybe": "^1.4.2",
|
||||
"handlebars": "^4.7.8",
|
||||
"he": "^1.2.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"semver": "^7.6.3",
|
||||
"tar-stream": "^3.1.7",
|
||||
"tmp": "^0.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/csv-parse": "^1.2.2",
|
||||
"@types/node": "^16.18.21",
|
||||
"@types/semver": "^7.5.0",
|
||||
"@types/tmp": "^0.2.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.56.0",
|
||||
"@typescript-eslint/parser": "^5.56.0",
|
||||
"cpy-cli": "^4.2.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"eslint": "^8.36.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"jest": "^29.5.0",
|
||||
"prettier": "^2.8.7",
|
||||
"rimraf": "^4.4.1",
|
||||
"ts-jest": "^29.0.5",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.9.5"
|
||||
"@types/gunzip-maybe": "^1.4.2",
|
||||
"@types/he": "^1.2.3",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/node": "^20.12.10",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@types/tar-stream": "^3.1.3",
|
||||
"@types/tmp": "^0.2.6",
|
||||
"@typescript-eslint/eslint-plugin": "^7.8.0",
|
||||
"@typescript-eslint/parser": "^7.8.0",
|
||||
"dotenv": "^16.4.5",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-jest": "^28.5.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.2.5",
|
||||
"rimraf": "^5.0.5",
|
||||
"ts-jest": "^29.1.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ import * as semver from 'semver';
|
||||
|
||||
import {Buildx} from '../buildx/buildx';
|
||||
import {Builder} from '../buildx/builder';
|
||||
import {Docker} from '../docker/docker';
|
||||
import {Config} from './config';
|
||||
import {Exec} from '../exec';
|
||||
|
||||
import {BuilderInfo, NodeInfo} from '../types/builder';
|
||||
import {BuilderInfo, NodeInfo} from '../types/buildx/builder';
|
||||
|
||||
export interface BuildKitOpts {
|
||||
buildx?: Buildx;
|
||||
@@ -51,13 +51,13 @@ export class BuildKit {
|
||||
|
||||
private async getVersionWithinImage(nodeName: string): Promise<string> {
|
||||
core.debug(`BuildKit.getVersionWithinImage nodeName: ${nodeName}`);
|
||||
return Exec.getExecOutput(`docker`, ['inspect', '--format', '{{.Config.Image}}', `${Buildx.containerNamePrefix}${nodeName}`], {
|
||||
return Docker.getExecOutput(['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'], {
|
||||
return Docker.getExecOutput(['run', '--rm', bkitimage.stdout.trim(), '--version'], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
}).then(bkitversion => {
|
||||
|
||||
113
src/buildkit/git.ts
Normal file
113
src/buildkit/git.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Copyright 2024 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 {GitRef, GitURL, GitURLFragment, URLUserInfo} from '../types/buildkit/git';
|
||||
|
||||
export class Git {
|
||||
private static protoRegexp = new RegExp('^[a-zA-Z0-9]+://');
|
||||
private static supportedProtos = {
|
||||
http: {},
|
||||
https: {},
|
||||
ssh: {},
|
||||
git: {}
|
||||
};
|
||||
|
||||
// https://github.com/moby/buildkit/blob/2ec1338fc13f73b43f0b1b4f4678d7cd654bc86c/util/gitutil/git_url.go#L79
|
||||
public static parseURL(remote: string): GitURL {
|
||||
const match = remote.match(Git.protoRegexp);
|
||||
if (match && match.length > 0) {
|
||||
let proto = match[0].toLowerCase();
|
||||
proto = proto.slice(0, proto.lastIndexOf('://'));
|
||||
if (!(proto in Git.supportedProtos)) {
|
||||
throw new Error(`Invalid protocol: ${proto}`);
|
||||
}
|
||||
return Git.fromURL(new URL(remote));
|
||||
}
|
||||
|
||||
throw new Error('Unknown protocol');
|
||||
}
|
||||
|
||||
// https://github.com/moby/buildkit/blob/2ec1338fc13f73b43f0b1b4f4678d7cd654bc86c/util/gitutil/git_url.go#L108
|
||||
private static fromURL(url: URL): GitURL {
|
||||
const withoutFragment = new URL(url.toString());
|
||||
withoutFragment.hash = '';
|
||||
|
||||
let user: URLUserInfo | undefined;
|
||||
if (url.username || url.password) {
|
||||
user = {
|
||||
username: url.username,
|
||||
password: url.password,
|
||||
passwordSet: url.password !== ''
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: handle SCP-style URLs
|
||||
|
||||
return {
|
||||
scheme: url.protocol.slice(0, -1),
|
||||
user: user,
|
||||
host: `${url.hostname}${url.port ? ':' + url.port : ''}`,
|
||||
path: url.pathname,
|
||||
fragment: Git.splitGitFragment(url.hash),
|
||||
remote: withoutFragment.toString()
|
||||
};
|
||||
}
|
||||
|
||||
// https://github.com/moby/buildkit/blob/2ec1338fc13f73b43f0b1b4f4678d7cd654bc86c/util/gitutil/git_url.go#L69
|
||||
private static splitGitFragment(fragment: string): GitURLFragment | undefined {
|
||||
if (fragment === '') {
|
||||
return undefined;
|
||||
}
|
||||
const [ref, subdir] = fragment.slice(1).split(':');
|
||||
return {
|
||||
ref: ref,
|
||||
subdir: subdir
|
||||
};
|
||||
}
|
||||
|
||||
// https://github.com/moby/buildkit/blob/2ec1338fc13f73b43f0b1b4f4678d7cd654bc86c/util/gitutil/git_ref.go#L52
|
||||
public static parseRef(ref: string): GitRef | undefined {
|
||||
const res: GitRef = {};
|
||||
let remote: GitURL;
|
||||
if (ref.startsWith('./') || ref.startsWith('../')) {
|
||||
throw new Error('Invalid argument');
|
||||
} else if (ref.startsWith('github.com/')) {
|
||||
res.indistinguishableFromLocal = true; // Deprecated
|
||||
remote = Git.fromURL(new URL('https://' + ref));
|
||||
} else {
|
||||
remote = Git.parseURL(ref);
|
||||
if (['http', 'git'].includes(remote.scheme)) {
|
||||
res.unencryptedTCP = true; // Discouraged, but not deprecated
|
||||
}
|
||||
if (['http', 'https'].includes(remote.scheme) && !remote.path.endsWith('.git')) {
|
||||
throw new Error('Invalid argument');
|
||||
}
|
||||
}
|
||||
res.remote = remote.remote;
|
||||
|
||||
if (res.indistinguishableFromLocal) {
|
||||
res.remote = res.remote.split('://')[1];
|
||||
}
|
||||
if (remote.fragment) {
|
||||
res.commit = remote.fragment.ref;
|
||||
res.subDir = remote.fragment.subdir;
|
||||
}
|
||||
|
||||
const repoSplitBySlash = res.remote.split('/');
|
||||
res.shortName = repoSplitBySlash[repoSplitBySlash.length - 1].replace('.git', '');
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -14,31 +14,96 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import {Build} from './build';
|
||||
import {Buildx} from './buildx';
|
||||
import {Context} from '../context';
|
||||
import {Exec} from '../exec';
|
||||
import {Inputs} from './inputs';
|
||||
import {Util} from '../util';
|
||||
|
||||
import {BakeDefinition} from '../types/bake';
|
||||
import {ExecOptions} from '@actions/exec';
|
||||
import {BakeDefinition} from '../types/buildx/bake';
|
||||
import {BuildMetadata} from '../types/buildx/build';
|
||||
|
||||
export interface BakeOpts {
|
||||
buildx?: Buildx;
|
||||
}
|
||||
|
||||
export interface BakeCmdOpts {
|
||||
files?: Array<string>;
|
||||
load?: boolean;
|
||||
noCache?: boolean;
|
||||
overrides?: Array<string>;
|
||||
provenance?: string;
|
||||
push?: boolean;
|
||||
sbom?: string;
|
||||
source?: string;
|
||||
targets?: Array<string>;
|
||||
|
||||
githubToken?: string; // for auth with remote definitions on private repos
|
||||
}
|
||||
|
||||
export class Bake {
|
||||
private readonly buildx: Buildx;
|
||||
private readonly metadataFilename: string;
|
||||
|
||||
constructor(opts?: BakeOpts) {
|
||||
this.buildx = opts?.buildx || new Buildx();
|
||||
this.metadataFilename = `bake-metadata-${Util.generateRandomString()}.json`;
|
||||
}
|
||||
|
||||
public async parseDefinitions(sources: Array<string>, targets?: Array<string>, overrides?: Array<string>, load?: boolean, push?: boolean, workdir?: string): Promise<BakeDefinition> {
|
||||
public getMetadataFilePath(): string {
|
||||
return path.join(Context.tmpDir(), this.metadataFilename);
|
||||
}
|
||||
|
||||
public resolveMetadata(): BuildMetadata | undefined {
|
||||
const metadataFile = this.getMetadataFilePath();
|
||||
if (!fs.existsSync(metadataFile)) {
|
||||
return undefined;
|
||||
}
|
||||
const content = fs.readFileSync(metadataFile, {encoding: 'utf-8'}).trim();
|
||||
if (content === 'null') {
|
||||
return undefined;
|
||||
}
|
||||
return <BuildMetadata>JSON.parse(content);
|
||||
}
|
||||
|
||||
public resolveRefs(metadata?: BuildMetadata): Array<string> | undefined {
|
||||
if (!metadata) {
|
||||
metadata = this.resolveMetadata();
|
||||
if (!metadata) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
const refs = new Array<string>();
|
||||
for (const key in metadata) {
|
||||
if ('buildx.build.ref' in metadata[key]) {
|
||||
refs.push(metadata[key]['buildx.build.ref']);
|
||||
}
|
||||
}
|
||||
return refs.length > 0 ? refs : undefined;
|
||||
}
|
||||
|
||||
public async getDefinition(cmdOpts: BakeCmdOpts, execOptions?: ExecOptions): Promise<BakeDefinition> {
|
||||
execOptions = execOptions || {ignoreReturnCode: true};
|
||||
execOptions.ignoreReturnCode = true;
|
||||
if (cmdOpts.githubToken) {
|
||||
execOptions.env = Object.assign({}, process.env, {
|
||||
BUILDX_BAKE_GIT_AUTH_TOKEN: cmdOpts.githubToken
|
||||
}) as {
|
||||
[key: string]: string;
|
||||
};
|
||||
}
|
||||
|
||||
const args = ['bake'];
|
||||
|
||||
let remoteDef;
|
||||
let remoteDef: string | undefined;
|
||||
const files: Array<string> = [];
|
||||
const sources = [...(cmdOpts.files || []), cmdOpts.source];
|
||||
if (sources) {
|
||||
for (const source of sources.map(v => v.trim())) {
|
||||
for (const source of sources.map(v => (v ? v.trim() : ''))) {
|
||||
if (source.length == 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -47,7 +112,7 @@ export class Bake {
|
||||
continue;
|
||||
}
|
||||
if (remoteDef) {
|
||||
throw new Error(`Only one remote bake definition is allowed`);
|
||||
throw new Error(`Only one remote bake definition can be defined`);
|
||||
}
|
||||
remoteDef = source;
|
||||
}
|
||||
@@ -58,41 +123,50 @@ export class Bake {
|
||||
for (const file of files) {
|
||||
args.push('--file', file);
|
||||
}
|
||||
if (overrides) {
|
||||
for (const override of overrides) {
|
||||
if (cmdOpts.overrides) {
|
||||
for (const override of cmdOpts.overrides) {
|
||||
args.push('--set', override);
|
||||
}
|
||||
}
|
||||
if (load) {
|
||||
if (cmdOpts.load) {
|
||||
args.push('--load');
|
||||
}
|
||||
if (push) {
|
||||
if (cmdOpts.noCache) {
|
||||
args.push('--no-cache');
|
||||
}
|
||||
if (cmdOpts.provenance) {
|
||||
args.push('--provenance', cmdOpts.provenance);
|
||||
}
|
||||
if (cmdOpts.push) {
|
||||
args.push('--push');
|
||||
}
|
||||
if (cmdOpts.sbom) {
|
||||
args.push('--sbom', cmdOpts.sbom);
|
||||
}
|
||||
|
||||
const printCmd = await this.buildx.getCommand([...args, '--print', ...(targets || [])]);
|
||||
return await Exec.getExecOutput(printCmd.command, printCmd.args, {
|
||||
cwd: workdir,
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
}).then(res => {
|
||||
const printCmd = await this.buildx.getCommand([...args, '--print', ...(cmdOpts.targets || [])]);
|
||||
return await Exec.getExecOutput(printCmd.command, printCmd.args, execOptions).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr);
|
||||
throw new Error(`cannot parse bake definitions: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
|
||||
}
|
||||
return <BakeDefinition>JSON.parse(res.stdout.trim());
|
||||
return Bake.parseDefinition(res.stdout.trim());
|
||||
});
|
||||
}
|
||||
|
||||
public static parseDefinition(dt: string): BakeDefinition {
|
||||
return <BakeDefinition>JSON.parse(dt);
|
||||
}
|
||||
|
||||
public static hasLocalExporter(def: BakeDefinition): boolean {
|
||||
return Inputs.hasExporterType('local', Bake.exporters(def));
|
||||
return Build.hasExporterType('local', Bake.exporters(def));
|
||||
}
|
||||
|
||||
public static hasTarExporter(def: BakeDefinition): boolean {
|
||||
return Inputs.hasExporterType('tar', Bake.exporters(def));
|
||||
return Build.hasExporterType('tar', Bake.exporters(def));
|
||||
}
|
||||
|
||||
public static hasDockerExporter(def: BakeDefinition, load?: boolean): boolean {
|
||||
return load || Inputs.hasExporterType('docker', Bake.exporters(def));
|
||||
return load || Build.hasExporterType('docker', Bake.exporters(def));
|
||||
}
|
||||
|
||||
private static exporters(def: BakeDefinition): Array<string> {
|
||||
|
||||
322
src/buildx/build.ts
Normal file
322
src/buildx/build.ts
Normal file
@@ -0,0 +1,322 @@
|
||||
/**
|
||||
* 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 fs from 'fs';
|
||||
import path from 'path';
|
||||
import * as core from '@actions/core';
|
||||
import {parse} from 'csv-parse/sync';
|
||||
|
||||
import {Buildx} from './buildx';
|
||||
import {Context} from '../context';
|
||||
import {GitHub} from '../github';
|
||||
import {Util} from '../util';
|
||||
|
||||
import {BuildMetadata} from '../types/buildx/build';
|
||||
import {VertexWarning} from '../types/buildkit/client';
|
||||
import {ProvenancePredicate} from '../types/intoto/slsa_provenance/v0.2/provenance';
|
||||
|
||||
export interface BuildOpts {
|
||||
buildx?: Buildx;
|
||||
}
|
||||
|
||||
export class Build {
|
||||
private readonly buildx: Buildx;
|
||||
private readonly iidFilename: string;
|
||||
private readonly metadataFilename: string;
|
||||
|
||||
constructor(opts?: BuildOpts) {
|
||||
this.buildx = opts?.buildx || new Buildx();
|
||||
this.iidFilename = `build-iidfile-${Util.generateRandomString()}.txt`;
|
||||
this.metadataFilename = `build-metadata-${Util.generateRandomString()}.json`;
|
||||
}
|
||||
|
||||
public getImageIDFilePath(): string {
|
||||
return path.join(Context.tmpDir(), this.iidFilename);
|
||||
}
|
||||
|
||||
public resolveImageID(): string | undefined {
|
||||
const iidFile = this.getImageIDFilePath();
|
||||
if (!fs.existsSync(iidFile)) {
|
||||
return undefined;
|
||||
}
|
||||
return fs.readFileSync(iidFile, {encoding: 'utf-8'}).trim();
|
||||
}
|
||||
|
||||
public getMetadataFilePath(): string {
|
||||
return path.join(Context.tmpDir(), this.metadataFilename);
|
||||
}
|
||||
|
||||
public resolveMetadata(): BuildMetadata | undefined {
|
||||
const metadataFile = this.getMetadataFilePath();
|
||||
if (!fs.existsSync(metadataFile)) {
|
||||
return undefined;
|
||||
}
|
||||
const content = fs.readFileSync(metadataFile, {encoding: 'utf-8'}).trim();
|
||||
if (content === 'null') {
|
||||
return undefined;
|
||||
}
|
||||
return <BuildMetadata>JSON.parse(content);
|
||||
}
|
||||
|
||||
public resolveRef(metadata?: BuildMetadata): string | undefined {
|
||||
if (!metadata) {
|
||||
metadata = this.resolveMetadata();
|
||||
if (!metadata) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
if ('buildx.build.ref' in metadata) {
|
||||
return metadata['buildx.build.ref'];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public resolveProvenance(metadata?: BuildMetadata): ProvenancePredicate | undefined {
|
||||
if (!metadata) {
|
||||
metadata = this.resolveMetadata();
|
||||
if (!metadata) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
if ('buildx.build.provenance' in metadata) {
|
||||
return metadata['buildx.build.provenance'] as ProvenancePredicate;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public resolveWarnings(metadata?: BuildMetadata): Array<VertexWarning> | undefined {
|
||||
if (!metadata) {
|
||||
metadata = this.resolveMetadata();
|
||||
if (!metadata) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
if ('buildx.build.warnings' in metadata) {
|
||||
return metadata['buildx.build.warnings'] as Array<VertexWarning>;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public resolveDigest(metadata?: BuildMetadata): string | undefined {
|
||||
if (!metadata) {
|
||||
metadata = this.resolveMetadata();
|
||||
if (!metadata) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
if ('containerimage.digest' in metadata) {
|
||||
return metadata['containerimage.digest'];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public static resolveSecretString(kvp: string): string {
|
||||
const [key, file] = Build.resolveSecret(kvp, false);
|
||||
return `id=${key},src=${file}`;
|
||||
}
|
||||
|
||||
public static resolveSecretFile(kvp: string): string {
|
||||
const [key, file] = Build.resolveSecret(kvp, true);
|
||||
return `id=${key},src=${file}`;
|
||||
}
|
||||
|
||||
public static resolveSecretEnv(kvp: string): string {
|
||||
const [key, value] = Build.parseSecretKvp(kvp);
|
||||
return `id=${key},env=${value}`;
|
||||
}
|
||||
|
||||
public static resolveSecret(kvp: string, file: boolean): [string, string] {
|
||||
const [key, _value] = Build.parseSecretKvp(kvp);
|
||||
let value = _value;
|
||||
if (file) {
|
||||
if (!fs.existsSync(value)) {
|
||||
throw new Error(`secret file ${value} not found`);
|
||||
}
|
||||
value = fs.readFileSync(value, {encoding: 'utf-8'});
|
||||
}
|
||||
const secretFile = Context.tmpName({tmpdir: Context.tmpDir()});
|
||||
fs.writeFileSync(secretFile, value);
|
||||
return [key, secretFile];
|
||||
}
|
||||
|
||||
public static getProvenanceInput(name: string): string {
|
||||
const input = core.getInput(name);
|
||||
if (!input) {
|
||||
// if input is not set returns empty string
|
||||
return input;
|
||||
}
|
||||
try {
|
||||
return core.getBooleanInput(name) ? `builder-id=${GitHub.workflowRunURL(true)}` : 'false';
|
||||
} catch (err) {
|
||||
// not a valid boolean, so we assume it's a string
|
||||
return Build.resolveProvenanceAttrs(input);
|
||||
}
|
||||
}
|
||||
|
||||
public static resolveProvenanceAttrs(input: string): string {
|
||||
if (!input) {
|
||||
return `builder-id=${GitHub.workflowRunURL(true)}`;
|
||||
}
|
||||
// parse attributes from input
|
||||
const fields = parse(input, {
|
||||
relaxColumnCount: true,
|
||||
skipEmptyLines: true
|
||||
})[0];
|
||||
// check if builder-id attribute exists in the input
|
||||
for (const field of fields) {
|
||||
const parts = field
|
||||
.toString()
|
||||
.split(/(?<=^[^=]+?)=/)
|
||||
.map(item => item.trim());
|
||||
if (parts[0] == 'builder-id') {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
// if not add builder-id attribute
|
||||
return `${input},builder-id=${GitHub.workflowRunURL(true)}`;
|
||||
}
|
||||
|
||||
public static resolveCacheToAttrs(input: string, githubToken?: string): string {
|
||||
if (!input) {
|
||||
return input;
|
||||
}
|
||||
|
||||
let cacheType = 'registry';
|
||||
let ghaCacheRepository = '';
|
||||
let ghaCacheGHToken = '';
|
||||
|
||||
const fields = parse(input, {
|
||||
relaxColumnCount: true,
|
||||
skipEmptyLines: true
|
||||
})[0];
|
||||
for (const field of fields) {
|
||||
const parts = field
|
||||
.toString()
|
||||
.split(/(?<=^[^=]+?)=/)
|
||||
.map(item => item.trim());
|
||||
if (parts[0] === 'type') {
|
||||
cacheType = parts[1];
|
||||
} else if (parts[0] === 'repository') {
|
||||
ghaCacheRepository = parts[1];
|
||||
} else if (parts[0] === 'ghtoken') {
|
||||
ghaCacheGHToken = parts[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (cacheType === 'gha') {
|
||||
if (!ghaCacheRepository) {
|
||||
input = `${input},repository=${GitHub.repository}`;
|
||||
}
|
||||
if (!ghaCacheGHToken && githubToken) {
|
||||
input = `${input},ghtoken=${githubToken}`;
|
||||
}
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
public static hasLocalExporter(exporters: string[]): boolean {
|
||||
return Build.hasExporterType('local', exporters);
|
||||
}
|
||||
|
||||
public static hasTarExporter(exporters: string[]): boolean {
|
||||
return Build.hasExporterType('tar', exporters);
|
||||
}
|
||||
|
||||
public static hasDockerExporter(exporters: string[], load?: boolean): boolean {
|
||||
return load || Build.hasExporterType('docker', exporters);
|
||||
}
|
||||
|
||||
public static hasExporterType(name: string, exporters: string[]): boolean {
|
||||
const records = parse(exporters.join(`\n`), {
|
||||
delimiter: ',',
|
||||
trim: true,
|
||||
columns: false,
|
||||
relaxColumnCount: true
|
||||
});
|
||||
for (const record of records) {
|
||||
if (record.length == 1 && !record[0].startsWith('type=')) {
|
||||
// Local if no type is defined
|
||||
// https://github.com/docker/buildx/blob/d2bf42f8b4784d83fde17acb3ed84703ddc2156b/build/output.go#L29-L43
|
||||
return name == 'local';
|
||||
}
|
||||
for (const [key, value] of record.map(chunk => chunk.split('=').map(item => item.trim()))) {
|
||||
if (key == 'type' && value == name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static hasAttestationType(name: string, attrs: string): boolean {
|
||||
const records = parse(attrs, {
|
||||
delimiter: ',',
|
||||
trim: true,
|
||||
columns: false,
|
||||
relaxColumnCount: true
|
||||
});
|
||||
for (const record of records) {
|
||||
for (const [key, value] of record.map((chunk: string) => chunk.split('=').map(item => item.trim()))) {
|
||||
if (key == 'type' && value == name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static resolveAttestationAttrs(attrs: string): string {
|
||||
const records = parse(attrs, {
|
||||
delimiter: ',',
|
||||
trim: true,
|
||||
columns: false,
|
||||
relaxColumnCount: true
|
||||
});
|
||||
const res: Array<string> = [];
|
||||
for (const record of records) {
|
||||
for (const attr of record) {
|
||||
try {
|
||||
// https://github.com/docker/buildx/blob/8abef5908705e49f7ba88ef8c957e1127b597a2a/util/buildflags/attests.go#L13-L21
|
||||
const v = Util.parseBool(attr);
|
||||
res.push(`disabled=${!v}`);
|
||||
} catch (err) {
|
||||
res.push(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res.join(',');
|
||||
}
|
||||
|
||||
public static hasGitAuthTokenSecret(secrets: string[]): boolean {
|
||||
for (const secret of secrets) {
|
||||
if (secret.startsWith('GIT_AUTH_TOKEN=')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static parseSecretKvp(kvp: string): [string, string] {
|
||||
const delimiterIndex = kvp.indexOf('=');
|
||||
const key = kvp.substring(0, delimiterIndex);
|
||||
const value = kvp.substring(delimiterIndex + 1);
|
||||
if (key.length == 0 || value.length == 0) {
|
||||
throw new Error(`${kvp} is not a valid secret`);
|
||||
}
|
||||
return [key, value];
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ import * as core from '@actions/core';
|
||||
import {Buildx} from './buildx';
|
||||
import {Exec} from '../exec';
|
||||
|
||||
import {BuilderInfo, NodeInfo} from '../types/builder';
|
||||
import {BuilderInfo, GCPolicy, NodeInfo} from '../types/buildx/builder';
|
||||
|
||||
export interface BuilderOpts {
|
||||
buildx?: Buildx;
|
||||
@@ -55,11 +55,25 @@ export class Builder {
|
||||
return ok;
|
||||
}
|
||||
|
||||
public async inspect(name: string): Promise<BuilderInfo> {
|
||||
const cmd = await this.buildx.getCommand(['inspect', name]);
|
||||
public async inspect(name?: string): Promise<BuilderInfo> {
|
||||
// always enable debug for inspect command, so we can display additional
|
||||
// fields such as features: https://github.com/docker/buildx/pull/1854
|
||||
const envs = Object.assign({}, process.env, {
|
||||
DEBUG: '1'
|
||||
}) as {
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
const args = ['inspect'];
|
||||
if (name) {
|
||||
args.push(name);
|
||||
}
|
||||
|
||||
const cmd = await this.buildx.getCommand(args);
|
||||
return await Exec.getExecOutput(cmd.command, cmd.args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
silent: true,
|
||||
env: envs
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr.trim());
|
||||
@@ -72,75 +86,144 @@ export class Builder {
|
||||
const builder: BuilderInfo = {
|
||||
nodes: []
|
||||
};
|
||||
let node: NodeInfo = {};
|
||||
let parsingType: string | undefined;
|
||||
let currentNode: NodeInfo = {};
|
||||
let currentGCPolicy: GCPolicy | undefined;
|
||||
for (const line of data.trim().split(`\n`)) {
|
||||
const [key, ...rest] = line.split(':');
|
||||
const lkey = key.toLowerCase();
|
||||
const value = rest.map(v => v.trim()).join(':');
|
||||
if (key.length == 0 || value.length == 0) {
|
||||
if (key.length == 0) {
|
||||
continue;
|
||||
}
|
||||
switch (key.toLowerCase()) {
|
||||
case 'name': {
|
||||
switch (true) {
|
||||
case lkey == 'name':
|
||||
parsingType = undefined;
|
||||
if (builder.name == undefined) {
|
||||
builder.name = value;
|
||||
} else {
|
||||
if (Object.keys(node).length > 0) {
|
||||
builder.nodes.push(node);
|
||||
node = {};
|
||||
if (currentGCPolicy && currentNode.gcPolicy) {
|
||||
currentNode.gcPolicy.push(currentGCPolicy);
|
||||
currentGCPolicy = undefined;
|
||||
}
|
||||
node.name = value;
|
||||
if (currentNode.name) {
|
||||
builder.nodes.push(currentNode);
|
||||
}
|
||||
currentNode = {name: value};
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'driver': {
|
||||
case lkey == 'driver':
|
||||
parsingType = undefined;
|
||||
builder.driver = value;
|
||||
break;
|
||||
}
|
||||
case 'last activity': {
|
||||
case lkey == 'last activity':
|
||||
parsingType = undefined;
|
||||
builder.lastActivity = new Date(value);
|
||||
break;
|
||||
}
|
||||
case 'endpoint': {
|
||||
node.endpoint = value;
|
||||
case lkey == 'endpoint':
|
||||
parsingType = undefined;
|
||||
currentNode.endpoint = value;
|
||||
break;
|
||||
}
|
||||
case 'driver options': {
|
||||
node['driver-opts'] = (value.match(/([a-zA-Z0-9_.]+)="([^"]*)"/g) || []).map(v => v.replace(/^(.*)="(.*)"$/g, '$1=$2'));
|
||||
case lkey == 'driver options':
|
||||
parsingType = undefined;
|
||||
currentNode['driver-opts'] = (value.match(/([a-zA-Z0-9_.]+)="([^"]*)"/g) || []).map(v => v.replace(/^(.*)="(.*)"$/g, '$1=$2'));
|
||||
break;
|
||||
}
|
||||
case 'status': {
|
||||
node.status = value;
|
||||
case lkey == 'status':
|
||||
parsingType = undefined;
|
||||
currentNode.status = value;
|
||||
break;
|
||||
}
|
||||
case 'flags': {
|
||||
node['buildkitd-flags'] = value;
|
||||
case lkey == 'buildkit daemon flags':
|
||||
case lkey == 'flags': // buildx < v0.13
|
||||
parsingType = undefined;
|
||||
currentNode['buildkitd-flags'] = value;
|
||||
break;
|
||||
}
|
||||
case 'buildkit': {
|
||||
node.buildkit = value;
|
||||
case lkey == 'buildkit version':
|
||||
case lkey == 'buildkit': // buildx < v0.13
|
||||
parsingType = undefined;
|
||||
currentNode.buildkit = value;
|
||||
break;
|
||||
}
|
||||
case 'platforms': {
|
||||
case lkey == 'platforms': {
|
||||
parsingType = undefined;
|
||||
if (!value) {
|
||||
break;
|
||||
}
|
||||
let platforms: Array<string> = [];
|
||||
// if a preferred platform is being set then use only these
|
||||
// https://docs.docker.com/engine/reference/commandline/buildx_inspect/#get-information-about-a-builder-instance
|
||||
if (value.includes('*')) {
|
||||
for (const platform of value.split(', ')) {
|
||||
if (platform.includes('*')) {
|
||||
platforms.push(platform.replace('*', ''));
|
||||
platforms.push(platform.replace(/\*/g, ''));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// otherwise set all platforms available
|
||||
platforms = value.split(', ');
|
||||
}
|
||||
node.platforms = platforms.join(',');
|
||||
currentNode.platforms = platforms.join(',');
|
||||
break;
|
||||
}
|
||||
case lkey == 'features':
|
||||
parsingType = 'features';
|
||||
currentNode.features = {};
|
||||
break;
|
||||
case lkey == 'labels':
|
||||
parsingType = 'label';
|
||||
currentNode.labels = {};
|
||||
break;
|
||||
case lkey.startsWith('gc policy rule#'):
|
||||
parsingType = 'gcpolicy';
|
||||
if (currentNode.gcPolicy && currentGCPolicy) {
|
||||
currentNode.gcPolicy.push(currentGCPolicy);
|
||||
currentGCPolicy = undefined;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
switch (parsingType || '') {
|
||||
case 'features': {
|
||||
currentNode.features = currentNode.features || {};
|
||||
currentNode.features[key.trim()] = Boolean(value);
|
||||
break;
|
||||
}
|
||||
case 'label': {
|
||||
currentNode.labels = currentNode.labels || {};
|
||||
currentNode.labels[key.trim()] = value;
|
||||
break;
|
||||
}
|
||||
case 'gcpolicy': {
|
||||
currentNode.gcPolicy = currentNode.gcPolicy || [];
|
||||
currentGCPolicy = currentGCPolicy || {};
|
||||
switch (lkey.trim()) {
|
||||
case 'all': {
|
||||
currentGCPolicy.all = value == 'true';
|
||||
break;
|
||||
}
|
||||
case 'filters': {
|
||||
if (value) {
|
||||
currentGCPolicy.filter = value.split(',');
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'keep duration': {
|
||||
currentGCPolicy.keepDuration = value;
|
||||
break;
|
||||
}
|
||||
case 'keep bytes': {
|
||||
currentGCPolicy.keepBytes = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Object.keys(node).length > 0) {
|
||||
builder.nodes.push(node);
|
||||
if (currentGCPolicy && currentNode.gcPolicy) {
|
||||
currentNode.gcPolicy.push(currentGCPolicy);
|
||||
}
|
||||
if (currentNode.name) {
|
||||
builder.nodes.push(currentNode);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import * as semver from 'semver';
|
||||
import {Docker} from '../docker/docker';
|
||||
import {Exec} from '../exec';
|
||||
|
||||
import {Cert} from '../types/buildx';
|
||||
import {Cert, LocalRefsOpts, LocalRefsResponse, LocalState} from '../types/buildx/buildx';
|
||||
|
||||
export interface BuildxOpts {
|
||||
standalone?: boolean;
|
||||
@@ -45,6 +45,14 @@ export class Buildx {
|
||||
return process.env.BUILDX_CONFIG || path.join(Docker.configDir, 'buildx');
|
||||
}
|
||||
|
||||
static get refsDir(): string {
|
||||
return path.join(Buildx.configDir, 'refs');
|
||||
}
|
||||
|
||||
static get refsGroupDir(): string {
|
||||
return path.join(Buildx.refsDir, '__group__');
|
||||
}
|
||||
|
||||
static get certsDir(): string {
|
||||
return path.join(Buildx.configDir, 'certs');
|
||||
}
|
||||
@@ -86,13 +94,6 @@ export class Buildx {
|
||||
return ok;
|
||||
}
|
||||
|
||||
public async printInspect(name: string): Promise<void> {
|
||||
const cmd = await this.getCommand(['inspect', name]);
|
||||
await Exec.exec(cmd.command, cmd.args, {
|
||||
failOnStdErr: false
|
||||
});
|
||||
}
|
||||
|
||||
public async version(): Promise<string> {
|
||||
if (this._versionOnce) {
|
||||
return this._version;
|
||||
@@ -175,4 +176,94 @@ export class Buildx {
|
||||
}
|
||||
return driverOpts;
|
||||
}
|
||||
|
||||
public static localState(ref: string, dir?: string): LocalState {
|
||||
const [builderName, nodeName, id] = ref.split('/');
|
||||
if (!builderName || !nodeName || !id) {
|
||||
throw new Error(`Invalid build reference: ${ref}`);
|
||||
}
|
||||
const lsPath = path.join(dir || Buildx.refsDir, builderName, nodeName, id);
|
||||
if (!fs.existsSync(lsPath)) {
|
||||
throw new Error(`Local state not found in ${lsPath}`);
|
||||
}
|
||||
return Buildx.fixLocalState(<LocalState>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:\/{1,2}\S+|git:\/{1,2}\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('ssh:/', 'ssh://');
|
||||
}
|
||||
if (url.startsWith('git:/') && !url.startsWith('git://')) {
|
||||
url = url.replace('git:/', '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;
|
||||
|
||||
let dirpath = path.resolve(dir);
|
||||
if (opts.builderName) {
|
||||
dirpath = path.join(dirpath, opts.builderName);
|
||||
}
|
||||
if (opts.nodeName) {
|
||||
dirpath = path.join(dirpath, opts.nodeName);
|
||||
}
|
||||
if (!fs.existsSync(dirpath)) {
|
||||
return refs;
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(dirpath);
|
||||
for (const file of files) {
|
||||
const filePath = path.join(dirpath, file);
|
||||
const stat = fs.statSync(filePath);
|
||||
if (stat.isDirectory()) {
|
||||
const nopts: LocalRefsOpts = {...opts};
|
||||
if (!builderName) {
|
||||
if (file === '__group__') {
|
||||
continue;
|
||||
}
|
||||
nopts.builderName = file;
|
||||
} else if (!nodeName) {
|
||||
nopts.nodeName = file;
|
||||
}
|
||||
Buildx.refs(nopts, refs);
|
||||
} else {
|
||||
if (since && stat.mtime < since) {
|
||||
continue;
|
||||
}
|
||||
const localState = Buildx.fixLocalState(<LocalState>JSON.parse(fs.readFileSync(filePath, 'utf8')));
|
||||
const ref = `${builderName}/${nodeName}/${file}`;
|
||||
refs[ref] = localState;
|
||||
}
|
||||
}
|
||||
|
||||
return refs;
|
||||
}
|
||||
}
|
||||
|
||||
211
src/buildx/history.ts
Normal file
211
src/buildx/history.ts
Normal file
@@ -0,0 +1,211 @@
|
||||
/**
|
||||
* Copyright 2024 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 {ChildProcessByStdio, spawn} from 'child_process';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import {Readable, Writable} from 'stream';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
import {Buildx} from './buildx';
|
||||
import {Context} from '../context';
|
||||
import {Docker} from '../docker/docker';
|
||||
import {Exec} from '../exec';
|
||||
import {GitHub} from '../github';
|
||||
|
||||
import {ExportRecordOpts, ExportRecordResponse, Summaries} from '../types/buildx/history';
|
||||
|
||||
export interface HistoryOpts {
|
||||
buildx?: Buildx;
|
||||
}
|
||||
|
||||
export class History {
|
||||
private readonly buildx: Buildx;
|
||||
|
||||
private static readonly EXPORT_BUILD_IMAGE_DEFAULT: string = 'docker.io/dockereng/export-build:latest';
|
||||
private static readonly EXPORT_BUILD_IMAGE_ENV: string = 'DOCKER_BUILD_EXPORT_BUILD_IMAGE';
|
||||
|
||||
constructor(opts?: HistoryOpts) {
|
||||
this.buildx = opts?.buildx || new Buildx();
|
||||
}
|
||||
|
||||
public async export(opts: ExportRecordOpts): Promise<ExportRecordResponse> {
|
||||
if (os.platform() === 'win32') {
|
||||
throw new Error('Exporting a build record is currently not supported on Windows');
|
||||
}
|
||||
if (!(await Docker.isAvailable())) {
|
||||
throw new Error('Docker is required to export a build record');
|
||||
}
|
||||
if (!(await Docker.isDaemonRunning())) {
|
||||
throw new Error('Docker daemon is not running, skipping build record export');
|
||||
}
|
||||
if (!(await this.buildx.versionSatisfies('>=0.13.0'))) {
|
||||
throw new Error('Buildx >= 0.13.0 is required to export a build record');
|
||||
}
|
||||
|
||||
let builderName: string = '';
|
||||
let nodeName: string = '';
|
||||
const refs: Array<string> = [];
|
||||
for (const ref of opts.refs) {
|
||||
const refParts = ref.split('/');
|
||||
if (refParts.length != 3) {
|
||||
throw new Error(`Invalid build ref: ${ref}`);
|
||||
}
|
||||
refs.push(refParts[2]);
|
||||
|
||||
// Set builder name and node name from the first ref if not already set.
|
||||
// We assume all refs are from the same builder and node.
|
||||
if (!builderName) {
|
||||
builderName = refParts[0];
|
||||
}
|
||||
if (!nodeName) {
|
||||
nodeName = refParts[1];
|
||||
}
|
||||
}
|
||||
if (refs.length === 0) {
|
||||
throw new Error('No build refs provided');
|
||||
}
|
||||
|
||||
const outDir = path.join(Context.tmpDir(), 'export');
|
||||
core.info(`exporting build record to ${outDir}`);
|
||||
fs.mkdirSync(outDir, {recursive: true});
|
||||
|
||||
const buildxInFifoPath = Context.tmpName({
|
||||
template: 'buildx-in-XXXXXX.fifo',
|
||||
tmpdir: Context.tmpDir()
|
||||
});
|
||||
await Exec.exec('mkfifo', [buildxInFifoPath]);
|
||||
|
||||
const buildxOutFifoPath = Context.tmpName({
|
||||
template: 'buildx-out-XXXXXX.fifo',
|
||||
tmpdir: Context.tmpDir()
|
||||
});
|
||||
await Exec.exec('mkfifo', [buildxOutFifoPath]);
|
||||
|
||||
const buildxDialStdioCmd = await this.buildx.getCommand(['--builder', builderName, 'dial-stdio']);
|
||||
core.info(`[command]${buildxDialStdioCmd.command} ${buildxDialStdioCmd.args.join(' ')}`);
|
||||
const buildxDialStdioProc = spawn(buildxDialStdioCmd.command, buildxDialStdioCmd.args, {
|
||||
stdio: ['pipe', 'pipe', 'inherit'],
|
||||
detached: true
|
||||
});
|
||||
let buildxDialStdioKilled = false;
|
||||
fs.createReadStream(buildxInFifoPath).pipe(buildxDialStdioProc.stdin);
|
||||
buildxDialStdioProc.stdout.pipe(fs.createWriteStream(buildxOutFifoPath));
|
||||
buildxDialStdioProc.on('exit', (code, signal) => {
|
||||
buildxDialStdioKilled = true;
|
||||
if (signal) {
|
||||
core.info(`Process "buildx dial-stdio" was killed with signal ${signal}`);
|
||||
} else {
|
||||
core.info(`Process "buildx dial-stdio" exited with code ${code}`);
|
||||
}
|
||||
});
|
||||
|
||||
const tmpDockerbuildFilename = path.join(outDir, 'rec.dockerbuild');
|
||||
const summaryFilename = path.join(outDir, 'summary.json');
|
||||
|
||||
let dockerRunProc: ChildProcessByStdio<Writable, Readable, null> | undefined;
|
||||
let dockerRunProcKilled = false;
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const ebargs: Array<string> = ['--ref-state-dir=/buildx-refs', `--node=${builderName}/${nodeName}`];
|
||||
for (const ref of refs) {
|
||||
ebargs.push(`--ref=${ref}`);
|
||||
}
|
||||
if (typeof process.getuid === 'function') {
|
||||
ebargs.push(`--uid=${process.getuid()}`);
|
||||
}
|
||||
if (typeof process.getgid === 'function') {
|
||||
ebargs.push(`--gid=${process.getgid()}`);
|
||||
}
|
||||
// prettier-ignore
|
||||
const dockerRunArgs = [
|
||||
'run', '--rm', '-i',
|
||||
'-v', `${Buildx.refsDir}:/buildx-refs`,
|
||||
'-v', `${outDir}:/out`,
|
||||
opts.image || process.env[History.EXPORT_BUILD_IMAGE_ENV] || History.EXPORT_BUILD_IMAGE_DEFAULT,
|
||||
...ebargs
|
||||
]
|
||||
core.info(`[command]docker ${dockerRunArgs.join(' ')}`);
|
||||
dockerRunProc = spawn('docker', dockerRunArgs, {
|
||||
stdio: ['pipe', 'pipe', 'inherit'],
|
||||
env: {
|
||||
...process.env,
|
||||
DOCKER_CONTENT_TRUST: 'false'
|
||||
}
|
||||
});
|
||||
fs.createReadStream(buildxOutFifoPath).pipe(dockerRunProc.stdin);
|
||||
dockerRunProc.stdout.pipe(fs.createWriteStream(buildxInFifoPath));
|
||||
dockerRunProc.on('close', code => {
|
||||
if (code === 0) {
|
||||
if (!fs.existsSync(tmpDockerbuildFilename)) {
|
||||
reject(new Error(`Failed to export build record: ${tmpDockerbuildFilename} not found`));
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
} else {
|
||||
reject(new Error(`Process "docker run" closed with code ${code}`));
|
||||
}
|
||||
});
|
||||
dockerRunProc.on('error', err => {
|
||||
core.error(`Error executing "docker run": ${err}`);
|
||||
reject(err);
|
||||
});
|
||||
dockerRunProc.on('exit', (code, signal) => {
|
||||
dockerRunProcKilled = true;
|
||||
if (signal) {
|
||||
core.info(`Process "docker run" was killed with signal ${signal}`);
|
||||
} else {
|
||||
core.info(`Process "docker run" exited with code ${code}`);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
if (buildxDialStdioProc && !buildxDialStdioKilled) {
|
||||
core.debug('Force terminating "buildx dial-stdio" process');
|
||||
buildxDialStdioProc.kill('SIGKILL');
|
||||
}
|
||||
if (dockerRunProc && !dockerRunProcKilled) {
|
||||
core.debug('Force terminating "docker run" process');
|
||||
dockerRunProc.kill('SIGKILL');
|
||||
}
|
||||
});
|
||||
|
||||
let dockerbuildFilename = `${GitHub.context.repo.owner}~${GitHub.context.repo.repo}~${refs[0].substring(0, 6).toUpperCase()}`;
|
||||
if (refs.length > 1) {
|
||||
dockerbuildFilename += `+${refs.length - 1}`;
|
||||
}
|
||||
|
||||
const dockerbuildPath = path.join(outDir, `${dockerbuildFilename}.dockerbuild`);
|
||||
fs.renameSync(tmpDockerbuildFilename, dockerbuildPath);
|
||||
const dockerbuildStats = fs.statSync(dockerbuildPath);
|
||||
|
||||
core.info(`Parsing ${summaryFilename}`);
|
||||
fs.statSync(summaryFilename);
|
||||
const summaries = <Summaries>JSON.parse(fs.readFileSync(summaryFilename, {encoding: 'utf-8'}));
|
||||
|
||||
return {
|
||||
dockerbuildFilename: dockerbuildPath,
|
||||
dockerbuildSize: dockerbuildStats.size,
|
||||
summaries: summaries,
|
||||
builderName: builderName,
|
||||
nodeName: nodeName,
|
||||
refs: refs
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
/**
|
||||
* 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 fs from 'fs';
|
||||
import path from 'path';
|
||||
import * as core from '@actions/core';
|
||||
import {parse} from 'csv-parse/sync';
|
||||
|
||||
import {Context} from '../context';
|
||||
|
||||
const parseKvp = (kvp: string): [string, string] => {
|
||||
const delimiterIndex = kvp.indexOf('=');
|
||||
const key = kvp.substring(0, delimiterIndex);
|
||||
const value = kvp.substring(delimiterIndex + 1);
|
||||
|
||||
if (key.length == 0 || value.length == 0) {
|
||||
throw new Error(`${kvp} is not a valid secret`);
|
||||
}
|
||||
|
||||
return [key, value];
|
||||
};
|
||||
|
||||
export class Inputs {
|
||||
public static getBuildImageIDFilePath(): string {
|
||||
return path.join(Context.tmpDir(), 'iidfile');
|
||||
}
|
||||
|
||||
public static getBuildMetadataFilePath(): string {
|
||||
return path.join(Context.tmpDir(), 'metadata-file');
|
||||
}
|
||||
|
||||
public static resolveBuildImageID(): string | undefined {
|
||||
const iidFile = Inputs.getBuildImageIDFilePath();
|
||||
if (!fs.existsSync(iidFile)) {
|
||||
return undefined;
|
||||
}
|
||||
return fs.readFileSync(iidFile, {encoding: 'utf-8'}).trim();
|
||||
}
|
||||
|
||||
public static resolveBuildMetadata(): string | undefined {
|
||||
const metadataFile = Inputs.getBuildMetadataFilePath();
|
||||
if (!fs.existsSync(metadataFile)) {
|
||||
return undefined;
|
||||
}
|
||||
const content = fs.readFileSync(metadataFile, {encoding: 'utf-8'}).trim();
|
||||
if (content === 'null') {
|
||||
return undefined;
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
public static resolveDigest(): string | undefined {
|
||||
const metadata = Inputs.resolveBuildMetadata();
|
||||
if (metadata === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const metadataJSON = JSON.parse(metadata);
|
||||
if (metadataJSON['containerimage.digest']) {
|
||||
return metadataJSON['containerimage.digest'];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public static resolveBuildSecretString(kvp: string): string {
|
||||
return Inputs.resolveBuildSecret(kvp, false);
|
||||
}
|
||||
|
||||
public static resolveBuildSecretFile(kvp: string): string {
|
||||
return Inputs.resolveBuildSecret(kvp, true);
|
||||
}
|
||||
|
||||
public static resolveBuildSecretEnv(kvp: string): string {
|
||||
const [key, value] = parseKvp(kvp);
|
||||
|
||||
return `id=${key},env="${value}"`;
|
||||
}
|
||||
|
||||
public static resolveBuildSecret(kvp: string, file: boolean): string {
|
||||
const [key, _value] = parseKvp(kvp);
|
||||
|
||||
let value = _value;
|
||||
|
||||
if (file) {
|
||||
if (!fs.existsSync(value)) {
|
||||
throw new Error(`secret file ${value} not found`);
|
||||
}
|
||||
value = fs.readFileSync(value, {encoding: 'utf-8'});
|
||||
}
|
||||
const secretFile = Context.tmpName({tmpdir: Context.tmpDir()});
|
||||
fs.writeFileSync(secretFile, value);
|
||||
return `id=${key},src=${secretFile}`;
|
||||
}
|
||||
|
||||
public static getProvenanceInput(name: string): string {
|
||||
const input = core.getInput(name);
|
||||
if (!input) {
|
||||
// if input is not set returns empty string
|
||||
return input;
|
||||
}
|
||||
try {
|
||||
return core.getBooleanInput(name) ? `builder-id=${Context.provenanceBuilderID()}` : 'false';
|
||||
} catch (err) {
|
||||
// not a valid boolean, so we assume it's a string
|
||||
return Inputs.resolveProvenanceAttrs(input);
|
||||
}
|
||||
}
|
||||
|
||||
public static resolveProvenanceAttrs(input: string): string {
|
||||
if (!input) {
|
||||
return `builder-id=${Context.provenanceBuilderID()}`;
|
||||
}
|
||||
// parse attributes from input
|
||||
const fields = parse(input, {
|
||||
relaxColumnCount: true,
|
||||
skipEmptyLines: true
|
||||
})[0];
|
||||
// check if builder-id attribute exists in the input
|
||||
for (const field of fields) {
|
||||
const parts = field
|
||||
.toString()
|
||||
.split(/(?<=^[^=]+?)=/)
|
||||
.map(item => item.trim());
|
||||
if (parts[0] == 'builder-id') {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
// if not add builder-id attribute
|
||||
return `${input},builder-id=${Context.provenanceBuilderID()}`;
|
||||
}
|
||||
|
||||
public static hasLocalExporter(exporters: string[]): boolean {
|
||||
return Inputs.hasExporterType('local', exporters);
|
||||
}
|
||||
|
||||
public static hasTarExporter(exporters: string[]): boolean {
|
||||
return Inputs.hasExporterType('tar', exporters);
|
||||
}
|
||||
|
||||
public static hasDockerExporter(exporters: string[], load?: boolean): boolean {
|
||||
return load || Inputs.hasExporterType('docker', exporters);
|
||||
}
|
||||
|
||||
public static hasExporterType(name: string, exporters: string[]): boolean {
|
||||
const records = parse(exporters.join(`\n`), {
|
||||
delimiter: ',',
|
||||
trim: true,
|
||||
columns: false,
|
||||
relaxColumnCount: true
|
||||
});
|
||||
for (const record of records) {
|
||||
if (record.length == 1 && !record[0].startsWith('type=')) {
|
||||
// Local if no type is defined
|
||||
// https://github.com/docker/buildx/blob/d2bf42f8b4784d83fde17acb3ed84703ddc2156b/build/output.go#L29-L43
|
||||
return name == 'local';
|
||||
}
|
||||
for (const [key, value] of record.map(chunk => chunk.split('=').map(item => item.trim()))) {
|
||||
if (key == 'type' && value == name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static hasGitAuthTokenSecret(secrets: string[]): boolean {
|
||||
for (const secret of secrets) {
|
||||
if (secret.startsWith('GIT_AUTH_TOKEN=')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -24,11 +24,14 @@ import * as semver from 'semver';
|
||||
import * as util from 'util';
|
||||
|
||||
import {Buildx} from './buildx';
|
||||
import {Cache} from '../cache';
|
||||
import {Context} from '../context';
|
||||
import {Exec} from '../exec';
|
||||
import {Docker} from '../docker/docker';
|
||||
import {Git} from '../git';
|
||||
import {Util} from '../util';
|
||||
|
||||
import {DownloadVersion} from '../types/buildx/buildx';
|
||||
import {GitHubRelease} from '../types/github';
|
||||
|
||||
export interface InstallOpts {
|
||||
@@ -42,70 +45,104 @@ export class Install {
|
||||
this._standalone = opts?.standalone;
|
||||
}
|
||||
|
||||
public async download(version: string): Promise<string> {
|
||||
/*
|
||||
* Download buildx binary from GitHub release
|
||||
* @param v: version semver version or latest
|
||||
* @param ghaNoCache: disable binary caching in GitHub Actions cache backend
|
||||
* @returns path to the buildx binary
|
||||
*/
|
||||
public async download(v: string, ghaNoCache?: boolean): Promise<string> {
|
||||
const version: DownloadVersion = await Install.getDownloadVersion(v);
|
||||
core.debug(`Install.download version: ${version.version}`);
|
||||
|
||||
const release: GitHubRelease = await Install.getRelease(version);
|
||||
const fversion = release.tag_name.replace(/^v+|v+$/g, '');
|
||||
core.debug(`Install.download version: ${fversion}`);
|
||||
core.debug(`Install.download release tag name: ${release.tag_name}`);
|
||||
|
||||
let toolPath: string;
|
||||
toolPath = tc.find('buildx', fversion, this.platform());
|
||||
if (!toolPath) {
|
||||
const c = semver.clean(fversion) || '';
|
||||
if (!semver.valid(c)) {
|
||||
throw new Error(`Invalid Buildx version "${fversion}".`);
|
||||
const vspec = await this.vspec(release.tag_name);
|
||||
core.debug(`Install.download vspec: ${vspec}`);
|
||||
|
||||
const c = semver.clean(vspec) || '';
|
||||
if (!semver.valid(c)) {
|
||||
throw new Error(`Invalid Buildx version "${vspec}".`);
|
||||
}
|
||||
|
||||
const installCache = new Cache({
|
||||
htcName: version.key != 'official' ? `buildx-dl-bin-${version.key}` : 'buildx-dl-bin',
|
||||
htcVersion: vspec,
|
||||
baseCacheDir: path.join(Buildx.configDir, '.bin'),
|
||||
cacheFile: os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx',
|
||||
ghaNoCache: ghaNoCache
|
||||
});
|
||||
|
||||
const cacheFoundPath = await installCache.find();
|
||||
if (cacheFoundPath) {
|
||||
core.info(`Buildx binary found in ${cacheFoundPath}`);
|
||||
return cacheFoundPath;
|
||||
}
|
||||
|
||||
const downloadURL = util.format(version.downloadURL, vspec, this.filename(vspec));
|
||||
core.info(`Downloading ${downloadURL}`);
|
||||
|
||||
const htcDownloadPath = await tc.downloadTool(downloadURL);
|
||||
core.debug(`Install.download htcDownloadPath: ${htcDownloadPath}`);
|
||||
|
||||
const cacheSavePath = await installCache.save(htcDownloadPath);
|
||||
core.info(`Cached to ${cacheSavePath}`);
|
||||
return cacheSavePath;
|
||||
}
|
||||
|
||||
/*
|
||||
* Build buildx binary from source
|
||||
* @param gitContext: git repo context
|
||||
* @param ghaNoCache: disable binary caching in GitHub Actions cache backend
|
||||
* @returns path to the buildx binary
|
||||
*/
|
||||
public async build(gitContext: string, ghaNoCache?: boolean): Promise<string> {
|
||||
const vspec = await this.vspec(gitContext);
|
||||
core.debug(`Install.build vspec: ${vspec}`);
|
||||
|
||||
const installCache = new Cache({
|
||||
htcName: 'buildx-build-bin',
|
||||
htcVersion: vspec,
|
||||
baseCacheDir: path.join(Buildx.configDir, '.bin'),
|
||||
cacheFile: os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx',
|
||||
ghaNoCache: ghaNoCache
|
||||
});
|
||||
|
||||
const cacheFoundPath = await installCache.find();
|
||||
if (cacheFoundPath) {
|
||||
core.info(`Buildx binary found in ${cacheFoundPath}`);
|
||||
return cacheFoundPath;
|
||||
}
|
||||
|
||||
const outputDir = path.join(Context.tmpDir(), 'buildx-build-cache');
|
||||
const buildCmd = await this.buildCommand(gitContext, outputDir);
|
||||
|
||||
const buildBinPath = await Exec.getExecOutput(buildCmd.command, buildCmd.args, {
|
||||
ignoreReturnCode: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(`build failed with: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
|
||||
}
|
||||
toolPath = await this.fetchBinary(fversion);
|
||||
}
|
||||
core.debug(`Install.download toolPath: ${toolPath}`);
|
||||
return `${outputDir}/buildx`;
|
||||
});
|
||||
|
||||
return toolPath;
|
||||
const cacheSavePath = await installCache.save(buildBinPath);
|
||||
core.info(`Cached to ${cacheSavePath}`);
|
||||
return cacheSavePath;
|
||||
}
|
||||
|
||||
public async build(gitContext: string): Promise<string> {
|
||||
// eslint-disable-next-line prefer-const
|
||||
let [repo, ref] = gitContext.split('#');
|
||||
if (ref.length == 0) {
|
||||
ref = 'master';
|
||||
}
|
||||
|
||||
let vspec: string;
|
||||
// TODO: include full ref as fingerprint. Use commit sha as best-effort in the meantime.
|
||||
if (ref.match(/^[0-9a-fA-F]{40}$/)) {
|
||||
vspec = ref;
|
||||
} else {
|
||||
vspec = await Git.remoteSha(repo, ref, process.env.GIT_AUTH_TOKEN);
|
||||
}
|
||||
core.debug(`Install.build: tool version spec ${vspec}`);
|
||||
|
||||
let toolPath: string;
|
||||
toolPath = tc.find('buildx', vspec);
|
||||
if (!toolPath) {
|
||||
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) {
|
||||
throw new Error(`build failed with: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
|
||||
}
|
||||
return tc.cacheFile(`${outputDir}/buildx`, os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx', 'buildx', vspec, this.platform());
|
||||
});
|
||||
}
|
||||
|
||||
return toolPath;
|
||||
}
|
||||
|
||||
public async installStandalone(toolPath: string, dest?: string): Promise<string> {
|
||||
public async installStandalone(binPath: 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');
|
||||
|
||||
const binDir = path.join(dest, 'buildx-bin-standalone');
|
||||
if (!fs.existsSync(binDir)) {
|
||||
fs.mkdirSync(binDir, {recursive: true});
|
||||
}
|
||||
const filename: string = os.platform() == 'win32' ? 'buildx.exe' : 'buildx';
|
||||
const buildxPath: string = path.join(binDir, filename);
|
||||
fs.copyFileSync(toolBinPath, buildxPath);
|
||||
const binName: string = os.platform() == 'win32' ? 'buildx.exe' : 'buildx';
|
||||
const buildxPath: string = path.join(binDir, binName);
|
||||
fs.copyFileSync(binPath, buildxPath);
|
||||
|
||||
core.info('Fixing perms');
|
||||
fs.chmodSync(buildxPath, '0755');
|
||||
@@ -117,17 +154,17 @@ export class Install {
|
||||
return buildxPath;
|
||||
}
|
||||
|
||||
public async installPlugin(toolPath: string, dest?: string): Promise<string> {
|
||||
public async installPlugin(binPath: 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)) {
|
||||
fs.mkdirSync(pluginsDir, {recursive: true});
|
||||
}
|
||||
const filename: string = os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx';
|
||||
const pluginPath: string = path.join(pluginsDir, filename);
|
||||
fs.copyFileSync(toolBinPath, pluginPath);
|
||||
const binName: string = os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx';
|
||||
const pluginPath: string = path.join(pluginsDir, binName);
|
||||
fs.copyFileSync(binPath, pluginPath);
|
||||
|
||||
core.info('Fixing perms');
|
||||
fs.chmodSync(pluginPath, '0755');
|
||||
@@ -157,7 +194,7 @@ export class Install {
|
||||
throw new Error(`Neither buildx standalone or plugin have been found to build from ref ${gitContext}`);
|
||||
}
|
||||
|
||||
const args = ['build', '--target', 'binaries', '--build-arg', 'BUILDKIT_CONTEXT_KEEP_GIT_DIR=1', '--output', `type=local,dest=${outputDir}`];
|
||||
const args = ['build', '--target', 'binaries', '--platform', 'local', '--build-arg', 'BUILDKIT_CONTEXT_KEEP_GIT_DIR=1', '--output', `type=local,dest=${outputDir}`];
|
||||
if (process.env.GIT_AUTH_TOKEN) {
|
||||
args.push('--secret', 'id=GIT_AUTH_TOKEN');
|
||||
}
|
||||
@@ -173,21 +210,6 @@ export class Install {
|
||||
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(`Install.fetchBinary downloadPath: ${downloadPath}`);
|
||||
return await tc.cacheFile(downloadPath, targetFile, 'buildx', version, this.platform());
|
||||
}
|
||||
|
||||
private platform(): string {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const arm_version = (process.config.variables as any).arm_version;
|
||||
return `${os.platform()}-${os.arch()}${arm_version ? 'v' + arm_version : ''}`;
|
||||
}
|
||||
|
||||
private filename(version: string): string {
|
||||
let arch: string;
|
||||
switch (os.arch()) {
|
||||
@@ -215,19 +237,80 @@ export class Install {
|
||||
return util.format('buildx-v%s.%s-%s%s', version, platform, arch, ext);
|
||||
}
|
||||
|
||||
public static async getRelease(version: string): Promise<GitHubRelease> {
|
||||
const url = `https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/buildx-releases.json`;
|
||||
/*
|
||||
* Get version spec (fingerprint) for cache key. If versionOrRef is a valid
|
||||
* Git context, then return the SHA of the ref along the repo and owner and
|
||||
* create a hash of it. Otherwise, return the versionOrRef (semver) as is
|
||||
* without the 'v' prefix.
|
||||
*/
|
||||
private async vspec(versionOrRef: string): Promise<string> {
|
||||
if (!Util.isValidRef(versionOrRef)) {
|
||||
const v = versionOrRef.replace(/^v+|v+$/g, '');
|
||||
core.info(`Use ${v} version spec cache key for ${versionOrRef}`);
|
||||
return v;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line prefer-const
|
||||
let [baseURL, ref] = versionOrRef.split('#');
|
||||
if (ref.length == 0) {
|
||||
ref = 'master';
|
||||
}
|
||||
|
||||
let sha: string;
|
||||
if (ref.match(/^[0-9a-fA-F]{40}$/)) {
|
||||
sha = ref;
|
||||
} else {
|
||||
sha = await Git.remoteSha(baseURL, ref, process.env.GIT_AUTH_TOKEN);
|
||||
}
|
||||
|
||||
const [owner, repo] = baseURL.substring('https://github.com/'.length).split('/');
|
||||
const key = `${owner}/${Util.trimSuffix(repo, '.git')}/${sha}`;
|
||||
const hash = Util.hash(key);
|
||||
core.info(`Use ${hash} version spec cache key for ${key}`);
|
||||
return hash;
|
||||
}
|
||||
|
||||
public static async getDownloadVersion(v: string): Promise<DownloadVersion> {
|
||||
let [repoKey, version] = v.split(':');
|
||||
if (!version) {
|
||||
version = repoKey;
|
||||
repoKey = 'official';
|
||||
}
|
||||
switch (repoKey) {
|
||||
case 'official': {
|
||||
return {
|
||||
key: repoKey,
|
||||
version: version,
|
||||
downloadURL: 'https://github.com/docker/buildx/releases/download/v%s/%s',
|
||||
releasesURL: 'https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/buildx-releases.json'
|
||||
};
|
||||
}
|
||||
case 'lab': {
|
||||
return {
|
||||
key: repoKey,
|
||||
version: version,
|
||||
downloadURL: 'https://github.com/docker/buildx-desktop/releases/download/v%s/%s',
|
||||
releasesURL: 'https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/buildx-lab-releases.json'
|
||||
};
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Cannot find buildx version for ${v}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async getRelease(version: DownloadVersion): Promise<GitHubRelease> {
|
||||
const http: httpm.HttpClient = new httpm.HttpClient('docker-actions-toolkit');
|
||||
const resp: httpm.HttpClientResponse = await http.get(url);
|
||||
const resp: httpm.HttpClientResponse = await http.get(version.releasesURL);
|
||||
const body = await resp.readBody();
|
||||
const statusCode = resp.message.statusCode || 500;
|
||||
if (statusCode >= 400) {
|
||||
throw new Error(`Failed to get Buildx release ${version} from ${url} with status code ${statusCode}: ${body}`);
|
||||
throw new Error(`Failed to get Buildx releases from ${version.releasesURL} with status code ${statusCode}: ${body}`);
|
||||
}
|
||||
const releases = <Record<string, GitHubRelease>>JSON.parse(body);
|
||||
if (!releases[version]) {
|
||||
throw new Error(`Cannot find Buildx release ${version} in ${url}`);
|
||||
if (!releases[version.version]) {
|
||||
throw new Error(`Cannot find Buildx release ${version.version} in ${version.releasesURL}`);
|
||||
}
|
||||
return releases[version];
|
||||
return releases[version.version];
|
||||
}
|
||||
}
|
||||
|
||||
134
src/cache.ts
Normal file
134
src/cache.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* 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 fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import * as core from '@actions/core';
|
||||
import * as tc from '@actions/tool-cache';
|
||||
import * as cache from '@actions/cache';
|
||||
import * as util from 'util';
|
||||
|
||||
export interface CacheOpts {
|
||||
htcName: string;
|
||||
htcVersion: string;
|
||||
baseCacheDir: string;
|
||||
cacheFile: string;
|
||||
ghaNoCache?: boolean;
|
||||
}
|
||||
|
||||
export interface CachePostState {
|
||||
dir: string;
|
||||
key: string;
|
||||
}
|
||||
|
||||
export class Cache {
|
||||
private readonly opts: CacheOpts;
|
||||
private readonly ghaCacheKey: string;
|
||||
private readonly ghaNoCache?: boolean;
|
||||
private readonly cacheDir: string;
|
||||
private readonly cachePath: string;
|
||||
|
||||
private static readonly POST_CACHE_KEY = 'postCache';
|
||||
|
||||
constructor(opts: CacheOpts) {
|
||||
this.opts = opts;
|
||||
this.ghaCacheKey = util.format('%s-%s-%s', this.opts.htcName, this.opts.htcVersion, this.platform());
|
||||
this.ghaNoCache = this.opts.ghaNoCache;
|
||||
this.cacheDir = path.join(this.opts.baseCacheDir, this.opts.htcVersion, this.platform());
|
||||
this.cachePath = path.join(this.cacheDir, this.opts.cacheFile);
|
||||
if (!fs.existsSync(this.cacheDir)) {
|
||||
fs.mkdirSync(this.cacheDir, {recursive: true});
|
||||
}
|
||||
}
|
||||
|
||||
public async save(file: string): Promise<string> {
|
||||
core.debug(`Cache.save ${file}`);
|
||||
const cachePath = this.copyToCache(file);
|
||||
|
||||
const htcPath = await tc.cacheDir(this.cacheDir, this.opts.htcName, this.opts.htcVersion, this.platform());
|
||||
core.debug(`Cache.save cached to hosted tool cache ${htcPath}`);
|
||||
|
||||
if (!this.ghaNoCache && cache.isFeatureAvailable()) {
|
||||
core.debug(`Cache.save sending ${this.ghaCacheKey} to post state`);
|
||||
core.saveState(
|
||||
Cache.POST_CACHE_KEY,
|
||||
JSON.stringify({
|
||||
dir: this.cacheDir,
|
||||
key: this.ghaCacheKey
|
||||
} as CachePostState)
|
||||
);
|
||||
}
|
||||
|
||||
return cachePath;
|
||||
}
|
||||
|
||||
public async find(): Promise<string> {
|
||||
let htcPath = tc.find(this.opts.htcName, this.opts.htcVersion, this.platform());
|
||||
if (htcPath) {
|
||||
core.info(`Restored from hosted tool cache ${htcPath}`);
|
||||
return this.copyToCache(`${htcPath}/${this.opts.cacheFile}`);
|
||||
}
|
||||
|
||||
if (!this.ghaNoCache && cache.isFeatureAvailable()) {
|
||||
core.debug(`GitHub Actions cache feature available`);
|
||||
if (await cache.restoreCache([this.cacheDir], this.ghaCacheKey)) {
|
||||
core.info(`Restored ${this.ghaCacheKey} from GitHub Actions cache`);
|
||||
htcPath = await tc.cacheDir(this.cacheDir, this.opts.htcName, this.opts.htcVersion, this.platform());
|
||||
core.info(`Cached to hosted tool cache ${htcPath}`);
|
||||
return this.copyToCache(`${htcPath}/${this.opts.cacheFile}`);
|
||||
}
|
||||
} else if (this.ghaNoCache) {
|
||||
core.info(`GitHub Actions cache disabled`);
|
||||
} else {
|
||||
core.info(`GitHub Actions cache feature not available`);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public static async post(): Promise<CachePostState | undefined> {
|
||||
const state = core.getState(Cache.POST_CACHE_KEY);
|
||||
if (!state) {
|
||||
core.info(`State not set`);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
let cacheState: CachePostState;
|
||||
try {
|
||||
cacheState = <CachePostState>JSON.parse(state);
|
||||
} catch (e) {
|
||||
throw new Error(`Failed to parse cache post state: ${e}`);
|
||||
}
|
||||
if (!cacheState.dir || !cacheState.key) {
|
||||
throw new Error(`Invalid cache post state: ${state}`);
|
||||
}
|
||||
core.info(`Caching ${cacheState.key} to GitHub Actions cache`);
|
||||
await cache.saveCache([cacheState.dir], cacheState.key);
|
||||
return cacheState;
|
||||
}
|
||||
|
||||
private copyToCache(file: string): string {
|
||||
core.debug(`Copying ${file} to ${this.cachePath}`);
|
||||
fs.copyFileSync(file, this.cachePath);
|
||||
return this.cachePath;
|
||||
}
|
||||
|
||||
private platform(): string {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const arm_version = (process.config.variables as any).arm_version;
|
||||
return `${os.platform()}-${os.arch()}${arm_version ? 'v' + arm_version : ''}`;
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,12 @@ import * as github from '@actions/github';
|
||||
import {GitHub} from './github';
|
||||
|
||||
export class Context {
|
||||
private static readonly _tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-actions-toolkit-'));
|
||||
private static readonly _tmpDir = fs.mkdtempSync(path.join(Context.ensureDirExists(process.env.RUNNER_TEMP || os.tmpdir()), 'docker-actions-toolkit-'));
|
||||
|
||||
private static ensureDirExists(dir: string): string {
|
||||
fs.mkdirSync(dir, {recursive: true});
|
||||
return dir;
|
||||
}
|
||||
|
||||
public static tmpDir(): string {
|
||||
return Context._tmpDir;
|
||||
|
||||
@@ -17,10 +17,6 @@
|
||||
import fs from 'fs';
|
||||
import {Context} from '../context';
|
||||
|
||||
export const setupDockerLinuxSh = (): string => {
|
||||
return get('docker-setup-linux.sh', setupDockerLinuxShData, '0755');
|
||||
};
|
||||
|
||||
export const setupDockerWinPs1 = (): string => {
|
||||
return get('docker-setup-win.ps1', setupDockerWinPs1Data);
|
||||
};
|
||||
@@ -29,8 +25,8 @@ export const dockerServiceLogsPs1 = (): string => {
|
||||
return get('docker-service-logs.ps1', dockerServiceLogsPs1Data);
|
||||
};
|
||||
|
||||
export const colimaYaml = (): string => {
|
||||
return get('colima.yaml', colimaYamlData);
|
||||
export const limaYaml = (): string => {
|
||||
return get('lima.yaml', limaYamlData);
|
||||
};
|
||||
|
||||
const get = (filename: string, data: string, mode?: string): string => {
|
||||
@@ -45,42 +41,6 @@ const get = (filename: string, data: string, mode?: string): string => {
|
||||
return assetPath;
|
||||
};
|
||||
|
||||
export const setupDockerLinuxShData = `
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
|
||||
: "\${TOOLDIR=}"
|
||||
: "\${RUNDIR=}"
|
||||
: "\${DOCKER_HOST=}"
|
||||
|
||||
export PATH="$TOOLDIR::$PATH"
|
||||
|
||||
if [ -z "$DOCKER_HOST" ]; then
|
||||
echo >&2 'error: DOCKER_HOST required'
|
||||
false
|
||||
fi
|
||||
|
||||
if ! command -v dockerd &> /dev/null; then
|
||||
echo >&2 'error: dockerd missing from PATH'
|
||||
false
|
||||
fi
|
||||
|
||||
mkdir -p "$RUNDIR"
|
||||
|
||||
(
|
||||
echo "Starting dockerd"
|
||||
set -x
|
||||
exec dockerd \\
|
||||
--host="$DOCKER_HOST" \\
|
||||
--exec-root="$RUNDIR/execroot" \\
|
||||
--data-root="$RUNDIR/data" \\
|
||||
--pidfile="$RUNDIR/docker.pid" \\
|
||||
--userland-proxy=false \\
|
||||
2>&1 | tee "$RUNDIR/dockerd.log"
|
||||
) &
|
||||
`;
|
||||
|
||||
export const setupDockerWinPs1Data = `
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
@@ -91,7 +51,10 @@ param(
|
||||
[string]$RunDir,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$DockerHost)
|
||||
[string]$DockerHost,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$DaemonConfig)
|
||||
|
||||
$pwver = (Get-ItemProperty -Path HKLM:\\SOFTWARE\\Microsoft\\PowerShell\\3\\PowerShellEngine -Name 'PowerShellVersion').PowerShellVersion
|
||||
Write-Host "PowerShell version: $pwver"
|
||||
@@ -116,9 +79,18 @@ if (Get-Service docker -ErrorAction SilentlyContinue) {
|
||||
Write-Host "Service removed"
|
||||
}
|
||||
|
||||
$env:Path = "$ToolDir;" + [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
|
||||
Write-Host "Path: $env:Path"
|
||||
|
||||
$env:DOCKER_HOST = $DockerHost
|
||||
Write-Host "DOCKER_HOST: $env:DOCKER_HOST"
|
||||
|
||||
if ($DaemonConfig) {
|
||||
Write-Host "Writing Docker daemon config"
|
||||
New-Item -ItemType Directory -Force -Path "$env:ProgramData\\Docker\\config"
|
||||
$DaemonConfig | Out-File -FilePath "$env:ProgramData\\Docker\\config\\daemon.json"
|
||||
}
|
||||
|
||||
Write-Host "Creating service"
|
||||
New-Item -ItemType Directory "$RunDir\\moby-root" -ErrorAction SilentlyContinue | Out-Null
|
||||
New-Item -ItemType Directory "$RunDir\\moby-exec" -ErrorAction SilentlyContinue | Out-Null
|
||||
@@ -159,180 +131,127 @@ Get-WinEvent -ea SilentlyContinue \`
|
||||
ForEach-Object {"$($_.TimeCreated.ToUniversalTime().ToString("o")) [$($_.LevelDisplayName)] $($_.Message)"}
|
||||
`;
|
||||
|
||||
export const colimaYamlData = `
|
||||
# Number of CPUs to be allocated to the virtual machine.
|
||||
# Default: 2
|
||||
cpu: 2
|
||||
|
||||
# Size of the disk in GiB to be allocated to the virtual machine.
|
||||
# NOTE: changing this has no effect after the virtual machine has been created.
|
||||
# Default: 60
|
||||
disk: 60
|
||||
|
||||
# Size of the memory in GiB to be allocated to the virtual machine.
|
||||
# Default: 2
|
||||
memory: 2
|
||||
|
||||
# Architecture of the virtual machine (x86_64, aarch64, host).
|
||||
# Default: host
|
||||
arch: host
|
||||
|
||||
# Container runtime to be used (docker, containerd).
|
||||
# Default: docker
|
||||
runtime: docker
|
||||
|
||||
# Kubernetes configuration for the virtual machine.
|
||||
kubernetes:
|
||||
enabled: false
|
||||
|
||||
# Auto-activate on the Host for client access.
|
||||
# Setting to true does the following on startup
|
||||
# - sets as active Docker context (for Docker runtime).
|
||||
# - sets as active Kubernetes context (if Kubernetes is enabled).
|
||||
# Default: true
|
||||
autoActivate: false
|
||||
|
||||
# Network configurations for the virtual machine.
|
||||
network:
|
||||
# Assign reachable IP address to the virtual machine.
|
||||
# NOTE: this is currently macOS only and ignored on Linux.
|
||||
# Default: false
|
||||
address: false
|
||||
|
||||
# Custom DNS resolvers for the virtual machine.
|
||||
#
|
||||
# EXAMPLE
|
||||
# dns: [8.8.8.8, 1.1.1.1]
|
||||
#
|
||||
# Default: []
|
||||
dns: []
|
||||
|
||||
# DNS hostnames to resolve to custom targets using the internal resolver.
|
||||
# This setting has no effect if a custom DNS resolver list is supplied above.
|
||||
# It does not configure the /etc/hosts files of any machine or container.
|
||||
# The value can be an IP address or another host.
|
||||
#
|
||||
# EXAMPLE
|
||||
# dnsHosts:
|
||||
# example.com: 1.2.3.4
|
||||
dnsHosts:
|
||||
host.docker.internal: host.lima.internal
|
||||
|
||||
# Network driver to use (slirp, gvproxy), (requires vmType \`qemu\`)
|
||||
# - slirp is the default user mode networking provided by Qemu
|
||||
# - gvproxy is an alternative to VPNKit based on gVisor https://github.com/containers/gvisor-tap-vsock
|
||||
# Default: gvproxy
|
||||
driver: gvproxy
|
||||
|
||||
# Forward the host's SSH agent to the virtual machine.
|
||||
# Default: false
|
||||
forwardAgent: false
|
||||
|
||||
# Docker daemon configuration that maps directly to daemon.json.
|
||||
# https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file.
|
||||
# NOTE: some settings may affect Colima's ability to start docker. e.g. \`hosts\`.
|
||||
#
|
||||
# EXAMPLE - disable buildkit
|
||||
# docker:
|
||||
# features:
|
||||
# buildkit: false
|
||||
#
|
||||
# EXAMPLE - add insecure registries
|
||||
# docker:
|
||||
# insecure-registries:
|
||||
# - myregistry.com:5000
|
||||
# - host.docker.internal:5000
|
||||
#
|
||||
# Colima default behaviour: buildkit enabled
|
||||
# Default: {}
|
||||
docker: {}
|
||||
|
||||
# Virtual Machine type (qemu, vz)
|
||||
# NOTE: this is macOS 13 only. For Linux and macOS <13.0, qemu is always used.
|
||||
#
|
||||
# vz is macOS virtualization framework and requires macOS 13
|
||||
#
|
||||
# Default: qemu
|
||||
export const limaYamlData = `
|
||||
# VM type: "qemu" or "vz" (on macOS 13 and later).
|
||||
# The vmType can be specified only on creating the instance.
|
||||
# The vmType of existing instances cannot be changed.
|
||||
# Builtin default: "qemu"
|
||||
vmType: qemu
|
||||
|
||||
# Volume mount driver for the virtual machine (virtiofs, 9p, sshfs).
|
||||
#
|
||||
# virtiofs is limited to macOS and vmType \`vz\`. It is the fastest of the options.
|
||||
#
|
||||
# 9p is the recommended and the most stable option for vmType \`qemu\`.
|
||||
#
|
||||
# sshfs is faster than 9p but the least reliable of the options (when there are lots
|
||||
# of concurrent reads or writes).
|
||||
#
|
||||
# Default: virtiofs (for vz), sshfs (for qemu)
|
||||
mountType: 9p
|
||||
# OS: "Linux".
|
||||
# Builtin default: "Linux"
|
||||
os: null
|
||||
|
||||
# The CPU type for the virtual machine (requires vmType \`qemu\`).
|
||||
# Options available for host emulation can be checked with: \`qemu-system-$(arch) -cpu help\`.
|
||||
# Instructions are also supported by appending to the cpu type e.g. "qemu64,+ssse3".
|
||||
# Default: host
|
||||
cpuType: host
|
||||
# Arch: "default", "x86_64", "aarch64".
|
||||
# Builtin default: "default" (corresponds to the host architecture)
|
||||
arch: null
|
||||
|
||||
# For a more general purpose virtual machine, Ubuntu container is optionally provided
|
||||
# as a layer on the virtual machine.
|
||||
# The underlying virtual machine is still accessible via \`colima ssh --layer=false\` or running \`colima\` in
|
||||
# the Ubuntu session.
|
||||
#
|
||||
# Default: false
|
||||
layer: false
|
||||
images:
|
||||
{{#each customImages}}
|
||||
- location: "{{location}}"
|
||||
arch: "{{arch}}"
|
||||
digest: "{{digest}}"
|
||||
{{/each}}
|
||||
- location: "https://cloud-images.ubuntu.com/releases/22.04/release-20231026/ubuntu-22.04-server-cloudimg-amd64.img"
|
||||
arch: "x86_64"
|
||||
digest: "sha256:054db2d88c454bb0ad8dfd8883955e3946b57d2b0bf0d023f3ade3c93cdd14e5"
|
||||
- location: "https://cloud-images.ubuntu.com/releases/22.04/release-20231026/ubuntu-22.04-server-cloudimg-arm64.img"
|
||||
arch: "aarch64"
|
||||
digest: "sha256:eafa7742ce5ff109222ea313d31ea366d587b4e89b900b11d8285ae775dfe8c3"
|
||||
|
||||
# CPUs
|
||||
# Builtin default: min(4, host CPU cores)
|
||||
cpus: null
|
||||
|
||||
# Memory size
|
||||
# Builtin default: min("4GiB", half of host memory)
|
||||
memory: null
|
||||
|
||||
# Disk size
|
||||
# Builtin default: "100GiB"
|
||||
disk: 60GiB
|
||||
|
||||
# Expose host directories to the guest, the mount point might be accessible from all UIDs in the guest
|
||||
# Builtin default: null (Mount nothing)
|
||||
# This file: Mount the home as read-only, /tmp/lima as writable
|
||||
mounts:
|
||||
- location: "~"
|
||||
- location: "/tmp/lima"
|
||||
writable: true
|
||||
|
||||
# Mount type for above mounts, such as "reverse-sshfs" (from sshocker), "9p" (EXPERIMENTAL, from QEMU’s virtio-9p-pci, aka virtfs),
|
||||
# or "virtiofs" (EXPERIMENTAL, needs \`vmType: vz\`)
|
||||
# Builtin default: "reverse-sshfs" (for QEMU), "virtiofs" (for vz)
|
||||
mountType: null
|
||||
|
||||
containerd:
|
||||
system: false
|
||||
user: false
|
||||
|
||||
# Custom provision scripts for the virtual machine.
|
||||
# Provisioning scripts are executed on startup and therefore needs to be idempotent.
|
||||
#
|
||||
# EXAMPLE - script exected as root
|
||||
# provision:
|
||||
# - mode: system
|
||||
# script: apk add htop vim
|
||||
#
|
||||
# EXAMPLE - script exected as user
|
||||
# provision:
|
||||
# - mode: user
|
||||
# script: |
|
||||
# [ -f ~/.provision ] && exit 0;
|
||||
# echo provisioning as $USER...
|
||||
# touch ~/.provision
|
||||
#
|
||||
# Default: []
|
||||
provision:
|
||||
- mode: system
|
||||
script: |
|
||||
mkdir -p /tmp/docker-bins
|
||||
cd /tmp/docker-bins
|
||||
wget -qO- "https://download.docker.com/linux/static/{{dockerChannel}}/{{hostArch}}/docker-{{dockerVersion}}.tgz" | tar xvz --strip 1
|
||||
mv -f /tmp/docker-bins/* /usr/bin/
|
||||
- mode: system
|
||||
# This script defines the host.docker.internal hostname when hostResolver is disabled.
|
||||
# It is also needed for lima 0.8.2 and earlier, which does not support hostResolver.hosts.
|
||||
# Names defined in /etc/hosts inside the VM are not resolved inside containers when
|
||||
# using the hostResolver; use hostResolver.hosts instead (requires lima 0.8.3 or later).
|
||||
script: |
|
||||
#!/bin/sh
|
||||
sed -i 's/host.lima.internal.*/host.lima.internal host.docker.internal/' /etc/hosts
|
||||
- mode: system
|
||||
script: |
|
||||
#!/bin/sh
|
||||
apt-get install -f -y iptables
|
||||
- mode: system
|
||||
script: |
|
||||
#!/bin/bash
|
||||
set -eux -o pipefail
|
||||
command -v docker >/dev/null 2>&1 && exit 0
|
||||
if [ ! -e /etc/systemd/system/docker.socket.d/override.conf ]; then
|
||||
mkdir -p /etc/systemd/system/docker.socket.d
|
||||
# Alternatively we could just add the user to the "docker" group, but that requires restarting the user session
|
||||
cat <<-EOF >/etc/systemd/system/docker.socket.d/override.conf
|
||||
[Socket]
|
||||
SocketUser=\${LIMA_CIDATA_USER}
|
||||
EOF
|
||||
fi
|
||||
if [ ! -e /etc/docker/daemon.json ]; then
|
||||
mkdir -p /etc/docker
|
||||
cat <<-EOF >/etc/docker/daemon.json
|
||||
{{stringify daemonConfig}}
|
||||
EOF
|
||||
fi
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
curl -fsSL https://get.docker.com | sh -s -- --channel {{dockerBinChannel}} --version {{dockerBinVersion}}
|
||||
|
||||
# Modify ~/.ssh/config automatically to include a SSH config for the virtual machine.
|
||||
# SSH config will still be generated in ~/.colima/ssh_config regardless.
|
||||
# Default: true
|
||||
sshConfig: false
|
||||
probes:
|
||||
- script: |
|
||||
#!/bin/bash
|
||||
set -eux -o pipefail
|
||||
if ! timeout 30s bash -c "until command -v docker >/dev/null 2>&1; do sleep 3; done"; then
|
||||
echo >&2 "docker is not installed yet"
|
||||
exit 1
|
||||
fi
|
||||
if ! timeout 30s bash -c "until pgrep dockerd; do sleep 3; done"; then
|
||||
echo >&2 "dockerd is not running"
|
||||
exit 1
|
||||
fi
|
||||
hint: See "/var/log/cloud-init-output.log". in the guest
|
||||
|
||||
# Configure volume mounts for the virtual machine.
|
||||
# Colima mounts user's home directory by default to provide a familiar
|
||||
# user experience.
|
||||
#
|
||||
# EXAMPLE
|
||||
# mounts:
|
||||
# - location: ~/secrets
|
||||
# writable: false
|
||||
# - location: ~/projects
|
||||
# writable: true
|
||||
#
|
||||
# Colima default behaviour: $HOME and /tmp/colima are mounted as writable.
|
||||
# Default: []
|
||||
mounts: []
|
||||
hostResolver:
|
||||
# hostResolver.hosts requires lima 0.8.3 or later. Names defined here will also
|
||||
# resolve inside containers, and not just inside the VM itself.
|
||||
hosts:
|
||||
host.docker.internal: host.lima.internal
|
||||
|
||||
# Environment variables for the virtual machine.
|
||||
#
|
||||
# EXAMPLE
|
||||
# env:
|
||||
# KEY: value
|
||||
# ANOTHER_KEY: another value
|
||||
#
|
||||
# Default: {}
|
||||
env: {}
|
||||
portForwards:
|
||||
- guestSocket: "/var/run/docker.sock"
|
||||
hostSocket: "{{dockerSock}}"
|
||||
|
||||
audio:
|
||||
# EXPERIMENTAL
|
||||
# QEMU audiodev, e.g., "none", "coreaudio", "pa", "alsa", "oss".
|
||||
# VZ driver, use "vz" as device name
|
||||
# Choosing "none" will mute the audio output, and not play any sound.
|
||||
# Builtin default: ""
|
||||
device: none
|
||||
`;
|
||||
|
||||
@@ -18,11 +18,15 @@ import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import * as core from '@actions/core';
|
||||
import {ExecOptions, ExecOutput} from '@actions/exec';
|
||||
import * as io from '@actions/io';
|
||||
|
||||
import {Context} from '../context';
|
||||
import {Cache} from '../cache';
|
||||
import {Exec} from '../exec';
|
||||
import {Util} from '../util';
|
||||
|
||||
import {ConfigFile} from '../types/docker';
|
||||
import {ConfigFile, ContextInfo} from '../types/docker/docker';
|
||||
|
||||
export class Docker {
|
||||
static get configDir(): string {
|
||||
@@ -50,12 +54,47 @@ export class Docker {
|
||||
});
|
||||
}
|
||||
|
||||
public static async isDaemonRunning(): Promise<boolean> {
|
||||
try {
|
||||
await Docker.getExecOutput([`version`], {
|
||||
silent: true
|
||||
});
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static async exec(args?: string[], options?: ExecOptions): Promise<number> {
|
||||
return Exec.exec('docker', args, Docker.execOptions(options));
|
||||
}
|
||||
|
||||
public static async getExecOutput(args?: string[], options?: ExecOptions): Promise<ExecOutput> {
|
||||
return Exec.getExecOutput('docker', args, Docker.execOptions(options));
|
||||
}
|
||||
|
||||
private static execOptions(options?: ExecOptions): ExecOptions {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
if (!options.env) {
|
||||
options.env = Object.assign({}, process.env, {
|
||||
DOCKER_CONTENT_TRUST: 'false'
|
||||
}) as {
|
||||
[key: string]: string;
|
||||
};
|
||||
} else {
|
||||
options.env.DOCKER_CONTENT_TRUST = 'false';
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
public static async context(name?: string): Promise<string> {
|
||||
const args = ['context', 'inspect', '--format', '{{.Name}}'];
|
||||
if (name) {
|
||||
args.push(name);
|
||||
}
|
||||
return await Exec.getExecOutput(`docker`, args, {
|
||||
return await Docker.getExecOutput(args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
}).then(res => {
|
||||
@@ -66,11 +105,112 @@ export class Docker {
|
||||
});
|
||||
}
|
||||
|
||||
public static async contextInspect(name?: string): Promise<ContextInfo> {
|
||||
const args = ['context', 'inspect', '--format=json'];
|
||||
if (name) {
|
||||
args.push(name);
|
||||
}
|
||||
return await Docker.getExecOutput(args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr.trim());
|
||||
}
|
||||
return (<Array<ContextInfo>>JSON.parse(res.stdout.trim()))[0];
|
||||
});
|
||||
}
|
||||
|
||||
public static async printVersion(): Promise<void> {
|
||||
await Exec.exec('docker', ['version']);
|
||||
await Docker.exec(['version']);
|
||||
}
|
||||
|
||||
public static async printInfo(): Promise<void> {
|
||||
await Exec.exec('docker', ['info']);
|
||||
await Docker.exec(['info']);
|
||||
}
|
||||
|
||||
public static parseRepoTag(image: string): {repository: string; tag: string} {
|
||||
let sepPos: number;
|
||||
const digestPos = image.indexOf('@');
|
||||
const colonPos = image.lastIndexOf(':');
|
||||
if (digestPos >= 0) {
|
||||
// priority on digest
|
||||
sepPos = digestPos;
|
||||
} else if (colonPos >= 0) {
|
||||
sepPos = colonPos;
|
||||
} else {
|
||||
return {
|
||||
repository: image,
|
||||
tag: 'latest'
|
||||
};
|
||||
}
|
||||
const tag = image.slice(sepPos + 1);
|
||||
if (tag.indexOf('/') === -1) {
|
||||
return {
|
||||
repository: image.slice(0, sepPos),
|
||||
tag: tag
|
||||
};
|
||||
}
|
||||
return {
|
||||
repository: image,
|
||||
tag: 'latest'
|
||||
};
|
||||
}
|
||||
|
||||
public static async pull(image: string, cache?: boolean): Promise<void> {
|
||||
const parsedImage = Docker.parseRepoTag(image);
|
||||
const repoSanitized = parsedImage.repository.replace(/[^a-zA-Z0-9.]+/g, '--');
|
||||
const tagSanitized = parsedImage.tag.replace(/[^a-zA-Z0-9.]+/g, '--');
|
||||
|
||||
const imageCache = new Cache({
|
||||
htcName: repoSanitized,
|
||||
htcVersion: tagSanitized,
|
||||
baseCacheDir: path.join(Docker.configDir, '.cache', 'images', repoSanitized),
|
||||
cacheFile: 'image.tar'
|
||||
});
|
||||
|
||||
let cacheFoundPath: string | undefined;
|
||||
if (cache) {
|
||||
cacheFoundPath = await imageCache.find();
|
||||
if (cacheFoundPath) {
|
||||
core.info(`Image found from cache in ${cacheFoundPath}`);
|
||||
await Docker.getExecOutput(['load', '-i', cacheFoundPath], {
|
||||
ignoreReturnCode: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
core.warning(`Failed to load image from cache: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let pulled = true;
|
||||
await Docker.getExecOutput(['pull', image], {
|
||||
ignoreReturnCode: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
pulled = false;
|
||||
const err = res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error';
|
||||
if (cacheFoundPath) {
|
||||
core.warning(`Failed to pull image, using one from cache: ${err}`);
|
||||
} else {
|
||||
throw new Error(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (cache && pulled) {
|
||||
const imageTarPath = path.join(Context.tmpDir(), `${Util.hash(image)}.tar`);
|
||||
await Docker.getExecOutput(['save', '-o', imageTarPath, image], {
|
||||
ignoreReturnCode: true
|
||||
}).then(async res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
core.warning(`Failed to save image: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
|
||||
} else {
|
||||
const cachePath = await imageCache.save(imageTarPath);
|
||||
core.info(`Image cached to ${cachePath}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import * as child_process from 'child_process';
|
||||
import fs from 'fs';
|
||||
import fsp from 'fs/promises';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import retry from 'async-retry';
|
||||
@@ -27,9 +28,10 @@ import * as io from '@actions/io';
|
||||
import * as tc from '@actions/tool-cache';
|
||||
|
||||
import {Context} from '../context';
|
||||
import {Docker} from './docker';
|
||||
import {Exec} from '../exec';
|
||||
import {Util} from '../util';
|
||||
import {colimaYamlData, dockerServiceLogsPs1, setupDockerLinuxSh, setupDockerWinPs1} from './assets';
|
||||
import {limaYamlData, dockerServiceLogsPs1, setupDockerWinPs1} from './assets';
|
||||
import {GitHubRelease} from '../types/github';
|
||||
|
||||
export interface InstallOpts {
|
||||
@@ -37,6 +39,13 @@ export interface InstallOpts {
|
||||
channel?: string;
|
||||
runDir: string;
|
||||
contextName?: string;
|
||||
daemonConfig?: string;
|
||||
}
|
||||
|
||||
interface LimaImage {
|
||||
location: string;
|
||||
arch: string;
|
||||
digest?: string;
|
||||
}
|
||||
|
||||
export class Install {
|
||||
@@ -44,14 +53,18 @@ export class Install {
|
||||
private readonly version: string;
|
||||
private readonly channel: string;
|
||||
private readonly contextName: string;
|
||||
private readonly daemonConfig?: string;
|
||||
private _version: string | undefined;
|
||||
private _toolDir: string | undefined;
|
||||
|
||||
private readonly limaInstanceName = 'docker-actions-toolkit';
|
||||
|
||||
constructor(opts: InstallOpts) {
|
||||
this.runDir = opts.runDir;
|
||||
this.version = opts.version || 'latest';
|
||||
this.channel = opts.channel || 'stable';
|
||||
this.contextName = opts.contextName || 'setup-docker-action';
|
||||
this.daemonConfig = opts.daemonConfig;
|
||||
}
|
||||
|
||||
get toolDir(): string {
|
||||
@@ -99,7 +112,7 @@ export class Install {
|
||||
return tooldir;
|
||||
}
|
||||
|
||||
public async install(): Promise<void> {
|
||||
public async install(): Promise<string> {
|
||||
if (!this.toolDir) {
|
||||
throw new Error('toolDir must be set. Run download first.');
|
||||
}
|
||||
@@ -108,16 +121,13 @@ export class Install {
|
||||
}
|
||||
switch (os.platform()) {
|
||||
case 'darwin': {
|
||||
await this.installDarwin();
|
||||
break;
|
||||
return await this.installDarwin();
|
||||
}
|
||||
case 'linux': {
|
||||
await this.installLinux();
|
||||
break;
|
||||
return await this.installLinux();
|
||||
}
|
||||
case 'win32': {
|
||||
await this.installWindows();
|
||||
break;
|
||||
return await this.installWindows();
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Unsupported platform: ${os.platform()}`);
|
||||
@@ -125,108 +135,218 @@ export class Install {
|
||||
}
|
||||
}
|
||||
|
||||
private async installDarwin(): Promise<void> {
|
||||
const colimaDir = path.join(os.homedir(), '.colima', 'default'); // TODO: create a custom colima profile to avoid overlap with other actions
|
||||
await io.mkdirP(colimaDir);
|
||||
const dockerHost = `unix://${colimaDir}/docker.sock`;
|
||||
private async installDarwin(): Promise<string> {
|
||||
const limaDir = path.join(os.homedir(), '.lima', this.limaInstanceName);
|
||||
await io.mkdirP(limaDir);
|
||||
const dockerHost = `unix://${limaDir}/docker.sock`;
|
||||
|
||||
if (!(await Install.colimaInstalled())) {
|
||||
await core.group('Installing colima', async () => {
|
||||
await Exec.exec('brew', ['install', 'colima']);
|
||||
// avoid brew to auto update and upgrade unrelated packages.
|
||||
let envs = Object.assign({}, process.env, {
|
||||
HOMEBREW_NO_AUTO_UPDATE: '1',
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: '1'
|
||||
}) as {
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
if (!(await Install.limaInstalled())) {
|
||||
await core.group('Installing lima', async () => {
|
||||
await Exec.exec('brew', ['install', 'lima'], {env: envs});
|
||||
});
|
||||
}
|
||||
|
||||
await core.group('Creating colima config', async () => {
|
||||
const colimaCfg = handlebars.compile(colimaYamlData)({
|
||||
hostArch: Install.platformArch(),
|
||||
dockerVersion: this._version,
|
||||
dockerChannel: this.channel
|
||||
});
|
||||
core.info(`Writing colima config to ${path.join(colimaDir, 'colima.yaml')}`);
|
||||
fs.writeFileSync(path.join(colimaDir, 'colima.yaml'), colimaCfg);
|
||||
core.info(colimaCfg);
|
||||
await core.group('Lima version', async () => {
|
||||
await Exec.exec('lima', ['--version'], {env: envs});
|
||||
});
|
||||
|
||||
// colima is already started on the runner so env var added in download
|
||||
await core.group('Creating lima config', async () => {
|
||||
let limaDaemonConfig = {};
|
||||
if (this.daemonConfig) {
|
||||
limaDaemonConfig = JSON.parse(this.daemonConfig);
|
||||
}
|
||||
handlebars.registerHelper('stringify', function (obj) {
|
||||
return new handlebars.SafeString(JSON.stringify(obj));
|
||||
});
|
||||
const limaCfg = handlebars.compile(limaYamlData)({
|
||||
customImages: Install.limaCustomImages(),
|
||||
daemonConfig: limaDaemonConfig,
|
||||
dockerSock: `${limaDir}/docker.sock`,
|
||||
dockerBinVersion: this._version,
|
||||
dockerBinChannel: this.channel
|
||||
});
|
||||
core.info(`Writing lima config to ${path.join(limaDir, 'lima.yaml')}`);
|
||||
fs.writeFileSync(path.join(limaDir, 'lima.yaml'), limaCfg);
|
||||
core.info(limaCfg);
|
||||
});
|
||||
|
||||
const qemuArch = await Install.qemuArch();
|
||||
await core.group('QEMU version', async () => {
|
||||
await Exec.exec(`qemu-system-${qemuArch} --version`);
|
||||
});
|
||||
|
||||
// lima might already be started on the runner so env var added in download
|
||||
// method is not expanded to the running process.
|
||||
envs = Object.assign({}, envs, {
|
||||
PATH: `${this.toolDir}:${process.env.PATH}`
|
||||
}) as {
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
await core.group('Starting lima instance', async () => {
|
||||
const limaStartArgs = ['start', `--name=${this.limaInstanceName}`];
|
||||
if (process.env.LIMA_START_ARGS) {
|
||||
limaStartArgs.push(process.env.LIMA_START_ARGS);
|
||||
}
|
||||
try {
|
||||
await Exec.exec(`limactl ${limaStartArgs.join(' ')}`, [], {env: envs});
|
||||
} catch (e) {
|
||||
fsp
|
||||
.readdir(limaDir)
|
||||
.then(files => {
|
||||
files
|
||||
.filter(f => path.extname(f) === '.log')
|
||||
.forEach(f => {
|
||||
const logfile = path.join(limaDir, f);
|
||||
const logcontent = fs.readFileSync(logfile, {encoding: 'utf8'}).trim();
|
||||
if (logcontent.length > 0) {
|
||||
core.info(`### ${logfile}:\n${logcontent}`);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
// ignore
|
||||
});
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
await core.group('Create Docker context', async () => {
|
||||
await Docker.exec(['context', 'create', this.contextName, '--docker', `host=${dockerHost}`]);
|
||||
await Docker.exec(['context', 'use', this.contextName]);
|
||||
});
|
||||
|
||||
return dockerHost;
|
||||
}
|
||||
|
||||
private async installLinux(): Promise<string> {
|
||||
const dockerHost = `unix://${path.join(this.runDir, 'docker.sock')}`;
|
||||
await io.mkdirP(this.runDir);
|
||||
|
||||
const daemonConfigPath = path.join(this.runDir, 'daemon.json');
|
||||
await fs.writeFileSync(daemonConfigPath, '{}');
|
||||
|
||||
let daemonConfig = undefined;
|
||||
const daemonConfigDefaultPath = '/etc/docker/daemon.json';
|
||||
if (fs.existsSync(daemonConfigDefaultPath)) {
|
||||
await core.group('Default Docker daemon config found', async () => {
|
||||
core.info(JSON.stringify(JSON.parse(fs.readFileSync(daemonConfigDefaultPath, {encoding: 'utf8'})), null, 2));
|
||||
});
|
||||
daemonConfig = JSON.parse(fs.readFileSync(daemonConfigDefaultPath, {encoding: 'utf8'}));
|
||||
}
|
||||
if (this.daemonConfig) {
|
||||
daemonConfig = Object.assign(daemonConfig || {}, JSON.parse(this.daemonConfig));
|
||||
}
|
||||
|
||||
if (daemonConfig) {
|
||||
const daemonConfigStr = JSON.stringify(daemonConfig, null, 2);
|
||||
await core.group('Writing Docker daemon config', async () => {
|
||||
fs.writeFileSync(daemonConfigPath, daemonConfigStr);
|
||||
core.info(daemonConfigStr);
|
||||
});
|
||||
}
|
||||
|
||||
const envs = Object.assign({}, process.env, {
|
||||
PATH: `${this.toolDir}:${process.env.PATH}`
|
||||
}) as {
|
||||
[key: string]: string;
|
||||
};
|
||||
await core.group('Starting colima', async () => {
|
||||
await Exec.exec('colima', ['start', '--very-verbose'], {env: envs});
|
||||
});
|
||||
|
||||
await core.group('Create Docker context', async () => {
|
||||
await Exec.exec('docker', ['context', 'create', this.contextName, '--docker', `host=${dockerHost}`]);
|
||||
await Exec.exec('docker', ['context', 'use', this.contextName]);
|
||||
});
|
||||
}
|
||||
|
||||
private async installLinux(): Promise<void> {
|
||||
const dockerHost = `unix://${path.join(this.runDir, 'docker.sock')}`;
|
||||
await io.mkdirP(this.runDir);
|
||||
|
||||
await core.group('Start Docker daemon', async () => {
|
||||
const bashPath: string = await io.which('bash', true);
|
||||
const proc = await child_process.spawn(`sudo -E ${bashPath} ${setupDockerLinuxSh()}`, [], {
|
||||
detached: true,
|
||||
shell: true,
|
||||
stdio: ['ignore', process.stdout, process.stderr],
|
||||
env: Object.assign({}, process.env, {
|
||||
TOOLDIR: this.toolDir,
|
||||
RUNDIR: this.runDir,
|
||||
DOCKER_HOST: dockerHost
|
||||
}) as {
|
||||
[key: string]: string;
|
||||
const cmd = `${this.toolDir}/dockerd --host="${dockerHost}" --config-file="${daemonConfigPath}" --exec-root="${this.runDir}/execroot" --data-root="${this.runDir}/data" --pidfile="${this.runDir}/docker.pid" --userland-proxy=false`;
|
||||
core.info(`[command] ${cmd}`); // https://github.com/actions/toolkit/blob/3d652d3133965f63309e4b2e1c8852cdbdcb3833/packages/exec/src/toolrunner.ts#L47
|
||||
const proc = await child_process.spawn(
|
||||
// We can't use Exec.exec here because we need to detach the process to
|
||||
// avoid killing it when the action finishes running. Even if detached,
|
||||
// we also need to run dockerd in a subshell and unref the process so
|
||||
// GitHub Action doesn't wait for it to finish.
|
||||
`sudo env "PATH=$PATH" ${bashPath} << EOF
|
||||
( ${cmd} 2>&1 | tee "${this.runDir}/dockerd.log" ) &
|
||||
EOF`,
|
||||
[],
|
||||
{
|
||||
env: envs,
|
||||
detached: true,
|
||||
shell: true,
|
||||
stdio: ['ignore', process.stdout, process.stderr]
|
||||
}
|
||||
});
|
||||
);
|
||||
proc.unref();
|
||||
await Util.sleep(3);
|
||||
const retries = 10;
|
||||
await retry(
|
||||
async bail => {
|
||||
await Exec.getExecOutput(`docker version`, undefined, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true,
|
||||
env: Object.assign({}, process.env, {
|
||||
DOCKER_HOST: dockerHost
|
||||
}) as {
|
||||
[key: string]: string;
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
bail(new Error(res.stderr));
|
||||
return false;
|
||||
try {
|
||||
await Exec.getExecOutput(`docker version`, undefined, {
|
||||
silent: true,
|
||||
env: Object.assign({}, envs, {
|
||||
DOCKER_HOST: dockerHost,
|
||||
DOCKER_CONTENT_TRUST: 'false'
|
||||
}) as {
|
||||
[key: string]: string;
|
||||
}
|
||||
return res.exitCode == 0;
|
||||
})
|
||||
.catch(error => {
|
||||
bail(error);
|
||||
return false;
|
||||
});
|
||||
} catch (e) {
|
||||
bail(e);
|
||||
}
|
||||
},
|
||||
{
|
||||
retries: 5
|
||||
retries: retries,
|
||||
minTimeout: 1000,
|
||||
onRetry: (err, i) => {
|
||||
core.info(`${err}. Retrying (${i}/${retries})...`);
|
||||
}
|
||||
}
|
||||
);
|
||||
core.info(`Docker daemon started started successfully`);
|
||||
});
|
||||
|
||||
await core.group('Create Docker context', async () => {
|
||||
await Exec.exec('docker', ['context', 'create', this.contextName, '--docker', `host=${dockerHost}`]);
|
||||
await Exec.exec('docker', ['context', 'use', this.contextName]);
|
||||
await Docker.exec(['context', 'create', this.contextName, '--docker', `host=${dockerHost}`]);
|
||||
await Docker.exec(['context', 'use', this.contextName]);
|
||||
});
|
||||
|
||||
return dockerHost;
|
||||
}
|
||||
|
||||
private async installWindows(): Promise<void> {
|
||||
private async installWindows(): Promise<string> {
|
||||
const dockerHost = 'npipe:////./pipe/setup_docker_action';
|
||||
|
||||
let daemonConfig = undefined;
|
||||
const daemonConfigPath = path.join(this.runDir, 'daemon.json');
|
||||
if (fs.existsSync(daemonConfigPath)) {
|
||||
await core.group('Default Docker daemon config found', async () => {
|
||||
core.info(JSON.stringify(JSON.parse(fs.readFileSync(daemonConfigPath, {encoding: 'utf8'})), null, 2));
|
||||
});
|
||||
daemonConfig = JSON.parse(fs.readFileSync(daemonConfigPath, {encoding: 'utf8'}));
|
||||
}
|
||||
if (this.daemonConfig) {
|
||||
daemonConfig = Object.assign(daemonConfig || {}, JSON.parse(this.daemonConfig));
|
||||
}
|
||||
|
||||
let daemonConfigStr = '{}';
|
||||
if (daemonConfig) {
|
||||
daemonConfigStr = JSON.stringify(daemonConfig, null, 2);
|
||||
await core.group('Docker daemon config', async () => {
|
||||
core.info(daemonConfigStr);
|
||||
});
|
||||
}
|
||||
|
||||
await core.group('Install Docker daemon service', async () => {
|
||||
const setupCmd = await Util.powershellCommand(setupDockerWinPs1(), {
|
||||
ToolDir: this.toolDir,
|
||||
RunDir: this.runDir,
|
||||
DockerHost: dockerHost
|
||||
DockerHost: dockerHost,
|
||||
DaemonConfig: daemonConfigStr
|
||||
});
|
||||
await Exec.exec(setupCmd.command, setupCmd.args);
|
||||
const logCmd = await Util.powershellCommand(dockerServiceLogsPs1());
|
||||
@@ -234,9 +354,11 @@ export class Install {
|
||||
});
|
||||
|
||||
await core.group('Create Docker context', async () => {
|
||||
await Exec.exec('docker', ['context', 'create', this.contextName, '--docker', `host=${dockerHost}`]);
|
||||
await Exec.exec('docker', ['context', 'use', this.contextName]);
|
||||
await Docker.exec(['context', 'create', this.contextName, '--docker', `host=${dockerHost}`]);
|
||||
await Docker.exec(['context', 'use', this.contextName]);
|
||||
});
|
||||
|
||||
return dockerHost;
|
||||
}
|
||||
|
||||
public async tearDown(): Promise<void> {
|
||||
@@ -264,13 +386,18 @@ export class Install {
|
||||
|
||||
private async tearDownDarwin(): Promise<void> {
|
||||
await core.group('Docker daemon logs', async () => {
|
||||
await Exec.exec('colima', ['exec', '--', 'cat', '/var/log/docker.log']);
|
||||
await Exec.exec('limactl', ['shell', '--tty=false', this.limaInstanceName, 'sudo', 'journalctl', '-u', 'docker.service', '-l', '--no-pager']).catch(() => {
|
||||
core.warning(`Failed to get Docker daemon logs`);
|
||||
});
|
||||
});
|
||||
await core.group('Stopping colima', async () => {
|
||||
await Exec.exec('colima', ['stop', '--very-verbose']);
|
||||
await core.group('Stopping lima instance', async () => {
|
||||
await Exec.exec('limactl', ['stop', '--tty=false', this.limaInstanceName, '--force']);
|
||||
});
|
||||
await core.group('Removing lima instance', async () => {
|
||||
await Exec.exec('limactl', ['delete', '--tty=false', this.limaInstanceName, '--force']);
|
||||
});
|
||||
await core.group('Removing Docker context', async () => {
|
||||
await Exec.exec('docker', ['context', 'rm', '-f', this.contextName]);
|
||||
await Docker.exec(['context', 'rm', '-f', this.contextName]);
|
||||
});
|
||||
await core.group(`Cleaning up runDir`, async () => {
|
||||
await Exec.exec('sudo', ['rm', '-rf', this.runDir]);
|
||||
@@ -282,13 +409,17 @@ export class Install {
|
||||
core.info(fs.readFileSync(path.join(this.runDir, 'dockerd.log'), {encoding: 'utf8'}));
|
||||
});
|
||||
await core.group('Stopping Docker daemon', async () => {
|
||||
await Exec.exec('sudo', ['kill', fs.readFileSync(path.join(this.runDir, 'docker.pid')).toString().trim()]);
|
||||
await Exec.exec('sudo', ['kill', '-s', 'SIGTERM', fs.readFileSync(path.join(this.runDir, 'docker.pid')).toString().trim()]);
|
||||
await Util.sleep(5);
|
||||
});
|
||||
await core.group('Removing Docker context', async () => {
|
||||
await Exec.exec('docker', ['context', 'rm', '-f', this.contextName]);
|
||||
await Docker.exec(['context', 'rm', '-f', this.contextName]);
|
||||
});
|
||||
await core.group(`Cleaning up runDir`, async () => {
|
||||
await Exec.exec('sudo', ['rm', '-rf', this.runDir]);
|
||||
await Exec.exec('sudo', ['rm', '-rf', this.runDir], {
|
||||
ignoreReturnCode: true,
|
||||
failOnStdErr: false
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -298,7 +429,7 @@ export class Install {
|
||||
await Exec.exec(logCmd.command, logCmd.args);
|
||||
});
|
||||
await core.group('Removing Docker context', async () => {
|
||||
await Exec.exec('docker', ['context', 'rm', '-f', this.contextName]);
|
||||
await Docker.exec(['context', 'rm', '-f', this.contextName]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -334,6 +465,9 @@ export class Install {
|
||||
case 'ppc64': {
|
||||
return 'ppc64le';
|
||||
}
|
||||
case 'arm64': {
|
||||
return 'aarch64';
|
||||
}
|
||||
case 'arm': {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const arm_version = (process.config.variables as any).arm_version;
|
||||
@@ -355,19 +489,33 @@ export class Install {
|
||||
}
|
||||
}
|
||||
|
||||
private static async colimaInstalled(): Promise<boolean> {
|
||||
private static async limaInstalled(): Promise<boolean> {
|
||||
return await io
|
||||
.which('colima', true)
|
||||
.which('lima', true)
|
||||
.then(res => {
|
||||
core.debug(`docker.Install.colimaAvailable ok: ${res}`);
|
||||
core.debug(`docker.Install.limaAvailable ok: ${res}`);
|
||||
return true;
|
||||
})
|
||||
.catch(error => {
|
||||
core.debug(`docker.Install.colimaAvailable error: ${error}`);
|
||||
core.debug(`docker.Install.limaAvailable error: ${error}`);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
private static async qemuArch(): Promise<string> {
|
||||
switch (os.arch()) {
|
||||
case 'x64': {
|
||||
return 'x86_64';
|
||||
}
|
||||
case 'arm64': {
|
||||
return 'aarch64';
|
||||
}
|
||||
default: {
|
||||
return os.arch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async getRelease(version: string): Promise<GitHubRelease> {
|
||||
const url = `https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/docker-releases.json`;
|
||||
const http: httpm.HttpClient = new httpm.HttpClient('docker-actions-toolkit');
|
||||
@@ -383,4 +531,25 @@ export class Install {
|
||||
}
|
||||
return releases[version];
|
||||
}
|
||||
|
||||
public static limaCustomImages(): LimaImage[] {
|
||||
const res: LimaImage[] = [];
|
||||
const env = process.env.LIMA_IMAGES;
|
||||
if (!env) {
|
||||
return res;
|
||||
}
|
||||
for (const input of Util.getList(env, {ignoreComma: true, comment: '#'})) {
|
||||
const archIndex = input.indexOf(':');
|
||||
const arch = input.substring(0, archIndex).trim();
|
||||
const digestIndex = input.indexOf('@');
|
||||
const location = input.substring(archIndex + 1, digestIndex !== -1 ? digestIndex : undefined).trim();
|
||||
const digest = digestIndex !== -1 ? input.substring(digestIndex + 1).trim() : '';
|
||||
res.push({
|
||||
location: location,
|
||||
arch: arch,
|
||||
digest: digest
|
||||
});
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
51
src/git.ts
51
src/git.ts
@@ -89,13 +89,12 @@ export class Git {
|
||||
}
|
||||
|
||||
public static async ref(): Promise<string> {
|
||||
return await Git.exec(['symbolic-ref', 'HEAD']).catch(() => {
|
||||
// if it fails (for example in a detached HEAD state), falls back to
|
||||
// using git tag or describe to get the exact matching tag name.
|
||||
return Git.tag().then(tag => {
|
||||
return `refs/tags/${tag}`;
|
||||
});
|
||||
});
|
||||
const isHeadDetached = await Git.isHeadDetached();
|
||||
if (isHeadDetached) {
|
||||
return await Git.getDetachedRef();
|
||||
}
|
||||
|
||||
return await Git.exec(['symbolic-ref', 'HEAD']);
|
||||
}
|
||||
|
||||
public static async fullCommit(): Promise<string> {
|
||||
@@ -115,6 +114,44 @@ export class Git {
|
||||
});
|
||||
}
|
||||
|
||||
private static async isHeadDetached(): Promise<boolean> {
|
||||
return await Git.exec(['branch', '--show-current']).then(res => {
|
||||
return res.length == 0;
|
||||
});
|
||||
}
|
||||
|
||||
private static async getDetachedRef(): Promise<string> {
|
||||
const res = await Git.exec(['show', '-s', '--pretty=%D']);
|
||||
|
||||
// Can be "HEAD, <tagname>" or "grafted, HEAD, <tagname>"
|
||||
const refMatch = res.match(/^(grafted, )?HEAD, (.*)$/);
|
||||
|
||||
if (!refMatch || !refMatch[2]) {
|
||||
throw new Error(`Cannot find detached HEAD ref in "${res}"`);
|
||||
}
|
||||
|
||||
const ref = refMatch[2].trim();
|
||||
|
||||
// Tag refs are formatted as "tag: <tagname>"
|
||||
if (ref.startsWith('tag: ')) {
|
||||
return `refs/tags/${ref.split(':')[1].trim()}`;
|
||||
}
|
||||
|
||||
// Branch refs are formatted as "<origin>/<branch-name>, <branch-name>"
|
||||
const branchMatch = ref.match(/^[^/]+\/[^/]+, (.+)$/);
|
||||
if (branchMatch) {
|
||||
return `refs/heads/${branchMatch[1].trim()}`;
|
||||
}
|
||||
|
||||
// Pull request merge refs are formatted as "pull/<number>/<state>"
|
||||
const prMatch = ref.match(/^pull\/\d+\/(head|merge)$/);
|
||||
if (prMatch) {
|
||||
return `refs/${ref}`;
|
||||
}
|
||||
|
||||
throw new Error(`Unsupported detached HEAD ref in "${res}"`);
|
||||
}
|
||||
|
||||
private static async exec(args: string[] = []): Promise<string> {
|
||||
return await Exec.getExecOutput(`git`, args, {
|
||||
ignoreReturnCode: true,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user