Compare commits
213 Commits
v0.1.0-bet
...
v0.7.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
495c96b050 | ||
|
|
b1e0aeed50 | ||
|
|
d0ee813215 | ||
|
|
b2a51dd6b4 | ||
|
|
acd3c9df19 | ||
|
|
8ad595b445 | ||
|
|
9450a454a7 | ||
|
|
a7221012c8 | ||
|
|
6fc5565c73 | ||
|
|
7492c7193a | ||
|
|
f05a598a08 | ||
|
|
fc85cef9e1 | ||
|
|
a5b683b46e | ||
|
|
0b166c63ef | ||
|
|
e072607266 | ||
|
|
a1ffbe9606 | ||
|
|
fdd740da2d | ||
|
|
8a9577d5e2 | ||
|
|
ca7a29d2d7 | ||
|
|
d39585b339 | ||
|
|
2e3ba6678f | ||
|
|
337a7240a5 | ||
|
|
728fcdbea9 | ||
|
|
dfa1a320c4 | ||
|
|
4ff86b974f | ||
|
|
181782ba21 | ||
|
|
dd977d3597 | ||
|
|
776422c908 | ||
|
|
d86a125551 | ||
|
|
633f41191f | ||
|
|
79def6b218 | ||
|
|
31e5d12fd9 | ||
|
|
1eda4b6a6c | ||
|
|
c71f3fe1ba | ||
|
|
8c8294806e | ||
|
|
ec382328c4 | ||
|
|
051c91700a | ||
|
|
471068fc6f | ||
|
|
60feaf2f84 | ||
|
|
ec33a95de8 | ||
|
|
b45f7f151f | ||
|
|
0ad6a34d2a | ||
|
|
4445b1e4fc | ||
|
|
9cca84f1d8 | ||
|
|
cf39a26d01 | ||
|
|
3ebf172e37 | ||
|
|
dba2a69f61 | ||
|
|
dd07d9ea06 | ||
|
|
0af70ae7cf | ||
|
|
0f6ebcb798 | ||
|
|
3f543accc6 | ||
|
|
16bbae82de | ||
|
|
8b597ca8bc | ||
|
|
dc9c9bc2b7 | ||
|
|
63659873d5 | ||
|
|
6327a9b5dc | ||
|
|
50b16df20c | ||
|
|
0b1e18cfc2 | ||
|
|
741d2e1319 | ||
|
|
9e10ac6818 | ||
|
|
65f12dcfd0 | ||
|
|
46da20f01d | ||
|
|
0af3fda4f0 | ||
|
|
6179a5a445 | ||
|
|
26d9901f07 | ||
|
|
462c95e83d | ||
|
|
e185293749 | ||
|
|
2d1ce9a223 | ||
|
|
2d105f7337 | ||
|
|
5df47fe964 | ||
|
|
61527248dd | ||
|
|
210b7421e4 | ||
|
|
e9aa8365e3 | ||
|
|
85557d0e0d | ||
|
|
a7448298e0 | ||
|
|
d0929eeb16 | ||
|
|
da9600bbef | ||
|
|
70fba4e078 | ||
|
|
a89868cdc5 | ||
|
|
49bde5a54a | ||
|
|
4fcbf75fc4 | ||
|
|
314f8f431e | ||
|
|
7fb0476dc8 | ||
|
|
9b9ff70b75 | ||
|
|
e7eee6e401 | ||
|
|
b2fd32e0ef | ||
|
|
417136db1e | ||
|
|
e033e82024 | ||
|
|
b3328f5ec4 | ||
|
|
b0518231d0 | ||
|
|
c0da63f810 | ||
|
|
041d9693ab | ||
|
|
39158d8047 | ||
|
|
a6c94b5167 | ||
|
|
a5943234fd | ||
|
|
03977693c1 | ||
|
|
d6d770f303 | ||
|
|
8df8cee02f | ||
|
|
94febd1da7 | ||
|
|
b7cdc617ce | ||
|
|
75c0c7fac0 | ||
|
|
e9cfd63e16 | ||
|
|
ac61bd8949 | ||
|
|
7b50104faa | ||
|
|
d7735e9ddf | ||
|
|
dd1544e1be | ||
|
|
32af66cb28 | ||
|
|
2090433c0d | ||
|
|
50c11e6dce | ||
|
|
0f9cc7c29f | ||
|
|
dfc72fd31c | ||
|
|
317ef51ab5 | ||
|
|
3a30337d24 | ||
|
|
fc16ecda91 | ||
|
|
48cefc1da0 | ||
|
|
fda3be9699 | ||
|
|
53ca96fcc4 | ||
|
|
70390c899b | ||
|
|
ac9d9d9a1b | ||
|
|
3c2fe5ddb2 | ||
|
|
adad1e3786 | ||
|
|
3a0f4db686 | ||
|
|
2201fc1194 | ||
|
|
6210eb507a | ||
|
|
3b532d1b91 | ||
|
|
93fa96f54f | ||
|
|
3ec6f00f46 | ||
|
|
4d66b2fa08 | ||
|
|
964381b7e9 | ||
|
|
f78f708678 | ||
|
|
6fe7d54029 | ||
|
|
8a69d6cb01 | ||
|
|
1cc5fc87fb | ||
|
|
97e647fdd0 | ||
|
|
e08fc168a1 | ||
|
|
9128f56258 | ||
|
|
2e59ae7030 | ||
|
|
99487d6986 | ||
|
|
3d9ec9f02d | ||
|
|
f2b1224b00 | ||
|
|
1383a2bcaf | ||
|
|
1acd6c2fc0 | ||
|
|
d153cfaf3c | ||
|
|
d09114e0c5 | ||
|
|
c3aa7f205d | ||
|
|
62f8c6bef6 | ||
|
|
a9ce06b57e | ||
|
|
cb6ca3829f | ||
|
|
1098847fe7 | ||
|
|
35a8193474 | ||
|
|
2915834633 | ||
|
|
a0e8f0bf18 | ||
|
|
580aee99c0 | ||
|
|
89ecd37681 | ||
|
|
139fb39ab0 | ||
|
|
67957d8c7a | ||
|
|
768df5fbf4 | ||
|
|
e9db81b6a1 | ||
|
|
cd825ae548 | ||
|
|
28c11a1819 | ||
|
|
ed087e5b0d | ||
|
|
2038d87306 | ||
|
|
252c717cc3 | ||
|
|
9b338b58a7 | ||
|
|
abe37ab72b | ||
|
|
b3a30a9e32 | ||
|
|
31e915c017 | ||
|
|
05bbe49fe1 | ||
|
|
c80fedbbae | ||
|
|
2c60cad840 | ||
|
|
847887b312 | ||
|
|
d9984214c9 | ||
|
|
33b4390bc2 | ||
|
|
5e8f679709 | ||
|
|
f288f4f7ea | ||
|
|
cb9121174a | ||
|
|
464dfbe1ec | ||
|
|
5695c0049b | ||
|
|
44b1545abd | ||
|
|
4d9d62d542 | ||
|
|
aa3c8ef106 | ||
|
|
259abb56df | ||
|
|
76e5a25cff |
320
.github/buildx-releases.json
vendored
320
.github/buildx-releases.json
vendored
@@ -1,43 +1,289 @@
|
||||
{
|
||||
"latest": {
|
||||
"id": 92694870,
|
||||
"tag_name": "v0.10.3",
|
||||
"html_url": "https://github.com/docker/buildx/releases/tag/v0.10.3",
|
||||
"id": 111149999,
|
||||
"tag_name": "v0.11.1",
|
||||
"html_url": "https://github.com/docker/buildx/releases/tag/v0.11.1",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-amd64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-arm64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-amd64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v6",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v7",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-ppc64le",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-riscv64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-s390x",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.3/checksums.txt"
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.darwin-amd64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.darwin-arm64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-amd64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm-v6",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm-v7",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-ppc64le",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-riscv64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-s390x",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.11.1": {
|
||||
"id": 111149999,
|
||||
"tag_name": "v0.11.1",
|
||||
"html_url": "https://github.com/docker/buildx/releases/tag/v0.11.1",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.darwin-amd64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.darwin-arm64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-amd64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm-v6",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm-v7",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-ppc64le",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-riscv64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-s390x",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/buildx-v0.11.1.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.1/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.11.0": {
|
||||
"id": 108385289,
|
||||
"tag_name": "v0.11.0",
|
||||
"html_url": "https://github.com/docker/buildx/releases/tag/v0.11.0",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.darwin-amd64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.darwin-arm64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-amd64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-arm-v6",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-arm-v7",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-arm64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-ppc64le",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-riscv64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-s390x",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.11.0-rc2": {
|
||||
"id": 107680036,
|
||||
"tag_name": "v0.11.0-rc2",
|
||||
"html_url": "https://github.com/docker/buildx/releases/tag/v0.11.0-rc2",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.darwin-amd64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.darwin-arm64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-amd64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-arm-v6",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-arm-v7",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-arm64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-ppc64le",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-riscv64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-s390x",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/buildx-v0.11.0-rc2.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc2/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.10.5": {
|
||||
"id": 103872471,
|
||||
"tag_name": "v0.10.5",
|
||||
"html_url": "https://github.com/docker/buildx/releases/tag/v0.10.5",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.darwin-amd64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.darwin-arm64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-amd64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-arm-v6",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-arm-v7",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-arm64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-ppc64le",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-riscv64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-s390x",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/buildx-v0.10.5.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.5/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.11.0-rc1": {
|
||||
"id": 102797153,
|
||||
"tag_name": "v0.11.0-rc1",
|
||||
"html_url": "https://github.com/docker/buildx/releases/tag/v0.11.0-rc1",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.darwin-amd64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.darwin-arm64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-amd64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-arm-v6",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-arm-v7",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-arm64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-ppc64le",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-riscv64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-s390x",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/buildx-v0.11.0-rc1.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.11.0-rc1/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.10.4": {
|
||||
"id": 94659464,
|
||||
"tag_name": "v0.10.4",
|
||||
"html_url": "https://github.com/docker/buildx/releases/tag/v0.10.4",
|
||||
"assets": [
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.darwin-amd64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.darwin-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.darwin-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.darwin-arm64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.darwin-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.darwin-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-amd64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-arm-v6",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-arm-v6.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-arm-v6.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-arm-v7",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-arm-v7.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-arm-v7.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-arm64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-ppc64le",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-ppc64le.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-ppc64le.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-riscv64",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-riscv64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-riscv64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-s390x",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-s390x.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.linux-s390x.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.windows-amd64.exe",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.windows-amd64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.windows-amd64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.windows-arm64.exe",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.windows-arm64.provenance.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/buildx-v0.10.4.windows-arm64.sbom.json",
|
||||
"https://github.com/docker/buildx/releases/download/v0.10.4/checksums.txt"
|
||||
]
|
||||
},
|
||||
"v0.10.3": {
|
||||
|
||||
836
.github/docker-releases.json
vendored
Normal file
836
.github/docker-releases.json
vendored
Normal file
@@ -0,0 +1,836 @@
|
||||
{
|
||||
"latest": {
|
||||
"id": 111464537,
|
||||
"tag_name": "v24.0.4",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.4",
|
||||
"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": {
|
||||
"id": 104366762,
|
||||
"tag_name": "v24.0.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.2",
|
||||
"assets": []
|
||||
},
|
||||
"v24.0.1": {
|
||||
"id": 103671743,
|
||||
"tag_name": "v24.0.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.1",
|
||||
"assets": []
|
||||
},
|
||||
"v24.0.0": {
|
||||
"id": 103200193,
|
||||
"tag_name": "v24.0.0",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.0",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.25": {
|
||||
"id": 103070540,
|
||||
"tag_name": "v20.10.25",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.25",
|
||||
"assets": []
|
||||
},
|
||||
"v24.0.0-rc.4": {
|
||||
"id": 102846110,
|
||||
"tag_name": "v24.0.0-rc.4",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.0-rc.4",
|
||||
"assets": []
|
||||
},
|
||||
"v24.0.0-rc.3": {
|
||||
"id": 102708870,
|
||||
"tag_name": "v24.0.0-rc.3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.0-rc.3",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.6": {
|
||||
"id": 102196340,
|
||||
"tag_name": "v23.0.6",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.6",
|
||||
"assets": []
|
||||
},
|
||||
"v24.0.0-rc.2": {
|
||||
"id": 102091676,
|
||||
"tag_name": "v24.0.0-rc.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.0-rc.2",
|
||||
"assets": []
|
||||
},
|
||||
"v24.0.0-rc.1": {
|
||||
"id": 101305950,
|
||||
"tag_name": "v24.0.0-rc.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.0-rc.1",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.5": {
|
||||
"id": 101005794,
|
||||
"tag_name": "v23.0.5",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.5",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.4": {
|
||||
"id": 99811576,
|
||||
"tag_name": "v23.0.4",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.4",
|
||||
"assets": []
|
||||
},
|
||||
"v24.0.0-beta.2": {
|
||||
"id": 99544545,
|
||||
"tag_name": "v24.0.0-beta.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.0-beta.2",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.3": {
|
||||
"id": 98122882,
|
||||
"tag_name": "v23.0.3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.3",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.24": {
|
||||
"id": 98096018,
|
||||
"tag_name": "v20.10.24",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.24",
|
||||
"assets": []
|
||||
},
|
||||
"v24.0.0-beta.1": {
|
||||
"id": 97703002,
|
||||
"tag_name": "v24.0.0-beta.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v24.0.0-beta.1",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.2": {
|
||||
"id": 97163508,
|
||||
"tag_name": "v23.0.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.2",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.1": {
|
||||
"id": 91964526,
|
||||
"tag_name": "v23.0.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.1",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.0": {
|
||||
"id": 91109643,
|
||||
"tag_name": "v23.0.0",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.0",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.0-rc.4": {
|
||||
"id": 91003797,
|
||||
"tag_name": "v23.0.0-rc.4",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.0-rc.4",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.0-rc.3": {
|
||||
"id": 89780703,
|
||||
"tag_name": "v23.0.0-rc.3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.0-rc.3",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.23": {
|
||||
"id": 89647366,
|
||||
"tag_name": "v20.10.23",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.23",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.0-rc.2": {
|
||||
"id": 88712255,
|
||||
"tag_name": "v23.0.0-rc.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.0-rc.2",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.0-rc.1": {
|
||||
"id": 87299039,
|
||||
"tag_name": "v23.0.0-rc.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.0-rc.1",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.22": {
|
||||
"id": 86325342,
|
||||
"tag_name": "v20.10.22",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.22",
|
||||
"assets": []
|
||||
},
|
||||
"v23.0.0-beta.1": {
|
||||
"id": 85159482,
|
||||
"tag_name": "v23.0.0-beta.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.0-beta.1",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.21": {
|
||||
"id": 80977884,
|
||||
"tag_name": "v20.10.21",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.21",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.20": {
|
||||
"id": 80248420,
|
||||
"tag_name": "v20.10.20",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.20",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.19": {
|
||||
"id": 79847378,
|
||||
"tag_name": "v20.10.19",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.19",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.18": {
|
||||
"id": 76694729,
|
||||
"tag_name": "v20.10.18",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.18",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.17": {
|
||||
"id": 68777665,
|
||||
"tag_name": "v20.10.17",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.17",
|
||||
"assets": []
|
||||
},
|
||||
"v22.06.0-beta.0": {
|
||||
"id": 68600276,
|
||||
"tag_name": "v22.06.0-beta.0",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v22.06.0-beta.0",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.16": {
|
||||
"id": 66708640,
|
||||
"tag_name": "v20.10.16",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.16",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.15": {
|
||||
"id": 66170410,
|
||||
"tag_name": "v20.10.15",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.15",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.14": {
|
||||
"id": 62642891,
|
||||
"tag_name": "v20.10.14",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.14",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.13": {
|
||||
"id": 61523032,
|
||||
"tag_name": "v20.10.13",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.13",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.12": {
|
||||
"id": 56724849,
|
||||
"tag_name": "v20.10.12",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.12",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.11": {
|
||||
"id": 53604359,
|
||||
"tag_name": "v20.10.11",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.11",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.10": {
|
||||
"id": 51991530,
|
||||
"tag_name": "v20.10.10",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.10",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.9": {
|
||||
"id": 50763745,
|
||||
"tag_name": "v20.10.9",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.9",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.8": {
|
||||
"id": 47261111,
|
||||
"tag_name": "v20.10.8",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.8",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.7": {
|
||||
"id": 44002175,
|
||||
"tag_name": "v20.10.7",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.7",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.6": {
|
||||
"id": 41439201,
|
||||
"tag_name": "v20.10.6",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.6",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.5": {
|
||||
"id": 39216180,
|
||||
"tag_name": "v20.10.5",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.5",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.4": {
|
||||
"id": 39014860,
|
||||
"tag_name": "v20.10.4",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.4",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.3": {
|
||||
"id": 37231470,
|
||||
"tag_name": "v20.10.3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.3",
|
||||
"assets": []
|
||||
},
|
||||
"v19.03.15": {
|
||||
"id": 37231443,
|
||||
"tag_name": "v19.03.15",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v19.03.15",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.2": {
|
||||
"id": 35990169,
|
||||
"tag_name": "v20.10.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.2",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.1": {
|
||||
"id": 35281927,
|
||||
"tag_name": "v20.10.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.1",
|
||||
"assets": []
|
||||
},
|
||||
"v20.10.0": {
|
||||
"id": 35069369,
|
||||
"tag_name": "v20.10.0",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v20.10.0",
|
||||
"assets": []
|
||||
},
|
||||
"v19.03.14": {
|
||||
"id": 34677482,
|
||||
"tag_name": "v19.03.14",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v19.03.14",
|
||||
"assets": []
|
||||
},
|
||||
"v19.03.13": {
|
||||
"id": 31493434,
|
||||
"tag_name": "v19.03.13",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v19.03.13",
|
||||
"assets": []
|
||||
},
|
||||
"v19.03.12": {
|
||||
"id": 28065393,
|
||||
"tag_name": "v19.03.12",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v19.03.12",
|
||||
"assets": []
|
||||
},
|
||||
"v19.03.11": {
|
||||
"id": 27237950,
|
||||
"tag_name": "v19.03.11",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v19.03.11",
|
||||
"assets": []
|
||||
},
|
||||
"v19.03.10": {
|
||||
"id": 27043306,
|
||||
"tag_name": "v19.03.10",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v19.03.10",
|
||||
"assets": []
|
||||
},
|
||||
"v19.03.9": {
|
||||
"id": 27002855,
|
||||
"tag_name": "v19.03.9",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v19.03.9",
|
||||
"assets": []
|
||||
},
|
||||
"v19.03.8": {
|
||||
"id": 25372883,
|
||||
"tag_name": "v19.03.8",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v19.03.8",
|
||||
"assets": []
|
||||
},
|
||||
"v17.03.2-ce": {
|
||||
"id": 6858533,
|
||||
"tag_name": "v17.03.2-ce",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v17.03.2-ce",
|
||||
"assets": []
|
||||
},
|
||||
"v17.03.2-ce-rc1": {
|
||||
"id": 6547028,
|
||||
"tag_name": "v17.03.2-ce-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v17.03.2-ce-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v17.05.0-ce": {
|
||||
"id": 6295254,
|
||||
"tag_name": "v17.05.0-ce",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v17.05.0-ce",
|
||||
"assets": []
|
||||
},
|
||||
"v17.05.0-ce-rc3": {
|
||||
"id": 6259851,
|
||||
"tag_name": "v17.05.0-ce-rc3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v17.05.0-ce-rc3",
|
||||
"assets": []
|
||||
},
|
||||
"v17.05.0-ce-rc2": {
|
||||
"id": 6216216,
|
||||
"tag_name": "v17.05.0-ce-rc2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v17.05.0-ce-rc2",
|
||||
"assets": []
|
||||
},
|
||||
"v17.05.0-ce-rc1": {
|
||||
"id": 6066291,
|
||||
"tag_name": "v17.05.0-ce-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v17.05.0-ce-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v17.04.0-ce": {
|
||||
"id": 5992837,
|
||||
"tag_name": "v17.04.0-ce",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v17.04.0-ce",
|
||||
"assets": []
|
||||
},
|
||||
"v17.04.0-ce-rc2": {
|
||||
"id": 5930499,
|
||||
"tag_name": "v17.04.0-ce-rc2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v17.04.0-ce-rc2",
|
||||
"assets": []
|
||||
},
|
||||
"v17.03.1-ce": {
|
||||
"id": 5889333,
|
||||
"tag_name": "v17.03.1-ce",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v17.03.1-ce",
|
||||
"assets": []
|
||||
},
|
||||
"v17.04.0-ce-rc1": {
|
||||
"id": 5821903,
|
||||
"tag_name": "v17.04.0-ce-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v17.04.0-ce-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v17.03.1-ce-rc1": {
|
||||
"id": 5787909,
|
||||
"tag_name": "v17.03.1-ce-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v17.03.1-ce-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v17.03.0-ce": {
|
||||
"id": 5616072,
|
||||
"tag_name": "v17.03.0-ce",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v17.03.0-ce",
|
||||
"assets": []
|
||||
},
|
||||
"v17.03.0-ce-rc1": {
|
||||
"id": 5516127,
|
||||
"tag_name": "v17.03.0-ce-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v17.03.0-ce-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.13.1": {
|
||||
"id": 5400129,
|
||||
"tag_name": "v1.13.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.13.1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.13.1-rc2": {
|
||||
"id": 5385634,
|
||||
"tag_name": "v1.13.1-rc2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.13.1-rc2",
|
||||
"assets": []
|
||||
},
|
||||
"v1.13.1-rc1": {
|
||||
"id": 5307652,
|
||||
"tag_name": "v1.13.1-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.13.1-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.13.0": {
|
||||
"id": 5196571,
|
||||
"tag_name": "v1.13.0",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.13.0",
|
||||
"assets": []
|
||||
},
|
||||
"v1.13.0-rc7": {
|
||||
"id": 5157693,
|
||||
"tag_name": "v1.13.0-rc7",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.13.0-rc7",
|
||||
"assets": []
|
||||
},
|
||||
"v1.13.0-rc6": {
|
||||
"id": 5135134,
|
||||
"tag_name": "v1.13.0-rc6",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.13.0-rc6",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.6": {
|
||||
"id": 5123890,
|
||||
"tag_name": "v1.12.6",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.6",
|
||||
"assets": []
|
||||
},
|
||||
"v1.13.0-rc5": {
|
||||
"id": 5080578,
|
||||
"tag_name": "v1.13.0-rc5",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.13.0-rc5",
|
||||
"assets": []
|
||||
},
|
||||
"v1.13.0-rc4": {
|
||||
"id": 4948866,
|
||||
"tag_name": "v1.13.0-rc4",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.13.0-rc4",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.5": {
|
||||
"id": 4938198,
|
||||
"tag_name": "v1.12.5",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.5",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.5-rc1": {
|
||||
"id": 4926422,
|
||||
"tag_name": "v1.12.5-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.5-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.4": {
|
||||
"id": 4901878,
|
||||
"tag_name": "v1.12.4",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.4",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.4-rc1": {
|
||||
"id": 4863914,
|
||||
"tag_name": "v1.12.4-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.4-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.13.0-rc3": {
|
||||
"id": 4840704,
|
||||
"tag_name": "v1.13.0-rc3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.13.0-rc3",
|
||||
"assets": []
|
||||
},
|
||||
"v1.13.0-rc2": {
|
||||
"id": 4744761,
|
||||
"tag_name": "v1.13.0-rc2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.13.0-rc2",
|
||||
"assets": []
|
||||
},
|
||||
"v1.13.0-rc1": {
|
||||
"id": 4641203,
|
||||
"tag_name": "v1.13.0-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.13.0-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.3": {
|
||||
"id": 4495222,
|
||||
"tag_name": "v1.12.3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.3",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.3-rc1": {
|
||||
"id": 4481016,
|
||||
"tag_name": "v1.12.3-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.3-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.2": {
|
||||
"id": 4364345,
|
||||
"tag_name": "v1.12.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.2",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.2-rc3": {
|
||||
"id": 4336430,
|
||||
"tag_name": "v1.12.2-rc3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.2-rc3",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.2-rc2": {
|
||||
"id": 4304701,
|
||||
"tag_name": "v1.12.2-rc2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.2-rc2",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.2-rc1": {
|
||||
"id": 4246481,
|
||||
"tag_name": "v1.12.2-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.2-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.1": {
|
||||
"id": 3919520,
|
||||
"tag_name": "v1.12.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.1-rc2": {
|
||||
"id": 3909470,
|
||||
"tag_name": "v1.12.1-rc2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.1-rc2",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.1-rc1": {
|
||||
"id": 3879305,
|
||||
"tag_name": "v1.12.1-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.1-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.0": {
|
||||
"id": 3766135,
|
||||
"tag_name": "v1.12.0",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.0",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.0-rc5": {
|
||||
"id": 3744904,
|
||||
"tag_name": "v1.12.0-rc5",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.0-rc5",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.0-rc4": {
|
||||
"id": 3644623,
|
||||
"tag_name": "v1.12.0-rc4",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.0-rc4",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.0-rc3": {
|
||||
"id": 3573896,
|
||||
"tag_name": "v1.12.0-rc3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.0-rc3",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.0-rc2": {
|
||||
"id": 3471944,
|
||||
"tag_name": "v1.12.0-rc2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.0-rc2",
|
||||
"assets": []
|
||||
},
|
||||
"v1.12.0-rc1": {
|
||||
"id": 3447699,
|
||||
"tag_name": "v1.12.0-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.12.0-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.11.2": {
|
||||
"id": 3354503,
|
||||
"tag_name": "v1.11.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.11.2",
|
||||
"assets": []
|
||||
},
|
||||
"v1.11.2-rc1": {
|
||||
"id": 3327300,
|
||||
"tag_name": "v1.11.2-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.11.2-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.11.1": {
|
||||
"id": 3105125,
|
||||
"tag_name": "v1.11.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.11.1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.11.1-rc1": {
|
||||
"id": 3097597,
|
||||
"tag_name": "v1.11.1-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.11.1-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.11.0": {
|
||||
"id": 3014278,
|
||||
"tag_name": "v1.11.0",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.11.0",
|
||||
"assets": []
|
||||
},
|
||||
"v1.11.0-rc5": {
|
||||
"id": 2998258,
|
||||
"tag_name": "v1.11.0-rc5",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.11.0-rc5",
|
||||
"assets": []
|
||||
},
|
||||
"v1.11.0-rc4": {
|
||||
"id": 2968912,
|
||||
"tag_name": "v1.11.0-rc4",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.11.0-rc4",
|
||||
"assets": []
|
||||
},
|
||||
"v1.11.0-rc3": {
|
||||
"id": 2937939,
|
||||
"tag_name": "v1.11.0-rc3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.11.0-rc3",
|
||||
"assets": []
|
||||
},
|
||||
"v1.11.0-rc2": {
|
||||
"id": 2890861,
|
||||
"tag_name": "v1.11.0-rc2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.11.0-rc2",
|
||||
"assets": []
|
||||
},
|
||||
"v1.11.0-rc1": {
|
||||
"id": 2875983,
|
||||
"tag_name": "v1.11.0-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.11.0-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.10.3": {
|
||||
"id": 2788494,
|
||||
"tag_name": "v1.10.3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.10.3",
|
||||
"assets": []
|
||||
},
|
||||
"v1.10.3-rc2": {
|
||||
"id": 2780060,
|
||||
"tag_name": "v1.10.3-rc2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.10.3-rc2",
|
||||
"assets": []
|
||||
},
|
||||
"v1.10.3-rc1": {
|
||||
"id": 2777835,
|
||||
"tag_name": "v1.10.3-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.10.3-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.10.2": {
|
||||
"id": 2666504,
|
||||
"tag_name": "v1.10.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.10.2",
|
||||
"assets": []
|
||||
},
|
||||
"v1.10.2-rc1": {
|
||||
"id": 2652399,
|
||||
"tag_name": "v1.10.2-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.10.2-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.10.1": {
|
||||
"id": 2598018,
|
||||
"tag_name": "v1.10.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.10.1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.10.1-rc1": {
|
||||
"id": 2590708,
|
||||
"tag_name": "v1.10.1-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.10.1-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.10.0": {
|
||||
"id": 2555659,
|
||||
"tag_name": "v1.10.0",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.10.0",
|
||||
"assets": []
|
||||
},
|
||||
"v1.10.0-rc4": {
|
||||
"id": 2549294,
|
||||
"tag_name": "v1.10.0-rc4",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.10.0-rc4",
|
||||
"assets": []
|
||||
},
|
||||
"v1.10.0-rc3": {
|
||||
"id": 2541607,
|
||||
"tag_name": "v1.10.0-rc3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.10.0-rc3",
|
||||
"assets": []
|
||||
},
|
||||
"v1.10.0-rc2": {
|
||||
"id": 2505382,
|
||||
"tag_name": "v1.10.0-rc2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.10.0-rc2",
|
||||
"assets": []
|
||||
},
|
||||
"v1.10.0-rc1": {
|
||||
"id": 2437435,
|
||||
"tag_name": "v1.10.0-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.10.0-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.9.1": {
|
||||
"id": 2161885,
|
||||
"tag_name": "v1.9.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.9.1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.9.1-rc1": {
|
||||
"id": 2124307,
|
||||
"tag_name": "v1.9.1-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.9.1-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.9.0": {
|
||||
"id": 2065556,
|
||||
"tag_name": "v1.9.0",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.9.0",
|
||||
"assets": []
|
||||
},
|
||||
"v1.9.0-rc5": {
|
||||
"id": 2063038,
|
||||
"tag_name": "v1.9.0-rc5",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.9.0-rc5",
|
||||
"assets": []
|
||||
},
|
||||
"v1.9.0-rc4": {
|
||||
"id": 2051407,
|
||||
"tag_name": "v1.9.0-rc4",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.9.0-rc4",
|
||||
"assets": []
|
||||
},
|
||||
"v1.9.0-rc3": {
|
||||
"id": 2030176,
|
||||
"tag_name": "v1.9.0-rc3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.9.0-rc3",
|
||||
"assets": []
|
||||
},
|
||||
"v1.9.0-rc2": {
|
||||
"id": 2006252,
|
||||
"tag_name": "v1.9.0-rc2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.9.0-rc2",
|
||||
"assets": []
|
||||
},
|
||||
"v1.9.0-rc1": {
|
||||
"id": 1960642,
|
||||
"tag_name": "v1.9.0-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.9.0-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.8.3": {
|
||||
"id": 1948004,
|
||||
"tag_name": "v1.8.3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.8.3",
|
||||
"assets": []
|
||||
},
|
||||
"v1.8.2": {
|
||||
"id": 1796575,
|
||||
"tag_name": "v1.8.2",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.8.2",
|
||||
"assets": []
|
||||
},
|
||||
"v1.8.2-rc1": {
|
||||
"id": 1765231,
|
||||
"tag_name": "v1.8.2-rc1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.8.2-rc1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.8.1": {
|
||||
"id": 1665370,
|
||||
"tag_name": "v1.8.1",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.8.1",
|
||||
"assets": []
|
||||
},
|
||||
"v1.8.0": {
|
||||
"id": 1657439,
|
||||
"tag_name": "v1.8.0",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.8.0",
|
||||
"assets": []
|
||||
},
|
||||
"v1.8.0-rc3": {
|
||||
"id": 1643499,
|
||||
"tag_name": "v1.8.0-rc3",
|
||||
"html_url": "https://github.com/moby/moby/releases/tag/v1.8.0-rc3",
|
||||
"assets": []
|
||||
}
|
||||
}
|
||||
26
.github/workflows/build.yml
vendored
Normal file
26
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: build
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '.github/*-releases.json'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@v3
|
||||
with:
|
||||
targets: build
|
||||
6
.github/workflows/buildx-releases-json.yml
vendored
6
.github/workflows/buildx-releases-json.yml
vendored
@@ -13,11 +13,11 @@ on:
|
||||
- 'main'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '.github/buildx-releases.json'
|
||||
- '.github/*-releases.json'
|
||||
|
||||
jobs:
|
||||
generate:
|
||||
uses: crazy-max/.github/.github/workflows/releases-json.yml@2a596c917a8ad3e6203ae99b777148525a2e00d5
|
||||
uses: crazy-max/.github/.github/workflows/releases-json.yml@6dc31870ca6c4f8489bf5a408ab38fae60f47eec
|
||||
with:
|
||||
repository: docker/buildx
|
||||
artifact_name: buildx-releases-json
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
git add -A .
|
||||
-
|
||||
name: Create PR
|
||||
uses: peter-evans/create-pull-request@2b011faafdcbc9ceb11414d64d0573f37c774b04
|
||||
uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38
|
||||
with:
|
||||
base: main
|
||||
branch: bot/buildx-releases-json
|
||||
|
||||
58
.github/workflows/docker-releases-json.yml
vendored
Normal file
58
.github/workflows/docker-releases-json.yml
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
name: docker-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-ignore:
|
||||
- '.github/*-releases.json'
|
||||
|
||||
jobs:
|
||||
generate:
|
||||
uses: crazy-max/.github/.github/workflows/releases-json.yml@6dc31870ca6c4f8489bf5a408ab38fae60f47eec
|
||||
with:
|
||||
repository: moby/moby
|
||||
artifact_name: docker-releases-json
|
||||
filename: docker-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@v3
|
||||
-
|
||||
name: Download
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: docker-releases-json
|
||||
path: .github
|
||||
-
|
||||
name: Commit changes
|
||||
run: |
|
||||
git add -A .
|
||||
-
|
||||
name: Create PR
|
||||
uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38
|
||||
with:
|
||||
base: main
|
||||
branch: bot/docker-releases-json
|
||||
commit-message: "github: update .github/docker-releases.json"
|
||||
signoff: true
|
||||
delete-branch: true
|
||||
title: "Update `.github/docker-releases.json`"
|
||||
body: |
|
||||
Update `.github/docker-releases.json` to keep in sync with [https://github.com/moby/moby](https://github.com/moby/moby).
|
||||
draft: false
|
||||
6
.github/workflows/publish.yml
vendored
6
.github/workflows/publish.yml
vendored
@@ -1,5 +1,9 @@
|
||||
name: publish
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
@@ -17,7 +21,7 @@ jobs:
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Publish
|
||||
uses: docker/bake-action@v2
|
||||
uses: docker/bake-action@v3
|
||||
with:
|
||||
targets: publish
|
||||
env:
|
||||
|
||||
102
.github/workflows/test.yml
vendored
102
.github/workflows/test.yml
vendored
@@ -1,33 +1,19 @@
|
||||
name: test
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '.github/buildx-releases.json'
|
||||
- '.github/*-releases.json'
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target:
|
||||
- lint
|
||||
- vendor-validate
|
||||
- license-validate
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Validate
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -36,7 +22,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Test
|
||||
uses: docker/bake-action@v2
|
||||
uses: docker/bake-action@v3
|
||||
with:
|
||||
targets: test-coverage
|
||||
env:
|
||||
@@ -46,3 +32,77 @@ jobs:
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
file: ./coverage/clover.xml
|
||||
flags: unit
|
||||
|
||||
prepare-itg:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.tests.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'yarn'
|
||||
-
|
||||
name: Install
|
||||
run: yarn install
|
||||
-
|
||||
name: Create matrix
|
||||
id: tests
|
||||
run: |
|
||||
declare -a tests
|
||||
for test in $(yarn run test:itg-list); do
|
||||
tests+=("${test#$(pwd)/__tests__/}")
|
||||
done
|
||||
echo "matrix=$(echo ${tests[@]} | jq -cR 'split(" ")')" >>${GITHUB_OUTPUT}
|
||||
-
|
||||
name: Show matrix
|
||||
run: |
|
||||
echo ${{ steps.tests.outputs.matrix }}
|
||||
|
||||
test-itg:
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs:
|
||||
- prepare-itg
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
test: ${{ fromJson(needs.prepare-itg.outputs.matrix) }}
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
- 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
|
||||
-
|
||||
name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'yarn'
|
||||
-
|
||||
name: Install
|
||||
run: yarn install
|
||||
-
|
||||
name: Test
|
||||
run: yarn test:itg-coverage --runTestsByPath __tests__/${{ matrix.test }} --coverageDirectory=./coverage
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
-
|
||||
name: Upload coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
file: ./coverage/clover.xml
|
||||
flags: itg
|
||||
|
||||
47
.github/workflows/validate.yml
vendored
Normal file
47
.github/workflows/validate.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
name: validate
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '.github/*-releases.json'
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
runs-on: ubuntu-20.04
|
||||
outputs:
|
||||
targets: ${{ steps.targets.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Matrix
|
||||
id: targets
|
||||
run: |
|
||||
echo "matrix=$(docker buildx bake validate --print | jq -cr '.group.validate.targets')" >> $GITHUB_OUTPUT
|
||||
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- prepare
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: ${{ fromJson(needs.prepare.outputs.targets) }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Validate
|
||||
uses: docker/bake-action@v3
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
1
.github/workflows/virtual-env.yml
vendored
1
.github/workflows/virtual-env.yml
vendored
@@ -23,7 +23,6 @@ jobs:
|
||||
- ubuntu-latest
|
||||
- ubuntu-22.04
|
||||
- ubuntu-20.04
|
||||
- ubuntu-18.04
|
||||
steps:
|
||||
-
|
||||
name: File system
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
[](https://www.npmjs.com/package/@docker/actions-toolkit)
|
||||
[](https://www.npmjs.com/package/@docker/actions-toolkit)
|
||||
[](https://github.com/docker/actions-toolkit/actions?workflow=build)
|
||||
[](https://github.com/docker/actions-toolkit/actions?workflow=test)
|
||||
[](https://github.com/docker/actions-toolkit/actions?workflow=validate)
|
||||
[](https://codecov.io/gh/docker/actions-toolkit)
|
||||
|
||||
# Actions Toolkit
|
||||
@@ -39,7 +41,7 @@ $ npm install @docker/actions-toolkit
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const { Toolkit } = require('@docker/actions-toolkit')
|
||||
const { Toolkit } = require('@docker/actions-toolkit/lib/toolkit')
|
||||
const toolkit = new Toolkit()
|
||||
```
|
||||
|
||||
|
||||
@@ -15,11 +15,9 @@
|
||||
*/
|
||||
|
||||
import {beforeEach, describe, expect, it, jest, test} from '@jest/globals';
|
||||
import * as semver from 'semver';
|
||||
|
||||
import {BuildKit} from '../../src/buildkit/buildkit';
|
||||
import {Builder} from '../../src/buildx/builder';
|
||||
import {Context} from '../../src/context';
|
||||
|
||||
import {BuilderInfo} from '../../src/types/builder';
|
||||
|
||||
@@ -34,9 +32,9 @@ jest.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise<Bu
|
||||
lastActivity: new Date('2023-01-16 09:45:23 +0000 UTC'),
|
||||
nodes: [
|
||||
{
|
||||
buildkitVersion: 'v0.11.0',
|
||||
buildkitdFlags: '--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
|
||||
driverOpts: ['BUILDKIT_STEP_LOG_MAX_SIZE=10485760', 'BUILDKIT_STEP_LOG_MAX_SPEED=10485760', 'JAEGER_TRACE=localhost:6831', 'image=moby/buildkit:latest', 'network=host'],
|
||||
buildkit: 'v0.11.0',
|
||||
'buildkitd-flags': '--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
|
||||
'driver-opts': ['BUILDKIT_STEP_LOG_MAX_SIZE=10485760', 'BUILDKIT_STEP_LOG_MAX_SPEED=10485760', 'JAEGER_TRACE=localhost:6831', 'image=moby/buildkit:latest', 'network=host'],
|
||||
endpoint: 'unix:///var/run/docker.sock',
|
||||
name: 'builder20',
|
||||
platforms: 'linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6',
|
||||
@@ -48,11 +46,11 @@ jest.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise<Bu
|
||||
|
||||
describe('getVersion', () => {
|
||||
it('valid', async () => {
|
||||
const buildkit = new BuildKit({
|
||||
context: new Context()
|
||||
});
|
||||
const version = await buildkit.getVersion('builder2');
|
||||
expect(semver.valid(version)).not.toBeNull();
|
||||
const builder = new Builder();
|
||||
const builderInfo = await builder.inspect('builder2');
|
||||
const buildkit = new BuildKit();
|
||||
const version = await buildkit.getVersion(builderInfo.nodes[0]);
|
||||
expect(version).toBe('v0.11.0');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -61,9 +59,7 @@ describe('satisfies', () => {
|
||||
['builder2', '>=0.10.0', true],
|
||||
['builder2', '>0.11.0', false]
|
||||
])('given %p', async (builderName, range, expected) => {
|
||||
const buildkit = new BuildKit({
|
||||
context: new Context()
|
||||
});
|
||||
const buildkit = new BuildKit();
|
||||
expect(await buildkit.versionSatisfies(builderName, range)).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -24,16 +24,17 @@ import {Context} from '../../src/context';
|
||||
|
||||
const fixturesDir = path.join(__dirname, '..', 'fixtures');
|
||||
// prettier-ignore
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildkit-config-jest').split(path.sep).join(path.posix.sep);
|
||||
const tmpName = path.join(tmpDir, '.tmpname-jest').split(path.sep).join(path.posix.sep);
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildkit-config-jest');
|
||||
const tmpName = path.join(tmpDir, '.tmpname-jest');
|
||||
|
||||
jest.spyOn(Context.prototype, 'tmpDir').mockImplementation((): string => {
|
||||
jest.spyOn(Context, 'tmpDir').mockImplementation((): string => {
|
||||
if (!fs.existsSync(tmpDir)) {
|
||||
fs.mkdirSync(tmpDir, {recursive: true});
|
||||
}
|
||||
return tmpDir;
|
||||
});
|
||||
jest.spyOn(Context.prototype, 'tmpName').mockImplementation((): string => {
|
||||
|
||||
jest.spyOn(Context, 'tmpName').mockImplementation((): string => {
|
||||
return tmpName;
|
||||
});
|
||||
|
||||
@@ -50,7 +51,7 @@ describe('resolve', () => {
|
||||
['debug = true', false, 'debug = true', null],
|
||||
[`notfound.toml`, true, '', new Error('config file notfound.toml not found')],
|
||||
[
|
||||
`${path.join(fixturesDir, 'buildkitd.toml').split(path.sep).join(path.posix.sep)}`,
|
||||
`${path.join(fixturesDir, 'buildkitd.toml')}`,
|
||||
true,
|
||||
`debug = true
|
||||
[registry."docker.io"]
|
||||
@@ -58,11 +59,9 @@ describe('resolve', () => {
|
||||
`,
|
||||
null
|
||||
]
|
||||
])('given %p config', async (val, file, exValue, error: Error) => {
|
||||
])('given %p config', async (val: string, file: boolean, exValue: string, error: Error | null) => {
|
||||
try {
|
||||
const buildkit = new BuildKit({
|
||||
context: new Context()
|
||||
});
|
||||
const buildkit = new BuildKit();
|
||||
let config: string;
|
||||
if (file) {
|
||||
config = buildkit.config.resolveFromFile(val);
|
||||
|
||||
43
__tests__/buildx/bake.test.itg.ts
Normal file
43
__tests__/buildx/bake.test.itg.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright 2023 actions-toolkit authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {beforeEach, describe, expect, jest, 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';
|
||||
|
||||
const fixturesDir = path.join(__dirname, '..', 'fixtures');
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('parseDefinitions', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
['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) => {
|
||||
const bake = new Bake();
|
||||
const expectedDef = <BakeDefinition>JSON.parse(fs.readFileSync(out, {encoding: 'utf-8'}).trim())
|
||||
expect(await bake.parseDefinitions(sources, targets)).toEqual(expectedDef);
|
||||
});
|
||||
});
|
||||
430
__tests__/buildx/bake.test.ts
Normal file
430
__tests__/buildx/bake.test.ts
Normal file
@@ -0,0 +1,430 @@
|
||||
/**
|
||||
* Copyright 2023 actions-toolkit authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {beforeEach, describe, expect, jest, 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';
|
||||
|
||||
const fixturesDir = path.join(__dirname, '..', 'fixtures');
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('parseDefinitions', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
[path.join(fixturesDir, 'bake-01.hcl')],
|
||||
['validate'],
|
||||
[],
|
||||
path.join(fixturesDir, 'bake-01-validate.json')
|
||||
],
|
||||
[
|
||||
[path.join(fixturesDir, 'bake-02.hcl')],
|
||||
['build'],
|
||||
[],
|
||||
path.join(fixturesDir, 'bake-02-build.json')
|
||||
],
|
||||
[
|
||||
[path.join(fixturesDir, 'bake-01.hcl')],
|
||||
['image'],
|
||||
['*.output=type=docker', '*.platform=linux/amd64'],
|
||||
path.join(fixturesDir, 'bake-01-overrides.json')
|
||||
]
|
||||
])('given %p', async (sources: string[], targets: string[], overrides: string[], 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);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasLocalExporter', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"build": {
|
||||
"output": [
|
||||
"type=docker"
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
false
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"build": {
|
||||
"target": "build"
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
false
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"local": {
|
||||
"output": [
|
||||
"type=local,dest=./release-out"
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
true
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"tar": {
|
||||
"output": [
|
||||
"type=tar,dest=/tmp/image.tar"
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
false
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"tar": {
|
||||
"output": [
|
||||
'"type=tar","dest=/tmp/image.tar"',
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
false
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"local": {
|
||||
"output": [
|
||||
'" type= local" , dest=./release-out',
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
true
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"local": {
|
||||
"output": [
|
||||
".",
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
true
|
||||
]
|
||||
])('given %o returns %p', async (def: BakeDefinition, expected: boolean) => {
|
||||
expect(Bake.hasLocalExporter(def)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasTarExporter', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"reg": {
|
||||
"output": [
|
||||
"type=registry,ref=user/app"
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
false
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"build": {
|
||||
"output": [
|
||||
"type=docker"
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
false
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"local": {
|
||||
"output": [
|
||||
"type=local,dest=./release-out"
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
false
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"tar": {
|
||||
"output": [
|
||||
"type=tar,dest=/tmp/image.tar"
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
true
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"multi": {
|
||||
"output": [
|
||||
"type=docker",
|
||||
"type=tar,dest=/tmp/image.tar"
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
true
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"tar": {
|
||||
"output": [
|
||||
'"type=tar","dest=/tmp/image.tar"',
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
true
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"local": {
|
||||
"output": [
|
||||
'" type= local" , dest=./release-out',
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
false
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"local": {
|
||||
"output": [
|
||||
".",
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
false
|
||||
],
|
||||
])('given %o returns %p', async (def: BakeDefinition, expected: boolean) => {
|
||||
expect(Bake.hasTarExporter(def)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasDockerExporter', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"reg": {
|
||||
"output": [
|
||||
"type=registry,ref=user/app"
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
false,
|
||||
undefined
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"build": {
|
||||
"output": [
|
||||
"type=docker"
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
true,
|
||||
undefined
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"multi": {
|
||||
"output": [
|
||||
"type=docker",
|
||||
"type=tar,dest=/tmp/image.tar"
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
true,
|
||||
undefined
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"local": {
|
||||
"output": [
|
||||
'" type= local" , dest=./release-out'
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
false,
|
||||
undefined
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"local": {
|
||||
"output": [
|
||||
"type=local,dest=./release-out"
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
false,
|
||||
undefined
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"tar": {
|
||||
"output": [
|
||||
"type=tar,dest=/tmp/image.tar"
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
false,
|
||||
undefined
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"multi": {
|
||||
"output": [
|
||||
"type=docker",
|
||||
"type=tar,dest=/tmp/image.tar"
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
true,
|
||||
undefined
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"tar": {
|
||||
"output": [
|
||||
'"type=tar","dest=/tmp/image.tar"'
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
false,
|
||||
undefined
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"tar": {
|
||||
"output": [
|
||||
'"type=tar","dest=/tmp/image.tar"'
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
false,
|
||||
undefined
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"local": {
|
||||
"output": [
|
||||
'" type= local" , dest=./release-out'
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
false,
|
||||
undefined
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"build": {
|
||||
"output": [
|
||||
"type=docker"
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
true,
|
||||
false
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"build": {
|
||||
"output": [
|
||||
"type=docker"
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
true,
|
||||
true
|
||||
],
|
||||
[
|
||||
{
|
||||
"target": {
|
||||
"build": {
|
||||
"output": [
|
||||
"."
|
||||
]
|
||||
},
|
||||
}
|
||||
} as unknown as BakeDefinition,
|
||||
true,
|
||||
true
|
||||
],
|
||||
])('given %o and load:%p returns %p', async (def: BakeDefinition, expected: boolean, load: boolean | undefined) => {
|
||||
expect(Bake.hasDockerExporter(def, load)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
@@ -19,7 +19,7 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import {Builder} from '../../src/buildx/builder';
|
||||
import {Context} from '../../src/context';
|
||||
import {Exec} from '../../src/exec';
|
||||
|
||||
import {BuilderInfo} from '../../src/types/builder';
|
||||
|
||||
@@ -36,9 +36,9 @@ jest.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise<Bu
|
||||
lastActivity: new Date('2023-01-16 09:45:23 +0000 UTC'),
|
||||
nodes: [
|
||||
{
|
||||
buildkitVersion: 'v0.11.0',
|
||||
buildkitdFlags: '--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
|
||||
driverOpts: ['BUILDKIT_STEP_LOG_MAX_SIZE=10485760', 'BUILDKIT_STEP_LOG_MAX_SPEED=10485760', 'JAEGER_TRACE=localhost:6831', 'image=moby/buildkit:latest', 'network=host'],
|
||||
buildkit: 'v0.11.0',
|
||||
'buildkitd-flags': '--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
|
||||
'driver-opts': ['BUILDKIT_STEP_LOG_MAX_SIZE=10485760', 'BUILDKIT_STEP_LOG_MAX_SPEED=10485760', 'JAEGER_TRACE=localhost:6831', 'image=moby/buildkit:latest', 'network=host', 'qemu.install=true'],
|
||||
endpoint: 'unix:///var/run/docker.sock',
|
||||
name: 'builder20',
|
||||
platforms: 'linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6',
|
||||
@@ -48,11 +48,22 @@ jest.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise<Bu
|
||||
};
|
||||
});
|
||||
|
||||
describe('exists', () => {
|
||||
it('valid', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'getExecOutput');
|
||||
const builder = new Builder();
|
||||
await builder.exists('foo');
|
||||
// eslint-disable-next-line jest/no-standalone-expect
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx', 'inspect', 'foo'], {
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('inspect', () => {
|
||||
it('valid', async () => {
|
||||
const builder = new Builder({
|
||||
context: new Context()
|
||||
});
|
||||
const builder = new Builder();
|
||||
const builderInfo = await builder.inspect('');
|
||||
expect(builderInfo).not.toBeUndefined();
|
||||
expect(builderInfo.name).not.toEqual('');
|
||||
@@ -74,8 +85,8 @@ describe('parseInspect', () => {
|
||||
"name": "builder-5cb467f7-0940-47e1-b94b-d51f54054d620",
|
||||
"endpoint": "unix:///var/run/docker.sock",
|
||||
"status": "running",
|
||||
"buildkitdFlags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
|
||||
"buildkitVersion": "v0.10.4",
|
||||
"buildkitd-flags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
|
||||
"buildkit": "v0.10.4",
|
||||
"platforms": "linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/amd64/v4,linux/arm64,linux/riscv64,linux/386,linux/arm/v7,linux/arm/v6"
|
||||
}
|
||||
]
|
||||
@@ -90,12 +101,12 @@ describe('parseInspect', () => {
|
||||
{
|
||||
"name": "builder-5f449644-ff29-48af-8344-abb0292d06730",
|
||||
"endpoint": "unix:///var/run/docker.sock",
|
||||
"driverOpts": [
|
||||
"driver-opts": [
|
||||
"image=moby/buildkit:latest"
|
||||
],
|
||||
"status": "running",
|
||||
"buildkitdFlags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
|
||||
"buildkitVersion": "v0.10.4",
|
||||
"buildkitd-flags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
|
||||
"buildkit": "v0.10.4",
|
||||
"platforms": "linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/amd64/v4,linux/386"
|
||||
}
|
||||
]
|
||||
@@ -110,13 +121,13 @@ describe('parseInspect', () => {
|
||||
{
|
||||
"name": "builder-9929e463-7954-4dc3-89cd-514cca29ff800",
|
||||
"endpoint": "unix:///var/run/docker.sock",
|
||||
"driverOpts": [
|
||||
"driver-opts": [
|
||||
"image=moby/buildkit:master",
|
||||
"network=host"
|
||||
],
|
||||
"status": "running",
|
||||
"buildkitdFlags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
|
||||
"buildkitVersion": "3fab389",
|
||||
"buildkitd-flags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
|
||||
"buildkit": "3fab389",
|
||||
"platforms": "linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/amd64/v4,linux/386"
|
||||
}
|
||||
]
|
||||
@@ -132,7 +143,7 @@ describe('parseInspect', () => {
|
||||
"name": "default",
|
||||
"endpoint": "default",
|
||||
"status": "running",
|
||||
"buildkitVersion": "20.10.17",
|
||||
"buildkit": "20.10.17",
|
||||
"platforms": "linux/amd64,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6"
|
||||
}
|
||||
]
|
||||
@@ -147,7 +158,7 @@ describe('parseInspect', () => {
|
||||
{
|
||||
"name": "aws_graviton2",
|
||||
"endpoint": "tcp://1.23.45.67:1234",
|
||||
"driverOpts": [
|
||||
"driver-opts": [
|
||||
"cert=/home/user/.certs/aws_graviton2/cert.pem",
|
||||
"key=/home/user/.certs/aws_graviton2/key.pem",
|
||||
"cacert=/home/user/.certs/aws_graviton2/ca.pem"
|
||||
@@ -166,7 +177,7 @@ describe('parseInspect', () => {
|
||||
"name": "builder-17cfff01-48d9-4c3d-9332-9992e308a5100",
|
||||
"endpoint": "unix:///var/run/docker.sock",
|
||||
"status": "running",
|
||||
"buildkitdFlags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
|
||||
"buildkitd-flags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
|
||||
"platforms": "linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/386"
|
||||
}
|
||||
],
|
||||
@@ -182,14 +193,15 @@ describe('parseInspect', () => {
|
||||
"lastActivity": new Date("2023-01-16T09:45:23.000Z"),
|
||||
"nodes": [
|
||||
{
|
||||
"buildkitVersion": "v0.11.0",
|
||||
"buildkitdFlags": "--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
|
||||
"driverOpts": [
|
||||
"BUILDKIT_STEP_LOG_MAX_SIZE=10485760",
|
||||
"BUILDKIT_STEP_LOG_MAX_SPEED=10485760",
|
||||
"JAEGER_TRACE=localhost:6831",
|
||||
"buildkit": "v0.11.0",
|
||||
"buildkitd-flags": "--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
|
||||
"driver-opts": [
|
||||
"env.BUILDKIT_STEP_LOG_MAX_SIZE=10485760",
|
||||
"env.BUILDKIT_STEP_LOG_MAX_SPEED=10485760",
|
||||
"env.JAEGER_TRACE=localhost:6831",
|
||||
"image=moby/buildkit:latest",
|
||||
"network=host"
|
||||
"network=host",
|
||||
"qemu.install=true"
|
||||
],
|
||||
"endpoint": "unix:///var/run/docker.sock",
|
||||
"name": "builder20",
|
||||
@@ -198,6 +210,189 @@ 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
])('given %p', async (inspectFile, expected) => {
|
||||
expect(await Builder.parseInspect(fs.readFileSync(path.join(fixturesDir, inspectFile)).toString())).toEqual(expected);
|
||||
|
||||
@@ -19,24 +19,25 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as rimraf from 'rimraf';
|
||||
import * as semver from 'semver';
|
||||
import * as exec from '@actions/exec';
|
||||
|
||||
import {Buildx} from '../../src/buildx/buildx';
|
||||
import {Context} from '../../src/context';
|
||||
import {Exec} from '../../src/exec';
|
||||
|
||||
import {Cert} from '../../src/types/buildx';
|
||||
|
||||
// prettier-ignore
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-jest').split(path.sep).join(path.posix.sep);
|
||||
const tmpName = path.join(tmpDir, '.tmpname-jest').split(path.sep).join(path.posix.sep);
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-jest');
|
||||
const tmpName = path.join(tmpDir, '.tmpname-jest');
|
||||
|
||||
jest.spyOn(Context.prototype, 'tmpDir').mockImplementation((): string => {
|
||||
jest.spyOn(Context, 'tmpDir').mockImplementation((): string => {
|
||||
if (!fs.existsSync(tmpDir)) {
|
||||
fs.mkdirSync(tmpDir, {recursive: true});
|
||||
}
|
||||
return tmpDir;
|
||||
});
|
||||
jest.spyOn(Context.prototype, 'tmpName').mockImplementation((): string => {
|
||||
|
||||
jest.spyOn(Context, 'tmpName').mockImplementation((): string => {
|
||||
return tmpName;
|
||||
});
|
||||
|
||||
@@ -90,14 +91,11 @@ describe('certsDir', () => {
|
||||
|
||||
describe('isAvailable', () => {
|
||||
it('docker cli', async () => {
|
||||
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||
const execSpy = jest.spyOn(Exec, 'getExecOutput');
|
||||
const buildx = new Buildx({
|
||||
context: new Context(),
|
||||
standalone: false
|
||||
});
|
||||
buildx.isAvailable().catch(() => {
|
||||
// noop
|
||||
});
|
||||
await buildx.isAvailable();
|
||||
// eslint-disable-next-line jest/no-standalone-expect
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx'], {
|
||||
silent: true,
|
||||
@@ -105,14 +103,11 @@ describe('isAvailable', () => {
|
||||
});
|
||||
});
|
||||
it('standalone', async () => {
|
||||
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||
const execSpy = jest.spyOn(Exec, 'getExecOutput');
|
||||
const buildx = new Buildx({
|
||||
context: new Context(),
|
||||
standalone: true
|
||||
});
|
||||
buildx.isAvailable().catch(() => {
|
||||
// noop
|
||||
});
|
||||
await buildx.isAvailable();
|
||||
// eslint-disable-next-line jest/no-standalone-expect
|
||||
expect(execSpy).toHaveBeenCalledWith(`buildx`, [], {
|
||||
silent: true,
|
||||
@@ -122,13 +117,12 @@ describe('isAvailable', () => {
|
||||
});
|
||||
|
||||
describe('printInspect', () => {
|
||||
it('prints builder2 instance', () => {
|
||||
const execSpy = jest.spyOn(exec, 'exec');
|
||||
it('prints builder2 instance', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'exec');
|
||||
const buildx = new Buildx({
|
||||
context: new Context(),
|
||||
standalone: true
|
||||
});
|
||||
buildx.printInspect('builder2').catch(() => {
|
||||
await buildx.printInspect('builder2').catch(() => {
|
||||
// noop
|
||||
});
|
||||
expect(execSpy).toHaveBeenCalledWith(`buildx`, ['inspect', 'builder2'], {
|
||||
@@ -138,24 +132,22 @@ describe('printInspect', () => {
|
||||
});
|
||||
|
||||
describe('printVersion', () => {
|
||||
it('docker cli', () => {
|
||||
const execSpy = jest.spyOn(exec, 'exec');
|
||||
it('docker cli', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'exec');
|
||||
const buildx = new Buildx({
|
||||
context: new Context(),
|
||||
standalone: false
|
||||
});
|
||||
buildx.printVersion();
|
||||
await buildx.printVersion();
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx', 'version'], {
|
||||
failOnStdErr: false
|
||||
});
|
||||
});
|
||||
it('standalone', () => {
|
||||
const execSpy = jest.spyOn(exec, 'exec');
|
||||
it('standalone', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'exec');
|
||||
const buildx = new Buildx({
|
||||
context: new Context(),
|
||||
standalone: true
|
||||
});
|
||||
buildx.printVersion();
|
||||
await buildx.printVersion();
|
||||
expect(execSpy).toHaveBeenCalledWith(`buildx`, ['version'], {
|
||||
failOnStdErr: false
|
||||
});
|
||||
@@ -164,10 +156,8 @@ describe('printVersion', () => {
|
||||
|
||||
describe('version', () => {
|
||||
it('valid', async () => {
|
||||
const buildx = new Buildx({
|
||||
context: new Context()
|
||||
});
|
||||
expect(semver.valid(await buildx.version)).not.toBeUndefined();
|
||||
const buildx = new Buildx();
|
||||
expect(semver.valid(await buildx.version())).not.toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -188,9 +178,7 @@ describe('versionSatisfies', () => {
|
||||
['bda4882a65349ca359216b135896bddc1d92461c', '>0.1.0', false],
|
||||
['f117971', '>0.6.0', true]
|
||||
])('given %p', async (version, range, expected) => {
|
||||
const buildx = new Buildx({
|
||||
context: new Context()
|
||||
});
|
||||
const buildx = new Buildx();
|
||||
expect(await buildx.versionSatisfies(range, version)).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,25 +20,25 @@ import * as path from 'path';
|
||||
import * as rimraf from 'rimraf';
|
||||
|
||||
import {Context} from '../../src/context';
|
||||
import {Buildx} from '../../src/buildx/buildx';
|
||||
import {Inputs} from '../../src/buildx/inputs';
|
||||
|
||||
const fixturesDir = path.join(__dirname, '..', 'fixtures');
|
||||
// prettier-ignore
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-inputs-jest').split(path.sep).join(path.posix.sep);
|
||||
const tmpName = path.join(tmpDir, '.tmpname-jest').split(path.sep).join(path.posix.sep);
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-inputs-jest');
|
||||
const tmpName = path.join(tmpDir, '.tmpname-jest');
|
||||
const metadata = `{
|
||||
"containerimage.config.digest": "sha256:059b68a595b22564a1cbc167af369349fdc2ecc1f7bc092c2235cbf601a795fd",
|
||||
"containerimage.digest": "sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c"
|
||||
}`;
|
||||
|
||||
jest.spyOn(Context.prototype, 'tmpDir').mockImplementation((): string => {
|
||||
jest.spyOn(Context, 'tmpDir').mockImplementation((): string => {
|
||||
if (!fs.existsSync(tmpDir)) {
|
||||
fs.mkdirSync(tmpDir, {recursive: true});
|
||||
}
|
||||
return tmpDir;
|
||||
});
|
||||
jest.spyOn(Context.prototype, 'tmpName').mockImplementation((): string => {
|
||||
|
||||
jest.spyOn(Context, 'tmpName').mockImplementation((): string => {
|
||||
return tmpName;
|
||||
});
|
||||
|
||||
@@ -52,37 +52,28 @@ afterEach(() => {
|
||||
|
||||
describe('resolveBuildImageID', () => {
|
||||
it('matches', async () => {
|
||||
const buildx = new Buildx({
|
||||
context: new Context()
|
||||
});
|
||||
const imageID = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9';
|
||||
const imageIDFile = buildx.inputs.getBuildImageIDFilePath();
|
||||
const imageIDFile = Inputs.getBuildImageIDFilePath();
|
||||
await fs.writeFileSync(imageIDFile, imageID);
|
||||
const expected = buildx.inputs.resolveBuildImageID();
|
||||
const expected = Inputs.resolveBuildImageID();
|
||||
expect(expected).toEqual(imageID);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveBuildMetadata', () => {
|
||||
it('matches', async () => {
|
||||
const buildx = new Buildx({
|
||||
context: new Context()
|
||||
});
|
||||
const metadataFile = buildx.inputs.getBuildMetadataFilePath();
|
||||
const metadataFile = Inputs.getBuildMetadataFilePath();
|
||||
await fs.writeFileSync(metadataFile, metadata);
|
||||
const expected = buildx.inputs.resolveBuildMetadata();
|
||||
const expected = Inputs.resolveBuildMetadata();
|
||||
expect(expected).toEqual(metadata);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveDigest', () => {
|
||||
it('matches', async () => {
|
||||
const buildx = new Buildx({
|
||||
context: new Context()
|
||||
});
|
||||
const metadataFile = buildx.inputs.getBuildMetadataFilePath();
|
||||
const metadataFile = Inputs.getBuildMetadataFilePath();
|
||||
await fs.writeFileSync(metadataFile, metadata);
|
||||
const expected = buildx.inputs.resolveDigest();
|
||||
const expected = Inputs.resolveDigest();
|
||||
expect(expected).toEqual('sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c');
|
||||
});
|
||||
});
|
||||
@@ -129,10 +120,7 @@ describe('getProvenanceInput', () => {
|
||||
],
|
||||
])('given input %p', async (input: string, expected: string) => {
|
||||
await setInput('provenance', input);
|
||||
const buildx = new Buildx({
|
||||
context: new Context()
|
||||
});
|
||||
expect(buildx.inputs.getProvenanceInput('provenance')).toEqual(expected);
|
||||
expect(Inputs.getProvenanceInput('provenance')).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -160,10 +148,7 @@ describe('resolveProvenanceAttrs', () => {
|
||||
'builder-id=https://github.com/docker/actions-toolkit/actions/runs/123'
|
||||
],
|
||||
])('given %p', async (input: string, expected: string) => {
|
||||
const buildx = new Buildx({
|
||||
context: new Context()
|
||||
});
|
||||
expect(buildx.inputs.resolveProvenanceAttrs(input)).toEqual(expected);
|
||||
expect(Inputs.resolveProvenanceAttrs(input)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -175,18 +160,15 @@ describe('resolveBuildSecret', () => {
|
||||
['aaaaaaaa', false, '', '', new Error('aaaaaaaa is not a valid secret')],
|
||||
['aaaaaaaa=', false, '', '', new Error('aaaaaaaa= is not a valid secret')],
|
||||
['=bbbbbbb', false, '', '', new Error('=bbbbbbb is not a valid secret')],
|
||||
[`foo=${path.join(fixturesDir, 'secret.txt').split(path.sep).join(path.posix.sep)}`, true, 'foo', 'bar', null],
|
||||
[`foo=${path.join(fixturesDir, 'secret.txt')}`, true, 'foo', 'bar', null],
|
||||
[`notfound=secret`, true, '', '', new Error('secret file secret not found')]
|
||||
])('given %p key and %p secret', async (kvp: string, file: boolean, exKey: string, exValue: string, error: Error) => {
|
||||
])('given %p key and %p secret', async (kvp: string, file: boolean, exKey: string, exValue: string, error: Error | null) => {
|
||||
try {
|
||||
const buildx = new Buildx({
|
||||
context: new Context()
|
||||
});
|
||||
let secret: string;
|
||||
if (file) {
|
||||
secret = buildx.inputs.resolveBuildSecretFile(kvp);
|
||||
secret = Inputs.resolveBuildSecretFile(kvp);
|
||||
} else {
|
||||
secret = buildx.inputs.resolveBuildSecretString(kvp);
|
||||
secret = Inputs.resolveBuildSecretString(kvp);
|
||||
}
|
||||
expect(secret).toEqual(`id=${exKey},src=${tmpName}`);
|
||||
expect(fs.readFileSync(tmpName, 'utf-8')).toEqual(exValue);
|
||||
@@ -195,6 +177,21 @@ describe('resolveBuildSecret', () => {
|
||||
expect(e.message).toEqual(error?.message);
|
||||
}
|
||||
});
|
||||
|
||||
test.each([
|
||||
['FOO=bar', 'FOO', 'bar', null],
|
||||
['FOO=', 'FOO', '', new Error('FOO= is not a valid secret')],
|
||||
['=bar', '', '', new Error('=bar is not a valid secret')],
|
||||
['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}"`);
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line jest/no-conditional-expect
|
||||
expect(e.message).toEqual(error?.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasLocalExporter', () => {
|
||||
@@ -239,6 +236,8 @@ describe('hasDockerExporter', () => {
|
||||
[['type=docker', 'type=tar,dest=/tmp/image.tar'], true, undefined],
|
||||
[['"type=tar","dest=/tmp/image.tar"'], false, undefined],
|
||||
[['" type= local" , dest=./release-out'], false, undefined],
|
||||
[['type=docker'], true, false],
|
||||
[['type=docker'], true, true],
|
||||
[['.'], true, true],
|
||||
])('given %p returns %p', async (exporters: Array<string>, expected: boolean, load: boolean | undefined) => {
|
||||
expect(Inputs.hasDockerExporter(exporters, load)).toEqual(expected);
|
||||
|
||||
@@ -23,7 +23,7 @@ import osm = require('os');
|
||||
import {Install} from '../../src/buildx/install';
|
||||
|
||||
// prettier-ignore
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-jest').split(path.sep).join(path.posix.sep);
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-jest');
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
@@ -36,19 +36,37 @@ 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) => {
|
||||
const install = new Install({standalone: standalone});
|
||||
const buildxBin = await install.download(version, tmpDir);
|
||||
const toolPath = await install.download(version);
|
||||
expect(fs.existsSync(toolPath)).toBe(true);
|
||||
let buildxBin: string;
|
||||
if (standalone) {
|
||||
buildxBin = await install.installStandalone(toolPath, tmpDir);
|
||||
} else {
|
||||
buildxBin = await install.installPlugin(toolPath, tmpDir);
|
||||
}
|
||||
expect(fs.existsSync(buildxBin)).toBe(true);
|
||||
},
|
||||
100000
|
||||
);
|
||||
|
||||
// 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);
|
||||
});
|
||||
|
||||
// TODO: add tests for arm
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
@@ -62,10 +80,10 @@ describe('download', () => {
|
||||
['linux', 's390x'],
|
||||
])(
|
||||
'acquires buildx for %s/%s', async (os, arch) => {
|
||||
jest.spyOn(osm, 'platform').mockImplementation(() => os);
|
||||
jest.spyOn(osm, 'platform').mockImplementation(() => os as NodeJS.Platform);
|
||||
jest.spyOn(osm, 'arch').mockImplementation(() => arch);
|
||||
const install = new Install();
|
||||
const buildxBin = await install.download('latest', tmpDir);
|
||||
const buildxBin = await install.download('latest');
|
||||
expect(fs.existsSync(buildxBin)).toBe(true);
|
||||
},
|
||||
100000
|
||||
@@ -82,14 +100,18 @@ describe('build', () => {
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
it.skip('builds refs/pull/648/head', async () => {
|
||||
const install = new Install();
|
||||
const buildxBin = await install.build('https://github.com/docker/buildx.git#refs/pull/648/head', tmpDir);
|
||||
const toolPath = await install.build('https://github.com/docker/buildx.git#refs/pull/648/head');
|
||||
expect(fs.existsSync(toolPath)).toBe(true);
|
||||
const buildxBin = await install.installStandalone(toolPath, tmpDir);
|
||||
expect(fs.existsSync(buildxBin)).toBe(true);
|
||||
}, 100000);
|
||||
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
it.skip('builds 67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', async () => {
|
||||
const install = new Install();
|
||||
const buildxBin = await install.build('https://github.com/docker/buildx.git#67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', tmpDir);
|
||||
const toolPath = await install.build('https://github.com/docker/buildx.git#67bd6f4dc82a9cd96f34133dab3f6f7af803bb14');
|
||||
expect(fs.existsSync(toolPath)).toBe(true);
|
||||
const buildxBin = await install.installPlugin(toolPath, tmpDir);
|
||||
expect(fs.existsSync(buildxBin)).toBe(true);
|
||||
}, 100000);
|
||||
});
|
||||
@@ -118,6 +140,6 @@ describe('getRelease', () => {
|
||||
});
|
||||
|
||||
it('unknown release', async () => {
|
||||
await expect(Install.getRelease('foo')).rejects.toThrowError(new Error('Cannot find Buildx release foo in https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/buildx-releases.json'));
|
||||
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'));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,16 +22,17 @@ import {describe, expect, jest, it, beforeEach, afterEach} from '@jest/globals';
|
||||
import {Context} from '../src/context';
|
||||
|
||||
// prettier-ignore
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'context-jest').split(path.sep).join(path.posix.sep);
|
||||
const tmpName = path.join(tmpDir, '.tmpname-jest').split(path.sep).join(path.posix.sep);
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'context-jest');
|
||||
const tmpName = path.join(tmpDir, '.tmpname-jest');
|
||||
|
||||
jest.spyOn(Context.prototype, 'tmpDir').mockImplementation((): string => {
|
||||
jest.spyOn(Context, 'tmpDir').mockImplementation((): string => {
|
||||
if (!fs.existsSync(tmpDir)) {
|
||||
fs.mkdirSync(tmpDir, {recursive: true});
|
||||
}
|
||||
return tmpDir;
|
||||
});
|
||||
jest.spyOn(Context.prototype, 'tmpName').mockImplementation((): string => {
|
||||
|
||||
jest.spyOn(Context, 'tmpName').mockImplementation((): string => {
|
||||
return tmpName;
|
||||
});
|
||||
|
||||
@@ -43,16 +44,20 @@ afterEach(() => {
|
||||
rimraf.sync(tmpDir);
|
||||
});
|
||||
|
||||
describe('gitRef', () => {
|
||||
it('returns refs/heads/master', async () => {
|
||||
expect(Context.gitRef()).toEqual('refs/heads/master');
|
||||
});
|
||||
});
|
||||
|
||||
describe('gitContext', () => {
|
||||
it('returns refs/heads/master', async () => {
|
||||
const context = new Context();
|
||||
expect(context.buildGitContext).toEqual('https://github.com/docker/actions-toolkit.git#refs/heads/master');
|
||||
expect(Context.gitContext()).toEqual('https://github.com/docker/actions-toolkit.git#refs/heads/master');
|
||||
});
|
||||
});
|
||||
|
||||
describe('provenanceBuilderID', () => {
|
||||
it('returns 123', async () => {
|
||||
const context = new Context();
|
||||
expect(context.provenanceBuilderID).toEqual('https://github.com/docker/actions-toolkit/actions/runs/123');
|
||||
expect(Context.provenanceBuilderID()).toEqual('https://github.com/docker/actions-toolkit/actions/runs/123');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,102 +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 {afterEach, beforeEach, describe, expect, it, jest} from '@jest/globals';
|
||||
import * as exec from '@actions/exec';
|
||||
import path from 'path';
|
||||
import osm = require('os');
|
||||
|
||||
import {Docker} from '../src/docker';
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('configDir', () => {
|
||||
const originalEnv = process.env;
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
process.env = {
|
||||
...originalEnv,
|
||||
DOCKER_CONFIG: '/var/docker/config'
|
||||
};
|
||||
});
|
||||
afterEach(() => {
|
||||
process.env = originalEnv;
|
||||
});
|
||||
it('returns default', async () => {
|
||||
process.env.DOCKER_CONFIG = '';
|
||||
jest.spyOn(osm, 'homedir').mockImplementation(() => path.join('/tmp', 'home'));
|
||||
expect(Docker.configDir).toEqual(path.join('/tmp', 'home', '.docker'));
|
||||
});
|
||||
it('returns from env', async () => {
|
||||
expect(Docker.configDir).toEqual('/var/docker/config');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAvailable', () => {
|
||||
it('cli', () => {
|
||||
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||
Docker.isAvailable;
|
||||
// eslint-disable-next-line jest/no-standalone-expect
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, undefined, {
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('printVersion', () => {
|
||||
it('docker cli', () => {
|
||||
const execSpy = jest.spyOn(exec, 'exec');
|
||||
Docker.printVersion(false).catch(() => {
|
||||
// noop
|
||||
});
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['version'], {
|
||||
failOnStdErr: false
|
||||
});
|
||||
});
|
||||
it('standalone', () => {
|
||||
const execSpy = jest.spyOn(exec, 'exec');
|
||||
Docker.printVersion(true).catch(() => {
|
||||
// noop
|
||||
});
|
||||
expect(execSpy).not.toHaveBeenCalledWith(`docker`, ['version'], {
|
||||
failOnStdErr: false
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('printInfo', () => {
|
||||
it('docker cli', () => {
|
||||
const execSpy = jest.spyOn(exec, 'exec');
|
||||
Docker.printInfo(false).catch(() => {
|
||||
// noop
|
||||
});
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['info'], {
|
||||
failOnStdErr: false
|
||||
});
|
||||
});
|
||||
it('standalone', () => {
|
||||
const execSpy = jest.spyOn(exec, 'exec');
|
||||
Docker.printInfo(true).catch(() => {
|
||||
// noop
|
||||
});
|
||||
expect(execSpy).not.toHaveBeenCalledWith(`docker`, ['info'], {
|
||||
failOnStdErr: false
|
||||
});
|
||||
});
|
||||
});
|
||||
143
__tests__/docker/docker.test.ts
Normal file
143
__tests__/docker/docker.test.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* 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 {afterEach, beforeEach, describe, expect, it, jest} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import path from 'path';
|
||||
import * as io from '@actions/io';
|
||||
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';
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
describe('configDir', () => {
|
||||
const originalEnv = process.env;
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
process.env = {
|
||||
...originalEnv,
|
||||
DOCKER_CONFIG: '/var/docker/config'
|
||||
};
|
||||
});
|
||||
afterEach(() => {
|
||||
process.env = originalEnv;
|
||||
});
|
||||
it('returns default', async () => {
|
||||
process.env.DOCKER_CONFIG = '';
|
||||
jest.spyOn(osm, 'homedir').mockImplementation(() => path.join('/tmp', 'home'));
|
||||
expect(Docker.configDir).toEqual(path.join('/tmp', 'home', '.docker'));
|
||||
});
|
||||
it('returns from env', async () => {
|
||||
expect(Docker.configDir).toEqual('/var/docker/config');
|
||||
});
|
||||
});
|
||||
|
||||
describe('configFile', () => {
|
||||
const originalEnv = process.env;
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
if (!fs.existsSync(tmpDir)) {
|
||||
fs.mkdirSync(tmpDir, {recursive: true});
|
||||
}
|
||||
process.env = {
|
||||
...originalEnv,
|
||||
DOCKER_CONFIG: tmpDir
|
||||
};
|
||||
});
|
||||
afterEach(() => {
|
||||
process.env = originalEnv;
|
||||
});
|
||||
it('auths', async () => {
|
||||
fs.copyFileSync(path.join(fixturesDir, 'docker-config-auths.json'), path.join(tmpDir, 'config.json'));
|
||||
expect(Docker.configFile()).toEqual({
|
||||
auths: {
|
||||
'https://index.docker.io/v1/': {
|
||||
auth: 'am9lam9lOmhlbGxv',
|
||||
email: 'user@example.com'
|
||||
}
|
||||
}
|
||||
} as unknown as ConfigFile);
|
||||
});
|
||||
it('proxies', async () => {
|
||||
fs.copyFileSync(path.join(fixturesDir, 'docker-config-proxies.json'), path.join(tmpDir, 'config.json'));
|
||||
expect(Docker.configFile()).toEqual({
|
||||
proxies: {
|
||||
default: {
|
||||
httpProxy: 'http://127.0.0.1:3128',
|
||||
httpsProxy: 'http://127.0.0.1:3128'
|
||||
}
|
||||
}
|
||||
} as unknown as ConfigFile);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAvailable', () => {
|
||||
it('cli', async () => {
|
||||
const ioWhichSpy = jest.spyOn(io, 'which');
|
||||
await Docker.isAvailable();
|
||||
expect(ioWhichSpy).toHaveBeenCalledTimes(1);
|
||||
expect(ioWhichSpy).toHaveBeenCalledWith('docker', true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('context', () => {
|
||||
it('call docker context show', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'getExecOutput');
|
||||
await Docker.context().catch(() => {
|
||||
// noop
|
||||
});
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['context', 'inspect', '--format', '{{.Name}}'], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('printVersion', () => {
|
||||
it('call docker version', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'exec');
|
||||
await Docker.printVersion().catch(() => {
|
||||
// noop
|
||||
});
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['version']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('printInfo', () => {
|
||||
it('call docker info', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'exec');
|
||||
await Docker.printInfo().catch(() => {
|
||||
// noop
|
||||
});
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['info']);
|
||||
});
|
||||
});
|
||||
44
__tests__/docker/install.test.itg.ts
Normal file
44
__tests__/docker/install.test.itg.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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 path from 'path';
|
||||
import {jest, describe, expect, test} from '@jest/globals';
|
||||
|
||||
import {Install} from '../../src/docker/install';
|
||||
import {Docker} from '../../src/docker/docker';
|
||||
|
||||
// prettier-ignore
|
||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'docker-install-jest');
|
||||
|
||||
describe('install', () => {
|
||||
jest.retryTimes(2, {logErrorsBeforeRetry: true});
|
||||
// prettier-ignore
|
||||
test.each(['v23.0.0'])(
|
||||
'install docker %s', async (version) => {
|
||||
await expect((async () => {
|
||||
const install = new Install({
|
||||
version: version,
|
||||
runDir: tmpDir,
|
||||
contextName: 'foo'
|
||||
});
|
||||
await install.download();
|
||||
await install.install();
|
||||
await Docker.printVersion();
|
||||
await Docker.printInfo();
|
||||
await install.tearDown();
|
||||
})()).resolves.not.toThrow();
|
||||
});
|
||||
});
|
||||
73
__tests__/docker/install.test.ts
Normal file
73
__tests__/docker/install.test.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* 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, jest, test, beforeEach, afterEach, it} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as rimraf from 'rimraf';
|
||||
import osm = require('os');
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
describe('download', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
['v19.03.14', 'linux'],
|
||||
['v20.10.22', 'linux'],
|
||||
['v20.10.22', 'darwin'],
|
||||
['v20.10.22', 'win32'],
|
||||
])(
|
||||
'acquires %p of docker (%s)', async (version, platformOS) => {
|
||||
jest.spyOn(osm, 'platform').mockImplementation(() => platformOS as NodeJS.Platform);
|
||||
const install = new Install({
|
||||
version: version,
|
||||
runDir: tmpDir,
|
||||
});
|
||||
const toolPath = await install.download();
|
||||
expect(fs.existsSync(toolPath)).toBe(true);
|
||||
}, 100000);
|
||||
});
|
||||
|
||||
describe('getRelease', () => {
|
||||
it('returns latest docker GitHub release', async () => {
|
||||
const release = await Install.getRelease('latest');
|
||||
expect(release).not.toBeNull();
|
||||
expect(release?.tag_name).not.toEqual('');
|
||||
});
|
||||
|
||||
it('returns v23.0.0 buildx GitHub release', async () => {
|
||||
const release = await Install.getRelease('v23.0.0');
|
||||
expect(release).not.toBeNull();
|
||||
expect(release?.id).toEqual(91109643);
|
||||
expect(release?.tag_name).toEqual('v23.0.0');
|
||||
expect(release?.html_url).toEqual('https://github.com/moby/moby/releases/tag/v23.0.0');
|
||||
});
|
||||
|
||||
it('unknown release', async () => {
|
||||
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'));
|
||||
});
|
||||
});
|
||||
51
__tests__/exec.test.ts
Normal file
51
__tests__/exec.test.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright 2023 actions-toolkit authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {beforeEach, describe, expect, it, jest} from '@jest/globals';
|
||||
|
||||
import {Exec} from '../src/exec';
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('exec', () => {
|
||||
it('returns docker version', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'exec');
|
||||
await Exec.exec('docker', ['version'], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
});
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['version'], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getExecOutput', () => {
|
||||
it('returns docker version', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'getExecOutput');
|
||||
await Exec.getExecOutput('docker', ['version'], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
});
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['version'], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
});
|
||||
});
|
||||
});
|
||||
29
__tests__/fixtures/bake-01-overrides.json
Normal file
29
__tests__/fixtures/bake-01-overrides.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"group": {
|
||||
"default": {
|
||||
"targets": [
|
||||
"image"
|
||||
]
|
||||
}
|
||||
},
|
||||
"target": {
|
||||
"image": {
|
||||
"context": ".",
|
||||
"dockerfile": "Dockerfile",
|
||||
"args": {
|
||||
"BUILDKIT_CONTEXT_KEEP_GIT_DIR": "1",
|
||||
"GO_VERSION": "1.20"
|
||||
},
|
||||
"tags": [
|
||||
"docker/buildx-bin:local"
|
||||
],
|
||||
"target": "binaries",
|
||||
"platforms": [
|
||||
"linux/amd64"
|
||||
],
|
||||
"output": [
|
||||
"type=docker"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
55
__tests__/fixtures/bake-01-validate.json
Normal file
55
__tests__/fixtures/bake-01-validate.json
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"group": {
|
||||
"default": {
|
||||
"targets": [
|
||||
"validate"
|
||||
]
|
||||
},
|
||||
"validate": {
|
||||
"targets": [
|
||||
"lint",
|
||||
"validate-vendor",
|
||||
"validate-docs"
|
||||
]
|
||||
}
|
||||
},
|
||||
"target": {
|
||||
"lint": {
|
||||
"context": ".",
|
||||
"dockerfile": "./hack/dockerfiles/lint.Dockerfile",
|
||||
"args": {
|
||||
"BUILDKIT_CONTEXT_KEEP_GIT_DIR": "1",
|
||||
"GO_VERSION": "1.20"
|
||||
},
|
||||
"output": [
|
||||
"type=cacheonly"
|
||||
]
|
||||
},
|
||||
"validate-docs": {
|
||||
"context": ".",
|
||||
"dockerfile": "./hack/dockerfiles/docs.Dockerfile",
|
||||
"args": {
|
||||
"BUILDKIT_CONTEXT_KEEP_GIT_DIR": "1",
|
||||
"BUILDX_EXPERIMENTAL": "1",
|
||||
"FORMATS": "md",
|
||||
"GO_VERSION": "1.20"
|
||||
},
|
||||
"target": "validate",
|
||||
"output": [
|
||||
"type=cacheonly"
|
||||
]
|
||||
},
|
||||
"validate-vendor": {
|
||||
"context": ".",
|
||||
"dockerfile": "./hack/dockerfiles/vendor.Dockerfile",
|
||||
"args": {
|
||||
"BUILDKIT_CONTEXT_KEEP_GIT_DIR": "1",
|
||||
"GO_VERSION": "1.20"
|
||||
},
|
||||
"target": "validate",
|
||||
"output": [
|
||||
"type=cacheonly"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
172
__tests__/fixtures/bake-01.hcl
Normal file
172
__tests__/fixtures/bake-01.hcl
Normal file
@@ -0,0 +1,172 @@
|
||||
// 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.
|
||||
|
||||
variable "GO_VERSION" {
|
||||
default = "1.20"
|
||||
}
|
||||
variable "DOCS_FORMATS" {
|
||||
default = "md"
|
||||
}
|
||||
variable "DESTDIR" {
|
||||
default = "./bin"
|
||||
}
|
||||
|
||||
# Special target: https://github.com/docker/metadata-action#bake-definition
|
||||
target "meta-helper" {
|
||||
tags = ["docker/buildx-bin:local"]
|
||||
}
|
||||
|
||||
target "_common" {
|
||||
args = {
|
||||
GO_VERSION = GO_VERSION
|
||||
BUILDKIT_CONTEXT_KEEP_GIT_DIR = 1
|
||||
}
|
||||
}
|
||||
|
||||
group "default" {
|
||||
targets = ["binaries"]
|
||||
}
|
||||
|
||||
group "validate" {
|
||||
targets = ["lint", "validate-vendor", "validate-docs"]
|
||||
}
|
||||
|
||||
target "lint" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "./hack/dockerfiles/lint.Dockerfile"
|
||||
output = ["type=cacheonly"]
|
||||
}
|
||||
|
||||
target "validate-vendor" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "./hack/dockerfiles/vendor.Dockerfile"
|
||||
target = "validate"
|
||||
output = ["type=cacheonly"]
|
||||
}
|
||||
|
||||
target "validate-docs" {
|
||||
inherits = ["_common"]
|
||||
args = {
|
||||
FORMATS = DOCS_FORMATS
|
||||
BUILDX_EXPERIMENTAL = 1 // enables experimental cmds/flags for docs generation
|
||||
}
|
||||
dockerfile = "./hack/dockerfiles/docs.Dockerfile"
|
||||
target = "validate"
|
||||
output = ["type=cacheonly"]
|
||||
}
|
||||
|
||||
target "validate-authors" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "./hack/dockerfiles/authors.Dockerfile"
|
||||
target = "validate"
|
||||
output = ["type=cacheonly"]
|
||||
}
|
||||
|
||||
target "validate-generated-files" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "./hack/dockerfiles/generated-files.Dockerfile"
|
||||
target = "validate"
|
||||
output = ["type=cacheonly"]
|
||||
}
|
||||
|
||||
target "update-vendor" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "./hack/dockerfiles/vendor.Dockerfile"
|
||||
target = "update"
|
||||
output = ["."]
|
||||
}
|
||||
|
||||
target "update-docs" {
|
||||
inherits = ["_common"]
|
||||
args = {
|
||||
FORMATS = DOCS_FORMATS
|
||||
BUILDX_EXPERIMENTAL = 1 // enables experimental cmds/flags for docs generation
|
||||
}
|
||||
dockerfile = "./hack/dockerfiles/docs.Dockerfile"
|
||||
target = "update"
|
||||
output = ["./docs/reference"]
|
||||
}
|
||||
|
||||
target "update-authors" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "./hack/dockerfiles/authors.Dockerfile"
|
||||
target = "update"
|
||||
output = ["."]
|
||||
}
|
||||
|
||||
target "update-generated-files" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "./hack/dockerfiles/generated-files.Dockerfile"
|
||||
target = "update"
|
||||
output = ["."]
|
||||
}
|
||||
|
||||
target "mod-outdated" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "./hack/dockerfiles/vendor.Dockerfile"
|
||||
target = "outdated"
|
||||
no-cache-filter = ["outdated"]
|
||||
output = ["type=cacheonly"]
|
||||
}
|
||||
|
||||
target "test" {
|
||||
inherits = ["_common"]
|
||||
target = "test-coverage"
|
||||
output = ["${DESTDIR}/coverage"]
|
||||
}
|
||||
|
||||
target "binaries" {
|
||||
inherits = ["_common"]
|
||||
target = "binaries"
|
||||
output = ["${DESTDIR}/build"]
|
||||
platforms = ["local"]
|
||||
}
|
||||
|
||||
target "binaries-cross" {
|
||||
inherits = ["binaries"]
|
||||
platforms = [
|
||||
"darwin/amd64",
|
||||
"darwin/arm64",
|
||||
"linux/amd64",
|
||||
"linux/arm/v6",
|
||||
"linux/arm/v7",
|
||||
"linux/arm64",
|
||||
"linux/ppc64le",
|
||||
"linux/riscv64",
|
||||
"linux/s390x",
|
||||
"windows/amd64",
|
||||
"windows/arm64"
|
||||
]
|
||||
}
|
||||
|
||||
target "release" {
|
||||
inherits = ["binaries-cross"]
|
||||
target = "release"
|
||||
output = ["${DESTDIR}/release"]
|
||||
}
|
||||
|
||||
target "image" {
|
||||
inherits = ["meta-helper", "binaries"]
|
||||
output = ["type=image"]
|
||||
}
|
||||
|
||||
target "image-cross" {
|
||||
inherits = ["meta-helper", "binaries-cross"]
|
||||
output = ["type=image"]
|
||||
}
|
||||
|
||||
target "image-local" {
|
||||
inherits = ["image"]
|
||||
output = ["type=docker"]
|
||||
}
|
||||
20
__tests__/fixtures/bake-02-build.json
Normal file
20
__tests__/fixtures/bake-02-build.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"group": {
|
||||
"default": {
|
||||
"targets": [
|
||||
"build"
|
||||
]
|
||||
}
|
||||
},
|
||||
"target": {
|
||||
"build": {
|
||||
"context": ".",
|
||||
"dockerfile": "Dockerfile",
|
||||
"args": {
|
||||
"BUILDKIT_CONTEXT_KEEP_GIT_DIR": "1",
|
||||
"GO_VERSION": "1.20"
|
||||
},
|
||||
"target": "build"
|
||||
}
|
||||
}
|
||||
}
|
||||
33
__tests__/fixtures/bake-02.hcl
Normal file
33
__tests__/fixtures/bake-02.hcl
Normal file
@@ -0,0 +1,33 @@
|
||||
// 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.
|
||||
|
||||
variable "GO_VERSION" {
|
||||
default = "1.20"
|
||||
}
|
||||
|
||||
target "_common" {
|
||||
args = {
|
||||
GO_VERSION = GO_VERSION
|
||||
BUILDKIT_CONTEXT_KEEP_GIT_DIR = 1
|
||||
}
|
||||
}
|
||||
|
||||
group "default" {
|
||||
targets = ["build"]
|
||||
}
|
||||
|
||||
target "build" {
|
||||
inherits = ["_common"]
|
||||
target = "build"
|
||||
}
|
||||
36
__tests__/fixtures/bake-buildx-0.10.4-binaries-cross.json
Normal file
36
__tests__/fixtures/bake-buildx-0.10.4-binaries-cross.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"group": {
|
||||
"default": {
|
||||
"targets": [
|
||||
"binaries-cross"
|
||||
]
|
||||
}
|
||||
},
|
||||
"target": {
|
||||
"binaries-cross": {
|
||||
"context": "https://github.com/docker/buildx.git#v0.10.4",
|
||||
"dockerfile": "Dockerfile",
|
||||
"args": {
|
||||
"BUILDKIT_CONTEXT_KEEP_GIT_DIR": "1",
|
||||
"GO_VERSION": "1.19"
|
||||
},
|
||||
"target": "binaries",
|
||||
"platforms": [
|
||||
"darwin/amd64",
|
||||
"darwin/arm64",
|
||||
"linux/amd64",
|
||||
"linux/arm/v6",
|
||||
"linux/arm/v7",
|
||||
"linux/arm64",
|
||||
"linux/ppc64le",
|
||||
"linux/riscv64",
|
||||
"linux/s390x",
|
||||
"windows/amd64",
|
||||
"windows/arm64"
|
||||
],
|
||||
"output": [
|
||||
"./bin/build"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
8
__tests__/fixtures/docker-config-auths.json
Normal file
8
__tests__/fixtures/docker-config-auths.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"auths": {
|
||||
"https://index.docker.io/v1/": {
|
||||
"auth": "am9lam9lOmhlbGxv",
|
||||
"email": "user@example.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
8
__tests__/fixtures/docker-config-proxies.json
Normal file
8
__tests__/fixtures/docker-config-proxies.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"proxies": {
|
||||
"default": {
|
||||
"httpProxy": "http://127.0.0.1:3128",
|
||||
"httpsProxy": "http://127.0.0.1:3128"
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
@@ -5,7 +5,7 @@ Last Activity: 2023-01-16 09:45:23 +0000 UTC
|
||||
Nodes:
|
||||
Name: builder20
|
||||
Endpoint: unix:///var/run/docker.sock
|
||||
Driver Options: env.BUILDKIT_STEP_LOG_MAX_SIZE="10485760" env.BUILDKIT_STEP_LOG_MAX_SPEED="10485760" env.JAEGER_TRACE="localhost:6831" image="moby/buildkit:latest" network="host"
|
||||
Driver Options: env.BUILDKIT_STEP_LOG_MAX_SIZE="10485760" env.BUILDKIT_STEP_LOG_MAX_SPEED="10485760" env.JAEGER_TRACE="localhost:6831" image="moby/buildkit:latest" network="host" qemu.install="true"
|
||||
Status: running
|
||||
Flags: --debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host
|
||||
Buildkit: v0.11.0
|
||||
|
||||
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
|
||||
@@ -17,18 +17,134 @@
|
||||
import {beforeEach, describe, expect, it, jest} from '@jest/globals';
|
||||
|
||||
import {Git} from '../src/git';
|
||||
import {Exec} from '../src/exec';
|
||||
import {ExecOutput} from '@actions/exec';
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('git', () => {
|
||||
it('returns git remote ref', async () => {
|
||||
try {
|
||||
expect(await Git.getRemoteSha('https://github.com/docker/buildx.git', 'refs/pull/648/head')).toEqual('f11797113e5a9b86bd976329c5dbb8a8bfdfadfa');
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line jest/no-conditional-expect
|
||||
expect(e).toEqual(null);
|
||||
}
|
||||
describe('context', () => {
|
||||
it('returns mocked ref and sha', async () => {
|
||||
jest.spyOn(Exec, 'getExecOutput').mockImplementation((cmd, args): Promise<ExecOutput> => {
|
||||
const fullCmd = `${cmd} ${args?.join(' ')}`;
|
||||
let result = '';
|
||||
switch (fullCmd) {
|
||||
case 'git show --format=%H HEAD --quiet --':
|
||||
result = 'test-sha';
|
||||
break;
|
||||
case 'git symbolic-ref HEAD':
|
||||
result = 'refs/heads/test';
|
||||
break;
|
||||
}
|
||||
return Promise.resolve({
|
||||
stdout: result,
|
||||
stderr: '',
|
||||
exitCode: 0
|
||||
});
|
||||
});
|
||||
const ctx = await Git.context();
|
||||
expect(ctx.ref).toEqual('refs/heads/test');
|
||||
expect(ctx.sha).toEqual('test-sha');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isInsideWorkTree', () => {
|
||||
it('have been called', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'getExecOutput');
|
||||
try {
|
||||
await Git.isInsideWorkTree();
|
||||
} catch (err) {
|
||||
// noop
|
||||
}
|
||||
expect(execSpy).toHaveBeenCalledWith(`git`, ['rev-parse', '--is-inside-work-tree'], {
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('remoteSha', () => {
|
||||
it('returns sha using git ls-remote', async () => {
|
||||
expect(await Git.remoteSha('https://github.com/docker/buildx.git', 'refs/pull/648/head')).toEqual('f11797113e5a9b86bd976329c5dbb8a8bfdfadfa');
|
||||
});
|
||||
it('returns sha using github api', async () => {
|
||||
expect(await Git.remoteSha('https://github.com/docker/buildx.git', 'refs/pull/648/head', process.env.GITHUB_TOKEN)).toEqual('f11797113e5a9b86bd976329c5dbb8a8bfdfadfa');
|
||||
});
|
||||
});
|
||||
|
||||
describe('remoteURL', () => {
|
||||
it('have been called', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'getExecOutput');
|
||||
try {
|
||||
await Git.remoteURL();
|
||||
} catch (err) {
|
||||
// noop
|
||||
}
|
||||
expect(execSpy).toHaveBeenCalledWith(`git`, ['remote', 'get-url', 'origin'], {
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('fullCommit', () => {
|
||||
it('have been called', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'getExecOutput');
|
||||
try {
|
||||
await Git.fullCommit();
|
||||
} catch (err) {
|
||||
// noop
|
||||
}
|
||||
expect(execSpy).toHaveBeenCalledWith(`git`, ['show', '--format=%H', 'HEAD', '--quiet', '--'], {
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('shortCommit', () => {
|
||||
it('have been called', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'getExecOutput');
|
||||
try {
|
||||
await Git.shortCommit();
|
||||
} catch (err) {
|
||||
// noop
|
||||
}
|
||||
expect(execSpy).toHaveBeenCalledWith(`git`, ['show', '--format=%h', 'HEAD', '--quiet', '--'], {
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('tag', () => {
|
||||
it('have been called', async () => {
|
||||
const execSpy = jest.spyOn(Exec, 'getExecOutput');
|
||||
try {
|
||||
await Git.tag();
|
||||
} catch (err) {
|
||||
// noop
|
||||
}
|
||||
expect(execSpy).toHaveBeenCalledWith(`git`, ['tag', '--points-at', 'HEAD', '--sort', '-version:creatordate'], {
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -108,7 +108,7 @@ describe('actionsRuntimeToken', () => {
|
||||
process.env.ACTIONS_RUNTIME_TOKEN = 'foo';
|
||||
expect(() => {
|
||||
GitHub.actionsRuntimeToken;
|
||||
}).toThrowError();
|
||||
}).toThrow();
|
||||
});
|
||||
it('fixture', async () => {
|
||||
process.env.ACTIONS_RUNTIME_TOKEN = fs.readFileSync(path.join(__dirname, 'fixtures', 'runtimeToken.txt')).toString().trim();
|
||||
@@ -130,18 +130,12 @@ describe('printActionsRuntimeTokenACs', () => {
|
||||
process.env = originalEnv;
|
||||
});
|
||||
it('empty', async () => {
|
||||
const warnSpy = jest.spyOn(core, 'warning');
|
||||
process.env.ACTIONS_RUNTIME_TOKEN = '';
|
||||
await GitHub.printActionsRuntimeTokenACs();
|
||||
expect(warnSpy).toHaveBeenCalledTimes(1);
|
||||
expect(warnSpy).toHaveBeenCalledWith(`ACTIONS_RUNTIME_TOKEN not set`);
|
||||
await expect(GitHub.printActionsRuntimeTokenACs()).rejects.toThrow(new Error('ACTIONS_RUNTIME_TOKEN not set'));
|
||||
});
|
||||
it('malformed', async () => {
|
||||
const warnSpy = jest.spyOn(core, 'warning');
|
||||
process.env.ACTIONS_RUNTIME_TOKEN = 'foo';
|
||||
await GitHub.printActionsRuntimeTokenACs();
|
||||
expect(warnSpy).toHaveBeenCalledTimes(1);
|
||||
expect(warnSpy).toHaveBeenCalledWith(`Cannot parse Actions Runtime Token: Invalid token specified: Cannot read properties of undefined (reading 'replace')`);
|
||||
await expect(GitHub.printActionsRuntimeTokenACs()).rejects.toThrow(new Error("Cannot parse GitHub Actions Runtime Token: Invalid token specified: Cannot read properties of undefined (reading 'replace')"));
|
||||
});
|
||||
it('refs/heads/master', async () => {
|
||||
const infoSpy = jest.spyOn(core, 'info');
|
||||
|
||||
@@ -69,16 +69,40 @@ describe('getInputList', () => {
|
||||
|
||||
it('multiline and ignoring comma correctly', async () => {
|
||||
setInput('cache-from', 'user/app:cache\ntype=local,src=path/to/dir');
|
||||
const res = Util.getInputList('cache-from', true);
|
||||
const res = Util.getInputList('cache-from', {ignoreComma: true});
|
||||
expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']);
|
||||
});
|
||||
|
||||
it('multiline and ignoring comment correctly', async () => {
|
||||
setInput('labels', 'foo=bar\nbar=qux#baz');
|
||||
const res = Util.getInputList('labels');
|
||||
expect(res).toEqual(['foo=bar', 'bar=qux#baz']);
|
||||
});
|
||||
|
||||
it('multiline with comment', async () => {
|
||||
setInput('labels', 'foo=bar\nbar=qux#baz');
|
||||
const res = Util.getInputList('labels', {comment: '#'});
|
||||
expect(res).toEqual(['foo=bar', 'bar=qux']);
|
||||
});
|
||||
|
||||
it('different new lines and ignoring comma correctly', async () => {
|
||||
setInput('cache-from', 'user/app:cache\r\ntype=local,src=path/to/dir');
|
||||
const res = Util.getInputList('cache-from', true);
|
||||
const res = Util.getInputList('cache-from', {ignoreComma: true});
|
||||
expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']);
|
||||
});
|
||||
|
||||
it('do not escape surrounding quotes', async () => {
|
||||
setInput('driver-opts', `"env.no_proxy=localhost,127.0.0.1,.mydomain"`);
|
||||
const res = Util.getInputList('driver-opts', {ignoreComma: true, quote: false});
|
||||
expect(res).toEqual(['"env.no_proxy=localhost,127.0.0.1,.mydomain"']);
|
||||
});
|
||||
|
||||
it('escape surrounding quotes', async () => {
|
||||
setInput('platforms', 'linux/amd64\n"linux/arm64,linux/arm/v7"');
|
||||
const res = Util.getInputList('platforms');
|
||||
expect(res).toEqual(['linux/amd64', 'linux/arm64', 'linux/arm/v7']);
|
||||
});
|
||||
|
||||
it('multiline values', async () => {
|
||||
setInput(
|
||||
'secrets',
|
||||
@@ -88,7 +112,7 @@ bbbbbbb
|
||||
ccccccccc"
|
||||
FOO=bar`
|
||||
);
|
||||
const res = Util.getInputList('secrets', true);
|
||||
const res = Util.getInputList('secrets', {ignoreComma: true});
|
||||
expect(res).toEqual([
|
||||
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
||||
`MYSECRET=aaaaaaaa
|
||||
@@ -111,7 +135,7 @@ FOO=bar
|
||||
bbbb
|
||||
ccc"`
|
||||
);
|
||||
const res = Util.getInputList('secrets', true);
|
||||
const res = Util.getInputList('secrets', {ignoreComma: true});
|
||||
expect(res).toEqual([
|
||||
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
||||
`MYSECRET=aaaaaaaa
|
||||
@@ -134,7 +158,7 @@ bbbbbbb
|
||||
ccccccccc
|
||||
FOO=bar`
|
||||
);
|
||||
const res = Util.getInputList('secrets', true);
|
||||
const res = Util.getInputList('secrets', {ignoreComma: true});
|
||||
expect(res).toEqual(['GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789', 'MYSECRET=aaaaaaaa', 'bbbbbbb', 'ccccccccc', 'FOO=bar']);
|
||||
});
|
||||
|
||||
@@ -145,7 +169,7 @@ FOO=bar`
|
||||
`"GPG_KEY=${pgp}"
|
||||
FOO=bar`
|
||||
);
|
||||
const res = Util.getInputList('secrets', true);
|
||||
const res = Util.getInputList('secrets', {ignoreComma: true});
|
||||
expect(res).toEqual([`GPG_KEY=${pgp}`, 'FOO=bar']);
|
||||
});
|
||||
|
||||
@@ -158,7 +182,7 @@ bbbb""bbb
|
||||
ccccccccc"
|
||||
FOO=bar`
|
||||
);
|
||||
const res = Util.getInputList('secrets', true);
|
||||
const res = Util.getInputList('secrets', {ignoreComma: true});
|
||||
expect(res).toEqual([
|
||||
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
||||
`MYSECRET=aaaaaaaa
|
||||
@@ -182,13 +206,64 @@ describe('asyncForEach', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('isValidUrl', () => {
|
||||
describe('isValidURL', () => {
|
||||
test.each([
|
||||
['https://github.com/docker/buildx.git', true],
|
||||
['https://github.com/docker/buildx.git#refs/pull/648/head', true],
|
||||
['git@github.com:moby/buildkit.git', false],
|
||||
['git://github.com/user/repo.git', false],
|
||||
['github.com/moby/buildkit.git#main', false],
|
||||
['v0.4.1', false]
|
||||
])('given %p', async (url, expected) => {
|
||||
expect(Util.isValidUrl(url)).toEqual(expected);
|
||||
expect(Util.isValidURL(url)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isValidRef', () => {
|
||||
test.each([
|
||||
['https://github.com/docker/buildx.git', true],
|
||||
['https://github.com/docker/buildx.git#refs/pull/648/head', true],
|
||||
['git@github.com:moby/buildkit.git', true],
|
||||
['git://github.com/user/repo.git', true],
|
||||
['github.com/moby/buildkit.git#main', true],
|
||||
['v0.4.1', false]
|
||||
])('given %p', async (url, expected) => {
|
||||
expect(Util.isValidRef(url)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ RUN --mount=type=bind,target=.,rw \
|
||||
--mount=type=bind,from=buildx,source=/buildx,target=/usr/libexec/docker/cli-plugins/docker-buildx \
|
||||
--mount=type=bind,from=buildx,source=/buildx,target=/usr/bin/buildx \
|
||||
--mount=type=secret,id=GITHUB_TOKEN \
|
||||
GITHUB_TOKEN=$(cat /run/secrets/GITHUB_TOKEN) yarn run test-coverage --coverageDirectory=/tmp/coverage
|
||||
GITHUB_TOKEN=$(cat /run/secrets/GITHUB_TOKEN) yarn run test:coverage --coverageDirectory=/tmp/coverage
|
||||
|
||||
FROM scratch AS test-coverage
|
||||
COPY --from=test /tmp/coverage /
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
ARG LICENSE_HOLDER="actions-toolkit authors"
|
||||
ARG LICENSE_TYPE="apache"
|
||||
ARG LICENSE_FILES=".*\(Dockerfile\|Makefile\|\.js\|\.ts\|\.hcl\|\.sh\)"
|
||||
ARG LICENSE_FILES=".*\(Dockerfile\|Makefile\|\.js\|\.ts\|\.hcl\|\.sh|\.ps1\)"
|
||||
ARG ADDLICENSE_VERSION="v1.0.0"
|
||||
|
||||
FROM ghcr.io/google/addlicense:${ADDLICENSE_VERSION} AS addlicense
|
||||
|
||||
31
jest.config.itg.ts
Normal file
31
jest.config.itg.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright 2023 actions-toolkit authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
clearMocks: true,
|
||||
testEnvironment: 'node',
|
||||
moduleFileExtensions: ['js', 'ts'],
|
||||
setupFiles: ['dotenv/config'],
|
||||
testMatch: ['**/*.test.itg.ts'],
|
||||
testTimeout: 1800000, // 30 minutes
|
||||
transform: {
|
||||
'^.+\\.ts$': 'ts-jest'
|
||||
},
|
||||
moduleNameMapper: {
|
||||
'^csv-parse/sync': '<rootDir>/node_modules/csv-parse/dist/cjs/sync.cjs'
|
||||
},
|
||||
verbose: false
|
||||
};
|
||||
@@ -18,13 +18,13 @@ import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-actions-toolkit-')).split(path.sep).join(path.posix.sep);
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-actions-toolkit-'));
|
||||
|
||||
process.env = Object.assign({}, process.env, {
|
||||
TEMP: tmpDir,
|
||||
GITHUB_REPOSITORY: 'docker/actions-toolkit',
|
||||
RUNNER_TEMP: path.join(tmpDir, 'runner-temp').split(path.sep).join(path.posix.sep),
|
||||
RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache').split(path.sep).join(path.posix.sep)
|
||||
RUNNER_TEMP: path.join(tmpDir, 'runner-temp'),
|
||||
RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache')
|
||||
}) as {
|
||||
[key: string]: string;
|
||||
};
|
||||
@@ -41,7 +41,7 @@ module.exports = {
|
||||
moduleNameMapper: {
|
||||
'^csv-parse/sync': '<rootDir>/node_modules/csv-parse/dist/cjs/sync.cjs'
|
||||
},
|
||||
collectCoverageFrom: ['src/**/{!(toolkit.ts),}.ts'],
|
||||
collectCoverageFrom: ['src/**/{!(index.ts),}.ts'],
|
||||
coveragePathIgnorePatterns: ['lib/', 'node_modules/', '__mocks__/', '__tests__/'],
|
||||
verbose: true
|
||||
};
|
||||
|
||||
42
package.json
42
package.json
@@ -11,7 +11,10 @@
|
||||
"prettier": "prettier --check \"./**/*.ts\"",
|
||||
"prettier:fix": "prettier --write \"./**/*.ts\"",
|
||||
"test": "jest",
|
||||
"test-coverage": "jest --coverage"
|
||||
"test:coverage": "jest --coverage",
|
||||
"test:itg": "jest -c jest.config.itg.ts --runInBand --detectOpenHandles",
|
||||
"test:itg-list": "jest -c jest.config.itg.ts --listTests",
|
||||
"test:itg-coverage": "jest --coverage -c jest.config.itg.ts --runInBand --detectOpenHandles"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -28,8 +31,8 @@
|
||||
"author": "Docker Inc.",
|
||||
"license": "Apache-2.0",
|
||||
"packageManager": "yarn@3.3.1",
|
||||
"main": "lib/toolkit.js",
|
||||
"types": "lib/toolkit.d.ts",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"directories": {
|
||||
"lib": "lib",
|
||||
"test": "__tests__"
|
||||
@@ -42,35 +45,40 @@
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/cache": "^3.2.1",
|
||||
"@actions/core": "^1.10.0",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/github": "^5.1.1",
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"@actions/io": "^1.1.2",
|
||||
"@actions/tool-cache": "^2.0.1",
|
||||
"csv-parse": "^5.3.5",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^7.2.3",
|
||||
"async-retry": "^1.3.3",
|
||||
"csv-parse": "^5.4.0",
|
||||
"handlebars": "^4.7.7",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"semver": "^7.3.8",
|
||||
"semver": "^7.5.4",
|
||||
"tmp": "^0.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/csv-parse": "^1.2.2",
|
||||
"@types/node": "^16.18.11",
|
||||
"@types/semver": "^7.3.13",
|
||||
"@types/node": "^16.18.21",
|
||||
"@types/semver": "^7.5.0",
|
||||
"@types/tmp": "^0.2.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.49.0",
|
||||
"@typescript-eslint/parser": "^5.49.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.56.0",
|
||||
"@typescript-eslint/parser": "^5.56.0",
|
||||
"cpy-cli": "^4.2.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"eslint": "^8.33.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint": "^8.36.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-jest": "^26.9.0",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"jest": "^27.5.1",
|
||||
"prettier": "^2.8.3",
|
||||
"rimraf": "^4.1.2",
|
||||
"ts-jest": "^27.1.5",
|
||||
"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.4"
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,95 +15,82 @@
|
||||
*/
|
||||
|
||||
import * as core from '@actions/core';
|
||||
import * as exec from '@actions/exec';
|
||||
import * as semver from 'semver';
|
||||
|
||||
import {Context} from '../context';
|
||||
import {Buildx} from '../buildx/buildx';
|
||||
import {Builder} from '../buildx/builder';
|
||||
import {Config} from './config';
|
||||
import {Exec} from '../exec';
|
||||
|
||||
import {BuilderInfo} from '../types/builder';
|
||||
import {BuilderInfo, NodeInfo} from '../types/builder';
|
||||
|
||||
export interface BuildKitOpts {
|
||||
context: Context;
|
||||
buildx?: Buildx;
|
||||
}
|
||||
|
||||
export class BuildKit {
|
||||
private readonly context: Context;
|
||||
private readonly buildx: Buildx;
|
||||
private containerNamePrefix = 'buildx_buildkit_';
|
||||
|
||||
public readonly config: Config;
|
||||
|
||||
constructor(opts: BuildKitOpts) {
|
||||
this.context = opts.context;
|
||||
this.config = new Config(this.context);
|
||||
this.buildx =
|
||||
opts?.buildx ||
|
||||
new Buildx({
|
||||
context: this.context
|
||||
});
|
||||
constructor(opts?: BuildKitOpts) {
|
||||
this.config = new Config();
|
||||
this.buildx = opts?.buildx || new Buildx();
|
||||
}
|
||||
|
||||
public async getVersion(builderName: string): Promise<string | undefined> {
|
||||
const builderInfo = await this.getBuilderInfo(builderName);
|
||||
if (builderInfo.nodes.length == 0) {
|
||||
// a builder always have on node, should not happen.
|
||||
return undefined;
|
||||
}
|
||||
// TODO: get version for all nodes
|
||||
const node = builderInfo.nodes[0];
|
||||
if (!node.buildkitVersion && node.name) {
|
||||
public async getVersion(node: NodeInfo): Promise<string | undefined> {
|
||||
if (!node.buildkit && node.name) {
|
||||
try {
|
||||
return await this.getVersionWithinImage(node.name);
|
||||
} catch (e) {
|
||||
core.warning(e);
|
||||
}
|
||||
}
|
||||
return node.buildkitVersion;
|
||||
return node.buildkit;
|
||||
}
|
||||
|
||||
private async getVersionWithinImage(nodeName: string): Promise<string> {
|
||||
return exec
|
||||
.getExecOutput(`docker`, ['inspect', '--format', '{{.Config.Image}}', `${this.containerNamePrefix}${nodeName}`], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
.then(bkitimage => {
|
||||
if (bkitimage.exitCode == 0 && bkitimage.stdout.length > 0) {
|
||||
return exec
|
||||
.getExecOutput(`docker`, ['run', '--rm', bkitimage.stdout.trim(), '--version'], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
.then(bkitversion => {
|
||||
if (bkitversion.exitCode == 0 && bkitversion.stdout.length > 0) {
|
||||
return `${bkitimage.stdout.trim()} => ${bkitversion.stdout.trim()}`;
|
||||
} else if (bkitversion.stderr.length > 0) {
|
||||
throw new Error(bkitimage.stderr.trim());
|
||||
}
|
||||
return bkitversion.stdout.trim();
|
||||
});
|
||||
} else if (bkitimage.stderr.length > 0) {
|
||||
throw new Error(bkitimage.stderr.trim());
|
||||
}
|
||||
return bkitimage.stdout.trim();
|
||||
});
|
||||
core.debug(`BuildKit.getVersionWithinImage nodeName: ${nodeName}`);
|
||||
return Exec.getExecOutput(`docker`, ['inspect', '--format', '{{.Config.Image}}', `${Buildx.containerNamePrefix}${nodeName}`], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
}).then(bkitimage => {
|
||||
if (bkitimage.exitCode == 0 && bkitimage.stdout.length > 0) {
|
||||
core.debug(`BuildKit.getVersionWithinImage image: ${bkitimage.stdout.trim()}`);
|
||||
return Exec.getExecOutput(`docker`, ['run', '--rm', bkitimage.stdout.trim(), '--version'], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
}).then(bkitversion => {
|
||||
if (bkitversion.exitCode == 0 && bkitversion.stdout.length > 0) {
|
||||
return `${bkitimage.stdout.trim()} => ${bkitversion.stdout.trim()}`;
|
||||
} else if (bkitversion.stderr.length > 0) {
|
||||
throw new Error(bkitimage.stderr.trim());
|
||||
}
|
||||
return bkitversion.stdout.trim();
|
||||
});
|
||||
} else if (bkitimage.stderr.length > 0) {
|
||||
throw new Error(bkitimage.stderr.trim());
|
||||
}
|
||||
return bkitimage.stdout.trim();
|
||||
});
|
||||
}
|
||||
|
||||
public async versionSatisfies(builderName: string, range: string): Promise<boolean> {
|
||||
const builderInfo = await this.getBuilderInfo(builderName);
|
||||
public async versionSatisfies(builderName: string, range: string, builderInfo?: BuilderInfo): Promise<boolean> {
|
||||
if (!builderInfo) {
|
||||
builderInfo = await new Builder({buildx: this.buildx}).inspect(builderName);
|
||||
}
|
||||
for (const node of builderInfo.nodes) {
|
||||
let bkversion = node.buildkitVersion;
|
||||
let bkversion = node.buildkit;
|
||||
core.debug(`BuildKit.versionSatisfies ${bkversion}: ${range}`);
|
||||
if (!bkversion) {
|
||||
try {
|
||||
bkversion = await this.getVersionWithinImage(node.name || '');
|
||||
} catch (e) {
|
||||
core.debug(`BuildKit.versionSatisfies ${node.name}: can't get version`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
core.debug(`BuildKit.versionSatisfies ${node.name}: version ${bkversion}`);
|
||||
// BuildKit version reported by moby is in the format of `v0.11.0-moby`
|
||||
if (builderInfo.driver == 'docker' && !bkversion.endsWith('-moby')) {
|
||||
return false;
|
||||
@@ -114,12 +101,4 @@ export class BuildKit {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private async getBuilderInfo(name: string): Promise<BuilderInfo> {
|
||||
const builder = new Builder({
|
||||
context: this.context,
|
||||
buildx: this.buildx
|
||||
});
|
||||
return builder.inspect(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,6 @@ import fs from 'fs';
|
||||
import {Context} from '../context';
|
||||
|
||||
export class Config {
|
||||
private readonly context: Context;
|
||||
|
||||
constructor(context: Context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public resolveFromString(s: string): string {
|
||||
return this.resolve(s, false);
|
||||
}
|
||||
@@ -40,7 +34,7 @@ export class Config {
|
||||
}
|
||||
s = fs.readFileSync(s, {encoding: 'utf-8'});
|
||||
}
|
||||
const configFile = this.context.tmpName({tmpdir: this.context.tmpDir()});
|
||||
const configFile = Context.tmpName({tmpdir: Context.tmpDir()});
|
||||
fs.writeFileSync(configFile, s);
|
||||
return configFile;
|
||||
}
|
||||
|
||||
108
src/buildx/bake.ts
Normal file
108
src/buildx/bake.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* 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 {Buildx} from './buildx';
|
||||
import {Exec} from '../exec';
|
||||
import {Inputs} from './inputs';
|
||||
import {Util} from '../util';
|
||||
|
||||
import {BakeDefinition} from '../types/bake';
|
||||
|
||||
export interface BakeOpts {
|
||||
buildx?: Buildx;
|
||||
}
|
||||
|
||||
export class Bake {
|
||||
private readonly buildx: Buildx;
|
||||
|
||||
constructor(opts?: BakeOpts) {
|
||||
this.buildx = opts?.buildx || new Buildx();
|
||||
}
|
||||
|
||||
public async parseDefinitions(sources: Array<string>, targets?: Array<string>, overrides?: Array<string>, load?: boolean, push?: boolean, workdir?: string): Promise<BakeDefinition> {
|
||||
const args = ['bake'];
|
||||
|
||||
let remoteDef;
|
||||
const files: Array<string> = [];
|
||||
if (sources) {
|
||||
for (const source of sources.map(v => v.trim())) {
|
||||
if (source.length == 0) {
|
||||
continue;
|
||||
}
|
||||
if (!Util.isValidRef(source)) {
|
||||
files.push(source);
|
||||
continue;
|
||||
}
|
||||
if (remoteDef) {
|
||||
throw new Error(`Only one remote bake definition is allowed`);
|
||||
}
|
||||
remoteDef = source;
|
||||
}
|
||||
}
|
||||
if (remoteDef) {
|
||||
args.push(remoteDef);
|
||||
}
|
||||
for (const file of files) {
|
||||
args.push('--file', file);
|
||||
}
|
||||
if (overrides) {
|
||||
for (const override of overrides) {
|
||||
args.push('--set', override);
|
||||
}
|
||||
}
|
||||
if (load) {
|
||||
args.push('--load');
|
||||
}
|
||||
if (push) {
|
||||
args.push('--push');
|
||||
}
|
||||
|
||||
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 => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr);
|
||||
}
|
||||
return <BakeDefinition>JSON.parse(res.stdout.trim());
|
||||
});
|
||||
}
|
||||
|
||||
public static hasLocalExporter(def: BakeDefinition): boolean {
|
||||
return Inputs.hasExporterType('local', Bake.exporters(def));
|
||||
}
|
||||
|
||||
public static hasTarExporter(def: BakeDefinition): boolean {
|
||||
return Inputs.hasExporterType('tar', Bake.exporters(def));
|
||||
}
|
||||
|
||||
public static hasDockerExporter(def: BakeDefinition, load?: boolean): boolean {
|
||||
return load || Inputs.hasExporterType('docker', Bake.exporters(def));
|
||||
}
|
||||
|
||||
private static exporters(def: BakeDefinition): Array<string> {
|
||||
const exporters = new Array<string>();
|
||||
for (const key in def.target) {
|
||||
const target = def.target[key];
|
||||
if (target.output) {
|
||||
exporters.push(...target.output);
|
||||
}
|
||||
}
|
||||
return exporters;
|
||||
}
|
||||
}
|
||||
@@ -14,99 +14,131 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as exec from '@actions/exec';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
import {Buildx} from './buildx';
|
||||
import {Context} from '../context';
|
||||
import {Exec} from '../exec';
|
||||
|
||||
import {BuilderInfo, NodeInfo} from '../types/builder';
|
||||
import {BuilderInfo, GCPolicy, NodeInfo} from '../types/builder';
|
||||
|
||||
export interface BuilderOpts {
|
||||
context: Context;
|
||||
buildx?: Buildx;
|
||||
}
|
||||
|
||||
export class Builder {
|
||||
private readonly context: Context;
|
||||
private readonly buildx: Buildx;
|
||||
|
||||
constructor(opts: BuilderOpts) {
|
||||
this.context = opts.context;
|
||||
this.buildx =
|
||||
opts?.buildx ||
|
||||
new Buildx({
|
||||
context: this.context
|
||||
constructor(opts?: BuilderOpts) {
|
||||
this.buildx = opts?.buildx || new Buildx();
|
||||
}
|
||||
|
||||
public async exists(name: string): Promise<boolean> {
|
||||
const cmd = await this.buildx.getCommand(['inspect', name]);
|
||||
|
||||
const ok: boolean = await Exec.getExecOutput(cmd.command, cmd.args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
core.debug(`Builder.exists cmd err: ${res.stderr.trim()}`);
|
||||
return false;
|
||||
}
|
||||
return res.exitCode == 0;
|
||||
})
|
||||
.catch(error => {
|
||||
core.debug(`Builder.exists error: ${error}`);
|
||||
return false;
|
||||
});
|
||||
|
||||
core.debug(`Builder.exists: ${ok}`);
|
||||
return ok;
|
||||
}
|
||||
|
||||
public async inspect(name: string): Promise<BuilderInfo> {
|
||||
const cmd = this.buildx.getCommand(['inspect', name]);
|
||||
return await exec
|
||||
.getExecOutput(cmd.command, cmd.args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr.trim());
|
||||
}
|
||||
return Builder.parseInspect(res.stdout);
|
||||
});
|
||||
const cmd = await this.buildx.getCommand(['inspect', name]);
|
||||
return await Exec.getExecOutput(cmd.command, cmd.args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr.trim());
|
||||
}
|
||||
return Builder.parseInspect(res.stdout);
|
||||
});
|
||||
}
|
||||
|
||||
public static parseInspect(data: string): BuilderInfo {
|
||||
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.driverOpts = (value.match(/(\w+)="([^"]*)"/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.buildkitdFlags = value;
|
||||
case lkey == 'flags': {
|
||||
parsingType = undefined;
|
||||
currentNode['buildkitd-flags'] = value;
|
||||
break;
|
||||
}
|
||||
case 'buildkit': {
|
||||
node.buildkitVersion = value;
|
||||
case lkey == 'buildkit': {
|
||||
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
|
||||
@@ -120,13 +152,63 @@ export class Builder {
|
||||
// otherwise set all platforms available
|
||||
platforms = value.split(', ');
|
||||
}
|
||||
node.platforms = platforms.join(',');
|
||||
currentNode.platforms = platforms.join(',');
|
||||
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 '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;
|
||||
}
|
||||
|
||||
@@ -16,31 +16,29 @@
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import * as exec from '@actions/exec';
|
||||
import * as core from '@actions/core';
|
||||
import * as semver from 'semver';
|
||||
|
||||
import {Docker} from '../docker';
|
||||
import {Context} from '../context';
|
||||
import {Inputs} from './inputs';
|
||||
import {Docker} from '../docker/docker';
|
||||
import {Exec} from '../exec';
|
||||
|
||||
import {Cert} from '../types/buildx';
|
||||
|
||||
export interface BuildxOpts {
|
||||
context: Context;
|
||||
standalone?: boolean;
|
||||
}
|
||||
|
||||
export class Buildx {
|
||||
private readonly context: Context;
|
||||
private _version: string | undefined;
|
||||
private _version: string;
|
||||
private _versionOnce: boolean;
|
||||
private readonly _standalone: boolean | undefined;
|
||||
|
||||
public readonly inputs: Inputs;
|
||||
public readonly standalone: boolean;
|
||||
public static readonly containerNamePrefix = 'buildx_buildkit_';
|
||||
|
||||
constructor(opts: BuildxOpts) {
|
||||
this.context = opts.context;
|
||||
this.inputs = new Inputs(this.context);
|
||||
this.standalone = opts?.standalone ?? !Docker.isAvailable;
|
||||
constructor(opts?: BuildxOpts) {
|
||||
this._standalone = opts?.standalone;
|
||||
this._version = '';
|
||||
this._versionOnce = false;
|
||||
}
|
||||
|
||||
static get configDir(): string {
|
||||
@@ -51,62 +49,71 @@ export class Buildx {
|
||||
return path.join(Buildx.configDir, 'certs');
|
||||
}
|
||||
|
||||
public getCommand(args: Array<string>) {
|
||||
public async isStandalone(): Promise<boolean> {
|
||||
const standalone = this._standalone ?? !(await Docker.isAvailable());
|
||||
core.debug(`Buildx.isStandalone: ${standalone}`);
|
||||
return standalone;
|
||||
}
|
||||
|
||||
public async getCommand(args: Array<string>) {
|
||||
const standalone = await this.isStandalone();
|
||||
return {
|
||||
command: this.standalone ? 'buildx' : 'docker',
|
||||
args: this.standalone ? args : ['buildx', ...args]
|
||||
command: standalone ? 'buildx' : 'docker',
|
||||
args: standalone ? args : ['buildx', ...args]
|
||||
};
|
||||
}
|
||||
|
||||
public async isAvailable(): Promise<boolean> {
|
||||
const cmd = this.getCommand([]);
|
||||
return await exec
|
||||
.getExecOutput(cmd.command, cmd.args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
const cmd = await this.getCommand([]);
|
||||
|
||||
const ok: boolean = await Exec.getExecOutput(cmd.command, cmd.args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
core.debug(`Buildx.isAvailable cmd err: ${res.stderr.trim()}`);
|
||||
return false;
|
||||
}
|
||||
return res.exitCode == 0;
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.catch(error => {
|
||||
core.debug(`Buildx.isAvailable error: ${error}`);
|
||||
return false;
|
||||
});
|
||||
|
||||
core.debug(`Buildx.isAvailable: ${ok}`);
|
||||
return ok;
|
||||
}
|
||||
|
||||
public async printInspect(name: string): Promise<void> {
|
||||
const cmd = this.getCommand(['inspect', name]);
|
||||
await exec.exec(cmd.command, cmd.args, {
|
||||
const cmd = await this.getCommand(['inspect', name]);
|
||||
await Exec.exec(cmd.command, cmd.args, {
|
||||
failOnStdErr: false
|
||||
});
|
||||
}
|
||||
|
||||
get version() {
|
||||
return (async () => {
|
||||
if (!this._version) {
|
||||
const cmd = this.getCommand(['version']);
|
||||
this._version = await exec
|
||||
.getExecOutput(cmd.command, cmd.args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr.trim());
|
||||
}
|
||||
return Buildx.parseVersion(res.stdout.trim());
|
||||
});
|
||||
}
|
||||
public async version(): Promise<string> {
|
||||
if (this._versionOnce) {
|
||||
return this._version;
|
||||
})();
|
||||
}
|
||||
this._versionOnce = true;
|
||||
const cmd = await this.getCommand(['version']);
|
||||
this._version = await Exec.getExecOutput(cmd.command, cmd.args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr.trim());
|
||||
}
|
||||
return Buildx.parseVersion(res.stdout.trim());
|
||||
});
|
||||
return this._version;
|
||||
}
|
||||
|
||||
public async printVersion() {
|
||||
const cmd = this.getCommand(['version']);
|
||||
await exec.exec(cmd.command, cmd.args, {
|
||||
const cmd = await this.getCommand(['version']);
|
||||
await Exec.exec(cmd.command, cmd.args, {
|
||||
failOnStdErr: false
|
||||
});
|
||||
}
|
||||
@@ -120,11 +127,14 @@ export class Buildx {
|
||||
}
|
||||
|
||||
public async versionSatisfies(range: string, version?: string): Promise<boolean> {
|
||||
const ver = version ?? (await this.version);
|
||||
const ver = version ?? (await this.version());
|
||||
if (!ver) {
|
||||
core.debug(`Buildx.versionSatisfies false: undefined version`);
|
||||
return false;
|
||||
}
|
||||
return semver.satisfies(ver, range) || /^[0-9a-f]{7}$/.exec(ver) !== null;
|
||||
const res = semver.satisfies(ver, range) || /^[0-9a-f]{7}$/.exec(ver) !== null;
|
||||
core.debug(`Buildx.versionSatisfies ${ver} statisfies ${range}: ${res}`);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static resolveCertsDriverOpts(driver: string, endpoint: string, cert: Cert): Array<string> {
|
||||
|
||||
@@ -21,31 +21,37 @@ 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 {
|
||||
private readonly context: Context;
|
||||
|
||||
constructor(context: Context) {
|
||||
this.context = context;
|
||||
public static getBuildImageIDFilePath(): string {
|
||||
return path.join(Context.tmpDir(), 'iidfile');
|
||||
}
|
||||
|
||||
public getBuildImageIDFilePath(): string {
|
||||
return path.join(this.context.tmpDir(), 'iidfile').split(path.sep).join(path.posix.sep);
|
||||
public static getBuildMetadataFilePath(): string {
|
||||
return path.join(Context.tmpDir(), 'metadata-file');
|
||||
}
|
||||
|
||||
public getBuildMetadataFilePath(): string {
|
||||
return path.join(this.context.tmpDir(), 'metadata-file').split(path.sep).join(path.posix.sep);
|
||||
}
|
||||
|
||||
public resolveBuildImageID(): string | undefined {
|
||||
const iidFile = this.getBuildImageIDFilePath();
|
||||
public static resolveBuildImageID(): string | undefined {
|
||||
const iidFile = Inputs.getBuildImageIDFilePath();
|
||||
if (!fs.existsSync(iidFile)) {
|
||||
return undefined;
|
||||
}
|
||||
return fs.readFileSync(iidFile, {encoding: 'utf-8'}).trim();
|
||||
}
|
||||
|
||||
public resolveBuildMetadata(): string | undefined {
|
||||
const metadataFile = this.getBuildMetadataFilePath();
|
||||
public static resolveBuildMetadata(): string | undefined {
|
||||
const metadataFile = Inputs.getBuildMetadataFilePath();
|
||||
if (!fs.existsSync(metadataFile)) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -56,8 +62,8 @@ export class Inputs {
|
||||
return content;
|
||||
}
|
||||
|
||||
public resolveDigest(): string | undefined {
|
||||
const metadata = this.resolveBuildMetadata();
|
||||
public static resolveDigest(): string | undefined {
|
||||
const metadata = Inputs.resolveBuildMetadata();
|
||||
if (metadata === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -68,50 +74,53 @@ export class Inputs {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public resolveBuildSecretString(kvp: string): string {
|
||||
return this.resolveBuildSecret(kvp, false);
|
||||
public static resolveBuildSecretString(kvp: string): string {
|
||||
return Inputs.resolveBuildSecret(kvp, false);
|
||||
}
|
||||
|
||||
public resolveBuildSecretFile(kvp: string): string {
|
||||
return this.resolveBuildSecret(kvp, true);
|
||||
public static resolveBuildSecretFile(kvp: string): string {
|
||||
return Inputs.resolveBuildSecret(kvp, true);
|
||||
}
|
||||
|
||||
public resolveBuildSecret(kvp: string, file: boolean): string {
|
||||
const delimiterIndex = kvp.indexOf('=');
|
||||
const key = kvp.substring(0, delimiterIndex);
|
||||
let value = kvp.substring(delimiterIndex + 1);
|
||||
if (key.length == 0 || value.length == 0) {
|
||||
throw new Error(`${kvp} is not a valid secret`);
|
||||
}
|
||||
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 = this.context.tmpName({tmpdir: this.context.tmpDir()});
|
||||
const secretFile = Context.tmpName({tmpdir: Context.tmpDir()});
|
||||
fs.writeFileSync(secretFile, value);
|
||||
return `id=${key},src=${secretFile}`;
|
||||
}
|
||||
|
||||
public getProvenanceInput(name: string): string {
|
||||
public static getProvenanceInput(name: string): string {
|
||||
const input = core.getInput(name);
|
||||
if (!input) {
|
||||
// if input is not set returns empty string
|
||||
return input;
|
||||
}
|
||||
const builderID = this.context.provenanceBuilderID;
|
||||
try {
|
||||
return core.getBooleanInput(name) ? `builder-id=${builderID}` : 'false';
|
||||
return core.getBooleanInput(name) ? `builder-id=${Context.provenanceBuilderID()}` : 'false';
|
||||
} catch (err) {
|
||||
// not a valid boolean, so we assume it's a string
|
||||
return this.resolveProvenanceAttrs(input);
|
||||
return Inputs.resolveProvenanceAttrs(input);
|
||||
}
|
||||
}
|
||||
|
||||
public resolveProvenanceAttrs(input: string): string {
|
||||
public static resolveProvenanceAttrs(input: string): string {
|
||||
if (!input) {
|
||||
return `builder-id=${this.context.provenanceBuilderID}`;
|
||||
return `builder-id=${Context.provenanceBuilderID()}`;
|
||||
}
|
||||
// parse attributes from input
|
||||
const fields = parse(input, {
|
||||
@@ -129,7 +138,7 @@ export class Inputs {
|
||||
}
|
||||
}
|
||||
// if not add builder-id attribute
|
||||
return `${input},builder-id=${this.context.provenanceBuilderID}`;
|
||||
return `${input},builder-id=${Context.provenanceBuilderID()}`;
|
||||
}
|
||||
|
||||
public static hasLocalExporter(exporters: string[]): boolean {
|
||||
@@ -141,7 +150,7 @@ export class Inputs {
|
||||
}
|
||||
|
||||
public static hasDockerExporter(exporters: string[], load?: boolean): boolean {
|
||||
return load ?? Inputs.hasExporterType('docker', exporters);
|
||||
return load || Inputs.hasExporterType('docker', exporters);
|
||||
}
|
||||
|
||||
public static hasExporterType(name: string, exporters: string[]): boolean {
|
||||
|
||||
@@ -14,167 +14,183 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import crypto from 'crypto';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import * as core from '@actions/core';
|
||||
import * as exec from '@actions/exec';
|
||||
import * as httpm from '@actions/http-client';
|
||||
import * as tc from '@actions/tool-cache';
|
||||
import * as cache from '@actions/cache';
|
||||
import * as semver from 'semver';
|
||||
import * as util from 'util';
|
||||
|
||||
import {Buildx} from './buildx';
|
||||
import {Context} from '../context';
|
||||
import {Docker} from '../docker';
|
||||
import {Exec} from '../exec';
|
||||
import {Docker} from '../docker/docker';
|
||||
import {Git} from '../git';
|
||||
import {Util} from '../util';
|
||||
|
||||
import {GitHubRelease} from '../types/github';
|
||||
|
||||
export interface InstallOpts {
|
||||
context?: Context;
|
||||
standalone?: boolean;
|
||||
}
|
||||
|
||||
export class Install {
|
||||
private readonly context: Context;
|
||||
private readonly standalone: boolean;
|
||||
private readonly _standalone: boolean | undefined;
|
||||
|
||||
constructor(opts?: InstallOpts) {
|
||||
this.context = opts?.context || new Context();
|
||||
this.standalone = opts?.standalone ?? !Docker.isAvailable;
|
||||
this._standalone = opts?.standalone;
|
||||
}
|
||||
|
||||
public async download(version: string, dest: string): Promise<string> {
|
||||
/*
|
||||
* Download buildx binary from GitHub release
|
||||
* @param version semver version or latest
|
||||
* @returns path to the buildx binary
|
||||
*/
|
||||
public async download(version: string): Promise<string> {
|
||||
const release: GitHubRelease = await Install.getRelease(version);
|
||||
const fversion = release.tag_name.replace(/^v+|v+$/g, '');
|
||||
core.debug(`Install.download 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}".`);
|
||||
}
|
||||
toolPath = await this.fetchBinary(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}".`);
|
||||
}
|
||||
|
||||
if (this.standalone) {
|
||||
return this.setStandalone(toolPath, dest);
|
||||
const installCache = new InstallCache('buildx-dl-bin', vspec);
|
||||
|
||||
const cacheFoundPath = await installCache.find();
|
||||
if (cacheFoundPath) {
|
||||
core.info(`Buildx binary found in ${cacheFoundPath}`);
|
||||
return cacheFoundPath;
|
||||
}
|
||||
return this.setPlugin(toolPath, dest);
|
||||
|
||||
const downloadURL = util.format('https://github.com/docker/buildx/releases/download/v%s/%s', 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;
|
||||
}
|
||||
|
||||
public async build(gitContext: string, dest: string): Promise<string> {
|
||||
// eslint-disable-next-line prefer-const
|
||||
let [repo, ref] = gitContext.split('#');
|
||||
if (ref.length == 0) {
|
||||
ref = 'master';
|
||||
/*
|
||||
* Build buildx binary from source
|
||||
* @param gitContext git repo context
|
||||
* @returns path to the buildx binary
|
||||
*/
|
||||
public async build(gitContext: string): Promise<string> {
|
||||
const vspec = await this.vspec(gitContext);
|
||||
core.debug(`Install.build vspec: ${vspec}`);
|
||||
|
||||
const installCache = new InstallCache('buildx-build-bin', vspec);
|
||||
|
||||
const cacheFoundPath = await installCache.find();
|
||||
if (cacheFoundPath) {
|
||||
core.info(`Buildx binary found in ${cacheFoundPath}`);
|
||||
return cacheFoundPath;
|
||||
}
|
||||
|
||||
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.getRemoteSha(repo, ref);
|
||||
}
|
||||
core.debug(`Tool version spec ${vspec}`);
|
||||
const outputDir = path.join(Context.tmpDir(), 'buildx-build-cache');
|
||||
const buildCmd = await this.buildCommand(gitContext, outputDir);
|
||||
|
||||
let toolPath: string;
|
||||
toolPath = tc.find('buildx', vspec);
|
||||
if (!toolPath) {
|
||||
const outputDir = path.join(this.context.tmpDir(), 'build-cache').split(path.sep).join(path.posix.sep);
|
||||
const buildCmd = await this.buildCommand(gitContext, outputDir);
|
||||
toolPath = await exec
|
||||
.getExecOutput(buildCmd.command, buildCmd.args, {
|
||||
ignoreReturnCode: true
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
core.warning(res.stderr.trim());
|
||||
}
|
||||
return tc.cacheFile(`${outputDir}/buildx`, os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx', 'buildx', vspec);
|
||||
});
|
||||
}
|
||||
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'}`);
|
||||
}
|
||||
return `${outputDir}/buildx`;
|
||||
});
|
||||
|
||||
if (this.standalone) {
|
||||
return this.setStandalone(toolPath, dest);
|
||||
const cacheSavePath = await installCache.save(buildBinPath);
|
||||
core.info(`Cached to ${cacheSavePath}`);
|
||||
return cacheSavePath;
|
||||
}
|
||||
|
||||
public async installStandalone(binPath: string, dest?: string): Promise<string> {
|
||||
core.info('Standalone mode');
|
||||
dest = dest || Context.tmpDir();
|
||||
|
||||
const binDir = path.join(dest, 'buildx-bin-standalone');
|
||||
if (!fs.existsSync(binDir)) {
|
||||
fs.mkdirSync(binDir, {recursive: true});
|
||||
}
|
||||
return this.setPlugin(toolPath, dest);
|
||||
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');
|
||||
|
||||
core.addPath(binDir);
|
||||
core.info('Added Buildx to PATH');
|
||||
|
||||
core.info(`Binary path: ${buildxPath}`);
|
||||
return buildxPath;
|
||||
}
|
||||
|
||||
public async installPlugin(binPath: string, dest?: string): Promise<string> {
|
||||
core.info('Docker plugin mode');
|
||||
dest = dest || Docker.configDir;
|
||||
|
||||
const pluginsDir: string = path.join(dest, 'cli-plugins');
|
||||
if (!fs.existsSync(pluginsDir)) {
|
||||
fs.mkdirSync(pluginsDir, {recursive: true});
|
||||
}
|
||||
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');
|
||||
|
||||
core.info(`Plugin path: ${pluginPath}`);
|
||||
return pluginPath;
|
||||
}
|
||||
|
||||
private async buildCommand(gitContext: string, outputDir: string): Promise<{args: Array<string>; command: string}> {
|
||||
const buildxStandaloneFound = await new Buildx({context: this.context, standalone: true}).isAvailable();
|
||||
const buildxPluginFound = await new Buildx({context: this.context, standalone: false}).isAvailable();
|
||||
const buildxStandaloneFound = await new Buildx({standalone: true}).isAvailable();
|
||||
const buildxPluginFound = await new Buildx({standalone: false}).isAvailable();
|
||||
|
||||
let buildStandalone = false;
|
||||
if (this.standalone && buildxStandaloneFound) {
|
||||
core.debug(`Buildx standalone found, build with it`);
|
||||
if ((await this.isStandalone()) && buildxStandaloneFound) {
|
||||
core.debug(`Install.buildCommand: Buildx standalone found, build with it`);
|
||||
buildStandalone = true;
|
||||
} else if (!this.standalone && buildxPluginFound) {
|
||||
core.debug(`Buildx plugin found, build with it`);
|
||||
} else if (!(await this.isStandalone()) && buildxPluginFound) {
|
||||
core.debug(`Install.buildCommand: Buildx plugin found, build with it`);
|
||||
buildStandalone = false;
|
||||
} else if (buildxStandaloneFound) {
|
||||
core.debug(`Buildx plugin not found, but standalone found so trying to build with it`);
|
||||
core.debug(`Install.buildCommand: Buildx plugin not found, but standalone found so trying to build with it`);
|
||||
buildStandalone = true;
|
||||
} else if (buildxPluginFound) {
|
||||
core.debug(`Buildx standalone not found, but plugin found so trying to build with it`);
|
||||
core.debug(`Install.buildCommand: Buildx standalone not found, but plugin found so trying to build with it`);
|
||||
buildStandalone = false;
|
||||
} else {
|
||||
throw new Error(`Neither buildx standalone or plugin have been found to build from ref ${gitContext}`);
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
args.push(gitContext);
|
||||
|
||||
//prettier-ignore
|
||||
return new Buildx({context: this.context, standalone: buildStandalone}).getCommand([
|
||||
'build',
|
||||
'--target', 'binaries',
|
||||
'--build-arg', 'BUILDKIT_CONTEXT_KEEP_GIT_DIR=1',
|
||||
'--output', `type=local,dest=${outputDir}`,
|
||||
gitContext
|
||||
]);
|
||||
return await new Buildx({standalone: buildStandalone}).getCommand(args);
|
||||
}
|
||||
|
||||
private async setStandalone(toolPath: string, dest: string): Promise<string> {
|
||||
const toolBinPath = path.join(toolPath, os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx');
|
||||
const binDir = path.join(dest, 'bin');
|
||||
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);
|
||||
fs.chmodSync(buildxPath, '0755');
|
||||
core.addPath(binDir);
|
||||
return buildxPath;
|
||||
}
|
||||
|
||||
private async setPlugin(toolPath: string, dest: string): Promise<string> {
|
||||
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);
|
||||
fs.chmodSync(pluginPath, '0755');
|
||||
return pluginPath;
|
||||
}
|
||||
|
||||
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));
|
||||
const downloadPath = await tc.downloadTool(downloadURL);
|
||||
core.debug(`downloadURL: ${downloadURL}`);
|
||||
core.debug(`downloadPath: ${downloadPath}`);
|
||||
return await tc.cacheFile(downloadPath, targetFile, 'buildx', version);
|
||||
}
|
||||
|
||||
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 async isStandalone(): Promise<boolean> {
|
||||
const standalone = this._standalone ?? !(await Docker.isAvailable());
|
||||
core.debug(`Install.isStandalone: ${standalone}`);
|
||||
return standalone;
|
||||
}
|
||||
|
||||
private filename(version: string): string {
|
||||
@@ -204,6 +220,39 @@ export class Install {
|
||||
return util.format('buildx-v%s.%s-%s%s', version, platform, arch, ext);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 = crypto.createHash('sha256').update(key).digest('hex');
|
||||
core.info(`Use ${hash} version spec cache key for ${key}`);
|
||||
return hash;
|
||||
}
|
||||
|
||||
public static async getRelease(version: string): Promise<GitHubRelease> {
|
||||
const url = `https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/buildx-releases.json`;
|
||||
const http: httpm.HttpClient = new httpm.HttpClient('docker-actions-toolkit');
|
||||
@@ -220,3 +269,74 @@ export class Install {
|
||||
return releases[version];
|
||||
}
|
||||
}
|
||||
|
||||
class InstallCache {
|
||||
private readonly htcName: string;
|
||||
private readonly htcVersion: string;
|
||||
private readonly ghaCacheKey: string;
|
||||
private readonly cacheDir: string;
|
||||
private readonly cacheFile: string;
|
||||
private readonly cachePath: string;
|
||||
|
||||
constructor(htcName: string, htcVersion: string) {
|
||||
this.htcName = htcName;
|
||||
this.htcVersion = htcVersion;
|
||||
this.ghaCacheKey = util.format('%s-%s-%s', this.htcName, this.htcVersion, this.platform());
|
||||
this.cacheDir = path.join(Buildx.configDir, '.bin', htcVersion, this.platform());
|
||||
this.cacheFile = os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx';
|
||||
this.cachePath = path.join(this.cacheDir, this.cacheFile);
|
||||
if (!fs.existsSync(this.cacheDir)) {
|
||||
fs.mkdirSync(this.cacheDir, {recursive: true});
|
||||
}
|
||||
}
|
||||
|
||||
public async save(file: string): Promise<string> {
|
||||
core.debug(`InstallCache.save ${file}`);
|
||||
const cachePath = this.copyToCache(file);
|
||||
|
||||
const htcPath = await tc.cacheDir(this.cacheDir, this.htcName, this.htcVersion, this.platform());
|
||||
core.debug(`InstallCache.save cached to hosted tool cache ${htcPath}`);
|
||||
|
||||
if (cache.isFeatureAvailable()) {
|
||||
core.debug(`InstallCache.save caching ${this.ghaCacheKey} to GitHub Actions cache`);
|
||||
await cache.saveCache([this.cacheDir], this.ghaCacheKey);
|
||||
}
|
||||
|
||||
return cachePath;
|
||||
}
|
||||
|
||||
public async find(): Promise<string> {
|
||||
let htcPath = tc.find(this.htcName, this.htcVersion, this.platform());
|
||||
if (htcPath) {
|
||||
core.info(`Restored from hosted tool cache ${htcPath}`);
|
||||
return this.copyToCache(`${htcPath}/${this.cacheFile}`);
|
||||
}
|
||||
|
||||
if (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.htcName, this.htcVersion, this.platform());
|
||||
core.info(`Restored to hosted tool cache ${htcPath}`);
|
||||
return this.copyToCache(`${htcPath}/${this.cacheFile}`);
|
||||
}
|
||||
} else {
|
||||
core.info(`GitHub Actions cache feature not available`);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private copyToCache(file: string): string {
|
||||
core.debug(`Copying ${file} to ${this.cachePath}`);
|
||||
fs.copyFileSync(file, this.cachePath);
|
||||
fs.chmodSync(this.cachePath, '0755');
|
||||
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,29 +23,32 @@ import * as github from '@actions/github';
|
||||
import {GitHub} from './github';
|
||||
|
||||
export class Context {
|
||||
public gitRef: string;
|
||||
public buildGitContext: string;
|
||||
public provenanceBuilderID: string;
|
||||
private static readonly _tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-actions-toolkit-'));
|
||||
|
||||
private readonly _tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-actions-toolkit-')).split(path.sep).join(path.posix.sep);
|
||||
|
||||
constructor() {
|
||||
this.gitRef = github.context.ref;
|
||||
if (github.context.sha && this.gitRef && !this.gitRef.startsWith('refs/')) {
|
||||
this.gitRef = `refs/heads/${github.context.ref}`;
|
||||
}
|
||||
if (github.context.sha && !this.gitRef.startsWith(`refs/pull/`)) {
|
||||
this.gitRef = github.context.sha;
|
||||
}
|
||||
this.buildGitContext = `${GitHub.serverURL}/${github.context.repo.owner}/${github.context.repo.repo}.git#${this.gitRef}`;
|
||||
this.provenanceBuilderID = `${GitHub.serverURL}/${github.context.repo.owner}/${github.context.repo.repo}/actions/runs/${github.context.runId}`;
|
||||
public static tmpDir(): string {
|
||||
return Context._tmpDir;
|
||||
}
|
||||
|
||||
public tmpDir(): string {
|
||||
return this._tmpDir;
|
||||
}
|
||||
|
||||
public tmpName(options?: tmp.TmpNameOptions): string {
|
||||
public static tmpName(options?: tmp.TmpNameOptions): string {
|
||||
return tmp.tmpNameSync(options);
|
||||
}
|
||||
|
||||
public static gitRef(): string {
|
||||
let gitRef = github.context.ref;
|
||||
if (github.context.sha && gitRef && !gitRef.startsWith('refs/')) {
|
||||
gitRef = `refs/heads/${github.context.ref}`;
|
||||
}
|
||||
if (github.context.sha && !gitRef.startsWith(`refs/pull/`)) {
|
||||
gitRef = github.context.sha;
|
||||
}
|
||||
return gitRef;
|
||||
}
|
||||
|
||||
public static gitContext(): string {
|
||||
return `${GitHub.serverURL}/${github.context.repo.owner}/${github.context.repo.repo}.git#${Context.gitRef()}`;
|
||||
}
|
||||
|
||||
public static provenanceBuilderID(): string {
|
||||
return `${GitHub.serverURL}/${github.context.repo.owner}/${github.context.repo.repo}/actions/runs/${github.context.runId}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,66 +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 os from 'os';
|
||||
import path from 'path';
|
||||
import * as exec from '@actions/exec';
|
||||
|
||||
export class Docker {
|
||||
static get configDir(): string {
|
||||
return process.env.DOCKER_CONFIG || path.join(os.homedir(), '.docker');
|
||||
}
|
||||
|
||||
static get isAvailable(): boolean {
|
||||
let dockerAvailable = false;
|
||||
exec
|
||||
.getExecOutput('docker', undefined, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
dockerAvailable = false;
|
||||
} else {
|
||||
dockerAvailable = res.exitCode == 0;
|
||||
}
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.catch(error => {
|
||||
dockerAvailable = false;
|
||||
});
|
||||
return dockerAvailable;
|
||||
}
|
||||
|
||||
public static async printVersion(standalone?: boolean) {
|
||||
const noDocker = standalone ?? !Docker.isAvailable;
|
||||
if (noDocker) {
|
||||
return;
|
||||
}
|
||||
await exec.exec('docker', ['version'], {
|
||||
failOnStdErr: false
|
||||
});
|
||||
}
|
||||
|
||||
public static async printInfo(standalone?: boolean) {
|
||||
const noDocker = standalone ?? !Docker.isAvailable;
|
||||
if (noDocker) {
|
||||
return;
|
||||
}
|
||||
await exec.exec('docker', ['info'], {
|
||||
failOnStdErr: false
|
||||
});
|
||||
}
|
||||
}
|
||||
338
src/docker/assets.ts
Normal file
338
src/docker/assets.ts
Normal file
@@ -0,0 +1,338 @@
|
||||
/**
|
||||
* 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 {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);
|
||||
};
|
||||
|
||||
export const dockerServiceLogsPs1 = (): string => {
|
||||
return get('docker-service-logs.ps1', dockerServiceLogsPs1Data);
|
||||
};
|
||||
|
||||
export const colimaYaml = (): string => {
|
||||
return get('colima.yaml', colimaYamlData);
|
||||
};
|
||||
|
||||
const get = (filename: string, data: string, mode?: string): string => {
|
||||
const assetPath = Context.tmpName({
|
||||
template: `docker-asset-XXXXXX-${filename}`,
|
||||
tmpdir: Context.tmpDir()
|
||||
});
|
||||
fs.writeFileSync(assetPath, data);
|
||||
if (mode) {
|
||||
fs.chmodSync(assetPath, mode);
|
||||
}
|
||||
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(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ToolDir,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$RunDir,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$DockerHost)
|
||||
|
||||
$pwver = (Get-ItemProperty -Path HKLM:\\SOFTWARE\\Microsoft\\PowerShell\\3\\PowerShellEngine -Name 'PowerShellVersion').PowerShellVersion
|
||||
Write-Host "PowerShell version: $pwver"
|
||||
|
||||
# Create run directory
|
||||
New-Item -ItemType Directory "$RunDir" -ErrorAction SilentlyContinue | Out-Null
|
||||
|
||||
# Remove existing service
|
||||
if (Get-Service docker -ErrorAction SilentlyContinue) {
|
||||
$dockerVersion = (docker version -f "{{.Server.Version}}")
|
||||
Write-Host "Current installed Docker version: $dockerVersion"
|
||||
# stop service
|
||||
Stop-Service -Force -Name docker
|
||||
Write-Host "Service stopped"
|
||||
# remove service
|
||||
sc.exe delete "docker"
|
||||
# removes event log entry. we could use "Remove-EventLog -LogName -Source docker"
|
||||
# but this cmd is not available atm
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
& reg delete "HKLM\\SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\docker" /f 2>&1 | Out-Null
|
||||
$ErrorActionPreference = "Stop"
|
||||
Write-Host "Service removed"
|
||||
}
|
||||
|
||||
$env:DOCKER_HOST = $DockerHost
|
||||
Write-Host "DOCKER_HOST: $env:DOCKER_HOST"
|
||||
|
||||
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
|
||||
Start-Process -Wait -NoNewWindow "$ToolDir\\dockerd" \`
|
||||
-ArgumentList \`
|
||||
"--host=$DockerHost", \`
|
||||
"--data-root=$RunDir\\moby-root", \`
|
||||
"--exec-root=$RunDir\\moby-exec", \`
|
||||
"--pidfile=$RunDir\\docker.pid", \`
|
||||
"--register-service"
|
||||
Write-Host "Starting service"
|
||||
Start-Service -Name docker
|
||||
Write-Host "Service started successfully!"
|
||||
|
||||
$tries=20
|
||||
Write-Host "Waiting for Docker daemon to start..."
|
||||
While ($true) {
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
& "$ToolDir\\docker" version | Out-Null
|
||||
$ErrorActionPreference = "Stop"
|
||||
If ($LastExitCode -eq 0) {
|
||||
break
|
||||
}
|
||||
$tries--
|
||||
If ($tries -le 0) {
|
||||
Throw "Failed to get a response from Docker daemon"
|
||||
}
|
||||
Write-Host -NoNewline "."
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
Write-Host "Docker daemon started successfully!"
|
||||
`;
|
||||
|
||||
export const dockerServiceLogsPs1Data = `
|
||||
Get-WinEvent -ea SilentlyContinue \`
|
||||
-FilterHashtable @{ProviderName= "docker"; LogName = "application"} |
|
||||
Sort-Object @{Expression="TimeCreated";Descending=$false} |
|
||||
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
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
# 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/
|
||||
|
||||
# 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
|
||||
|
||||
# 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: []
|
||||
|
||||
# Environment variables for the virtual machine.
|
||||
#
|
||||
# EXAMPLE
|
||||
# env:
|
||||
# KEY: value
|
||||
# ANOTHER_KEY: another value
|
||||
#
|
||||
# Default: {}
|
||||
env: {}
|
||||
`;
|
||||
76
src/docker/docker.ts
Normal file
76
src/docker/docker.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 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 io from '@actions/io';
|
||||
|
||||
import {Exec} from '../exec';
|
||||
|
||||
import {ConfigFile} from '../types/docker';
|
||||
|
||||
export class Docker {
|
||||
static get configDir(): string {
|
||||
return process.env.DOCKER_CONFIG || path.join(os.homedir(), '.docker');
|
||||
}
|
||||
|
||||
public static configFile(): ConfigFile | undefined {
|
||||
const f = path.join(Docker.configDir, 'config.json');
|
||||
if (!fs.existsSync(f)) {
|
||||
return undefined;
|
||||
}
|
||||
return <ConfigFile>JSON.parse(fs.readFileSync(f, {encoding: 'utf-8'}));
|
||||
}
|
||||
|
||||
public static async isAvailable(): Promise<boolean> {
|
||||
return await io
|
||||
.which('docker', true)
|
||||
.then(res => {
|
||||
core.debug(`Docker.isAvailable ok: ${res}`);
|
||||
return true;
|
||||
})
|
||||
.catch(error => {
|
||||
core.debug(`Docker.isAvailable error: ${error}`);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
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, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr);
|
||||
}
|
||||
return res.stdout.trim();
|
||||
});
|
||||
}
|
||||
|
||||
public static async printVersion(): Promise<void> {
|
||||
await Exec.exec('docker', ['version']);
|
||||
}
|
||||
|
||||
public static async printInfo(): Promise<void> {
|
||||
await Exec.exec('docker', ['info']);
|
||||
}
|
||||
}
|
||||
386
src/docker/install.ts
Normal file
386
src/docker/install.ts
Normal file
@@ -0,0 +1,386 @@
|
||||
/**
|
||||
* Copyright 2023 actions-toolkit authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as child_process from 'child_process';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import retry from 'async-retry';
|
||||
import * as handlebars from 'handlebars';
|
||||
import * as util from 'util';
|
||||
import * as core from '@actions/core';
|
||||
import * as httpm from '@actions/http-client';
|
||||
import * as io from '@actions/io';
|
||||
import * as tc from '@actions/tool-cache';
|
||||
|
||||
import {Context} from '../context';
|
||||
import {Exec} from '../exec';
|
||||
import {Util} from '../util';
|
||||
import {colimaYamlData, dockerServiceLogsPs1, setupDockerLinuxSh, setupDockerWinPs1} from './assets';
|
||||
import {GitHubRelease} from '../types/github';
|
||||
|
||||
export interface InstallOpts {
|
||||
version?: string;
|
||||
channel?: string;
|
||||
runDir: string;
|
||||
contextName?: string;
|
||||
}
|
||||
|
||||
export class Install {
|
||||
private readonly runDir: string;
|
||||
private readonly version: string;
|
||||
private readonly channel: string;
|
||||
private readonly contextName: string;
|
||||
private _version: string | undefined;
|
||||
private _toolDir: string | undefined;
|
||||
|
||||
constructor(opts: InstallOpts) {
|
||||
this.runDir = opts.runDir;
|
||||
this.version = opts.version || 'latest';
|
||||
this.channel = opts.channel || 'stable';
|
||||
this.contextName = opts.contextName || 'setup-docker-action';
|
||||
}
|
||||
|
||||
get toolDir(): string {
|
||||
return this._toolDir || Context.tmpDir();
|
||||
}
|
||||
|
||||
public async download(): Promise<string> {
|
||||
const release: GitHubRelease = await Install.getRelease(this.version);
|
||||
this._version = release.tag_name.replace(/^v+|v+$/g, '');
|
||||
core.debug(`docker.Install.download version: ${this._version}`);
|
||||
|
||||
const downloadURL = this.downloadURL(this._version, this.channel);
|
||||
core.info(`Downloading ${downloadURL}`);
|
||||
|
||||
const downloadPath = await tc.downloadTool(downloadURL);
|
||||
core.debug(`docker.Install.download downloadPath: ${downloadPath}`);
|
||||
|
||||
let extractFolder: string;
|
||||
if (os.platform() == 'win32') {
|
||||
extractFolder = await tc.extractZip(downloadPath);
|
||||
} else {
|
||||
extractFolder = await tc.extractTar(downloadPath);
|
||||
}
|
||||
if (Util.isDirectory(path.join(extractFolder, 'docker'))) {
|
||||
extractFolder = path.join(extractFolder, 'docker');
|
||||
}
|
||||
core.debug(`docker.Install.download extractFolder: ${extractFolder}`);
|
||||
|
||||
core.info('Fixing perms');
|
||||
fs.readdir(path.join(extractFolder), function (err, files) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
files.forEach(function (file, index) {
|
||||
fs.chmodSync(path.join(extractFolder, file), '0755');
|
||||
});
|
||||
});
|
||||
|
||||
const tooldir = await tc.cacheDir(extractFolder, `docker-${this.channel}`, this._version.replace(/(0+)([1-9]+)/, '$2'));
|
||||
core.addPath(tooldir);
|
||||
core.info('Added Docker to PATH');
|
||||
|
||||
this._toolDir = tooldir;
|
||||
return tooldir;
|
||||
}
|
||||
|
||||
public async install(): Promise<void> {
|
||||
if (!this.toolDir) {
|
||||
throw new Error('toolDir must be set. Run download first.');
|
||||
}
|
||||
if (!this.runDir) {
|
||||
throw new Error('runDir must be set');
|
||||
}
|
||||
switch (os.platform()) {
|
||||
case 'darwin': {
|
||||
await this.installDarwin();
|
||||
break;
|
||||
}
|
||||
case 'linux': {
|
||||
await this.installLinux();
|
||||
break;
|
||||
}
|
||||
case 'win32': {
|
||||
await this.installWindows();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Unsupported platform: ${os.platform()}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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`;
|
||||
|
||||
if (!(await Install.colimaInstalled())) {
|
||||
await core.group('Installing colima', async () => {
|
||||
await Exec.exec('brew', ['install', 'colima']);
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
// colima is already started on the runner so env var added in download
|
||||
// method is not expanded to the running process.
|
||||
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;
|
||||
}
|
||||
});
|
||||
proc.unref();
|
||||
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;
|
||||
}
|
||||
return res.exitCode == 0;
|
||||
})
|
||||
.catch(error => {
|
||||
bail(error);
|
||||
return false;
|
||||
});
|
||||
},
|
||||
{
|
||||
retries: 5
|
||||
}
|
||||
);
|
||||
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]);
|
||||
});
|
||||
}
|
||||
|
||||
private async installWindows(): Promise<void> {
|
||||
const dockerHost = 'npipe:////./pipe/setup_docker_action';
|
||||
|
||||
await core.group('Install Docker daemon service', async () => {
|
||||
const setupCmd = await Util.powershellCommand(setupDockerWinPs1(), {
|
||||
ToolDir: this.toolDir,
|
||||
RunDir: this.runDir,
|
||||
DockerHost: dockerHost
|
||||
});
|
||||
await Exec.exec(setupCmd.command, setupCmd.args);
|
||||
const logCmd = await Util.powershellCommand(dockerServiceLogsPs1());
|
||||
await Exec.exec(logCmd.command, logCmd.args);
|
||||
});
|
||||
|
||||
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]);
|
||||
});
|
||||
}
|
||||
|
||||
public async tearDown(): Promise<void> {
|
||||
if (!this.runDir) {
|
||||
throw new Error('runDir must be set');
|
||||
}
|
||||
switch (os.platform()) {
|
||||
case 'darwin': {
|
||||
await this.tearDownDarwin();
|
||||
break;
|
||||
}
|
||||
case 'linux': {
|
||||
await this.tearDownLinux();
|
||||
break;
|
||||
}
|
||||
case 'win32': {
|
||||
await this.tearDownWindows();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Unsupported platform: ${os.platform()}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async tearDownDarwin(): Promise<void> {
|
||||
await core.group('Docker daemon logs', async () => {
|
||||
await Exec.exec('colima', ['exec', '--', 'cat', '/var/log/docker.log']);
|
||||
});
|
||||
await core.group('Stopping colima', async () => {
|
||||
await Exec.exec('colima', ['stop', '--very-verbose']);
|
||||
});
|
||||
await core.group('Removing Docker context', async () => {
|
||||
await Exec.exec('docker', ['context', 'rm', '-f', this.contextName]);
|
||||
});
|
||||
await core.group(`Cleaning up runDir`, async () => {
|
||||
await Exec.exec('sudo', ['rm', '-rf', this.runDir]);
|
||||
});
|
||||
}
|
||||
|
||||
private async tearDownLinux(): Promise<void> {
|
||||
await core.group('Docker daemon logs', async () => {
|
||||
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 core.group('Removing Docker context', async () => {
|
||||
await Exec.exec('docker', ['context', 'rm', '-f', this.contextName]);
|
||||
});
|
||||
await core.group(`Cleaning up runDir`, async () => {
|
||||
await Exec.exec('sudo', ['rm', '-rf', this.runDir]);
|
||||
});
|
||||
}
|
||||
|
||||
private async tearDownWindows(): Promise<void> {
|
||||
await core.group('Docker daemon logs', async () => {
|
||||
const logCmd = await Util.powershellCommand(dockerServiceLogsPs1());
|
||||
await Exec.exec(logCmd.command, logCmd.args);
|
||||
});
|
||||
await core.group('Removing Docker context', async () => {
|
||||
await Exec.exec('docker', ['context', 'rm', '-f', this.contextName]);
|
||||
});
|
||||
}
|
||||
|
||||
private downloadURL(version: string, channel: string): string {
|
||||
const platformOS = Install.platformOS();
|
||||
const platformArch = Install.platformArch();
|
||||
const ext = platformOS === 'win' ? '.zip' : '.tgz';
|
||||
return util.format('https://download.docker.com/%s/static/%s/%s/docker-%s%s', platformOS, channel, platformArch, version, ext);
|
||||
}
|
||||
|
||||
private static platformOS(): string {
|
||||
switch (os.platform()) {
|
||||
case 'darwin': {
|
||||
return 'mac';
|
||||
}
|
||||
case 'linux': {
|
||||
return 'linux';
|
||||
}
|
||||
case 'win32': {
|
||||
return 'win';
|
||||
}
|
||||
default: {
|
||||
return os.platform();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static platformArch(): string {
|
||||
switch (os.arch()) {
|
||||
case 'x64': {
|
||||
return 'x86_64';
|
||||
}
|
||||
case 'ppc64': {
|
||||
return 'ppc64le';
|
||||
}
|
||||
case 'arm': {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const arm_version = (process.config.variables as any).arm_version;
|
||||
switch (arm_version) {
|
||||
case 6: {
|
||||
return 'armel';
|
||||
}
|
||||
case 7: {
|
||||
return 'armhf';
|
||||
}
|
||||
default: {
|
||||
return `v${arm_version}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
default: {
|
||||
return os.arch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async colimaInstalled(): Promise<boolean> {
|
||||
return await io
|
||||
.which('colima', true)
|
||||
.then(res => {
|
||||
core.debug(`docker.Install.colimaAvailable ok: ${res}`);
|
||||
return true;
|
||||
})
|
||||
.catch(error => {
|
||||
core.debug(`docker.Install.colimaAvailable error: ${error}`);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
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');
|
||||
const resp: httpm.HttpClientResponse = await http.get(url);
|
||||
const body = await resp.readBody();
|
||||
const statusCode = resp.message.statusCode || 500;
|
||||
if (statusCode >= 400) {
|
||||
throw new Error(`Failed to get Docker release ${version} from ${url} with status code ${statusCode}: ${body}`);
|
||||
}
|
||||
const releases = <Record<string, GitHubRelease>>JSON.parse(body);
|
||||
if (!releases[version]) {
|
||||
throw new Error(`Cannot find Docker release ${version} in ${url}`);
|
||||
}
|
||||
return releases[version];
|
||||
}
|
||||
}
|
||||
31
src/exec.ts
Normal file
31
src/exec.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright 2023 actions-toolkit authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as core from '@actions/core';
|
||||
import * as exec from '@actions/exec';
|
||||
import {ExecOptions, ExecOutput} from '@actions/exec';
|
||||
|
||||
export class Exec {
|
||||
public static async exec(commandLine: string, args?: string[], options?: ExecOptions): Promise<number> {
|
||||
core.debug(`Exec.exec: ${commandLine} ${args?.join(' ')}`);
|
||||
return exec.exec(commandLine, args, options);
|
||||
}
|
||||
|
||||
public static async getExecOutput(commandLine: string, args?: string[], options?: ExecOptions): Promise<ExecOutput> {
|
||||
core.debug(`Exec.getExecOutput: ${commandLine} ${args?.join(' ')}`);
|
||||
return exec.getExecOutput(commandLine, args, options);
|
||||
}
|
||||
}
|
||||
122
src/git.ts
122
src/git.ts
@@ -14,24 +14,116 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as exec from '@actions/exec';
|
||||
import * as core from '@actions/core';
|
||||
import {Octokit} from '@octokit/core';
|
||||
import {restEndpointMethods} from '@octokit/plugin-rest-endpoint-methods';
|
||||
|
||||
import {Exec} from './exec';
|
||||
import {GitHub} from './github';
|
||||
import {Context} from '@actions/github/lib/context';
|
||||
|
||||
import {Context as GitContext} from './types/git';
|
||||
|
||||
export class Git {
|
||||
public static async getRemoteSha(repo: string, ref: string): Promise<string> {
|
||||
return await exec
|
||||
.getExecOutput(`git`, ['ls-remote', repo, ref], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
public static async context(): Promise<GitContext> {
|
||||
const ctx = new Context();
|
||||
ctx.ref = await Git.ref();
|
||||
ctx.sha = await Git.fullCommit();
|
||||
return ctx;
|
||||
}
|
||||
|
||||
public static async isInsideWorkTree(): Promise<boolean> {
|
||||
return await Git.exec(['rev-parse', '--is-inside-work-tree'])
|
||||
.then(out => {
|
||||
return out === 'true';
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr);
|
||||
}
|
||||
const [rsha] = res.stdout.trim().split(/[\s\t]/);
|
||||
if (rsha.length == 0) {
|
||||
throw new Error(`Cannot find remote ref for ${repo}#${ref}`);
|
||||
}
|
||||
return rsha;
|
||||
.catch(() => {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
public static async remoteSha(repo: string, ref: string, token?: string): Promise<string> {
|
||||
const repoMatch = repo.match(/github.com\/([^/]+)\/([^/]+?)(?:\.git)?(\/|$)/);
|
||||
// if we have a token and this is a GitHub repo we can use the GitHub API
|
||||
if (token && repoMatch) {
|
||||
core.setSecret(token);
|
||||
const octokit = new (Octokit.plugin(restEndpointMethods).defaults({
|
||||
baseUrl: GitHub.apiURL
|
||||
}))({auth: token});
|
||||
const [owner, repoName] = repoMatch.slice(1, 3);
|
||||
try {
|
||||
return (
|
||||
await octokit.rest.repos.listCommits({
|
||||
owner: owner,
|
||||
repo: repoName,
|
||||
sha: ref,
|
||||
per_page: 1
|
||||
})
|
||||
).data[0].sha;
|
||||
} catch (e) {
|
||||
throw new Error(`Cannot find remote ref for ${repo}#${ref}: ${e.message}`);
|
||||
}
|
||||
}
|
||||
// otherwise we fall back to git ls-remote
|
||||
return await Git.exec(['ls-remote', repo, ref]).then(out => {
|
||||
const [rsha] = out.split(/[\s\t]/);
|
||||
if (rsha.length == 0) {
|
||||
throw new Error(`Cannot find remote ref for ${repo}#${ref}`);
|
||||
}
|
||||
return rsha;
|
||||
});
|
||||
}
|
||||
|
||||
public static async remoteURL(): Promise<string> {
|
||||
return await Git.exec(['remote', 'get-url', 'origin']).then(rurl => {
|
||||
if (rurl.length == 0) {
|
||||
return Git.exec(['remote', 'get-url', 'upstream']).then(rurl => {
|
||||
if (rurl.length == 0) {
|
||||
throw new Error(`Cannot find remote URL for origin or upstream`);
|
||||
}
|
||||
return rurl;
|
||||
});
|
||||
}
|
||||
return rurl;
|
||||
});
|
||||
}
|
||||
|
||||
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}`;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static async fullCommit(): Promise<string> {
|
||||
return await Git.exec(['show', '--format=%H', 'HEAD', '--quiet', '--']);
|
||||
}
|
||||
|
||||
public static async shortCommit(): Promise<string> {
|
||||
return await Git.exec(['show', '--format=%h', 'HEAD', '--quiet', '--']);
|
||||
}
|
||||
|
||||
public static async tag(): Promise<string> {
|
||||
return await Git.exec(['tag', '--points-at', 'HEAD', '--sort', '-version:creatordate']).then(tags => {
|
||||
if (tags.length == 0) {
|
||||
return Git.exec(['describe', '--tags', '--abbrev=0']);
|
||||
}
|
||||
return tags.split('\n')[0];
|
||||
});
|
||||
}
|
||||
|
||||
private static async exec(args: string[] = []): Promise<string> {
|
||||
return await Exec.getExecOutput(`git`, args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr);
|
||||
}
|
||||
return res.stdout.trim();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,12 +59,10 @@ export class GitHub {
|
||||
try {
|
||||
jwt = GitHub.actionsRuntimeToken;
|
||||
} catch (e) {
|
||||
core.warning(`Cannot parse Actions Runtime Token: ${e.message}`);
|
||||
return;
|
||||
throw new Error(`Cannot parse GitHub Actions Runtime Token: ${e.message}`);
|
||||
}
|
||||
if (!jwt) {
|
||||
core.warning(`ACTIONS_RUNTIME_TOKEN not set`);
|
||||
return;
|
||||
throw new Error(`ACTIONS_RUNTIME_TOKEN not set`);
|
||||
}
|
||||
try {
|
||||
<Array<GitHubActionsRuntimeTokenAC>>JSON.parse(`${jwt.ac}`).forEach(ac => {
|
||||
@@ -85,7 +83,7 @@ export class GitHub {
|
||||
core.info(`${ac.Scope}: ${permission}`);
|
||||
});
|
||||
} catch (e) {
|
||||
core.warning(`Cannot parse Actions Runtime Token Access Controls: ${e.message}`);
|
||||
throw new Error(`Cannot parse GitHub Actions Runtime Token ACs: ${e.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
42
src/index.ts
Normal file
42
src/index.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 * as core from '@actions/core';
|
||||
|
||||
const isPost = !!process.env['STATE_isPost'];
|
||||
if (!isPost) {
|
||||
core.saveState('isPost', 'true');
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a GitHub Action.
|
||||
* Output will be streamed to the live console.
|
||||
*
|
||||
* @param main runs the defined function.
|
||||
* @param post runs the defined function at the end of the job if set.
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
export async function run(main: () => Promise<void>, post?: () => Promise<void>): Promise<void> {
|
||||
if (!isPost) {
|
||||
try {
|
||||
await main();
|
||||
} catch (e) {
|
||||
core.setFailed(e.message);
|
||||
}
|
||||
} else if (post) {
|
||||
await post();
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Context} from './context';
|
||||
import {Buildx} from './buildx/buildx';
|
||||
import {Install} from './buildx/install';
|
||||
import {Install as BuildxInstall} from './buildx/install';
|
||||
import {Bake} from './buildx/bake';
|
||||
import {Builder} from './buildx/builder';
|
||||
import {BuildKit} from './buildkit/buildkit';
|
||||
import {GitHub} from './github';
|
||||
|
||||
@@ -29,17 +30,19 @@ export interface ToolkitOpts {
|
||||
}
|
||||
|
||||
export class Toolkit {
|
||||
public context: Context;
|
||||
public github: GitHub;
|
||||
public buildx: Buildx;
|
||||
public buildxInstall: Install;
|
||||
public buildxInstall: BuildxInstall;
|
||||
public bake: Bake;
|
||||
public builder: Builder;
|
||||
public buildkit: BuildKit;
|
||||
|
||||
constructor(opts: ToolkitOpts = {}) {
|
||||
this.context = new Context();
|
||||
this.github = new GitHub({token: opts.githubToken});
|
||||
this.buildx = new Buildx({context: this.context});
|
||||
this.buildxInstall = new Install({context: this.context, standalone: this.buildx.standalone});
|
||||
this.buildkit = new BuildKit({context: this.context, buildx: this.buildx});
|
||||
this.buildx = new Buildx();
|
||||
this.buildxInstall = new BuildxInstall();
|
||||
this.bake = new Bake({buildx: this.buildx});
|
||||
this.builder = new Builder({buildx: this.buildx});
|
||||
this.buildkit = new BuildKit({buildx: this.buildx});
|
||||
}
|
||||
}
|
||||
|
||||
45
src/types/bake.ts
Normal file
45
src/types/bake.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export interface BakeDefinition {
|
||||
group: Record<string, Group>;
|
||||
target: Record<string, Target>;
|
||||
}
|
||||
|
||||
export interface Group {
|
||||
targets: Array<string>;
|
||||
}
|
||||
|
||||
export interface Target {
|
||||
args?: Record<string, string>;
|
||||
attest?: Array<string>;
|
||||
'cache-from'?: Array<string>;
|
||||
'cache-to'?: Array<string>;
|
||||
context: string;
|
||||
contexts?: Record<string, string>;
|
||||
dockerfile: string;
|
||||
'dockerfile-inline'?: string;
|
||||
labels?: Record<string, string>;
|
||||
'no-cache'?: boolean;
|
||||
'no-cache-filter'?: Array<string>;
|
||||
output?: Array<string>;
|
||||
platforms?: Array<string>;
|
||||
pull?: boolean;
|
||||
secret?: Array<string>;
|
||||
ssh?: Array<string>;
|
||||
tags?: Array<string>;
|
||||
target?: string;
|
||||
}
|
||||
@@ -21,12 +21,24 @@ export interface BuilderInfo {
|
||||
nodes: NodeInfo[];
|
||||
}
|
||||
|
||||
export interface NodeInfo {
|
||||
export interface Node {
|
||||
name?: string;
|
||||
endpoint?: string;
|
||||
driverOpts?: Array<string>;
|
||||
status?: string;
|
||||
buildkitdFlags?: string;
|
||||
buildkitVersion?: string;
|
||||
'driver-opts'?: Array<string>;
|
||||
'buildkitd-flags'?: string;
|
||||
platforms?: string;
|
||||
}
|
||||
|
||||
export interface NodeInfo extends Node {
|
||||
status?: string;
|
||||
buildkit?: string;
|
||||
labels?: Record<string, string>;
|
||||
gcPolicy?: Array<GCPolicy>;
|
||||
}
|
||||
|
||||
export interface GCPolicy {
|
||||
all?: boolean;
|
||||
filter?: string[];
|
||||
keepDuration?: string;
|
||||
keepBytes?: string;
|
||||
}
|
||||
|
||||
66
src/types/docker.ts
Normal file
66
src/types/docker.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// https://github.com/docker/cli/blob/master/cli/config/configfile/file.go
|
||||
export interface ConfigFile {
|
||||
auths: Record<string, AuthConfig>;
|
||||
HttpHeaders?: Record<string, string>;
|
||||
psFormat?: string;
|
||||
imagesFormat?: string;
|
||||
networksFormat?: string;
|
||||
pluginsFormat?: string;
|
||||
volumesFormat?: string;
|
||||
statsFormat?: string;
|
||||
detachKeys?: string;
|
||||
credsStore?: string;
|
||||
credHelpers?: Record<string, string>;
|
||||
serviceInspectFormat?: string;
|
||||
servicesFormat?: string;
|
||||
tasksFormat?: string;
|
||||
secretFormat?: string;
|
||||
configFormat?: string;
|
||||
nodesFormat?: string;
|
||||
pruneFilters?: string[];
|
||||
proxies?: Record<string, ProxyConfig>;
|
||||
experimental?: string;
|
||||
stackOrchestrator?: string;
|
||||
kubernetes?: KubernetesConfig;
|
||||
currentContext?: string;
|
||||
cliPluginsExtraDirs?: string[];
|
||||
plugins?: Record<string, Record<string, string>>;
|
||||
aliases?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface ProxyConfig {
|
||||
httpProxy?: string;
|
||||
httpsProxy?: string;
|
||||
noProxy?: string;
|
||||
ftpProxy?: string;
|
||||
}
|
||||
|
||||
export interface KubernetesConfig {
|
||||
allNamespaces?: string;
|
||||
}
|
||||
|
||||
export interface AuthConfig {
|
||||
username?: string;
|
||||
password?: string;
|
||||
auth?: string;
|
||||
email?: string;
|
||||
serveraddress?: string;
|
||||
identitytoken?: string;
|
||||
registrytoken?: string;
|
||||
}
|
||||
19
src/types/git.ts
Normal file
19
src/types/git.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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 {Context as GitHubContext} from '@actions/github/lib/context';
|
||||
|
||||
export type Context = GitHubContext;
|
||||
93
src/util.ts
93
src/util.ts
@@ -14,11 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import * as core from '@actions/core';
|
||||
import * as io from '@actions/io';
|
||||
import {parse} from 'csv-parse/sync';
|
||||
|
||||
export interface InputListOpts {
|
||||
ignoreComma?: boolean;
|
||||
comment?: string;
|
||||
quote?: string | boolean | Buffer | null;
|
||||
}
|
||||
|
||||
export class Util {
|
||||
public static getInputList(name: string, ignoreComma?: boolean): string[] {
|
||||
public static getInputList(name: string, opts?: InputListOpts): string[] {
|
||||
const res: Array<string> = [];
|
||||
|
||||
const items = core.getInput(name);
|
||||
@@ -29,20 +37,24 @@ export class Util {
|
||||
const records = parse(items, {
|
||||
columns: false,
|
||||
relaxQuotes: true,
|
||||
comment: '#',
|
||||
comment: opts?.comment,
|
||||
relaxColumnCount: true,
|
||||
skipEmptyLines: true
|
||||
skipEmptyLines: true,
|
||||
quote: opts?.quote
|
||||
});
|
||||
|
||||
for (const record of records as Array<string[]>) {
|
||||
if (record.length == 1) {
|
||||
res.push(record[0]);
|
||||
continue;
|
||||
} else if (!ignoreComma) {
|
||||
if (opts?.ignoreComma) {
|
||||
res.push(record[0]);
|
||||
} else {
|
||||
res.push(...record[0].split(','));
|
||||
}
|
||||
} else if (!opts?.ignoreComma) {
|
||||
res.push(...record);
|
||||
continue;
|
||||
} else {
|
||||
res.push(record.join(','));
|
||||
}
|
||||
res.push(record.join(','));
|
||||
}
|
||||
|
||||
return res.filter(item => item).map(pat => pat.trim());
|
||||
@@ -54,12 +66,71 @@ export class Util {
|
||||
}
|
||||
}
|
||||
|
||||
public static isValidUrl(url: string): boolean {
|
||||
public static isValidURL(urlStr: string): boolean {
|
||||
let url;
|
||||
try {
|
||||
new URL(url);
|
||||
url = new URL(urlStr);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return url.protocol === 'http:' || url.protocol === 'https:';
|
||||
}
|
||||
|
||||
public static isValidRef(refStr: string): boolean {
|
||||
if (Util.isValidURL(refStr)) {
|
||||
return true;
|
||||
}
|
||||
for (const prefix of ['git://', 'github.com/', 'git@']) {
|
||||
if (refStr.startsWith(prefix)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static async powershellCommand(script: string, params?: Record<string, string>) {
|
||||
const powershellPath: string = await io.which('powershell', true);
|
||||
const escapedScript = script.replace(/'/g, "''").replace(/"|\n|\r/g, '');
|
||||
const escapedParams: string[] = [];
|
||||
if (params) {
|
||||
for (const key in params) {
|
||||
escapedParams.push(`-${key} '${params[key].replace(/'/g, "''").replace(/"|\n|\r/g, '')}'`);
|
||||
}
|
||||
}
|
||||
return {
|
||||
command: `"${powershellPath}"`,
|
||||
args: ['-NoLogo', '-Sta', '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Unrestricted', '-Command', `& '${escapedScript}' ${escapedParams.join(' ')}`]
|
||||
};
|
||||
}
|
||||
|
||||
public static isDirectory(p) {
|
||||
try {
|
||||
return fs.lstatSync(p).isDirectory();
|
||||
} catch (_) {
|
||||
// noop
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static trimPrefix(str: string, suffix: string): string {
|
||||
if (!str || !suffix) {
|
||||
return str;
|
||||
}
|
||||
const index = str.indexOf(suffix);
|
||||
if (index !== 0) {
|
||||
return str;
|
||||
}
|
||||
return str.substring(suffix.length);
|
||||
}
|
||||
|
||||
public static trimSuffix(str: string, suffix: string): string {
|
||||
if (!str || !suffix) {
|
||||
return str;
|
||||
}
|
||||
const index = str.lastIndexOf(suffix);
|
||||
if (index === -1 || index + suffix.length !== str.length) {
|
||||
return str;
|
||||
}
|
||||
return str.substring(0, index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
"./__tests__/**/*",
|
||||
"./lib/**/*",
|
||||
"node_modules",
|
||||
"jest.config.ts"
|
||||
"jest.config*.ts"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user