mirror of
https://github.com/docker/setup-buildx-action.git
synced 2026-03-05 13:47:42 +08:00
Compare commits
348 Commits
v2.2.1
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
241acbc5c2 | ||
|
|
b5d7068c19 | ||
|
|
28a438e9ed | ||
|
|
a8257dec35 | ||
|
|
9cd4410b76 | ||
|
|
7064bb6cb0 | ||
|
|
57d4a8d20c | ||
|
|
0dadf93d54 | ||
|
|
1a12f33edd | ||
|
|
1282d41a96 | ||
|
|
01144634a7 | ||
|
|
cb437c6618 | ||
|
|
4b6c254447 | ||
|
|
3d95d526ba | ||
|
|
2231aab25d | ||
|
|
483f4842ce | ||
|
|
a43d49b256 | ||
|
|
64bf327336 | ||
|
|
94782da071 | ||
|
|
d6c542fbcd | ||
|
|
eaf69fbc6f | ||
|
|
f95826b456 | ||
|
|
fb37e2879d | ||
|
|
099630bcb6 | ||
|
|
70d132ddbe | ||
|
|
7c525be6cc | ||
|
|
ca8948fcde | ||
|
|
86fc44fcc0 | ||
|
|
c7c4c00f3e | ||
|
|
7a35da204c | ||
|
|
d965a53926 | ||
|
|
16c25413c8 | ||
|
|
b278ce4ad9 | ||
|
|
8d2750c68a | ||
|
|
e81846bcc4 | ||
|
|
65d18f8f8a | ||
|
|
000d75d273 | ||
|
|
1583c0f09d | ||
|
|
ed158e7963 | ||
|
|
4cc794f83e | ||
|
|
4dfc3d6c5d | ||
|
|
af1b253b8d | ||
|
|
3c6ab92b04 | ||
|
|
2c8bcdab54 | ||
|
|
1051acaba6 | ||
|
|
e8cd182ec7 | ||
|
|
8c5c87276d | ||
|
|
90fa7ac870 | ||
|
|
7ebadadf6b | ||
|
|
ee3eb2f3a4 | ||
|
|
c65d441f38 | ||
|
|
da183f8ca3 | ||
|
|
f7a6c723e1 | ||
|
|
8424fa0070 | ||
|
|
c52693d481 | ||
|
|
5efa6e34fd | ||
|
|
774224adf6 | ||
|
|
5d221e8956 | ||
|
|
68163b97ca | ||
|
|
ae7d6893e8 | ||
|
|
ac3a803dd3 | ||
|
|
e468171a9d | ||
|
|
a3e7502fd0 | ||
|
|
b145473295 | ||
|
|
18ce135bb5 | ||
|
|
0e198e93af | ||
|
|
05f3f3ac10 | ||
|
|
622913496d | ||
|
|
c6f6a07025 | ||
|
|
6c5e29d848 | ||
|
|
548b297749 | ||
|
|
36590ad0c1 | ||
|
|
4143b5899b | ||
|
|
3f1544eb9e | ||
|
|
f3204bbfac | ||
|
|
4ba329ef89 | ||
|
|
e600775e52 | ||
|
|
b2b2ffa946 | ||
|
|
fe905840cd | ||
|
|
8998bbe94b | ||
|
|
830833e0c7 | ||
|
|
941183f0a0 | ||
|
|
311b62b254 | ||
|
|
afeb29a6e0 | ||
|
|
b560416601 | ||
|
|
516bb780e5 | ||
|
|
11445527f0 | ||
|
|
b5ca514318 | ||
|
|
1418a4ef33 | ||
|
|
93acf831ce | ||
|
|
f7ce87c1d6 | ||
|
|
aa1e2a0b49 | ||
|
|
673e008776 | ||
|
|
ba31df4664 | ||
|
|
5475af18ec | ||
|
|
acacad903e | ||
|
|
6a25f988bd | ||
|
|
ca1af179f5 | ||
|
|
6524bf65af | ||
|
|
8d5e0747fc | ||
|
|
7199e57b35 | ||
|
|
db63cee3de | ||
|
|
043ebe137f | ||
|
|
686da9073d | ||
|
|
a3d74876b8 | ||
|
|
4dcdbcec48 | ||
|
|
1a8ac74316 | ||
|
|
e827ebe8ba | ||
|
|
adacc1474e | ||
|
|
0f069ddc17 | ||
|
|
d036b3238c | ||
|
|
460e45646d | ||
|
|
93aa1c807f | ||
|
|
d391aad55c | ||
|
|
e5b688ea46 | ||
|
|
c47758b77c | ||
|
|
8fea382513 | ||
|
|
2874e980e8 | ||
|
|
8026d2bc36 | ||
|
|
e51aab53e9 | ||
|
|
fd7390e14d | ||
|
|
910a304005 | ||
|
|
3623ee443e | ||
|
|
e0e5ecf670 | ||
|
|
5334dd0cdd | ||
|
|
214bb6dac1 | ||
|
|
818c69a4ea | ||
|
|
b467d6aa7a | ||
|
|
7594cf3831 | ||
|
|
988b5a0280 | ||
|
|
2c215620b8 | ||
|
|
3382292cd5 | ||
|
|
3d68780484 | ||
|
|
d069e98648 | ||
|
|
8b850f86dc | ||
|
|
aa33708b10 | ||
|
|
2d99e3412d | ||
|
|
4dab43650b | ||
|
|
49a04d6890 | ||
|
|
a6ade2e34f | ||
|
|
2f2694b8d1 | ||
|
|
0a4bab6632 | ||
|
|
2ad185228a | ||
|
|
560ac469d6 | ||
|
|
b3a341759e | ||
|
|
4fd812986e | ||
|
|
3386dc4251 | ||
|
|
d191aef416 | ||
|
|
f686054aab | ||
|
|
78547859d7 | ||
|
|
830928c706 | ||
|
|
26d2aec173 | ||
|
|
ab17e3ec80 | ||
|
|
d79cb80903 | ||
|
|
13cf78894f | ||
|
|
0e592087a0 | ||
|
|
47032b9b53 | ||
|
|
abe89fb761 | ||
|
|
e027232c25 | ||
|
|
5d9397e7ca | ||
|
|
e9ab4c6a14 | ||
|
|
748835b452 | ||
|
|
554c728605 | ||
|
|
1c1261e632 | ||
|
|
5138f76647 | ||
|
|
eddcf46655 | ||
|
|
2740b29678 | ||
|
|
1113efed2b | ||
|
|
8a2a7ad780 | ||
|
|
e3c7deb79b | ||
|
|
be3701b211 | ||
|
|
e2ed622d10 | ||
|
|
b73b950903 | ||
|
|
157d6d0106 | ||
|
|
a530e948ad | ||
|
|
28ecb964cd | ||
|
|
dc25d8b2ee | ||
|
|
d70bba72b1 | ||
|
|
7638634cb7 | ||
|
|
c68420fe0b | ||
|
|
2b51285047 | ||
|
|
0f00370563 | ||
|
|
11c9683db9 | ||
|
|
56a16b8f2a | ||
|
|
c23f46eb91 | ||
|
|
f876da6242 | ||
|
|
b7cf918227 | ||
|
|
0150f0ed7a | ||
|
|
d89f1f9116 | ||
|
|
12d65f6595 | ||
|
|
8e1cfa56de | ||
|
|
0d103c3126 | ||
|
|
f19477aacd | ||
|
|
a4180f835d | ||
|
|
524315340d | ||
|
|
3679a54023 | ||
|
|
37a22a2fb2 | ||
|
|
65afe610a1 | ||
|
|
fcb8f722fd | ||
|
|
f62b9a17c0 | ||
|
|
74c5b717e5 | ||
|
|
0d7aea7476 | ||
|
|
edfb0fe620 | ||
|
|
ee40da0772 | ||
|
|
02e65a5ab9 | ||
|
|
6d5347c402 | ||
|
|
ab3fcb73e7 | ||
|
|
3762d454f3 | ||
|
|
cdd4983d88 | ||
|
|
a3e8dc13a7 | ||
|
|
5d98624985 | ||
|
|
fa0a3f8db8 | ||
|
|
0d99838e0e | ||
|
|
dedd61cf5d | ||
|
|
a9e6efb8d7 | ||
|
|
572af8c114 | ||
|
|
8bda7f18d0 | ||
|
|
36dc84a6af | ||
|
|
1eaf7017ec | ||
|
|
35db0cdb94 | ||
|
|
524ee0563f | ||
|
|
91c74bb1dc | ||
|
|
7d508e5a8a | ||
|
|
c9db9161e9 | ||
|
|
f95db51fdd | ||
|
|
998a87c2c1 | ||
|
|
28bae59336 | ||
|
|
c215341715 | ||
|
|
02e9319239 | ||
|
|
5c9160effc | ||
|
|
1283140f57 | ||
|
|
c6afe06e4a | ||
|
|
f35e0d5a04 | ||
|
|
baeb468fb2 | ||
|
|
8e48232775 | ||
|
|
a52126db3d | ||
|
|
2afcb42c88 | ||
|
|
2fbc37fd36 | ||
|
|
23d726350c | ||
|
|
885d1462b8 | ||
|
|
e5fad018d0 | ||
|
|
45161fd92a | ||
|
|
a4d51f53dd | ||
|
|
93b8ecaa2c | ||
|
|
7703e82fbc | ||
|
|
0005881963 | ||
|
|
b699069f49 | ||
|
|
9bfc5497b8 | ||
|
|
b92d4d8769 | ||
|
|
285be6c835 | ||
|
|
4c0219f9ac | ||
|
|
0db41bf51b | ||
|
|
62fc1a1dd6 | ||
|
|
2a1a44ac4a | ||
|
|
a6c26a99ef | ||
|
|
a5a7f565d9 | ||
|
|
7d7611f95b | ||
|
|
16c0bc4a6e | ||
|
|
ebcacb9c21 | ||
|
|
496a823b8b | ||
|
|
a56031a493 | ||
|
|
922550f064 | ||
|
|
ecf95283f0 | ||
|
|
b2a38ee0c6 | ||
|
|
7f79690cac | ||
|
|
bdd549bec0 | ||
|
|
be4a3855af | ||
|
|
6c4dbb29f6 | ||
|
|
6a58db7e0d | ||
|
|
d56292e348 | ||
|
|
790eb2db47 | ||
|
|
2a81c53912 | ||
|
|
00b2400aad | ||
|
|
484614d7a1 | ||
|
|
d95759405f | ||
|
|
5bb6d36be0 | ||
|
|
a99c5e53ef | ||
|
|
fc1a41d2e5 | ||
|
|
95cefc3c57 | ||
|
|
8ec3610541 | ||
|
|
a946f06b5d | ||
|
|
ce223e774e | ||
|
|
d267e74486 | ||
|
|
d350de3bba | ||
|
|
45a8690f10 | ||
|
|
b167a89702 | ||
|
|
81d4866861 | ||
|
|
07aea5fc9c | ||
|
|
1d91983c26 | ||
|
|
496312bcb8 | ||
|
|
4b4e9c3e2d | ||
|
|
eb27bcbef3 | ||
|
|
b7471d4240 | ||
|
|
e2df91e851 | ||
|
|
85ce96bcbc | ||
|
|
f549413411 | ||
|
|
99988698a5 | ||
|
|
e30725c029 | ||
|
|
f1dc97ee10 | ||
|
|
51ecd0a47f | ||
|
|
830f01a409 | ||
|
|
8b13d483f2 | ||
|
|
03a7a3d9fb | ||
|
|
30389db034 | ||
|
|
05ca2e6f5e | ||
|
|
774ea5c2f1 | ||
|
|
534bd3c5e6 | ||
|
|
0f5a2d6712 | ||
|
|
987520896f | ||
|
|
a19c171088 | ||
|
|
347dac9901 | ||
|
|
2dd22fa31c | ||
|
|
dd904132a2 | ||
|
|
f03ac48505 | ||
|
|
c8c479bb5b | ||
|
|
379311a773 | ||
|
|
6842354d08 | ||
|
|
7ce9a1f69d | ||
|
|
11e8a2e291 | ||
|
|
9407e67a52 | ||
|
|
15c905b16b | ||
|
|
a25d6a0130 | ||
|
|
39322d9057 | ||
|
|
0648fd6fd6 | ||
|
|
30d8a59ee0 | ||
|
|
71320d2e17 | ||
|
|
272f8b84cf | ||
|
|
5e716dcfd6 | ||
|
|
a83788eef0 | ||
|
|
d0d9a72195 | ||
|
|
a8165e7b70 | ||
|
|
a024221c60 | ||
|
|
4c3fce4ab2 | ||
|
|
7c965aebec | ||
|
|
7932f6210d | ||
|
|
70deadb37a | ||
|
|
165fe681b8 | ||
|
|
2d305372c4 | ||
|
|
c252a3bb80 | ||
|
|
4661366cb8 | ||
|
|
03d7e8ebf0 | ||
|
|
22f6533f7c | ||
|
|
b30c61b0de | ||
|
|
51cc8966ea | ||
|
|
db8b80b0d3 | ||
|
|
39a1a82492 | ||
|
|
c77919d12e | ||
|
|
341de1b1a5 |
@@ -1,2 +1,12 @@
|
||||
/coverage
|
||||
/node_modules
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true,
|
||||
"es2021": true,
|
||||
"jest/globals": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:jest/recommended",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint",
|
||||
"jest",
|
||||
"prettier"
|
||||
]
|
||||
}
|
||||
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1,2 +1,4 @@
|
||||
/.yarn/releases/** binary
|
||||
/.yarn/plugins/** binary
|
||||
/dist/** linguist-generated=true
|
||||
/lib/** linguist-generated=true
|
||||
|
||||
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -1 +0,0 @@
|
||||
* @crazy-max
|
||||
3
.github/CODE_OF_CONDUCT.md
vendored
Normal file
3
.github/CODE_OF_CONDUCT.md
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Code of conduct
|
||||
|
||||
- [Moby community guidelines](https://github.com/moby/moby/blob/master/CONTRIBUTING.md#moby-community-guidelines)
|
||||
101
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
101
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
|
||||
name: Bug Report
|
||||
description: Report a bug
|
||||
labels:
|
||||
- status/triage
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for taking the time to report a bug!
|
||||
If this is a security issue please report it to the [Docker Security team](mailto:security@docker.com).
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Contributing guidelines
|
||||
description: >
|
||||
Make sure you've read the contributing guidelines before proceeding.
|
||||
options:
|
||||
- label: I've read the [contributing guidelines](https://github.com/docker/setup-buildx-action/blob/master/.github/CONTRIBUTING.md) and wholeheartedly agree
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: "I've found a bug, and:"
|
||||
description: |
|
||||
Make sure that your request fulfills all of the following requirements.
|
||||
If one requirement cannot be satisfied, explain in detail why.
|
||||
options:
|
||||
- label: The documentation does not mention anything about my problem
|
||||
- label: There are no open or closed issues that are related to my problem
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: >
|
||||
Provide a brief description of the bug in 1-2 sentences.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected behaviour
|
||||
description: >
|
||||
Describe precisely what you'd expect to happen.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Actual behaviour
|
||||
description: >
|
||||
Describe precisely what is actually happening.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Repository URL
|
||||
description: >
|
||||
Enter the URL of the repository where you are experiencing the
|
||||
issue. If your repository is private, provide a link to a minimal
|
||||
repository that reproduces the issue.
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Workflow run URL
|
||||
description: >
|
||||
Enter the URL of the GitHub Action workflow run if public (e.g.
|
||||
`https://github.com/<user>/<repo>/actions/runs/<id>`)
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: YAML workflow
|
||||
description: |
|
||||
Provide the YAML of the workflow that's causing the issue.
|
||||
Make sure to remove any sensitive information.
|
||||
render: yaml
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Workflow logs
|
||||
description: >
|
||||
[Attach](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/attaching-files)
|
||||
the [log file of your workflow run](https://docs.github.com/en/actions/managing-workflow-runs/using-workflow-run-logs#downloading-logs)
|
||||
and make sure to remove any sensitive information.
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: BuildKit logs
|
||||
description: >
|
||||
If applicable, provide the [BuildKit container logs](https://docs.docker.com/build/ci/github-actions/configure-builder/#buildkit-container-logs)
|
||||
render: text
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional info
|
||||
description: |
|
||||
Provide any additional information that could be useful.
|
||||
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,34 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
---
|
||||
|
||||
### Behaviour
|
||||
|
||||
#### Steps to reproduce this issue
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
#### Expected behaviour
|
||||
|
||||
> Tell us what should happen
|
||||
|
||||
#### Actual behaviour
|
||||
|
||||
> Tell us what happens instead
|
||||
|
||||
### Configuration
|
||||
|
||||
* Repository URL (if public):
|
||||
* Build URL (if public):
|
||||
|
||||
```yml
|
||||
# paste your YAML workflow file here and remove sensitive data
|
||||
```
|
||||
|
||||
### Logs
|
||||
|
||||
> Download the [log file of your build](https://docs.github.com/en/actions/managing-workflow-runs/using-workflow-run-logs#downloading-logs)
|
||||
> and [attach it](https://docs.github.com/en/github/managing-your-work-on-github/file-attachments-on-issues-and-pull-requests) to this issue.
|
||||
9
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
9
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Questions and Discussions
|
||||
url: https://github.com/docker/setup-buildx-action/discussions/new
|
||||
about: Use Github Discussions to ask questions and/or open discussion topics.
|
||||
- name: Documentation
|
||||
url: https://docs.docker.com/build/ci/github-actions/
|
||||
about: Read the documentation.
|
||||
15
.github/ISSUE_TEMPLATE/feature.yml
vendored
Normal file
15
.github/ISSUE_TEMPLATE/feature.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
|
||||
name: Feature request
|
||||
description: Missing functionality? Come tell us about it!
|
||||
labels:
|
||||
- kind/enhancement
|
||||
- status/triage
|
||||
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: What is the feature you want to see?
|
||||
validations:
|
||||
required: true
|
||||
12
.github/SECURITY.md
vendored
Normal file
12
.github/SECURITY.md
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# Reporting security issues
|
||||
|
||||
The project maintainers take security seriously. If you discover a security
|
||||
issue, please bring it to their attention right away!
|
||||
|
||||
**Please _DO NOT_ file a public issue**, instead send your report privately to
|
||||
[security@docker.com](mailto:security@docker.com).
|
||||
|
||||
Security reports are greatly appreciated, and we will publicly thank you for it.
|
||||
We also like to send gifts—if you'd like Docker swag, make sure to let
|
||||
us know. We currently do not offer a paid security bounty program, but are not
|
||||
ruling it out in the future.
|
||||
31
.github/SUPPORT.md
vendored
31
.github/SUPPORT.md
vendored
@@ -1,31 +0,0 @@
|
||||
# Support [](https://isitmaintained.com/project/docker/setup-buildx-action)
|
||||
|
||||
First, [be a good guy](https://github.com/kossnocorp/etiquette/blob/master/README.md).
|
||||
|
||||
## Reporting an issue
|
||||
|
||||
Please do a search in [open issues](https://github.com/docker/setup-buildx-action/issues?utf8=%E2%9C%93&q=) to see if the issue or feature request has already been filed.
|
||||
|
||||
If you find your issue already exists, make relevant comments and add your [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a "+1" comment.
|
||||
|
||||
:+1: - upvote
|
||||
|
||||
:-1: - downvote
|
||||
|
||||
If you cannot find an existing issue that describes your bug or feature, submit an issue using the guidelines below.
|
||||
|
||||
## Writing good bug reports and feature requests
|
||||
|
||||
File a single issue per problem and feature request.
|
||||
|
||||
* Do not enumerate multiple bugs or feature requests in the same issue.
|
||||
* Do not add your issue as a comment to an existing issue unless it's for the identical input. Many issues look similar, but have different causes.
|
||||
|
||||
The more information you can provide, the more likely someone will be successful reproducing the issue and finding a fix.
|
||||
|
||||
You are now ready to [create a new issue](https://github.com/docker/setup-buildx-action/issues/new/choose)!
|
||||
|
||||
## Closure policy
|
||||
|
||||
* Issues that don't have the information requested above (when applicable) will be closed immediately and the poster directed to the support guidelines.
|
||||
* Issues that go a week without a response from original poster are subject to closure at our discretion.
|
||||
BIN
.github/buildkit-container-logs.png
vendored
BIN
.github/buildkit-container-logs.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
1
.github/dependabot.yml
vendored
1
.github/dependabot.yml
vendored
@@ -11,6 +11,7 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
versioning-strategy: "increase"
|
||||
allow:
|
||||
- dependency-type: "production"
|
||||
labels:
|
||||
|
||||
BIN
.github/setup-buildx-action.png
vendored
BIN
.github/setup-buildx-action.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 15 KiB |
274
.github/workflows/ci.yml
vendored
274
.github/workflows/ci.yml
vendored
@@ -1,8 +1,13 @@
|
||||
name: ci
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 10 * * *' # everyday at 10am
|
||||
- cron: '0 10 * * *'
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
@@ -10,9 +15,6 @@ on:
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'releases/v*'
|
||||
|
||||
jobs:
|
||||
main:
|
||||
@@ -21,13 +23,16 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
buildx-version:
|
||||
- latest
|
||||
- v0.4.1
|
||||
- ""
|
||||
- "latest"
|
||||
- "v0.4.1"
|
||||
- "cloud:latest"
|
||||
- "cloud:v0.11.2-desktop.2"
|
||||
- "lab:latest"
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
id: buildx
|
||||
@@ -46,7 +51,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up Docker Buildx 1
|
||||
uses: ./
|
||||
@@ -59,11 +64,11 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Stop docker
|
||||
run: |
|
||||
sudo systemctl stop docker
|
||||
sudo systemctl stop docker docker.socket
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
id: buildx
|
||||
@@ -80,14 +85,14 @@ jobs:
|
||||
-
|
||||
name: Dump context
|
||||
if: always()
|
||||
uses: crazy-max/ghaction-dump-context@v1
|
||||
uses: crazy-max/ghaction-dump-context@v2
|
||||
|
||||
debug:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Create Dockerfile
|
||||
run: |
|
||||
@@ -97,7 +102,7 @@ jobs:
|
||||
EOL
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: ./
|
||||
@@ -105,27 +110,11 @@ jobs:
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Build
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64,linux/ppc64le
|
||||
|
||||
install:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: ./
|
||||
with:
|
||||
install: true
|
||||
-
|
||||
name: Check cmd
|
||||
run: |
|
||||
docker build --help
|
||||
|
||||
use:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
@@ -137,7 +126,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: ./
|
||||
@@ -160,7 +149,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: ./
|
||||
@@ -173,7 +162,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: ./
|
||||
@@ -206,7 +195,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Create context
|
||||
run: |
|
||||
@@ -228,7 +217,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Create buildkitd conf
|
||||
run: |
|
||||
@@ -248,10 +237,10 @@ jobs:
|
||||
uses: ./
|
||||
with:
|
||||
buildkitd-flags: --debug
|
||||
config: /tmp/buildkitd.toml
|
||||
buildkitd-config: /tmp/buildkitd.toml
|
||||
-
|
||||
name: Build
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
|
||||
@@ -260,7 +249,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Create Dockerfile
|
||||
run: |
|
||||
@@ -272,13 +261,13 @@ jobs:
|
||||
uses: ./
|
||||
with:
|
||||
buildkitd-flags: --debug
|
||||
config-inline: |
|
||||
buildkitd-config-inline: |
|
||||
debug = true
|
||||
[registry."docker.io"]
|
||||
mirrors = ["mirror.gcr.io"]
|
||||
-
|
||||
name: Build
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
|
||||
@@ -288,8 +277,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
buildx-version:
|
||||
- latest
|
||||
- v0.4.1
|
||||
- v0.9.1
|
||||
- ""
|
||||
qemu-platforms:
|
||||
- all
|
||||
@@ -297,10 +285,10 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
with:
|
||||
platforms: ${{ matrix.qemu-platforms }}
|
||||
-
|
||||
@@ -326,7 +314,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: ./
|
||||
@@ -349,11 +337,15 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Uninstall docker cli
|
||||
run: |
|
||||
sudo apt-get purge -y moby-cli moby-buildx
|
||||
if dpkg -s "docker-ce" >/dev/null 2>&1; then
|
||||
sudo dpkg -r --force-depends docker-ce-cli docker-buildx-plugin
|
||||
else
|
||||
sudo apt-get purge -y moby-cli moby-buildx
|
||||
fi
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: ./
|
||||
@@ -373,11 +365,15 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Uninstall docker cli
|
||||
run: |
|
||||
sudo apt-get purge -y moby-cli moby-buildx
|
||||
if dpkg -s "docker-ce" >/dev/null 2>&1; then
|
||||
sudo dpkg -r --force-depends docker-ce-cli docker-buildx-plugin
|
||||
else
|
||||
sudo apt-get purge -y moby-cli moby-buildx
|
||||
fi
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: ./
|
||||
@@ -400,11 +396,15 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Uninstall docker cli
|
||||
run: |
|
||||
sudo apt-get purge -y moby-cli moby-buildx
|
||||
if dpkg -s "docker-ce" >/dev/null 2>&1; then
|
||||
sudo dpkg -r --force-depends docker-ce-cli docker-buildx-plugin
|
||||
else
|
||||
sudo apt-get purge -y moby-cli moby-buildx
|
||||
fi
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
id: buildx
|
||||
@@ -426,7 +426,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Create dummy contexts
|
||||
run: |
|
||||
@@ -455,12 +455,178 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: ./
|
||||
with:
|
||||
platforms: linux/amd64
|
||||
|
||||
docker-context:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Create Docker context
|
||||
run: |
|
||||
docker context create foo
|
||||
docker context use foo
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: ./
|
||||
with:
|
||||
driver: docker
|
||||
|
||||
cleanup:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
cleanup:
|
||||
- true
|
||||
- false
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: ./
|
||||
with:
|
||||
cleanup: ${{ matrix.cleanup }}
|
||||
|
||||
k3s:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version:
|
||||
- latest
|
||||
- v0.11.0
|
||||
- v0.10.5
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Install k3s
|
||||
uses: crazy-max/.github/.github/actions/install-k3s@a94383ec9e125b23907fb6fcebf7ff87964595e5
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: ./
|
||||
with:
|
||||
version: ${{ matrix.version }}
|
||||
driver: kubernetes
|
||||
platforms: linux/amd64
|
||||
driver-opts: |
|
||||
image=moby/buildkit:buildx-stable-1
|
||||
qemu.install=true
|
||||
append: |
|
||||
- platforms: linux/arm64
|
||||
driver-opts:
|
||||
- image=moby/buildkit:buildx-stable-1
|
||||
- qemu.install=true
|
||||
- platforms: linux/s390x
|
||||
driver-opts:
|
||||
- image=moby/buildkit:buildx-stable-1
|
||||
- qemu.install=true
|
||||
-
|
||||
name: Create Dockerfile
|
||||
run: |
|
||||
cat > ./Dockerfile <<EOL
|
||||
FROM alpine
|
||||
RUN uname -a
|
||||
EOL
|
||||
-
|
||||
name: Build
|
||||
uses: docker/build-push-action@master
|
||||
with:
|
||||
context: .
|
||||
|
||||
cache-binary:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
cache:
|
||||
- true
|
||||
- false
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: ./
|
||||
with:
|
||||
version: v0.11.2
|
||||
cache-binary: ${{ matrix.cache }}
|
||||
|
||||
windows-error:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
id: buildx
|
||||
continue-on-error: true
|
||||
uses: ./
|
||||
-
|
||||
name: Check
|
||||
run: |
|
||||
echo "${{ toJson(steps.buildx) }}"
|
||||
if [ "${{ steps.buildx.outcome }}" != "failure" ] || [ "${{ steps.buildx.conclusion }}" != "success" ]; then
|
||||
echo "::error::Should have failed"
|
||||
exit 1
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
keep-state:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: ./
|
||||
with:
|
||||
name: foo
|
||||
keep-state: true
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: ./
|
||||
with:
|
||||
name: foo
|
||||
keep-state: true
|
||||
|
||||
keep-state-error:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
id: buildx
|
||||
continue-on-error: true
|
||||
uses: ./
|
||||
with:
|
||||
driver: docker
|
||||
keep-state: true
|
||||
-
|
||||
name: Check
|
||||
run: |
|
||||
echo "${{ toJson(steps.buildx) }}"
|
||||
if [ "${{ steps.buildx.outcome }}" != "failure" ] || [ "${{ steps.buildx.conclusion }}" != "success" ]; then
|
||||
echo "::error::Should have failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
17
.github/workflows/pr-assign-author.yml
vendored
Normal file
17
.github/workflows/pr-assign-author.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
name: pr-assign-author
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
|
||||
jobs:
|
||||
run:
|
||||
uses: crazy-max/.github/.github/workflows/pr-assign-author.yml@1b673f36fad86812f538c1df9794904038a23cbf
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
21
.github/workflows/publish.yml
vendored
Normal file
21
.github/workflows/publish.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: publish
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
packages: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Publish
|
||||
uses: actions/publish-immutable-action@v0.0.4
|
||||
21
.github/workflows/test.yml
vendored
21
.github/workflows/test.yml
vendored
@@ -1,14 +1,15 @@
|
||||
name: test
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'releases/v*'
|
||||
pull_request:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'releases/v*'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
@@ -16,22 +17,18 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Validate
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: validate
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: ./
|
||||
-
|
||||
name: Test
|
||||
uses: docker/bake-action@v2
|
||||
uses: docker/bake-action@v6
|
||||
with:
|
||||
targets: test
|
||||
-
|
||||
name: Upload coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
file: ./coverage/clover.xml
|
||||
files: ./coverage/clover.xml
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
49
.github/workflows/update-dist.yml
vendored
Normal file
49
.github/workflows/update-dist.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
name: update-dist
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
|
||||
jobs:
|
||||
update-dist:
|
||||
if: github.actor == 'dependabot[bot]'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: GitHub auth token from GitHub App
|
||||
id: docker-read-app
|
||||
uses: actions/create-github-app-token@v2
|
||||
with:
|
||||
app-id: ${{ secrets.GHACTIONS_REPO_WRITE_APP_ID }}
|
||||
private-key: ${{ secrets.GHACTIONS_REPO_WRITE_APP_PRIVATE_KEY }}
|
||||
owner: docker
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
fetch-depth: 0
|
||||
token: ${{ steps.docker-read-app.outputs.token || github.token }}
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@v6
|
||||
with:
|
||||
source: .
|
||||
targets: build
|
||||
-
|
||||
name: Commit and push dist
|
||||
run: |
|
||||
if [ -n "$(git status --porcelain -- dist)" ]; then
|
||||
(
|
||||
set -x
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git add dist
|
||||
git commit -m "chore: update generated content"
|
||||
git push
|
||||
)
|
||||
else
|
||||
echo "No changes in dist"
|
||||
fi
|
||||
43
.github/workflows/validate.yml
vendored
Normal file
43
.github/workflows/validate.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: validate
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'releases/v*'
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
targets: ${{ steps.generate.outputs.targets }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: List targets
|
||||
id: generate
|
||||
uses: docker/bake-action/subaction/list-targets@v6
|
||||
with:
|
||||
target: validate
|
||||
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- prepare
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: ${{ fromJson(needs.prepare.outputs.targets) }}
|
||||
steps:
|
||||
-
|
||||
name: Validate
|
||||
uses: docker/bake-action@v6
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
71
.gitignore
vendored
71
.gitignore
vendored
@@ -1,12 +1,5 @@
|
||||
/.dev
|
||||
node_modules
|
||||
lib
|
||||
# https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
|
||||
|
||||
# Jetbrains
|
||||
/.idea
|
||||
/*.iml
|
||||
|
||||
# Rest of the file pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
@@ -14,6 +7,7 @@ npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
@@ -24,34 +18,14 @@ pids
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
@@ -61,36 +35,19 @@ typings/
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.test
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
6
.prettierignore
Normal file
6
.prettierignore
Normal file
@@ -0,0 +1,6 @@
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# yarn v2
|
||||
.yarn/
|
||||
@@ -6,6 +6,5 @@
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"bracketSpacing": false,
|
||||
"arrowParens": "avoid",
|
||||
"parser": "typescript"
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
|
||||
17
.yarnrc.yml
Normal file
17
.yarnrc.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
# https://yarnpkg.com/configuration/yarnrc
|
||||
|
||||
compressionLevel: mixed
|
||||
enableGlobalCache: false
|
||||
enableHardenedMode: true
|
||||
|
||||
logFilters:
|
||||
- code: YN0013
|
||||
level: discard
|
||||
- code: YN0019
|
||||
level: discard
|
||||
- code: YN0076
|
||||
level: discard
|
||||
- code: YN0086
|
||||
level: discard
|
||||
|
||||
nodeLinker: node-modules
|
||||
136
README.md
136
README.md
@@ -1,7 +1,7 @@
|
||||
[](https://github.com/docker/setup-buildx-action/releases/latest)
|
||||
[](https://github.com/marketplace/actions/docker-setup-buildx)
|
||||
[](https://github.com/docker/setup-buildx-action/actions?workflow=ci)
|
||||
[](https://github.com/docker/setup-buildx-action/actions?workflow=test)
|
||||
[](https://github.com/docker/setup-buildx-action/actions?workflow=ci)
|
||||
[](https://github.com/docker/setup-buildx-action/actions?workflow=test)
|
||||
[](https://codecov.io/gh/docker/setup-buildx-action)
|
||||
|
||||
## About
|
||||
@@ -19,20 +19,14 @@ a [BuildKit](https://github.com/moby/buildkit) container.
|
||||
___
|
||||
|
||||
* [Usage](#usage)
|
||||
* [Advanced usage](#advanced-usage)
|
||||
* [Authentication support](docs/advanced/auth.md)
|
||||
* [Append additional nodes to the builder](docs/advanced/append-nodes.md)
|
||||
* [Install by default](docs/advanced/install-default.md)
|
||||
* [BuildKit daemon configuration](docs/advanced/buildkit-config.md)
|
||||
* [Standalone mode](docs/advanced/standalone.md)
|
||||
* [Configuring your builder](#configuring-your-builder)
|
||||
* [Customizing](#customizing)
|
||||
* [inputs](#inputs)
|
||||
* [outputs](#outputs)
|
||||
* [environment variables](#environment-variables)
|
||||
* [Notes](#notes)
|
||||
* [`nodes` output](#nodes-output)
|
||||
* [BuildKit container logs](#buildkit-container-logs)
|
||||
* [Keep up-to-date with GitHub Dependabot](#keep-up-to-date-with-github-dependabot)
|
||||
* [Contributing](#contributing)
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -48,30 +42,36 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v5
|
||||
-
|
||||
# Add support for more platforms with QEMU (optional)
|
||||
# https://github.com/docker/setup-qemu-action
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
```
|
||||
|
||||
## Advanced usage
|
||||
## Configuring your builder
|
||||
|
||||
* [Authentication support](docs/advanced/auth.md)
|
||||
* [Append additional nodes to the builder](docs/advanced/append-nodes.md)
|
||||
* [Install by default](docs/advanced/install-default.md)
|
||||
* [BuildKit daemon configuration](docs/advanced/buildkit-config.md)
|
||||
* [Standalone mode](docs/advanced/standalone.md)
|
||||
* [Version pinning](https://docs.docker.com/build/ci/github-actions/configure-builder/#version-pinning): Pin to a specific Buildx or BuildKit version
|
||||
* [BuildKit container logs](https://docs.docker.com/build/ci/github-actions/configure-builder/#buildkit-container-logs): Enable BuildKit container logs for debugging purposes
|
||||
* [BuildKit Daemon configuration](https://docs.docker.com/build/ci/github-actions/configure-builder/#buildkit-daemon-configuration)
|
||||
* [Registry mirror](https://docs.docker.com/build/ci/github-actions/configure-builder/#registry-mirror): Configure a registry mirror for your builds
|
||||
* [Max parallelism](https://docs.docker.com/build/ci/github-actions/configure-builder/#max-parallelism): Configure the maximum parallelism for your builds
|
||||
* [Append additional nodes to the builder](https://docs.docker.com/build/ci/github-actions/configure-builder/#append-additional-nodes-to-the-builder): Create additional nodes for your builder
|
||||
* [Authentication for remote builders](https://docs.docker.com/build/ci/github-actions/configure-builder/#authentication-for-remote-builders)
|
||||
* [SSH authentication](https://docs.docker.com/build/ci/github-actions/configure-builder/#ssh-authentication): Authenticate to a remote builder using SSH
|
||||
* [TLS authentication](https://docs.docker.com/build/ci/github-actions/configure-builder/#tls-authentication): Authenticate to a remote builder using TLS
|
||||
* [Standalone mode](https://docs.docker.com/build/ci/github-actions/configure-builder/#standalone-mode): Use Buildx as a standalone binary (without the Docker CLI)
|
||||
* [Isolated builders](https://docs.docker.com/build/ci/github-actions/configure-builder/#isolated-builders): Create isolated builders for your builds
|
||||
|
||||
## Customizing
|
||||
|
||||
### inputs
|
||||
|
||||
Following inputs can be used as `step.with` keys:
|
||||
The following inputs can be used as `step.with` keys:
|
||||
|
||||
> `List` type is a newline-delimited string
|
||||
> ```yaml
|
||||
@@ -80,37 +80,55 @@ Following inputs can be used as `step.with` keys:
|
||||
> network=host
|
||||
> ```
|
||||
|
||||
> `CSV` type must be a newline-delimited string
|
||||
> `CSV` type must be a comma-delimited string
|
||||
> ```yaml
|
||||
> platforms: linux/amd64,linux/arm64
|
||||
> ```
|
||||
|
||||
| Name | Type | Description |
|
||||
|-------------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `version` | String | [Buildx](https://github.com/docker/buildx) version. (eg. `v0.3.0`, `latest`, `https://github.com/docker/buildx.git#master`) |
|
||||
| `driver` | String | Sets the [builder driver](https://docs.docker.com/engine/reference/commandline/buildx_create/#driver) to be used (default `docker-container`) |
|
||||
| `driver-opts` | List | List of additional [driver-specific options](https://docs.docker.com/engine/reference/commandline/buildx_create/#driver-opt) (eg. `image=moby/buildkit:master`) |
|
||||
| `buildkitd-flags` | String | [Flags for buildkitd](https://docs.docker.com/engine/reference/commandline/buildx_create/#buildkitd-flags) daemon (since [buildx v0.3.0](https://github.com/docker/buildx/releases/tag/v0.3.0)) |
|
||||
| `install` | Bool | Sets up `docker build` command as an alias to `docker buildx` (default `false`) |
|
||||
| `use` | Bool | Switch to this builder instance (default `true`) |
|
||||
| `endpoint` | String | [Optional address for docker socket](https://docs.docker.com/engine/reference/commandline/buildx_create/#description) or context from `docker context ls` |
|
||||
| `platforms` | List/CSV | Fixed [platforms](https://docs.docker.com/engine/reference/commandline/buildx_create/#platform) for current node. If not empty, values take priority over the detected ones. |
|
||||
| `config`¹ | String | [BuildKit config file](https://docs.docker.com/engine/reference/commandline/buildx_create/#config) |
|
||||
| `config-inline`¹ | String | Same as `config` but inline |
|
||||
| `append` | YAML | [Append additional nodes](docs/advanced/append-nodes.md) to the builder |
|
||||
| Name | Type | Default | Description |
|
||||
|------------------------------|----------|--------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `version` | String | | [Buildx](https://github.com/docker/buildx) version. (eg. `v0.3.0`, `latest`, `https://github.com/docker/buildx.git#master`) |
|
||||
| `name` | String | | Name of the builder. If not specified, one will be generated or if it already exists, it will be used instead of creating a new one |
|
||||
| `driver` | String | `docker-container` | Sets the [builder driver](https://docs.docker.com/engine/reference/commandline/buildx_create/#driver) to be used |
|
||||
| `driver-opts` | List | | List of additional [driver-specific options](https://docs.docker.com/engine/reference/commandline/buildx_create/#driver-opt) (eg. `image=moby/buildkit:master`) |
|
||||
| `buildkitd-flags` | String | | [BuildKit daemon flags](https://docs.docker.com/engine/reference/commandline/buildx_create/#buildkitd-flags) |
|
||||
| `buildkitd-config` \* | String | | [BuildKit daemon config file](https://docs.docker.com/engine/reference/commandline/buildx_create/#config) |
|
||||
| `buildkitd-config-inline` \* | String | | Same as `buildkitd-config` but inline |
|
||||
| `install` \* | Bool | `false` | Sets up `docker build` command as an alias to `docker buildx` |
|
||||
| `use` | Bool | `true` | Switch to this builder instance |
|
||||
| `endpoint` | String | | [Optional address for docker socket](https://docs.docker.com/engine/reference/commandline/buildx_create/#description) or context from `docker context ls` |
|
||||
| `platforms` | List/CSV | | Fixed [platforms](https://docs.docker.com/engine/reference/commandline/buildx_create/#platform) for current node. If not empty, values take priority over the detected ones |
|
||||
| `append` | YAML | | [Append additional nodes](https://docs.docker.com/build/ci/github-actions/configure-builder/#append-additional-nodes-to-the-builder) to the builder |
|
||||
| `keep-state` | Bool | `false` | Keep BuildKit state on `cleanup`. This is only useful on persistent self-hosted runners |
|
||||
| `cache-binary` | Bool | `true` | Cache buildx binary to GitHub Actions cache backend |
|
||||
| `cleanup` | Bool | `true` | Cleanup temp files and remove builder at the end of a job |
|
||||
|
||||
> * ¹ `config` and `config-inline` are mutually exclusive
|
||||
> [!IMPORTANT]
|
||||
> If you set the `buildkitd-flags` input, the default flags (`--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host`)
|
||||
> will be reset. If you want to retain the default behavior, make sure to
|
||||
> include these flags in your custom `buildkitd-flags` value.
|
||||
|
||||
> [!NOTE]
|
||||
> `buildkitd-config` and `buildkitd-config-inline` are mutually exclusive.
|
||||
|
||||
> [!NOTE]
|
||||
> `install` input is deprecated and will be removed in a future release. This
|
||||
> input is not necessary when building with our actions like
|
||||
> `docker/build-push-action` or `docker/bake-action`. If you are still building
|
||||
> with the `docker build` command then you can set the `BUILDX_BUILDER`
|
||||
> environment variable, or you can just directly invoke the
|
||||
> `docker buildx build` command: https://github.com/docker/setup-buildx-action/pull/455
|
||||
|
||||
### outputs
|
||||
|
||||
Following outputs are available
|
||||
The following outputs are available:
|
||||
|
||||
| Name | Type | Description |
|
||||
|-------------|--------|-------------------------------------------------|
|
||||
| `name` | String | Builder name |
|
||||
| `driver` | String | Builder driver |
|
||||
| `platforms` | String | Builder node platforms (preferred or available) |
|
||||
| `nodes` | JSON | Builder [nodes metadata](#nodes-output) |
|
||||
| Name | Type | Description |
|
||||
|-------------|--------|-----------------------------------------------------|
|
||||
| `name` | String | Builder name |
|
||||
| `driver` | String | Builder driver |
|
||||
| `platforms` | String | Builder node platforms (preferred and/or available) |
|
||||
| `nodes` | JSON | Builder [nodes metadata](#nodes-output) |
|
||||
|
||||
### environment variables
|
||||
|
||||
@@ -151,35 +169,7 @@ The following [official docker environment variables](https://docs.docker.com/en
|
||||
| `buildkit` | String | BuildKit version |
|
||||
| `platforms` | String | Platforms available |
|
||||
|
||||
### BuildKit container logs
|
||||
## Contributing
|
||||
|
||||
To display BuildKit container logs (when `docker-container` driver is used) you have to [enable step debug logging](https://docs.github.com/en/actions/managing-workflow-runs/enabling-debug-logging#enabling-step-debug-logging),
|
||||
or you can also enable debugging in the [setup-buildx action step](https://github.com/docker/setup-buildx-action):
|
||||
|
||||
```yaml
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
buildkitd-flags: --debug
|
||||
```
|
||||
|
||||
Logs will be available at the end of a job:
|
||||
|
||||

|
||||
|
||||
## Keep up-to-date with GitHub Dependabot
|
||||
|
||||
Since [Dependabot](https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-github-dependabot)
|
||||
has [native GitHub Actions support](https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#package-ecosystem),
|
||||
to enable it on your GitHub repo all you need to do is add the `.github/dependabot.yml` file:
|
||||
|
||||
```yaml
|
||||
version: 2
|
||||
updates:
|
||||
# Maintain dependencies for GitHub Actions
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
```
|
||||
Want to contribute? Awesome! You can find information about contributing to
|
||||
this project in the [CONTRIBUTING.md](/.github/CONTRIBUTING.md)
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
import {describe, expect, test, beforeEach} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as auth from '../src/auth';
|
||||
|
||||
const tmpdir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-setup-buildx-jest')).split(path.sep).join(path.posix.sep);
|
||||
const dockerConfigHome = path.join(tmpdir, '.docker');
|
||||
const credsdir = path.join(dockerConfigHome, 'buildx', 'creds');
|
||||
|
||||
describe('setCredentials', () => {
|
||||
beforeEach(() => {
|
||||
process.env = Object.keys(process.env).reduce((object, key) => {
|
||||
if (!key.startsWith(auth.envPrefix)) {
|
||||
object[key] = process.env[key];
|
||||
}
|
||||
return object;
|
||||
}, {});
|
||||
});
|
||||
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
'mycontext',
|
||||
'docker-container',
|
||||
{},
|
||||
[],
|
||||
[]
|
||||
],
|
||||
[
|
||||
'docker-container://mycontainer',
|
||||
'docker-container',
|
||||
{},
|
||||
[],
|
||||
[]
|
||||
],
|
||||
[
|
||||
'tcp://graviton2:1234',
|
||||
'remote',
|
||||
{},
|
||||
[],
|
||||
[]
|
||||
],
|
||||
[
|
||||
'tcp://graviton2:1234',
|
||||
'remote',
|
||||
{
|
||||
'BUILDER_NODE_0_AUTH_TLS_CACERT': 'foo',
|
||||
'BUILDER_NODE_0_AUTH_TLS_CERT': 'foo',
|
||||
'BUILDER_NODE_0_AUTH_TLS_KEY': 'foo'
|
||||
},
|
||||
[
|
||||
path.join(credsdir, 'cacert_graviton2-1234.pem'),
|
||||
path.join(credsdir, 'cert_graviton2-1234.pem'),
|
||||
path.join(credsdir, 'key_graviton2-1234.pem')
|
||||
],
|
||||
[
|
||||
`cacert=${path.join(credsdir, 'cacert_graviton2-1234.pem')}`,
|
||||
`cert=${path.join(credsdir, 'cert_graviton2-1234.pem')}`,
|
||||
`key=${path.join(credsdir, 'key_graviton2-1234.pem')}`
|
||||
]
|
||||
],
|
||||
[
|
||||
'tcp://graviton2:1234',
|
||||
'docker-container',
|
||||
{
|
||||
'BUILDER_NODE_0_AUTH_TLS_CACERT': 'foo',
|
||||
'BUILDER_NODE_0_AUTH_TLS_CERT': 'foo',
|
||||
'BUILDER_NODE_0_AUTH_TLS_KEY': 'foo'
|
||||
},
|
||||
[
|
||||
path.join(credsdir, 'cacert_graviton2-1234.pem'),
|
||||
path.join(credsdir, 'cert_graviton2-1234.pem'),
|
||||
path.join(credsdir, 'key_graviton2-1234.pem')
|
||||
],
|
||||
[]
|
||||
],
|
||||
])('given %p endpoint', async (endpoint: string, driver: string, envs: Record<string, string>, expectedFiles: Array<string>, expectedOpts: Array<string>) => {
|
||||
fs.mkdirSync(credsdir, {recursive: true});
|
||||
for (const [key, value] of Object.entries(envs)) {
|
||||
process.env[key] = value;
|
||||
}
|
||||
expect(auth.setCredentials(credsdir, 0, driver, endpoint)).toEqual(expectedOpts);
|
||||
expectedFiles.forEach( (file) => {
|
||||
expect(fs.existsSync(file)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,261 +0,0 @@
|
||||
import {describe, expect, it, jest, test} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as buildx from '../src/buildx';
|
||||
import * as context from '../src/context';
|
||||
import * as semver from 'semver';
|
||||
import * as exec from '@actions/exec';
|
||||
|
||||
const tmpdir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-setup-buildx-')).split(path.sep).join(path.posix.sep);
|
||||
jest.spyOn(context, 'tmpDir').mockImplementation((): string => {
|
||||
return tmpdir;
|
||||
});
|
||||
|
||||
const tmpname = path.join(tmpdir, '.tmpname').split(path.sep).join(path.posix.sep);
|
||||
jest.spyOn(context, 'tmpNameSync').mockImplementation((): string => {
|
||||
return tmpname;
|
||||
});
|
||||
|
||||
describe('isAvailable', () => {
|
||||
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||
buildx.isAvailable();
|
||||
|
||||
// eslint-disable-next-line jest/no-standalone-expect
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx'], {
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAvailable standalone', () => {
|
||||
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||
buildx.isAvailable(true);
|
||||
|
||||
// eslint-disable-next-line jest/no-standalone-expect
|
||||
expect(execSpy).toHaveBeenCalledWith(`buildx`, [], {
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
});
|
||||
});
|
||||
|
||||
describe('getVersion', () => {
|
||||
it('valid', async () => {
|
||||
const version = await buildx.getVersion();
|
||||
expect(semver.valid(version)).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseVersion', () => {
|
||||
test.each([
|
||||
['github.com/docker/buildx 0.4.1+azure bda4882a65349ca359216b135896bddc1d92461c', '0.4.1'],
|
||||
['github.com/docker/buildx v0.4.1 bda4882a65349ca359216b135896bddc1d92461c', '0.4.1'],
|
||||
['github.com/docker/buildx v0.4.2 fb7b670b764764dc4716df3eba07ffdae4cc47b2', '0.4.2'],
|
||||
['github.com/docker/buildx f117971 f11797113e5a9b86bd976329c5dbb8a8bfdfadfa', 'f117971']
|
||||
])('given %p', async (stdout, expected) => {
|
||||
expect(buildx.parseVersion(stdout)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('satisfies', () => {
|
||||
test.each([
|
||||
['0.4.1', '>=0.3.2', true],
|
||||
['bda4882a65349ca359216b135896bddc1d92461c', '>0.1.0', false],
|
||||
['f117971', '>0.6.0', true]
|
||||
])('given %p', async (version, range, expected) => {
|
||||
expect(buildx.satisfies(version, range)).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('inspect', () => {
|
||||
it('valid', async () => {
|
||||
const builder = await buildx.inspect('');
|
||||
expect(builder).not.toBeUndefined();
|
||||
expect(builder.name).not.toEqual('');
|
||||
expect(builder.driver).not.toEqual('');
|
||||
expect(builder.nodes).not.toEqual({});
|
||||
}, 100000);
|
||||
});
|
||||
|
||||
describe('parseInspect', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
'inspect1.txt',
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"name": "builder-5cb467f7-0940-47e1-b94b-d51f54054d620",
|
||||
"endpoint": "unix:///var/run/docker.sock",
|
||||
"status": "running",
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"name": "builder-5cb467f7-0940-47e1-b94b-d51f54054d62",
|
||||
"driver": "docker-container"
|
||||
}
|
||||
],
|
||||
[
|
||||
'inspect2.txt',
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"name": "builder-5f449644-ff29-48af-8344-abb0292d06730",
|
||||
"endpoint": "unix:///var/run/docker.sock",
|
||||
"driver-opts": [
|
||||
"image=moby/buildkit:latest"
|
||||
],
|
||||
"status": "running",
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"name": "builder-5f449644-ff29-48af-8344-abb0292d0673",
|
||||
"driver": "docker-container"
|
||||
}
|
||||
],
|
||||
[
|
||||
'inspect3.txt',
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"name": "builder-9929e463-7954-4dc3-89cd-514cca29ff800",
|
||||
"endpoint": "unix:///var/run/docker.sock",
|
||||
"driver-opts": [
|
||||
"image=moby/buildkit:master",
|
||||
"network=host"
|
||||
],
|
||||
"status": "running",
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"name": "builder-9929e463-7954-4dc3-89cd-514cca29ff80",
|
||||
"driver": "docker-container"
|
||||
}
|
||||
],
|
||||
[
|
||||
'inspect4.txt',
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"name": "default",
|
||||
"endpoint": "default",
|
||||
"status": "running",
|
||||
"buildkit": "20.10.17",
|
||||
"platforms": "linux/amd64,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6"
|
||||
}
|
||||
],
|
||||
"name": "default",
|
||||
"driver": "docker"
|
||||
}
|
||||
],
|
||||
[
|
||||
'inspect5.txt',
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"name": "aws_graviton2",
|
||||
"endpoint": "tcp://1.23.45.67:1234",
|
||||
"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"
|
||||
],
|
||||
"status": "running",
|
||||
"platforms": "darwin/arm64,linux/arm64,linux/arm/v5,linux/arm/v6,linux/arm/v7,windows/arm64"
|
||||
}
|
||||
],
|
||||
"name": "remote-builder",
|
||||
"driver": "remote"
|
||||
}
|
||||
],
|
||||
[
|
||||
'inspect6.txt',
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"name": "builder-17cfff01-48d9-4c3d-9332-9992e308a5100",
|
||||
"endpoint": "unix:///var/run/docker.sock",
|
||||
"status": "running",
|
||||
"buildkitd-flags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
|
||||
"platforms": "linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/386"
|
||||
}
|
||||
],
|
||||
"name": "builder-17cfff01-48d9-4c3d-9332-9992e308a510",
|
||||
"driver": "docker-container"
|
||||
}
|
||||
],
|
||||
])('given %p', async (inspectFile, expected) => {
|
||||
expect(await buildx.parseInspect(fs.readFileSync(path.join(__dirname, 'fixtures', inspectFile)).toString())).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('build', () => {
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-buildx-'));
|
||||
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
it.skip('builds refs/pull/648/head', async () => {
|
||||
const buildxBin = await buildx.build('https://github.com/docker/buildx.git#refs/pull/648/head', tmpDir, false);
|
||||
expect(fs.existsSync(buildxBin)).toBe(true);
|
||||
}, 100000);
|
||||
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
it.skip('builds 67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', async () => {
|
||||
const buildxBin = await buildx.build('https://github.com/docker/buildx.git#67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', tmpDir, false);
|
||||
expect(fs.existsSync(buildxBin)).toBe(true);
|
||||
}, 100000);
|
||||
});
|
||||
|
||||
describe('install', () => {
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-buildx-'));
|
||||
test.each([
|
||||
['v0.4.1', false],
|
||||
['latest', false],
|
||||
['v0.4.1', true],
|
||||
['latest', true]
|
||||
])(
|
||||
'acquires %p of buildx (standalone: %p)',
|
||||
async (version, standalone) => {
|
||||
const buildxBin = await buildx.install(version, tmpDir, standalone);
|
||||
expect(fs.existsSync(buildxBin)).toBe(true);
|
||||
},
|
||||
100000
|
||||
);
|
||||
});
|
||||
|
||||
describe('getConfig', () => {
|
||||
test.each([
|
||||
['debug = true', false, 'debug = true', false],
|
||||
[`notfound.toml`, true, '', true],
|
||||
[
|
||||
`${path.join(__dirname, 'fixtures', 'buildkitd.toml').split(path.sep).join(path.posix.sep)}`,
|
||||
true,
|
||||
`debug = true
|
||||
[registry."docker.io"]
|
||||
mirrors = ["mirror.gcr.io"]
|
||||
`,
|
||||
false
|
||||
]
|
||||
])('given %p config', async (val, file, exValue, invalid) => {
|
||||
try {
|
||||
let config: string;
|
||||
if (file) {
|
||||
config = await buildx.getConfigFile(val);
|
||||
} else {
|
||||
config = await buildx.getConfigInline(val);
|
||||
}
|
||||
expect(true).toBe(!invalid);
|
||||
expect(config).toEqual(tmpname);
|
||||
const configValue = fs.readFileSync(tmpname, 'utf-8');
|
||||
expect(configValue).toEqual(exValue);
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line jest/no-conditional-expect
|
||||
expect(true).toBe(invalid);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,22 +1,42 @@
|
||||
import {beforeEach, describe, expect, it, jest, test} from '@jest/globals';
|
||||
import {beforeEach, describe, expect, test, vi} from 'vitest';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as uuid from 'uuid';
|
||||
import * as context from '../src/context';
|
||||
import * as nodes from '../src/nodes';
|
||||
|
||||
const tmpdir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-setup-buildx-')).split(path.sep).join(path.posix.sep);
|
||||
jest.spyOn(context, 'tmpDir').mockImplementation((): string => {
|
||||
return tmpdir;
|
||||
import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx.js';
|
||||
import {Context} from '@docker/actions-toolkit/lib/context.js';
|
||||
import {Docker} from '@docker/actions-toolkit/lib/docker/docker.js';
|
||||
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit.js';
|
||||
|
||||
import {Node} from '@docker/actions-toolkit/lib/types/buildx/builder.js';
|
||||
|
||||
import * as context from '../src/context.js';
|
||||
|
||||
const fixturesDir = path.join(__dirname, 'fixtures');
|
||||
const tmpDir = fs.mkdtempSync(path.join(process.env.TEMP || os.tmpdir(), 'context-'));
|
||||
const tmpName = path.join(tmpDir, '.tmpname-vi');
|
||||
|
||||
vi.spyOn(Context, 'tmpDir').mockImplementation((): string => {
|
||||
if (!fs.existsSync(tmpDir)) {
|
||||
fs.mkdirSync(tmpDir, {recursive: true});
|
||||
}
|
||||
return tmpDir;
|
||||
});
|
||||
|
||||
jest.spyOn(context, 'tmpNameSync').mockImplementation((): string => {
|
||||
return path.join(tmpdir, '.tmpname').split(path.sep).join(path.posix.sep);
|
||||
vi.spyOn(Context, 'tmpName').mockImplementation((): string => {
|
||||
return tmpName;
|
||||
});
|
||||
|
||||
jest.mock('uuid');
|
||||
jest.spyOn(uuid, 'v4').mockReturnValue('9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d');
|
||||
vi.mock('crypto', async () => {
|
||||
return {
|
||||
...(await vi.importActual('crypto')),
|
||||
randomUUID: vi.fn(() => '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d')
|
||||
};
|
||||
});
|
||||
|
||||
vi.spyOn(Docker, 'context').mockImplementation((): Promise<string> => {
|
||||
return Promise.resolve('default');
|
||||
});
|
||||
|
||||
describe('getCreateArgs', () => {
|
||||
beforeEach(() => {
|
||||
@@ -32,9 +52,13 @@ describe('getCreateArgs', () => {
|
||||
test.each([
|
||||
[
|
||||
0,
|
||||
'v0.10.3',
|
||||
new Map<string, string>([
|
||||
['install', 'false'],
|
||||
['use', 'true'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false']
|
||||
]),
|
||||
[
|
||||
'create',
|
||||
@@ -46,10 +70,14 @@ describe('getCreateArgs', () => {
|
||||
],
|
||||
[
|
||||
1,
|
||||
'v0.10.3',
|
||||
new Map<string, string>([
|
||||
['driver', 'docker'],
|
||||
['install', 'false'],
|
||||
['use', 'true'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false']
|
||||
]),
|
||||
[
|
||||
'create',
|
||||
@@ -61,10 +89,14 @@ describe('getCreateArgs', () => {
|
||||
],
|
||||
[
|
||||
2,
|
||||
'v0.10.3',
|
||||
new Map<string, string>([
|
||||
['install', 'false'],
|
||||
['use', 'false'],
|
||||
['driver-opts', 'image=moby/buildkit:master\nnetwork=host'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false']
|
||||
]),
|
||||
[
|
||||
'create',
|
||||
@@ -77,11 +109,15 @@ describe('getCreateArgs', () => {
|
||||
],
|
||||
[
|
||||
3,
|
||||
'v0.10.3',
|
||||
new Map<string, string>([
|
||||
['driver', 'remote'],
|
||||
['endpoint', 'tls://foo:1234'],
|
||||
['install', 'false'],
|
||||
['use', 'true'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false']
|
||||
]),
|
||||
[
|
||||
'create',
|
||||
@@ -93,12 +129,16 @@ describe('getCreateArgs', () => {
|
||||
],
|
||||
[
|
||||
4,
|
||||
'v0.10.3',
|
||||
new Map<string, string>([
|
||||
['driver', 'remote'],
|
||||
['platforms', 'linux/arm64,linux/arm/v7'],
|
||||
['endpoint', 'tls://foo:1234'],
|
||||
['install', 'false'],
|
||||
['use', 'true'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false']
|
||||
]),
|
||||
[
|
||||
'create',
|
||||
@@ -111,10 +151,14 @@ describe('getCreateArgs', () => {
|
||||
],
|
||||
[
|
||||
5,
|
||||
'v0.10.3',
|
||||
new Map<string, string>([
|
||||
['install', 'false'],
|
||||
['use', 'false'],
|
||||
['driver-opts', `"env.no_proxy=localhost,127.0.0.1,.mydomain"`],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false'],
|
||||
]),
|
||||
[
|
||||
'create',
|
||||
@@ -126,10 +170,14 @@ describe('getCreateArgs', () => {
|
||||
],
|
||||
[
|
||||
6,
|
||||
'v0.10.3',
|
||||
new Map<string, string>([
|
||||
['install', 'false'],
|
||||
['use', 'false'],
|
||||
['platforms', 'linux/amd64\n"linux/arm64,linux/arm/v7"'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false'],
|
||||
]),
|
||||
[
|
||||
'create',
|
||||
@@ -139,14 +187,130 @@ describe('getCreateArgs', () => {
|
||||
'--platform', 'linux/amd64,linux/arm64,linux/arm/v7'
|
||||
]
|
||||
],
|
||||
[
|
||||
7,
|
||||
'v0.10.3',
|
||||
new Map<string, string>([
|
||||
['install', 'false'],
|
||||
['use', 'false'],
|
||||
['driver', 'unknown'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false'],
|
||||
]),
|
||||
[
|
||||
'create',
|
||||
'--name', 'builder-9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d',
|
||||
'--driver', 'unknown',
|
||||
]
|
||||
],
|
||||
[
|
||||
8,
|
||||
'v0.10.3',
|
||||
new Map<string, string>([
|
||||
['install', 'false'],
|
||||
['use', 'false'],
|
||||
['buildkitd-config', path.join(fixturesDir, 'buildkitd.toml')],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false'],
|
||||
]),
|
||||
[
|
||||
'create',
|
||||
'--name', 'builder-9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d',
|
||||
'--driver', 'docker-container',
|
||||
'--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
|
||||
'--config', tmpName,
|
||||
]
|
||||
],
|
||||
[
|
||||
9,
|
||||
'v0.10.3',
|
||||
new Map<string, string>([
|
||||
['install', 'false'],
|
||||
['use', 'false'],
|
||||
['buildkitd-config-inline', 'debug = true'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false'],
|
||||
]),
|
||||
[
|
||||
'create',
|
||||
'--name', 'builder-9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d',
|
||||
'--driver', 'docker-container',
|
||||
'--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
|
||||
'--config', tmpName,
|
||||
]
|
||||
],
|
||||
[
|
||||
10,
|
||||
'v0.10.3',
|
||||
new Map<string, string>([
|
||||
['install', 'false'],
|
||||
['use', 'false'],
|
||||
['driver', 'cloud'],
|
||||
['buildkitd-flags', '--allow-insecure-entitlement network.host'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false'],
|
||||
]),
|
||||
[
|
||||
'create',
|
||||
'--name', 'builder-9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d',
|
||||
'--driver', 'cloud',
|
||||
'--buildkitd-flags', '--allow-insecure-entitlement network.host',
|
||||
]
|
||||
],
|
||||
[
|
||||
11,
|
||||
'v0.10.3',
|
||||
new Map<string, string>([
|
||||
['install', 'false'],
|
||||
['use', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['cache-binary', 'true'],
|
||||
['keep-state', 'false'],
|
||||
['name', 'test-builder-name'],
|
||||
]),
|
||||
[
|
||||
'create',
|
||||
'--name', 'test-builder-name',
|
||||
'--driver', 'docker-container',
|
||||
'--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
|
||||
'--use'
|
||||
]
|
||||
],
|
||||
[
|
||||
12,
|
||||
'v0.10.3',
|
||||
new Map<string, string>([
|
||||
['install', 'false'],
|
||||
['use', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['cache-binary', 'true'],
|
||||
['keep-state', 'true'],
|
||||
['name', 'test-builder-name'],
|
||||
]),
|
||||
[
|
||||
'create',
|
||||
'--name', 'test-builder-name',
|
||||
'--driver', 'docker-container',
|
||||
'--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
|
||||
'--use',
|
||||
]
|
||||
],
|
||||
])(
|
||||
'[%d] given %p as inputs, returns %p',
|
||||
async (num: number, inputs: Map<string, string>, expected: Array<string>) => {
|
||||
'[%d] given buildx %o and %o as inputs, returns %o',
|
||||
async (num: number, buildxVersion: string, inputs: Map<string, string>, expected: Array<string>) => {
|
||||
inputs.forEach((value: string, name: string) => {
|
||||
setInput(name, value);
|
||||
});
|
||||
const toolkit = new Toolkit();
|
||||
vi.spyOn(Buildx.prototype, 'version').mockImplementation(async (): Promise<string> => {
|
||||
return buildxVersion;
|
||||
});
|
||||
const inp = await context.getInputs();
|
||||
const res = await context.getCreateArgs(inp, '0.9.0');
|
||||
const res = await context.getCreateArgs(inp, toolkit);
|
||||
expect(res).toEqual(expected);
|
||||
}
|
||||
);
|
||||
@@ -166,9 +330,13 @@ describe('getAppendArgs', () => {
|
||||
test.each([
|
||||
[
|
||||
0,
|
||||
'v0.10.3',
|
||||
new Map<string, string>([
|
||||
['install', 'false'],
|
||||
['use', 'true'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false']
|
||||
]),
|
||||
{
|
||||
"name": "aws_graviton2",
|
||||
@@ -191,85 +359,163 @@ describe('getAppendArgs', () => {
|
||||
]
|
||||
]
|
||||
])(
|
||||
'[%d] given %p as inputs, returns %p',
|
||||
async (num: number, inputs: Map<string, string>, node: nodes.Node, expected: Array<string>) => {
|
||||
'[%d] given buildx %o and %o as inputs, returns %o',
|
||||
async (num: number, buildxVersion: string, inputs: Map<string, string>, node: Node, expected: Array<string>) => {
|
||||
inputs.forEach((value: string, name: string) => {
|
||||
setInput(name, value);
|
||||
});
|
||||
const toolkit = new Toolkit();
|
||||
vi.spyOn(Buildx.prototype, 'version').mockImplementation(async (): Promise<string> => {
|
||||
return buildxVersion;
|
||||
});
|
||||
const inp = await context.getInputs();
|
||||
const res = await context.getAppendArgs(inp, node, '0.9.0');
|
||||
const res = await context.getAppendArgs(inp, node, toolkit);
|
||||
expect(res).toEqual(expected);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('getInputList', () => {
|
||||
it('handles single line correctly', async () => {
|
||||
await setInput('foo', 'bar');
|
||||
const res = await context.getInputList('foo');
|
||||
expect(res).toEqual(['bar']);
|
||||
describe('getVersion', () => {
|
||||
beforeEach(() => {
|
||||
process.env = Object.keys(process.env).reduce((object, key) => {
|
||||
if (!key.startsWith('INPUT_')) {
|
||||
object[key] = process.env[key];
|
||||
}
|
||||
return object;
|
||||
}, {});
|
||||
});
|
||||
|
||||
it('handles multiple lines correctly', async () => {
|
||||
setInput('foo', 'bar\nbaz');
|
||||
const res = await context.getInputList('foo');
|
||||
expect(res).toEqual(['bar', 'baz']);
|
||||
});
|
||||
|
||||
it('remove empty lines correctly', async () => {
|
||||
setInput('foo', 'bar\n\nbaz');
|
||||
const res = await context.getInputList('foo');
|
||||
expect(res).toEqual(['bar', 'baz']);
|
||||
});
|
||||
|
||||
it('handles comma correctly', async () => {
|
||||
setInput('foo', 'bar,baz');
|
||||
const res = await context.getInputList('foo');
|
||||
expect(res).toEqual(['bar', 'baz']);
|
||||
});
|
||||
|
||||
it('remove empty result correctly', async () => {
|
||||
setInput('foo', 'bar,baz,');
|
||||
const res = await context.getInputList('foo');
|
||||
expect(res).toEqual(['bar', 'baz']);
|
||||
});
|
||||
|
||||
it('handles different new lines correctly', async () => {
|
||||
setInput('foo', 'bar\r\nbaz');
|
||||
const res = await context.getInputList('foo');
|
||||
expect(res).toEqual(['bar', 'baz']);
|
||||
});
|
||||
|
||||
it('handles different new lines and comma correctly', async () => {
|
||||
setInput('foo', 'bar\r\nbaz,bat');
|
||||
const res = await context.getInputList('foo');
|
||||
expect(res).toEqual(['bar', 'baz', 'bat']);
|
||||
});
|
||||
|
||||
it('handles multiple lines and ignoring comma correctly', async () => {
|
||||
setInput('driver-opts', 'image=moby/buildkit:master\nnetwork=host');
|
||||
const res = await context.getInputList('driver-opts', true);
|
||||
expect(res).toEqual(['image=moby/buildkit:master', 'network=host']);
|
||||
});
|
||||
|
||||
it('handles different new lines and ignoring comma correctly', async () => {
|
||||
setInput('driver-opts', 'image=moby/buildkit:master\r\nnetwork=host');
|
||||
const res = await context.getInputList('driver-opts', true);
|
||||
expect(res).toEqual(['image=moby/buildkit:master', 'network=host']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('asyncForEach', () => {
|
||||
it('executes async tasks sequentially', async () => {
|
||||
const testValues = [1, 2, 3, 4, 5];
|
||||
const results: number[] = [];
|
||||
|
||||
await context.asyncForEach(testValues, async value => {
|
||||
results.push(value);
|
||||
});
|
||||
|
||||
expect(results).toEqual(testValues);
|
||||
});
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
0,
|
||||
new Map<string, string>([
|
||||
// defaults
|
||||
['install', 'false'],
|
||||
['use', 'true'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false']
|
||||
]),
|
||||
''
|
||||
],
|
||||
[
|
||||
1,
|
||||
new Map<string, string>([
|
||||
['version', 'latest'],
|
||||
// defaults
|
||||
['install', 'false'],
|
||||
['use', 'true'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false']
|
||||
]),
|
||||
'latest'
|
||||
],
|
||||
[
|
||||
2,
|
||||
new Map<string, string>([
|
||||
['version', 'edge'],
|
||||
// defaults
|
||||
['install', 'false'],
|
||||
['use', 'true'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false']
|
||||
]),
|
||||
'edge'
|
||||
],
|
||||
[
|
||||
3,
|
||||
new Map<string, string>([
|
||||
['version', 'v0.19.2'],
|
||||
// defaults
|
||||
['install', 'false'],
|
||||
['use', 'true'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false']
|
||||
]),
|
||||
'v0.19.2'
|
||||
],
|
||||
[
|
||||
4,
|
||||
new Map<string, string>([
|
||||
['version', 'latest'],
|
||||
['driver', 'cloud'],
|
||||
// defaults
|
||||
['install', 'false'],
|
||||
['use', 'true'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false']
|
||||
]),
|
||||
'cloud:latest'
|
||||
],
|
||||
[
|
||||
5,
|
||||
new Map<string, string>([
|
||||
['version', 'edge'],
|
||||
['driver', 'cloud'],
|
||||
// defaults
|
||||
['install', 'false'],
|
||||
['use', 'true'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false']
|
||||
]),
|
||||
'cloud:edge'
|
||||
],
|
||||
[
|
||||
6,
|
||||
new Map<string, string>([
|
||||
['driver', 'cloud'],
|
||||
// defaults
|
||||
['install', 'false'],
|
||||
['use', 'true'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false']
|
||||
]),
|
||||
'cloud:latest'
|
||||
],
|
||||
[
|
||||
7,
|
||||
new Map<string, string>([
|
||||
['version', 'cloud:v0.11.2-desktop.2'],
|
||||
['driver', 'cloud'],
|
||||
// defaults
|
||||
['install', 'false'],
|
||||
['use', 'true'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false']
|
||||
]),
|
||||
'cloud:v0.11.2-desktop.2'
|
||||
],
|
||||
[
|
||||
8,
|
||||
new Map<string, string>([
|
||||
['version', 'cloud:v0.11.2-desktop.2'],
|
||||
// defaults
|
||||
['install', 'false'],
|
||||
['use', 'true'],
|
||||
['cache-binary', 'true'],
|
||||
['cleanup', 'true'],
|
||||
['keep-state', 'false']
|
||||
]),
|
||||
'cloud:v0.11.2-desktop.2'
|
||||
],
|
||||
])(
|
||||
'[%d] given %o as inputs, returns version %o',
|
||||
async (num: number, inputs: Map<string, string>, expected: string) => {
|
||||
inputs.forEach((value: string, name: string) => {
|
||||
setInput(name, value);
|
||||
});
|
||||
const inp = await context.getInputs();
|
||||
expect(context.getVersion(inp)).toEqual(expected);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// See: https://github.com/actions/toolkit/blob/master/packages/core/src/core.ts#L67
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import {describe, expect, it, jest} from '@jest/globals';
|
||||
import * as docker from '../src/docker';
|
||||
import * as exec from '@actions/exec';
|
||||
|
||||
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
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1 @@
|
||||
debug = true
|
||||
[registry."docker.io"]
|
||||
mirrors = ["mirror.gcr.io"]
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
Name: builder-5cb467f7-0940-47e1-b94b-d51f54054d62
|
||||
Driver: docker-container
|
||||
|
||||
Nodes:
|
||||
Name: builder-5cb467f7-0940-47e1-b94b-d51f54054d620
|
||||
Endpoint: unix:///var/run/docker.sock
|
||||
Status: running
|
||||
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
|
||||
@@ -1,11 +0,0 @@
|
||||
Name: builder-5f449644-ff29-48af-8344-abb0292d0673
|
||||
Driver: docker-container
|
||||
|
||||
Nodes:
|
||||
Name: builder-5f449644-ff29-48af-8344-abb0292d06730
|
||||
Endpoint: unix:///var/run/docker.sock
|
||||
Driver Options: image="moby/buildkit:latest"
|
||||
Status: running
|
||||
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
|
||||
@@ -1,11 +0,0 @@
|
||||
Name: builder-9929e463-7954-4dc3-89cd-514cca29ff80
|
||||
Driver: docker-container
|
||||
|
||||
Nodes:
|
||||
Name: builder-9929e463-7954-4dc3-89cd-514cca29ff800
|
||||
Endpoint: unix:///var/run/docker.sock
|
||||
Driver Options: image="moby/buildkit:master" network="host"
|
||||
Status: running
|
||||
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
|
||||
@@ -1,9 +0,0 @@
|
||||
Name: default
|
||||
Driver: docker
|
||||
|
||||
Nodes:
|
||||
Name: default
|
||||
Endpoint: default
|
||||
Status: running
|
||||
Buildkit: 20.10.17
|
||||
Platforms: linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
|
||||
@@ -1,9 +0,0 @@
|
||||
Name: remote-builder
|
||||
Driver: remote
|
||||
|
||||
Nodes:
|
||||
Name: aws_graviton2
|
||||
Endpoint: tcp://1.23.45.67:1234
|
||||
Driver Options: cert="/home/user/.certs/aws_graviton2/cert.pem" key="/home/user/.certs/aws_graviton2/key.pem" cacert="/home/user/.certs/aws_graviton2/ca.pem"
|
||||
Status: running
|
||||
Platforms: darwin/arm64*, linux/arm64*, linux/arm/v5*, linux/arm/v6*, linux/arm/v7*, windows/arm64*, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/mips64le, linux/mips64
|
||||
@@ -1,9 +0,0 @@
|
||||
Name: builder-17cfff01-48d9-4c3d-9332-9992e308a510
|
||||
Driver: docker-container
|
||||
|
||||
Nodes:
|
||||
Name: builder-17cfff01-48d9-4c3d-9332-9992e308a5100
|
||||
Endpoint: unix:///var/run/docker.sock
|
||||
Status: running
|
||||
Flags: --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host
|
||||
Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
|
||||
@@ -1,9 +0,0 @@
|
||||
import {describe, expect, it} from '@jest/globals';
|
||||
import * as git from '../src/git';
|
||||
|
||||
describe('git', () => {
|
||||
it('returns git remote ref', async () => {
|
||||
const ref: string = await git.getRemoteSha('https://github.com/docker/buildx.git', 'refs/pull/648/head');
|
||||
expect(ref).toEqual('f11797113e5a9b86bd976329c5dbb8a8bfdfadfa');
|
||||
});
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
import {describe, expect, it} from '@jest/globals';
|
||||
import * as github from '../src/github';
|
||||
|
||||
describe('github', () => {
|
||||
it('returns latest buildx GitHub release', async () => {
|
||||
const release = await github.getRelease('latest');
|
||||
expect(release).not.toBeNull();
|
||||
expect(release?.tag_name).not.toEqual('');
|
||||
});
|
||||
|
||||
it('returns v0.2.2 buildx GitHub release', async () => {
|
||||
const release = await github.getRelease('v0.2.2');
|
||||
expect(release).not.toBeNull();
|
||||
expect(release?.tag_name).toEqual('v0.2.2');
|
||||
});
|
||||
});
|
||||
12
__tests__/setup.unit.ts
Normal file
12
__tests__/setup.unit.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-setup-buildx-action-'));
|
||||
|
||||
process.env = Object.assign({}, process.env, {
|
||||
TEMP: tmpDir,
|
||||
GITHUB_REPOSITORY: 'docker/setup-buildx-action',
|
||||
RUNNER_TEMP: path.join(tmpDir, 'runner-temp'),
|
||||
RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache')
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
import {describe, expect, test} from '@jest/globals';
|
||||
import * as util from '../src/util';
|
||||
|
||||
describe('isValidUrl', () => {
|
||||
test.each([
|
||||
['https://github.com/docker/buildx.git', true],
|
||||
['https://github.com/docker/buildx.git#refs/pull/648/head', true],
|
||||
['v0.4.1', false]
|
||||
])('given %p', async (url, expected) => {
|
||||
expect(util.isValidUrl(url)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
48
action.yml
48
action.yml
@@ -18,32 +18,56 @@ inputs:
|
||||
description: 'List of additional driver-specific options. (eg. image=moby/buildkit:master)'
|
||||
required: false
|
||||
buildkitd-flags:
|
||||
description: 'Flags for buildkitd daemon'
|
||||
default: '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host'
|
||||
description: 'BuildKit daemon flags'
|
||||
required: false
|
||||
install:
|
||||
description: 'Sets up docker build command as an alias to docker buildx build'
|
||||
default: 'false'
|
||||
buildkitd-config:
|
||||
description: 'BuildKit daemon config file'
|
||||
required: false
|
||||
buildkitd-config-inline:
|
||||
description: 'Inline BuildKit daemon config'
|
||||
required: false
|
||||
use:
|
||||
description: 'Switch to this builder instance'
|
||||
default: 'true'
|
||||
required: false
|
||||
name:
|
||||
description: 'Name of the builder. If not specified, one will be generated or if it already exists, it will be used instead of creating a new one.'
|
||||
required: false
|
||||
endpoint:
|
||||
description: 'Optional address for docker socket or context from `docker context ls`'
|
||||
required: false
|
||||
platforms:
|
||||
description: 'Fixed platforms for current node. If not empty, values take priority over the detected ones'
|
||||
required: false
|
||||
config:
|
||||
description: 'BuildKit config file'
|
||||
required: false
|
||||
config-inline:
|
||||
description: 'Inline BuildKit config'
|
||||
required: false
|
||||
append:
|
||||
description: 'Append additional nodes to the builder'
|
||||
required: false
|
||||
keep-state:
|
||||
description: 'Keep BuildKit state on cleanup. This is only useful on persistent self-hosted runners.'
|
||||
default: 'false'
|
||||
required: false
|
||||
cache-binary:
|
||||
description: 'Cache buildx binary to GitHub Actions cache backend'
|
||||
default: 'true'
|
||||
required: false
|
||||
cleanup:
|
||||
description: 'Cleanup temp files and remove builder at the end of a job'
|
||||
default: 'true'
|
||||
required: false
|
||||
# TODO: remove deprecated config, config-inline and install inputs
|
||||
config:
|
||||
description: 'BuildKit daemon config file'
|
||||
deprecationMessage: 'Use buildkitd-config instead'
|
||||
required: false
|
||||
config-inline:
|
||||
description: 'Inline BuildKit daemon config'
|
||||
deprecationMessage: 'Use buildkitd-config-inline instead'
|
||||
required: false
|
||||
install:
|
||||
description: 'Sets up docker build command as an alias to docker buildx build'
|
||||
deprecationMessage: '"docker buildx install" command is deprecated and will be removed in a future release, use BUILDX_BUILDER environment variable instead'
|
||||
default: 'false'
|
||||
required: false
|
||||
|
||||
outputs:
|
||||
name:
|
||||
@@ -62,6 +86,6 @@ outputs:
|
||||
description: 'Builder node flags (deprecated, use nodes output instead)'
|
||||
|
||||
runs:
|
||||
using: 'node16'
|
||||
using: 'node24'
|
||||
main: 'dist/index.js'
|
||||
post: 'dist/index.js'
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG NODE_VERSION=16
|
||||
ARG DOCKER_VERSION=20.10.13
|
||||
ARG BUILDX_VERSION=0.8.1
|
||||
ARG NODE_VERSION=24
|
||||
|
||||
FROM node:${NODE_VERSION}-alpine AS base
|
||||
RUN apk add --no-cache cpio findutils git
|
||||
RUN apk add --no-cache cpio findutils git rsync
|
||||
WORKDIR /src
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
--mount=type=cache,target=/src/.yarn/cache <<EOT
|
||||
set -e
|
||||
corepack enable
|
||||
yarn --version
|
||||
yarn config set --home enableTelemetry 0
|
||||
EOT
|
||||
|
||||
FROM base AS deps
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
--mount=type=cache,target=/src/.yarn/cache \
|
||||
--mount=type=cache,target=/src/node_modules \
|
||||
yarn install && mkdir /vendor && cp yarn.lock /vendor
|
||||
|
||||
@@ -18,61 +24,66 @@ COPY --from=deps /vendor /
|
||||
|
||||
FROM deps AS vendor-validate
|
||||
RUN --mount=type=bind,target=.,rw <<EOT
|
||||
set -e
|
||||
git add -A
|
||||
cp -rf /vendor/* .
|
||||
if [ -n "$(git status --porcelain -- yarn.lock)" ]; then
|
||||
echo >&2 'ERROR: Vendor result differs. Please vendor your package with "docker buildx bake vendor-update"'
|
||||
git status --porcelain -- yarn.lock
|
||||
exit 1
|
||||
fi
|
||||
set -e
|
||||
git add -A
|
||||
cp -rf /vendor/* .
|
||||
if [ -n "$(git status --porcelain -- yarn.lock)" ]; then
|
||||
echo >&2 'ERROR: Vendor result differs. Please vendor your package with "docker buildx bake vendor"'
|
||||
git status --porcelain -- yarn.lock
|
||||
exit 1
|
||||
fi
|
||||
EOT
|
||||
|
||||
FROM deps AS build
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
--mount=type=cache,target=/src/node_modules \
|
||||
yarn run build && mkdir /out && cp -Rf dist /out/
|
||||
RUN --mount=target=/context \
|
||||
--mount=type=cache,target=/src/.yarn/cache \
|
||||
--mount=type=cache,target=/src/node_modules <<EOT
|
||||
set -e
|
||||
rsync -a /context/. .
|
||||
rm -rf dist
|
||||
yarn run build
|
||||
mkdir /out
|
||||
cp -r dist /out
|
||||
EOT
|
||||
|
||||
FROM scratch AS build-update
|
||||
COPY --from=build /out /
|
||||
|
||||
FROM build AS build-validate
|
||||
RUN --mount=type=bind,target=.,rw <<EOT
|
||||
set -e
|
||||
git add -A
|
||||
cp -rf /out/* .
|
||||
if [ -n "$(git status --porcelain -- dist)" ]; then
|
||||
echo >&2 'ERROR: Build result differs. Please build first with "docker buildx bake build"'
|
||||
git status --porcelain -- dist
|
||||
exit 1
|
||||
fi
|
||||
RUN --mount=target=/context \
|
||||
--mount=target=.,type=tmpfs <<EOT
|
||||
set -e
|
||||
rsync -a /context/. .
|
||||
git add -A
|
||||
rm -rf dist
|
||||
cp -rf /out/* .
|
||||
if [ -n "$(git status --porcelain -- dist)" ]; then
|
||||
echo >&2 'ERROR: Build result differs. Please build first with "docker buildx bake build"'
|
||||
git status --porcelain -- dist
|
||||
exit 1
|
||||
fi
|
||||
EOT
|
||||
|
||||
FROM deps AS format
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
--mount=type=cache,target=/src/.yarn/cache \
|
||||
--mount=type=cache,target=/src/node_modules \
|
||||
yarn run format \
|
||||
&& mkdir /out && find . -name '*.ts' -not -path './node_modules/*' | cpio -pdm /out
|
||||
yarn run format && mkdir /out && find . -name '*.ts' -not -path './node_modules/*' -not -path './.yarn/*' | cpio -pdm /out
|
||||
|
||||
FROM scratch AS format-update
|
||||
COPY --from=format /out /
|
||||
|
||||
FROM deps AS lint
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
--mount=type=cache,target=/src/.yarn/cache \
|
||||
--mount=type=cache,target=/src/node_modules \
|
||||
yarn run lint
|
||||
|
||||
FROM docker:${DOCKER_VERSION} as docker
|
||||
FROM docker/buildx-bin:${BUILDX_VERSION} as buildx
|
||||
|
||||
FROM deps AS test
|
||||
ENV RUNNER_TEMP=/tmp/github_runner
|
||||
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
--mount=type=cache,target=/src/.yarn/cache \
|
||||
--mount=type=cache,target=/src/node_modules \
|
||||
--mount=type=bind,from=docker,source=/usr/local/bin/docker,target=/usr/bin/docker \
|
||||
--mount=type=bind,from=buildx,source=/buildx,target=/usr/libexec/docker/cli-plugins/docker-buildx \
|
||||
yarn run test --coverageDirectory=/tmp/coverage
|
||||
yarn run test --coverage --coverage.reportsDirectory=/tmp/coverage
|
||||
|
||||
FROM scratch AS test-coverage
|
||||
COPY --from=test /tmp/coverage /
|
||||
|
||||
301
dist/606.index.js
generated
vendored
Normal file
301
dist/606.index.js
generated
vendored
Normal file
@@ -0,0 +1,301 @@
|
||||
export const id = 606;
|
||||
export const ids = [606];
|
||||
export const modules = {
|
||||
|
||||
/***/ 606:
|
||||
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||
/* harmony export */ "default": () => (/* binding */ pMap)
|
||||
/* harmony export */ });
|
||||
/* unused harmony exports pMapIterable, pMapSkip */
|
||||
async function pMap(
|
||||
iterable,
|
||||
mapper,
|
||||
{
|
||||
concurrency = Number.POSITIVE_INFINITY,
|
||||
stopOnError = true,
|
||||
signal,
|
||||
} = {},
|
||||
) {
|
||||
return new Promise((resolve_, reject_) => {
|
||||
if (iterable[Symbol.iterator] === undefined && iterable[Symbol.asyncIterator] === undefined) {
|
||||
throw new TypeError(`Expected \`input\` to be either an \`Iterable\` or \`AsyncIterable\`, got (${typeof iterable})`);
|
||||
}
|
||||
|
||||
if (typeof mapper !== 'function') {
|
||||
throw new TypeError('Mapper function is required');
|
||||
}
|
||||
|
||||
if (!((Number.isSafeInteger(concurrency) && concurrency >= 1) || concurrency === Number.POSITIVE_INFINITY)) {
|
||||
throw new TypeError(`Expected \`concurrency\` to be an integer from 1 and up or \`Infinity\`, got \`${concurrency}\` (${typeof concurrency})`);
|
||||
}
|
||||
|
||||
const result = [];
|
||||
const errors = [];
|
||||
const skippedIndexesMap = new Map();
|
||||
let isRejected = false;
|
||||
let isResolved = false;
|
||||
let isIterableDone = false;
|
||||
let resolvingCount = 0;
|
||||
let currentIndex = 0;
|
||||
const iterator = iterable[Symbol.iterator] === undefined ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator]();
|
||||
|
||||
const signalListener = () => {
|
||||
reject(signal.reason);
|
||||
};
|
||||
|
||||
const cleanup = () => {
|
||||
signal?.removeEventListener('abort', signalListener);
|
||||
};
|
||||
|
||||
const resolve = value => {
|
||||
resolve_(value);
|
||||
cleanup();
|
||||
};
|
||||
|
||||
const reject = reason => {
|
||||
isRejected = true;
|
||||
isResolved = true;
|
||||
reject_(reason);
|
||||
cleanup();
|
||||
};
|
||||
|
||||
if (signal) {
|
||||
if (signal.aborted) {
|
||||
reject(signal.reason);
|
||||
}
|
||||
|
||||
signal.addEventListener('abort', signalListener, {once: true});
|
||||
}
|
||||
|
||||
const next = async () => {
|
||||
if (isResolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nextItem = await iterator.next();
|
||||
|
||||
const index = currentIndex;
|
||||
currentIndex++;
|
||||
|
||||
// Note: `iterator.next()` can be called many times in parallel.
|
||||
// This can cause multiple calls to this `next()` function to
|
||||
// receive a `nextItem` with `done === true`.
|
||||
// The shutdown logic that rejects/resolves must be protected
|
||||
// so it runs only one time as the `skippedIndex` logic is
|
||||
// non-idempotent.
|
||||
if (nextItem.done) {
|
||||
isIterableDone = true;
|
||||
|
||||
if (resolvingCount === 0 && !isResolved) {
|
||||
if (!stopOnError && errors.length > 0) {
|
||||
reject(new AggregateError(errors)); // eslint-disable-line unicorn/error-message
|
||||
return;
|
||||
}
|
||||
|
||||
isResolved = true;
|
||||
|
||||
if (skippedIndexesMap.size === 0) {
|
||||
resolve(result);
|
||||
return;
|
||||
}
|
||||
|
||||
const pureResult = [];
|
||||
|
||||
// Support multiple `pMapSkip`'s.
|
||||
for (const [index, value] of result.entries()) {
|
||||
if (skippedIndexesMap.get(index) === pMapSkip) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pureResult.push(value);
|
||||
}
|
||||
|
||||
resolve(pureResult);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
resolvingCount++;
|
||||
|
||||
// Intentionally detached
|
||||
(async () => {
|
||||
try {
|
||||
const element = await nextItem.value;
|
||||
|
||||
if (isResolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
const value = await mapper(element, index);
|
||||
|
||||
// Use Map to stage the index of the element.
|
||||
if (value === pMapSkip) {
|
||||
skippedIndexesMap.set(index, value);
|
||||
}
|
||||
|
||||
result[index] = value;
|
||||
|
||||
resolvingCount--;
|
||||
await next();
|
||||
} catch (error) {
|
||||
if (stopOnError) {
|
||||
reject(error);
|
||||
} else {
|
||||
errors.push(error);
|
||||
resolvingCount--;
|
||||
|
||||
// In that case we can't really continue regardless of `stopOnError` state
|
||||
// since an iterable is likely to continue throwing after it throws once.
|
||||
// If we continue calling `next()` indefinitely we will likely end up
|
||||
// in an infinite loop of failed iteration.
|
||||
try {
|
||||
await next();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
};
|
||||
|
||||
// Create the concurrent runners in a detached (non-awaited)
|
||||
// promise. We need this so we can await the `next()` calls
|
||||
// to stop creating runners before hitting the concurrency limit
|
||||
// if the iterable has already been marked as done.
|
||||
// NOTE: We *must* do this for async iterators otherwise we'll spin up
|
||||
// infinite `next()` calls by default and never start the event loop.
|
||||
(async () => {
|
||||
for (let index = 0; index < concurrency; index++) {
|
||||
try {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await next();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
break;
|
||||
}
|
||||
|
||||
if (isIterableDone || isRejected) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
function pMapIterable(
|
||||
iterable,
|
||||
mapper,
|
||||
{
|
||||
concurrency = Number.POSITIVE_INFINITY,
|
||||
backpressure = concurrency,
|
||||
} = {},
|
||||
) {
|
||||
if (iterable[Symbol.iterator] === undefined && iterable[Symbol.asyncIterator] === undefined) {
|
||||
throw new TypeError(`Expected \`input\` to be either an \`Iterable\` or \`AsyncIterable\`, got (${typeof iterable})`);
|
||||
}
|
||||
|
||||
if (typeof mapper !== 'function') {
|
||||
throw new TypeError('Mapper function is required');
|
||||
}
|
||||
|
||||
if (!((Number.isSafeInteger(concurrency) && concurrency >= 1) || concurrency === Number.POSITIVE_INFINITY)) {
|
||||
throw new TypeError(`Expected \`concurrency\` to be an integer from 1 and up or \`Infinity\`, got \`${concurrency}\` (${typeof concurrency})`);
|
||||
}
|
||||
|
||||
if (!((Number.isSafeInteger(backpressure) && backpressure >= concurrency) || backpressure === Number.POSITIVE_INFINITY)) {
|
||||
throw new TypeError(`Expected \`backpressure\` to be an integer from \`concurrency\` (${concurrency}) and up or \`Infinity\`, got \`${backpressure}\` (${typeof backpressure})`);
|
||||
}
|
||||
|
||||
return {
|
||||
async * [Symbol.asyncIterator]() {
|
||||
const iterator = iterable[Symbol.asyncIterator] === undefined ? iterable[Symbol.iterator]() : iterable[Symbol.asyncIterator]();
|
||||
|
||||
const promises = [];
|
||||
let pendingPromisesCount = 0;
|
||||
let isDone = false;
|
||||
let index = 0;
|
||||
|
||||
function trySpawn() {
|
||||
if (isDone || !(pendingPromisesCount < concurrency && promises.length < backpressure)) {
|
||||
return;
|
||||
}
|
||||
|
||||
pendingPromisesCount++;
|
||||
|
||||
const promise = (async () => {
|
||||
const {done, value} = await iterator.next();
|
||||
|
||||
if (done) {
|
||||
pendingPromisesCount--;
|
||||
return {done: true};
|
||||
}
|
||||
|
||||
// Spawn if still below concurrency and backpressure limit
|
||||
trySpawn();
|
||||
|
||||
try {
|
||||
const returnValue = await mapper(await value, index++);
|
||||
|
||||
pendingPromisesCount--;
|
||||
|
||||
if (returnValue === pMapSkip) {
|
||||
const index = promises.indexOf(promise);
|
||||
|
||||
if (index > 0) {
|
||||
promises.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Spawn if still below backpressure limit and just dropped below concurrency limit
|
||||
trySpawn();
|
||||
|
||||
return {done: false, value: returnValue};
|
||||
} catch (error) {
|
||||
pendingPromisesCount--;
|
||||
isDone = true;
|
||||
return {error};
|
||||
}
|
||||
})();
|
||||
|
||||
promises.push(promise);
|
||||
}
|
||||
|
||||
trySpawn();
|
||||
|
||||
while (promises.length > 0) {
|
||||
const {error, done, value} = await promises[0]; // eslint-disable-line no-await-in-loop
|
||||
|
||||
promises.shift();
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Spawn if just dropped below backpressure limit and below the concurrency limit
|
||||
trySpawn();
|
||||
|
||||
if (value === pMapSkip) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yield value;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const pMapSkip = Symbol('skip');
|
||||
|
||||
|
||||
/***/ })
|
||||
|
||||
};
|
||||
|
||||
//# sourceMappingURL=606.index.js.map
|
||||
1
dist/606.index.js.map
generated
vendored
Normal file
1
dist/606.index.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
47
dist/index.js
generated
vendored
47
dist/index.js
generated
vendored
File diff suppressed because one or more lines are too long
2
dist/index.js.map
generated
vendored
2
dist/index.js.map
generated
vendored
File diff suppressed because one or more lines are too long
518
dist/licenses.txt
generated
vendored
518
dist/licenses.txt
generated
vendored
@@ -1,525 +1,11 @@
|
||||
@actions/core
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2019 GitHub
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@actions/exec
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2019 GitHub
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@actions/http-client
|
||||
MIT
|
||||
Actions Http Client for Node.js
|
||||
|
||||
Copyright (c) GitHub, Inc.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
@actions/io
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2019 GitHub
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@actions/tool-cache
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2019 GitHub
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
balanced-match
|
||||
MIT
|
||||
(MIT)
|
||||
|
||||
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
brace-expansion
|
||||
p-map
|
||||
MIT
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
concat-map
|
||||
MIT
|
||||
This software is released under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
csv-parse
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2010 Adaltas
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
fs.realpath
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
----
|
||||
|
||||
This library bundles a version of the `fs.realpath` and `fs.realpathSync`
|
||||
methods from Node.js v0.10 under the terms of the Node.js MIT license.
|
||||
|
||||
Node's license follows, also included at the header of `old.js` which contains
|
||||
the licensed code:
|
||||
|
||||
Copyright Joyent, Inc. and other Node contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
glob
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
## Glob Logo
|
||||
|
||||
Glob's logo created by Tanya Brassie <http://tanyabrassie.com/>, licensed
|
||||
under a Creative Commons Attribution-ShareAlike 4.0 International License
|
||||
https://creativecommons.org/licenses/by-sa/4.0/
|
||||
|
||||
|
||||
inflight
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
inherits
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
|
||||
js-yaml
|
||||
MIT
|
||||
(The MIT License)
|
||||
|
||||
Copyright (C) 2011-2015 by Vitaly Puzrin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
lru-cache
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
minimatch
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
once
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
path-is-absolute
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
rimraf
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
semver
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
tmp
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 KARASZI István
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
tunnel
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012 Koichi Kobayashi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
uuid
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2010-2020 Robert Kieffer and other contributors
|
||||
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
wrappy
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
yallist
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
3
dist/package.json
generated
vendored
Normal file
3
dist/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
1
dist/sourcemap-register.cjs
generated
vendored
Normal file
1
dist/sourcemap-register.cjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/sourcemap-register.js
generated
vendored
1
dist/sourcemap-register.js
generated
vendored
File diff suppressed because one or more lines are too long
@@ -1,9 +1,15 @@
|
||||
target "_common" {
|
||||
args = {
|
||||
BUILDKIT_CONTEXT_KEEP_GIT_DIR = 1
|
||||
}
|
||||
}
|
||||
|
||||
group "default" {
|
||||
targets = ["build"]
|
||||
}
|
||||
|
||||
group "pre-checkin" {
|
||||
targets = ["vendor-update", "format", "build"]
|
||||
targets = ["vendor", "format", "build"]
|
||||
}
|
||||
|
||||
group "validate" {
|
||||
@@ -11,42 +17,49 @@ group "validate" {
|
||||
}
|
||||
|
||||
target "build" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "build-update"
|
||||
output = ["."]
|
||||
}
|
||||
|
||||
target "build-validate" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "build-validate"
|
||||
output = ["type=cacheonly"]
|
||||
}
|
||||
|
||||
target "format" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "format-update"
|
||||
output = ["."]
|
||||
}
|
||||
|
||||
target "lint" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "lint"
|
||||
output = ["type=cacheonly"]
|
||||
}
|
||||
|
||||
target "vendor-update" {
|
||||
target "vendor" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "vendor-update"
|
||||
output = ["."]
|
||||
}
|
||||
|
||||
target "vendor-validate" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "vendor-validate"
|
||||
output = ["type=cacheonly"]
|
||||
}
|
||||
|
||||
target "test" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "test-coverage"
|
||||
output = ["./coverage"]
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
# Append additional nodes to the builder
|
||||
|
||||
Buildx also supports running builds on multiple machines. This is useful for
|
||||
building [multi-platform images](https://docs.docker.com/build/building/multi-platform/)
|
||||
on native nodes for more complicated cases that are not handled by QEMU and
|
||||
generally have better performance or for distributing the build across multiple
|
||||
machines.
|
||||
|
||||
You can append nodes to the builder that is going to be created with the
|
||||
`append` input in the form of a YAML string document to remove limitations
|
||||
intrinsically linked to GitHub Actions (only string format is handled in the
|
||||
input fields):
|
||||
|
||||
| Name | Type | Description |
|
||||
|-------------------|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `name` | String | [Name of the node](https://docs.docker.com/engine/reference/commandline/buildx_create/#node). If empty, it is the name of the builder it belongs to, with an index number suffix. This is useful to set it if you want to modify/remove a node in an underlying step of you workflow. |
|
||||
| `endpoint` | String | [Docker context or endpoint](https://docs.docker.com/engine/reference/commandline/buildx_create/#description) of the node to add to the builder |
|
||||
| `driver-opts` | List | List of additional [driver-specific options](https://docs.docker.com/engine/reference/commandline/buildx_create/#driver-opt) |
|
||||
| `buildkitd-flags` | String | [Flags for buildkitd](https://docs.docker.com/engine/reference/commandline/buildx_create/#buildkitd-flags) daemon |
|
||||
| `platforms` | String | Fixed [platforms](https://docs.docker.com/engine/reference/commandline/buildx_create/#platform) for the node. If not empty, values take priority over the detected ones. |
|
||||
|
||||
Here is an example using remote nodes with the [`remote` driver](https://docs.docker.com/build/building/drivers/remote/)
|
||||
and [TLS authentication](auth.md#tls-authentication):
|
||||
|
||||
```yaml
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
buildx:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
driver: remote
|
||||
endpoint: tcp://oneprovider:1234
|
||||
append: |
|
||||
- endpoint: tcp://graviton2:1234
|
||||
platforms: linux/arm64
|
||||
- endpoint: tcp://linuxone:1234
|
||||
platforms: linux/s390x
|
||||
env:
|
||||
BUILDER_NODE_0_AUTH_TLS_CACERT: ${{ secrets.ONEPROVIDER_CA }}
|
||||
BUILDER_NODE_0_AUTH_TLS_CERT: ${{ secrets.ONEPROVIDER_CERT }}
|
||||
BUILDER_NODE_0_AUTH_TLS_KEY: ${{ secrets.ONEPROVIDER_KEY }}
|
||||
BUILDER_NODE_1_AUTH_TLS_CACERT: ${{ secrets.GRAVITON2_CA }}
|
||||
BUILDER_NODE_1_AUTH_TLS_CERT: ${{ secrets.GRAVITON2_CERT }}
|
||||
BUILDER_NODE_1_AUTH_TLS_KEY: ${{ secrets.GRAVITON2_KEY }}
|
||||
BUILDER_NODE_2_AUTH_TLS_CACERT: ${{ secrets.LINUXONE_CA }}
|
||||
BUILDER_NODE_2_AUTH_TLS_CERT: ${{ secrets.LINUXONE_CERT }}
|
||||
BUILDER_NODE_2_AUTH_TLS_KEY: ${{ secrets.LINUXONE_KEY }}
|
||||
```
|
||||
@@ -1,64 +0,0 @@
|
||||
# Authentication support
|
||||
|
||||
## SSH authentication
|
||||
|
||||
To be able to connect to an SSH endpoint using the [`docker-container` driver](https://docs.docker.com/build/building/drivers/docker-container/),
|
||||
you have to set up the SSH private key and configuration on the GitHub Runner:
|
||||
|
||||
```yaml
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
buildx:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Set up SSH
|
||||
uses: MrSquaare/ssh-setup-action@523473d91581ccbf89565e12b40faba93f2708bd # v1.1.0
|
||||
with:
|
||||
host: graviton2
|
||||
private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
private-key-name: aws_graviton2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
endpoint: ssh://me@graviton2
|
||||
```
|
||||
|
||||
## TLS authentication
|
||||
|
||||
You can also [set up a remote BuildKit instance](https://docs.docker.com/build/building/drivers/remote/#remote-buildkit-in-docker-container)
|
||||
using the remote driver. To ease the integration in your workflow, we put in
|
||||
place environment variables that will set up authentication using the BuildKit
|
||||
client certificates for the `tcp://` endpoint where `<idx>` is the position of
|
||||
the node in the list of nodes:
|
||||
|
||||
* `BUILDER_NODE_<idx>_AUTH_TLS_CACERT`
|
||||
* `BUILDER_NODE_<idx>_AUTH_TLS_CERT`
|
||||
* `BUILDER_NODE_<idx>_AUTH_TLS_KEY`
|
||||
|
||||
```yaml
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
buildx:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
driver: remote
|
||||
endpoint: tcp://graviton2:1234
|
||||
env:
|
||||
BUILDER_NODE_0_AUTH_TLS_CACERT: ${{ secrets.GRAVITON2_CA }}
|
||||
BUILDER_NODE_0_AUTH_TLS_CERT: ${{ secrets.GRAVITON2_CERT }}
|
||||
BUILDER_NODE_0_AUTH_TLS_KEY: ${{ secrets.GRAVITON2_KEY }}
|
||||
```
|
||||
@@ -1,67 +0,0 @@
|
||||
# BuildKit daemon configuration
|
||||
|
||||
You can provide a [BuildKit configuration](https://github.com/moby/buildkit/blob/master/docs/buildkitd.toml.md)
|
||||
to your builder if you're using the [`docker-container` driver](https://docs.docker.com/build/building/drivers/docker-container/)
|
||||
(default) with the `config` or `config-inline` inputs:
|
||||
|
||||
## Registry mirror
|
||||
|
||||
You can configure a registry mirror using an inline block directly in your
|
||||
workflow with the `config-inline` input:
|
||||
|
||||
```yaml
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
buildx:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
config-inline: |
|
||||
[registry."docker.io"]
|
||||
mirrors = ["mirror.gcr.io"]
|
||||
```
|
||||
|
||||
## Max parallelism
|
||||
|
||||
You can limit the parallelism of the BuildKit solver which is particularly
|
||||
useful for low-powered machines.
|
||||
|
||||
You can use the `config-inline` input like the previous example, or you can use
|
||||
a dedicated BuildKit config file from your repo if you want with the
|
||||
`config` input:
|
||||
|
||||
```toml
|
||||
# .github/buildkitd.toml
|
||||
[worker.oci]
|
||||
max-parallelism = 4
|
||||
```
|
||||
|
||||
```yaml
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
buildx:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
config: .github/buildkitd.toml
|
||||
```
|
||||
@@ -1,28 +0,0 @@
|
||||
# Install by default
|
||||
|
||||
If you want set up the `docker build` command as an alias to
|
||||
`docker buildx build`:
|
||||
|
||||
```yaml
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
buildx:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
install: true
|
||||
-
|
||||
name: Build
|
||||
run: |
|
||||
docker build . # will run buildx
|
||||
```
|
||||
@@ -1,29 +0,0 @@
|
||||
# Standalone mode
|
||||
|
||||
If you don't have the Docker CLI installed on the GitHub Runner, Buildx binary
|
||||
is invoked directly, instead of calling it as a docker plugin. This can be
|
||||
useful if you want to use the `kubernetes` driver in your self-hosted runner:
|
||||
|
||||
```yaml
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
buildx:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
driver: kubernetes
|
||||
-
|
||||
name: Build
|
||||
run: |
|
||||
buildx build .
|
||||
```
|
||||
52
eslint.config.mjs
Normal file
52
eslint.config.mjs
Normal file
@@ -0,0 +1,52 @@
|
||||
import {defineConfig} from 'eslint/config';
|
||||
import js from '@eslint/js';
|
||||
import tseslint from '@typescript-eslint/eslint-plugin';
|
||||
import vitest from '@vitest/eslint-plugin';
|
||||
import globals from 'globals';
|
||||
import eslintConfigPrettier from 'eslint-config-prettier/flat';
|
||||
import eslintPluginPrettier from 'eslint-plugin-prettier';
|
||||
|
||||
export default defineConfig([
|
||||
{
|
||||
ignores: ['.yarn/**/*', 'coverage/**/*', 'dist/**/*']
|
||||
},
|
||||
js.configs.recommended,
|
||||
...tseslint.configs['flat/recommended'],
|
||||
eslintConfigPrettier,
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['__tests__/**'],
|
||||
...vitest.configs.recommended,
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
...vitest.environments.env.globals
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
...vitest.configs.recommended.rules,
|
||||
'vitest/no-conditional-expect': 'error',
|
||||
'vitest/no-disabled-tests': 0
|
||||
}
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
prettier: eslintPluginPrettier
|
||||
},
|
||||
rules: {
|
||||
'prettier/prettier': 'error',
|
||||
'@typescript-eslint/no-require-imports': [
|
||||
'error',
|
||||
{
|
||||
allowAsImport: true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]);
|
||||
@@ -1,13 +0,0 @@
|
||||
module.exports = {
|
||||
clearMocks: true,
|
||||
moduleFileExtensions: ['js', 'ts'],
|
||||
setupFiles: ['dotenv/config'],
|
||||
testMatch: ['**/*.test.ts'],
|
||||
transform: {
|
||||
'^.+\\.ts$': 'ts-jest'
|
||||
},
|
||||
moduleNameMapper: {
|
||||
'^csv-parse/sync': '<rootDir>/node_modules/csv-parse/dist/cjs/sync.cjs'
|
||||
},
|
||||
verbose: true
|
||||
};
|
||||
64
package.json
64
package.json
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "docker-setup-buildx",
|
||||
"description": "Set up Docker Buildx",
|
||||
"main": "lib/main.js",
|
||||
"type": "module",
|
||||
"main": "src/main.ts",
|
||||
"scripts": {
|
||||
"build": "ncc build src/main.ts --source-map --minify --license licenses.txt",
|
||||
"lint": "eslint src/**/*.ts __tests__/**/*.ts",
|
||||
"format": "eslint --fix src/**/*.ts __tests__/**/*.ts",
|
||||
"test": "jest --coverage",
|
||||
"all": "yarn run build && yarn run format && yarn test"
|
||||
"build": "ncc build --source-map --minify --license licenses.txt",
|
||||
"lint": "eslint --max-warnings=0 .",
|
||||
"format": "eslint --fix .",
|
||||
"test": "vitest run"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -18,41 +18,29 @@
|
||||
"docker",
|
||||
"buildx"
|
||||
],
|
||||
"author": "Docker",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "CrazyMax",
|
||||
"url": "https://crazymax.dev"
|
||||
}
|
||||
],
|
||||
"author": "Docker Inc.",
|
||||
"license": "Apache-2.0",
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.0",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"@actions/tool-cache": "^2.0.1",
|
||||
"csv-parse": "^5.3.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"semver": "^7.3.7",
|
||||
"tmp": "^0.2.1",
|
||||
"uuid": "^9.0.0"
|
||||
"@actions/core": "^3.0.0",
|
||||
"@docker/actions-toolkit": "^0.79.0",
|
||||
"js-yaml": "^4.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.26",
|
||||
"@types/semver": "^7.3.9",
|
||||
"@types/tmp": "^0.2.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.14.0",
|
||||
"@typescript-eslint/parser": "^5.14.0",
|
||||
"@vercel/ncc": "^0.33.3",
|
||||
"dotenv": "^16.0.0",
|
||||
"eslint": "^8.11.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-jest": "^26.1.1",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest": "^27.2.5",
|
||||
"prettier": "^2.3.1",
|
||||
"ts-jest": "^27.1.2",
|
||||
"ts-node": "^10.7.0",
|
||||
"typescript": "^4.4.4"
|
||||
"@eslint/js": "^9.39.3",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/node": "^24.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
||||
"@typescript-eslint/parser": "^8.56.1",
|
||||
"@vercel/ncc": "^0.38.4",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
"@vitest/eslint-plugin": "^1.6.9",
|
||||
"eslint": "^9.39.3",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.5.5",
|
||||
"globals": "^17.3.0",
|
||||
"prettier": "^3.8.1",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.0.18"
|
||||
}
|
||||
}
|
||||
|
||||
51
src/auth.ts
51
src/auth.ts
@@ -1,51 +0,0 @@
|
||||
import * as fs from 'fs';
|
||||
|
||||
export const envPrefix = 'BUILDER_NODE';
|
||||
|
||||
export function setCredentials(credsdir: string, index: number, driver: string, endpoint: string): Array<string> {
|
||||
let url: URL;
|
||||
try {
|
||||
url = new URL(endpoint);
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
switch (url.protocol) {
|
||||
case 'tcp:': {
|
||||
return setBuildKitClientCerts(credsdir, index, driver, url);
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function setBuildKitClientCerts(credsdir: string, index: number, driver: string, endpoint: URL): Array<string> {
|
||||
const driverOpts: Array<string> = [];
|
||||
const buildkitCacert = process.env[`${envPrefix}_${index}_AUTH_TLS_CACERT`] || '';
|
||||
const buildkitCert = process.env[`${envPrefix}_${index}_AUTH_TLS_CERT`] || '';
|
||||
const buildkitKey = process.env[`${envPrefix}_${index}_AUTH_TLS_KEY`] || '';
|
||||
if (buildkitCacert.length == 0 && buildkitCert.length == 0 && buildkitKey.length == 0) {
|
||||
return driverOpts;
|
||||
}
|
||||
let host = endpoint.hostname;
|
||||
if (endpoint.port.length > 0) {
|
||||
host += `-${endpoint.port}`;
|
||||
}
|
||||
if (buildkitCacert.length > 0) {
|
||||
const cacertpath = `${credsdir}/cacert_${host}.pem`;
|
||||
fs.writeFileSync(cacertpath, buildkitCacert);
|
||||
driverOpts.push(`cacert=${cacertpath}`);
|
||||
}
|
||||
if (buildkitCert.length > 0) {
|
||||
const certpath = `${credsdir}/cert_${host}.pem`;
|
||||
fs.writeFileSync(certpath, buildkitCert);
|
||||
driverOpts.push(`cert=${certpath}`);
|
||||
}
|
||||
if (buildkitKey.length > 0) {
|
||||
const keypath = `${credsdir}/key_${host}.pem`;
|
||||
fs.writeFileSync(keypath, buildkitKey);
|
||||
driverOpts.push(`key=${keypath}`);
|
||||
}
|
||||
if (driver != 'remote') {
|
||||
return [];
|
||||
}
|
||||
return driverOpts;
|
||||
}
|
||||
378
src/buildx.ts
378
src/buildx.ts
@@ -1,378 +0,0 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as semver from 'semver';
|
||||
import * as util from 'util';
|
||||
import * as context from './context';
|
||||
import * as git from './git';
|
||||
import * as github from './github';
|
||||
import * as core from '@actions/core';
|
||||
import * as exec from '@actions/exec';
|
||||
import * as tc from '@actions/tool-cache';
|
||||
|
||||
export type Builder = {
|
||||
name?: string;
|
||||
driver?: string;
|
||||
nodes: Node[];
|
||||
};
|
||||
|
||||
export type Node = {
|
||||
name?: string;
|
||||
endpoint?: string;
|
||||
'driver-opts'?: Array<string>;
|
||||
status?: string;
|
||||
'buildkitd-flags'?: string;
|
||||
buildkit?: string;
|
||||
platforms?: string;
|
||||
};
|
||||
|
||||
export async function getConfigInline(s: string): Promise<string> {
|
||||
return getConfig(s, false);
|
||||
}
|
||||
|
||||
export async function getConfigFile(s: string): Promise<string> {
|
||||
return getConfig(s, true);
|
||||
}
|
||||
|
||||
export async function getConfig(s: string, file: boolean): Promise<string> {
|
||||
if (file) {
|
||||
if (!fs.existsSync(s)) {
|
||||
throw new Error(`config file ${s} not found`);
|
||||
}
|
||||
s = fs.readFileSync(s, {encoding: 'utf-8'});
|
||||
}
|
||||
const configFile = context.tmpNameSync({
|
||||
tmpdir: context.tmpDir()
|
||||
});
|
||||
fs.writeFileSync(configFile, s);
|
||||
return configFile;
|
||||
}
|
||||
|
||||
export async function isAvailable(standalone?: boolean): Promise<boolean> {
|
||||
const cmd = getCommand([], standalone);
|
||||
return await exec
|
||||
.getExecOutput(cmd.commandLine, cmd.args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
return false;
|
||||
}
|
||||
return res.exitCode == 0;
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.catch(error => {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
export async function getVersion(standalone?: boolean): Promise<string> {
|
||||
const cmd = getCommand(['version'], standalone);
|
||||
return await exec
|
||||
.getExecOutput(cmd.commandLine, cmd.args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr.trim());
|
||||
}
|
||||
return parseVersion(res.stdout.trim());
|
||||
});
|
||||
}
|
||||
|
||||
export function parseVersion(stdout: string): string {
|
||||
const matches = /\sv?([0-9a-f]{7}|[0-9.]+)/.exec(stdout);
|
||||
if (!matches) {
|
||||
throw new Error(`Cannot parse buildx version`);
|
||||
}
|
||||
return matches[1];
|
||||
}
|
||||
|
||||
export function satisfies(version: string, range: string): boolean {
|
||||
return semver.satisfies(version, range) || /^[0-9a-f]{7}$/.exec(version) !== null;
|
||||
}
|
||||
|
||||
export async function inspect(name: string, standalone?: boolean): Promise<Builder> {
|
||||
const cmd = getCommand(['inspect', name], standalone);
|
||||
return await exec
|
||||
.getExecOutput(cmd.commandLine, cmd.args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr.trim());
|
||||
}
|
||||
return parseInspect(res.stdout);
|
||||
});
|
||||
}
|
||||
|
||||
export async function parseInspect(data: string): Promise<Builder> {
|
||||
const builder: Builder = {
|
||||
nodes: []
|
||||
};
|
||||
let node: Node = {};
|
||||
for (const line of data.trim().split(`\n`)) {
|
||||
const [key, ...rest] = line.split(':');
|
||||
const value = rest.map(v => v.trim()).join(':');
|
||||
if (key.length == 0 || value.length == 0) {
|
||||
continue;
|
||||
}
|
||||
switch (key.toLowerCase()) {
|
||||
case 'name': {
|
||||
if (builder.name == undefined) {
|
||||
builder.name = value;
|
||||
} else {
|
||||
if (Object.keys(node).length > 0) {
|
||||
builder.nodes.push(node);
|
||||
node = {};
|
||||
}
|
||||
node.name = value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'driver': {
|
||||
builder.driver = value;
|
||||
break;
|
||||
}
|
||||
case 'endpoint': {
|
||||
node.endpoint = value;
|
||||
break;
|
||||
}
|
||||
case 'driver options': {
|
||||
node['driver-opts'] = (value.match(/(\w+)="([^"]*)"/g) || []).map(v => v.replace(/^(.*)="(.*)"$/g, '$1=$2'));
|
||||
break;
|
||||
}
|
||||
case 'status': {
|
||||
node.status = value;
|
||||
break;
|
||||
}
|
||||
case 'flags': {
|
||||
node['buildkitd-flags'] = value;
|
||||
break;
|
||||
}
|
||||
case 'buildkit': {
|
||||
node.buildkit = value;
|
||||
break;
|
||||
}
|
||||
case 'platforms': {
|
||||
let platforms: Array<string> = [];
|
||||
// if a preferred platform is being set then use only these
|
||||
// https://docs.docker.com/engine/reference/commandline/buildx_inspect/#get-information-about-a-builder-instance
|
||||
if (value.includes('*')) {
|
||||
for (const platform of value.split(', ')) {
|
||||
if (platform.includes('*')) {
|
||||
platforms.push(platform.replace('*', ''));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// otherwise set all platforms available
|
||||
platforms = value.split(', ');
|
||||
}
|
||||
node.platforms = platforms.join(',');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Object.keys(node).length > 0) {
|
||||
builder.nodes.push(node);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
export async function build(inputBuildRef: string, dest: string, standalone: boolean): Promise<string> {
|
||||
// eslint-disable-next-line prefer-const
|
||||
let [repo, ref] = inputBuildRef.split('#');
|
||||
if (ref.length == 0) {
|
||||
ref = 'master';
|
||||
}
|
||||
|
||||
let vspec: string;
|
||||
if (ref.match(/^[0-9a-fA-F]{40}$/)) {
|
||||
vspec = ref;
|
||||
} else {
|
||||
vspec = await git.getRemoteSha(repo, ref);
|
||||
}
|
||||
core.debug(`Tool version spec ${vspec}`);
|
||||
|
||||
let toolPath: string;
|
||||
toolPath = tc.find('buildx', vspec);
|
||||
if (!toolPath) {
|
||||
const outFolder = path.join(context.tmpDir(), 'out').split(path.sep).join(path.posix.sep);
|
||||
let buildWithStandalone = false;
|
||||
const standaloneFound = await isAvailable(true);
|
||||
const pluginFound = await isAvailable(false);
|
||||
if (standalone && standaloneFound) {
|
||||
core.debug(`Buildx standalone found, build with it`);
|
||||
buildWithStandalone = true;
|
||||
} else if (!standalone && pluginFound) {
|
||||
core.debug(`Buildx plugin found, build with it`);
|
||||
buildWithStandalone = false;
|
||||
} else if (standaloneFound) {
|
||||
core.debug(`Buildx plugin not found, but standalone found so trying to build with it`);
|
||||
buildWithStandalone = true;
|
||||
} else if (pluginFound) {
|
||||
core.debug(`Buildx standalone not found, but plugin found so trying to build with it`);
|
||||
buildWithStandalone = false;
|
||||
} else {
|
||||
throw new Error(`Neither buildx standalone or plugin have been found to build from ref`);
|
||||
}
|
||||
const buildCmd = getCommand(['build', '--target', 'binaries', '--build-arg', 'BUILDKIT_CONTEXT_KEEP_GIT_DIR=1', '--output', `type=local,dest=${outFolder}`, inputBuildRef], buildWithStandalone);
|
||||
toolPath = await exec
|
||||
.getExecOutput(buildCmd.commandLine, buildCmd.args, {
|
||||
ignoreReturnCode: true
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
core.warning(res.stderr.trim());
|
||||
}
|
||||
return tc.cacheFile(`${outFolder}/buildx`, context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx', 'buildx', vspec);
|
||||
});
|
||||
}
|
||||
|
||||
if (standalone) {
|
||||
return setStandalone(toolPath, dest);
|
||||
}
|
||||
return setPlugin(toolPath, dest);
|
||||
}
|
||||
|
||||
export async function install(inputVersion: string, dest: string, standalone: boolean): Promise<string> {
|
||||
const release: github.GitHubRelease | null = await github.getRelease(inputVersion);
|
||||
if (!release) {
|
||||
throw new Error(`Cannot find buildx ${inputVersion} release`);
|
||||
}
|
||||
core.debug(`Release ${release.tag_name} found`);
|
||||
const version = release.tag_name.replace(/^v+|v+$/g, '');
|
||||
|
||||
let toolPath: string;
|
||||
toolPath = tc.find('buildx', version);
|
||||
if (!toolPath) {
|
||||
const c = semver.clean(version) || '';
|
||||
if (!semver.valid(c)) {
|
||||
throw new Error(`Invalid Buildx version "${version}".`);
|
||||
}
|
||||
toolPath = await download(version);
|
||||
}
|
||||
|
||||
if (standalone) {
|
||||
return setStandalone(toolPath, dest);
|
||||
}
|
||||
return setPlugin(toolPath, dest);
|
||||
}
|
||||
|
||||
async function setStandalone(toolPath: string, dest: string): Promise<string> {
|
||||
core.info('Standalone mode');
|
||||
const toolBinPath = path.join(toolPath, context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx');
|
||||
|
||||
const binDir = path.join(dest, 'bin');
|
||||
core.debug(`Bin dir is ${binDir}`);
|
||||
if (!fs.existsSync(binDir)) {
|
||||
fs.mkdirSync(binDir, {recursive: true});
|
||||
}
|
||||
|
||||
const filename: string = context.osPlat == 'win32' ? 'buildx.exe' : 'buildx';
|
||||
const buildxPath: string = path.join(binDir, filename);
|
||||
core.debug(`Bin path is ${buildxPath}`);
|
||||
fs.copyFileSync(toolBinPath, buildxPath);
|
||||
|
||||
core.info('Fixing perms');
|
||||
fs.chmodSync(buildxPath, '0755');
|
||||
|
||||
core.addPath(binDir);
|
||||
core.info('Added buildx to the path');
|
||||
|
||||
return buildxPath;
|
||||
}
|
||||
|
||||
async function setPlugin(toolPath: string, dockerConfigHome: string): Promise<string> {
|
||||
core.info('Docker plugin mode');
|
||||
const toolBinPath = path.join(toolPath, context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx');
|
||||
|
||||
const pluginsDir: string = path.join(dockerConfigHome, 'cli-plugins');
|
||||
core.debug(`Plugins dir is ${pluginsDir}`);
|
||||
if (!fs.existsSync(pluginsDir)) {
|
||||
fs.mkdirSync(pluginsDir, {recursive: true});
|
||||
}
|
||||
|
||||
const filename: string = context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx';
|
||||
const pluginPath: string = path.join(pluginsDir, filename);
|
||||
core.debug(`Plugin path is ${pluginPath}`);
|
||||
fs.copyFileSync(toolBinPath, pluginPath);
|
||||
|
||||
core.info('Fixing perms');
|
||||
fs.chmodSync(pluginPath, '0755');
|
||||
|
||||
return pluginPath;
|
||||
}
|
||||
|
||||
async function download(version: string): Promise<string> {
|
||||
const targetFile: string = context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx';
|
||||
const downloadUrl = util.format('https://github.com/docker/buildx/releases/download/v%s/%s', version, await filename(version));
|
||||
core.info(`Downloading ${downloadUrl}`);
|
||||
const downloadPath = await tc.downloadTool(downloadUrl);
|
||||
core.debug(`Downloaded to ${downloadPath}`);
|
||||
return await tc.cacheFile(downloadPath, targetFile, 'buildx', version);
|
||||
}
|
||||
|
||||
async function filename(version: string): Promise<string> {
|
||||
let arch: string;
|
||||
switch (context.osArch) {
|
||||
case 'x64': {
|
||||
arch = 'amd64';
|
||||
break;
|
||||
}
|
||||
case 'ppc64': {
|
||||
arch = 'ppc64le';
|
||||
break;
|
||||
}
|
||||
case 'arm': {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const arm_version = (process.config.variables as any).arm_version;
|
||||
arch = arm_version ? 'arm-v' + arm_version : 'arm';
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
arch = context.osArch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const platform: string = context.osPlat == 'win32' ? 'windows' : context.osPlat;
|
||||
const ext: string = context.osPlat == 'win32' ? '.exe' : '';
|
||||
return util.format('buildx-v%s.%s-%s%s', version, platform, arch, ext);
|
||||
}
|
||||
|
||||
export async function getBuildKitVersion(containerID: string): Promise<string> {
|
||||
return exec
|
||||
.getExecOutput(`docker`, ['inspect', '--format', '{{.Config.Image}}', containerID], {
|
||||
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) {
|
||||
core.warning(bkitversion.stderr.trim());
|
||||
}
|
||||
return bkitversion.stdout.trim();
|
||||
});
|
||||
} else if (bkitimage.stderr.length > 0) {
|
||||
core.warning(bkitimage.stderr.trim());
|
||||
}
|
||||
return bkitimage.stdout.trim();
|
||||
});
|
||||
}
|
||||
|
||||
export function getCommand(args: Array<string>, standalone?: boolean) {
|
||||
return {
|
||||
commandLine: standalone ? 'buildx' : 'docker',
|
||||
args: standalone ? args : ['buildx', ...args]
|
||||
};
|
||||
}
|
||||
138
src/context.ts
138
src/context.ts
@@ -1,27 +1,14 @@
|
||||
import fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import path from 'path';
|
||||
import * as tmp from 'tmp';
|
||||
import * as uuid from 'uuid';
|
||||
import {parse} from 'csv-parse/sync';
|
||||
import * as buildx from './buildx';
|
||||
import * as nodes from './nodes';
|
||||
import * as crypto from 'crypto';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
let _tmpDir: string;
|
||||
export const osPlat: string = os.platform();
|
||||
export const osArch: string = os.arch();
|
||||
import {Docker} from '@docker/actions-toolkit/lib/docker/docker.js';
|
||||
import {Util} from '@docker/actions-toolkit/lib/util.js';
|
||||
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit.js';
|
||||
|
||||
export function tmpDir(): string {
|
||||
if (!_tmpDir) {
|
||||
_tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-setup-buildx-')).split(path.sep).join(path.posix.sep);
|
||||
}
|
||||
return _tmpDir;
|
||||
}
|
||||
import {Node} from '@docker/actions-toolkit/lib/types/buildx/builder.js';
|
||||
|
||||
export function tmpNameSync(options?: tmp.TmpNameOptions): string {
|
||||
return tmp.tmpNameSync(options);
|
||||
}
|
||||
export const builderNodeEnvPrefix = 'BUILDER_NODE';
|
||||
const defaultBuildkitdFlags = '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host';
|
||||
|
||||
export interface Inputs {
|
||||
version: string;
|
||||
@@ -29,44 +16,52 @@ export interface Inputs {
|
||||
driver: string;
|
||||
driverOpts: string[];
|
||||
buildkitdFlags: string;
|
||||
buildkitdConfig: string;
|
||||
buildkitdConfigInline: string;
|
||||
platforms: string[];
|
||||
install: boolean;
|
||||
use: boolean;
|
||||
endpoint: string;
|
||||
config: string;
|
||||
configInline: string;
|
||||
append: string;
|
||||
cacheBinary: boolean;
|
||||
cleanup: boolean;
|
||||
keepState: boolean;
|
||||
}
|
||||
|
||||
export async function getInputs(): Promise<Inputs> {
|
||||
return {
|
||||
version: core.getInput('version'),
|
||||
name: getBuilderName(core.getInput('driver') || 'docker-container'),
|
||||
name: await getBuilderName(core.getInput('name'), core.getInput('driver') || 'docker-container'),
|
||||
driver: core.getInput('driver') || 'docker-container',
|
||||
driverOpts: await getInputList('driver-opts', true),
|
||||
buildkitdFlags: core.getInput('buildkitd-flags') || '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
|
||||
platforms: await getInputList('platforms', false, true),
|
||||
driverOpts: Util.getInputList('driver-opts', {ignoreComma: true, quote: false}),
|
||||
buildkitdFlags: core.getInput('buildkitd-flags'),
|
||||
platforms: Util.getInputList('platforms'),
|
||||
install: core.getBooleanInput('install'),
|
||||
use: core.getBooleanInput('use'),
|
||||
endpoint: core.getInput('endpoint'),
|
||||
config: core.getInput('config'),
|
||||
configInline: core.getInput('config-inline'),
|
||||
append: core.getInput('append')
|
||||
buildkitdConfig: core.getInput('buildkitd-config') || core.getInput('config'),
|
||||
buildkitdConfigInline: core.getInput('buildkitd-config-inline') || core.getInput('config-inline'),
|
||||
append: core.getInput('append'),
|
||||
keepState: core.getBooleanInput('keep-state'),
|
||||
cacheBinary: core.getBooleanInput('cache-binary'),
|
||||
cleanup: core.getBooleanInput('cleanup')
|
||||
};
|
||||
}
|
||||
|
||||
export function getBuilderName(driver: string): string {
|
||||
return driver == 'docker' ? 'default' : `builder-${uuid.v4()}`;
|
||||
export async function getBuilderName(name: string, driver: string): Promise<string> {
|
||||
return driver == 'docker' ? await Docker.context() : name || `builder-${crypto.randomUUID()}`;
|
||||
}
|
||||
|
||||
export async function getCreateArgs(inputs: Inputs, buildxVersion: string): Promise<Array<string>> {
|
||||
export async function getCreateArgs(inputs: Inputs, toolkit: Toolkit): Promise<Array<string>> {
|
||||
const args: Array<string> = ['create', '--name', inputs.name, '--driver', inputs.driver];
|
||||
if (buildx.satisfies(buildxVersion, '>=0.3.0')) {
|
||||
await asyncForEach(inputs.driverOpts, async driverOpt => {
|
||||
if (await toolkit.buildx.versionSatisfies('>=0.3.0')) {
|
||||
await Util.asyncForEach(inputs.driverOpts, async (driverOpt: string) => {
|
||||
args.push('--driver-opt', driverOpt);
|
||||
});
|
||||
if (inputs.driver != 'remote' && inputs.buildkitdFlags) {
|
||||
if (inputs.buildkitdFlags) {
|
||||
args.push('--buildkitd-flags', inputs.buildkitdFlags);
|
||||
} else if (driverSupportsBuildkitdFlags(inputs.driver)) {
|
||||
args.push('--buildkitd-flags', defaultBuildkitdFlags);
|
||||
}
|
||||
}
|
||||
if (inputs.platforms.length > 0) {
|
||||
@@ -75,12 +70,10 @@ export async function getCreateArgs(inputs: Inputs, buildxVersion: string): Prom
|
||||
if (inputs.use) {
|
||||
args.push('--use');
|
||||
}
|
||||
if (inputs.driver != 'remote') {
|
||||
if (inputs.config) {
|
||||
args.push('--config', await buildx.getConfigFile(inputs.config));
|
||||
} else if (inputs.configInline) {
|
||||
args.push('--config', await buildx.getConfigInline(inputs.configInline));
|
||||
}
|
||||
if (inputs.buildkitdConfig) {
|
||||
args.push('--config', toolkit.buildkit.config.resolveFromFile(inputs.buildkitdConfig));
|
||||
} else if (inputs.buildkitdConfigInline) {
|
||||
args.push('--config', toolkit.buildkit.config.resolveFromString(inputs.buildkitdConfigInline));
|
||||
}
|
||||
if (inputs.endpoint) {
|
||||
args.push(inputs.endpoint);
|
||||
@@ -88,17 +81,21 @@ export async function getCreateArgs(inputs: Inputs, buildxVersion: string): Prom
|
||||
return args;
|
||||
}
|
||||
|
||||
export async function getAppendArgs(inputs: Inputs, node: nodes.Node, buildxVersion: string): Promise<Array<string>> {
|
||||
export async function getAppendArgs(inputs: Inputs, node: Node, toolkit: Toolkit): Promise<Array<string>> {
|
||||
const args: Array<string> = ['create', '--name', inputs.name, '--append'];
|
||||
if (node.name) {
|
||||
args.push('--node', node.name);
|
||||
} else if (inputs.driver == 'kubernetes' && (await toolkit.buildx.versionSatisfies('<0.11.0'))) {
|
||||
args.push('--node', `node-${crypto.randomUUID()}`);
|
||||
}
|
||||
if (node['driver-opts'] && buildx.satisfies(buildxVersion, '>=0.3.0')) {
|
||||
await asyncForEach(node['driver-opts'], async driverOpt => {
|
||||
if (node['driver-opts'] && (await toolkit.buildx.versionSatisfies('>=0.3.0'))) {
|
||||
await Util.asyncForEach(node['driver-opts'], async (driverOpt: string) => {
|
||||
args.push('--driver-opt', driverOpt);
|
||||
});
|
||||
if (inputs.driver != 'remote' && node['buildkitd-flags']) {
|
||||
if (node['buildkitd-flags']) {
|
||||
args.push('--buildkitd-flags', node['buildkitd-flags']);
|
||||
} else if (driverSupportsBuildkitdFlags(inputs.driver)) {
|
||||
args.push('--buildkitd-flags', defaultBuildkitdFlags);
|
||||
}
|
||||
}
|
||||
if (node.platforms) {
|
||||
@@ -110,47 +107,28 @@ export async function getAppendArgs(inputs: Inputs, node: nodes.Node, buildxVers
|
||||
return args;
|
||||
}
|
||||
|
||||
export async function getInspectArgs(inputs: Inputs, buildxVersion: string): Promise<Array<string>> {
|
||||
export async function getInspectArgs(inputs: Inputs, toolkit: Toolkit): Promise<Array<string>> {
|
||||
const args: Array<string> = ['inspect', '--bootstrap'];
|
||||
if (buildx.satisfies(buildxVersion, '>=0.4.0')) {
|
||||
if (await toolkit.buildx.versionSatisfies('>=0.4.0')) {
|
||||
args.push('--builder', inputs.name);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
export async function getInputList(name: string, ignoreComma?: boolean, escapeQuotes?: boolean): Promise<string[]> {
|
||||
const res: Array<string> = [];
|
||||
|
||||
const items = core.getInput(name);
|
||||
if (items == '') {
|
||||
return res;
|
||||
}
|
||||
|
||||
const records = parse(items, {
|
||||
columns: false,
|
||||
relaxQuotes: true,
|
||||
comment: '#',
|
||||
relaxColumnCount: true,
|
||||
skipEmptyLines: true,
|
||||
quote: escapeQuotes ? `"` : false
|
||||
});
|
||||
|
||||
for (const record of records as Array<string[]>) {
|
||||
if (record.length == 1) {
|
||||
res.push(record[0]);
|
||||
continue;
|
||||
} else if (!ignoreComma) {
|
||||
res.push(...record);
|
||||
continue;
|
||||
}
|
||||
res.push(record.join(','));
|
||||
}
|
||||
|
||||
return res.filter(item => item).map(pat => pat.trim());
|
||||
function driverSupportsBuildkitdFlags(driver: string): boolean {
|
||||
return driver == '' || driver == 'docker-container' || driver == 'docker' || driver == 'kubernetes';
|
||||
}
|
||||
|
||||
export const asyncForEach = async (array, callback) => {
|
||||
for (let index = 0; index < array.length; index++) {
|
||||
await callback(array[index], index, array);
|
||||
export function getVersion(inputs: Inputs): string {
|
||||
const version = inputs.version;
|
||||
if (inputs.driver === 'cloud') {
|
||||
if (!version || version === 'latest') {
|
||||
return 'cloud:latest';
|
||||
}
|
||||
if (version.startsWith('cloud:') || version.startsWith('lab:')) {
|
||||
return version;
|
||||
}
|
||||
return `cloud:${version}`;
|
||||
}
|
||||
};
|
||||
return version;
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import * as exec from '@actions/exec';
|
||||
|
||||
export async function isAvailable(): Promise<boolean> {
|
||||
return await exec
|
||||
.getExecOutput('docker', undefined, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
return false;
|
||||
}
|
||||
return res.exitCode == 0;
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.catch(error => {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
19
src/git.ts
19
src/git.ts
@@ -1,19 +0,0 @@
|
||||
import * as exec from '@actions/exec';
|
||||
|
||||
export async function getRemoteSha(repo: string, ref: string): Promise<string> {
|
||||
return await exec
|
||||
.getExecOutput(`git`, ['ls-remote', repo, ref], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr);
|
||||
}
|
||||
const [rsha] = res.stdout.trim().split(/[\s\t]/);
|
||||
if (rsha.length == 0) {
|
||||
throw new Error(`Cannot find remote ref for ${repo}#${ref}`);
|
||||
}
|
||||
return rsha;
|
||||
});
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import * as httpm from '@actions/http-client';
|
||||
|
||||
export interface GitHubRelease {
|
||||
id: number;
|
||||
tag_name: string;
|
||||
}
|
||||
|
||||
export const getRelease = async (version: string): Promise<GitHubRelease | null> => {
|
||||
const url = `https://github.com/docker/buildx/releases/${version}`;
|
||||
const http: httpm.HttpClient = new httpm.HttpClient('setup-buildx');
|
||||
return (await http.getJson<GitHubRelease>(url)).result;
|
||||
};
|
||||
393
src/main.ts
393
src/main.ts
@@ -1,182 +1,309 @@
|
||||
import * as crypto from 'crypto';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as auth from './auth';
|
||||
import * as buildx from './buildx';
|
||||
import * as context from './context';
|
||||
import * as docker from './docker';
|
||||
import * as nodes from './nodes';
|
||||
import * as stateHelper from './state-helper';
|
||||
import * as util from './util';
|
||||
import * as yaml from 'js-yaml';
|
||||
import * as core from '@actions/core';
|
||||
import * as exec from '@actions/exec';
|
||||
import * as actionsToolkit from '@docker/actions-toolkit';
|
||||
|
||||
async function run(): Promise<void> {
|
||||
try {
|
||||
import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx.js';
|
||||
import {Builder} from '@docker/actions-toolkit/lib/buildx/builder.js';
|
||||
import {Docker} from '@docker/actions-toolkit/lib/docker/docker.js';
|
||||
import {Exec} from '@docker/actions-toolkit/lib/exec.js';
|
||||
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit.js';
|
||||
import {Util} from '@docker/actions-toolkit/lib/util.js';
|
||||
|
||||
import {Node} from '@docker/actions-toolkit/lib/types/buildx/builder.js';
|
||||
import {ContextInfo} from '@docker/actions-toolkit/lib/types/docker/docker.js';
|
||||
|
||||
import * as context from './context.js';
|
||||
import * as stateHelper from './state-helper.js';
|
||||
|
||||
actionsToolkit.run(
|
||||
// main
|
||||
async () => {
|
||||
const inputs: context.Inputs = await context.getInputs();
|
||||
const dockerConfigHome: string = process.env.DOCKER_CONFIG || path.join(os.homedir(), '.docker');
|
||||
stateHelper.setCleanup(inputs.cleanup);
|
||||
const version = context.getVersion(inputs);
|
||||
|
||||
// standalone if docker cli not available
|
||||
const standalone = !(await docker.isAvailable());
|
||||
const toolkit = new Toolkit();
|
||||
const standalone = await toolkit.buildx.isStandalone();
|
||||
stateHelper.setStandalone(standalone);
|
||||
|
||||
core.startGroup(`Docker info`);
|
||||
if (standalone) {
|
||||
core.info(`Docker info skipped in standalone mode`);
|
||||
} else {
|
||||
await exec.exec('docker', ['version'], {
|
||||
failOnStdErr: false
|
||||
});
|
||||
await exec.exec('docker', ['info'], {
|
||||
failOnStdErr: false
|
||||
});
|
||||
if (inputs.keepState && inputs.driver !== 'docker-container') {
|
||||
// https://docs.docker.com/reference/cli/docker/buildx/rm/#keep-state
|
||||
throw new Error(`Cannot use keep-state with ${inputs.driver} driver`);
|
||||
}
|
||||
core.endGroup();
|
||||
stateHelper.setKeepState(inputs.keepState);
|
||||
|
||||
if (util.isValidUrl(inputs.version)) {
|
||||
await core.group(`Docker info`, async () => {
|
||||
try {
|
||||
await Docker.printVersion();
|
||||
await Docker.printInfo();
|
||||
} catch (e) {
|
||||
core.info(e.message);
|
||||
}
|
||||
});
|
||||
|
||||
let toolPath;
|
||||
if (Util.isValidRef(version)) {
|
||||
if (standalone) {
|
||||
throw new Error(`Cannot build from source without the Docker CLI`);
|
||||
}
|
||||
core.startGroup(`Build and install buildx`);
|
||||
await buildx.build(inputs.version, dockerConfigHome, standalone);
|
||||
core.endGroup();
|
||||
} else if (!(await buildx.isAvailable(standalone)) || inputs.version) {
|
||||
core.startGroup(`Download and install buildx`);
|
||||
await buildx.install(inputs.version || 'latest', standalone ? context.tmpDir() : dockerConfigHome, standalone);
|
||||
core.endGroup();
|
||||
await core.group(`Build buildx from source`, async () => {
|
||||
toolPath = await toolkit.buildxInstall.build(version, !inputs.cacheBinary);
|
||||
});
|
||||
} else if (!(await toolkit.buildx.isAvailable()) || version) {
|
||||
await core.group(`Download buildx from GitHub Releases`, async () => {
|
||||
toolPath = await toolkit.buildxInstall.download({
|
||||
version: version || 'latest',
|
||||
ghaNoCache: !inputs.cacheBinary
|
||||
});
|
||||
});
|
||||
}
|
||||
if (toolPath) {
|
||||
await core.group(`Install buildx`, async () => {
|
||||
if (standalone) {
|
||||
await toolkit.buildxInstall.installStandalone(toolPath);
|
||||
} else {
|
||||
await toolkit.buildxInstall.installPlugin(toolPath);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const buildxVersion = await buildx.getVersion(standalone);
|
||||
await core.group(`Buildx version`, async () => {
|
||||
const versionCmd = buildx.getCommand(['version'], standalone);
|
||||
await exec.exec(versionCmd.commandLine, versionCmd.args, {
|
||||
failOnStdErr: false
|
||||
});
|
||||
await toolkit.buildx.printVersion();
|
||||
});
|
||||
|
||||
core.setOutput('name', inputs.name);
|
||||
stateHelper.setBuilderName(inputs.name);
|
||||
stateHelper.setBuilderDriver(inputs.driver);
|
||||
|
||||
const credsdir = path.join(dockerConfigHome, 'buildx', 'creds', inputs.name);
|
||||
fs.mkdirSync(credsdir, {recursive: true});
|
||||
stateHelper.setCredsDir(credsdir);
|
||||
fs.mkdirSync(Buildx.certsDir, {recursive: true});
|
||||
stateHelper.setCertsDir(Buildx.certsDir);
|
||||
|
||||
// if the default context has TLS data loaded and endpoint is not set, then
|
||||
// we create a temporary docker context only if driver is docker-container
|
||||
// https://github.com/docker/buildx/blob/b96ad59f64d40873e4959336d294b648bb3937fe/builder/builder.go#L489
|
||||
// https://github.com/docker/setup-buildx-action/issues/105
|
||||
if (!standalone && inputs.driver == 'docker-container' && (await Docker.context()) == 'default' && inputs.endpoint.length == 0) {
|
||||
let defaultContextWithTLS: boolean = false;
|
||||
await core.group(`Inspecting default docker context`, async () => {
|
||||
await Docker.getExecOutput(['context', 'inspect', '--format=json', 'default'], {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
core.info(`Cannot inspect default docker context: ${res.stderr.trim()}`);
|
||||
} else {
|
||||
try {
|
||||
const contextInfo = (<Array<ContextInfo>>JSON.parse(res.stdout.trim()))[0];
|
||||
core.info(JSON.stringify(JSON.parse(res.stdout.trim()), undefined, 2));
|
||||
const hasTLSData = Object.keys(contextInfo.Endpoints).length > 0 && Object.values(contextInfo.Endpoints)[0].TLSData !== undefined;
|
||||
const hasTLSMaterial = Object.keys(contextInfo.TLSMaterial).length > 0 && Object.values(contextInfo.TLSMaterial)[0].length > 0;
|
||||
defaultContextWithTLS = hasTLSData || hasTLSMaterial;
|
||||
} catch (e) {
|
||||
core.info(`Unable to parse default docker context info: ${e}`);
|
||||
core.info(res.stdout.trim());
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
if (defaultContextWithTLS) {
|
||||
const tmpDockerContext = `buildx-${crypto.randomUUID()}`;
|
||||
await core.group(`Creating temp docker context (TLS data loaded in default one)`, async () => {
|
||||
await Docker.getExecOutput(['context', 'create', tmpDockerContext], {
|
||||
ignoreReturnCode: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
core.warning(`Cannot create docker context ${tmpDockerContext}: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
|
||||
} else {
|
||||
core.info(`Setting builder endpoint to ${tmpDockerContext} context`);
|
||||
inputs.endpoint = tmpDockerContext;
|
||||
stateHelper.setTmpDockerContext(tmpDockerContext);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (inputs.driver !== 'docker') {
|
||||
core.startGroup(`Creating a new builder instance`);
|
||||
const authOpts = auth.setCredentials(credsdir, 0, inputs.driver, inputs.endpoint);
|
||||
if (authOpts.length > 0) {
|
||||
inputs.driverOpts = [...inputs.driverOpts, ...authOpts];
|
||||
}
|
||||
const createCmd = buildx.getCommand(await context.getCreateArgs(inputs, buildxVersion), standalone);
|
||||
await exec.exec(createCmd.commandLine, createCmd.args);
|
||||
core.endGroup();
|
||||
await core.group(`Creating a new builder instance`, async () => {
|
||||
if (await toolkit.builder.exists(inputs.name)) {
|
||||
core.info(`Builder ${inputs.name} already exists, skipping creation`);
|
||||
} else {
|
||||
const certsDriverOpts = Buildx.resolveCertsDriverOpts(inputs.driver, inputs.endpoint, {
|
||||
cacert: process.env[`${context.builderNodeEnvPrefix}_0_AUTH_TLS_CACERT`],
|
||||
cert: process.env[`${context.builderNodeEnvPrefix}_0_AUTH_TLS_CERT`],
|
||||
key: process.env[`${context.builderNodeEnvPrefix}_0_AUTH_TLS_KEY`]
|
||||
});
|
||||
if (certsDriverOpts.length > 0) {
|
||||
inputs.driverOpts = [...inputs.driverOpts, ...certsDriverOpts];
|
||||
}
|
||||
const createCmd = await toolkit.buildx.getCommand(await context.getCreateArgs(inputs, toolkit));
|
||||
await Exec.getExecOutput(createCmd.command, createCmd.args, {
|
||||
ignoreReturnCode: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (inputs.append) {
|
||||
core.startGroup(`Appending node(s) to builder`);
|
||||
let nodeIndex = 1;
|
||||
for (const node of nodes.Parse(inputs.append)) {
|
||||
const authOpts = auth.setCredentials(credsdir, nodeIndex, inputs.driver, node.endpoint || '');
|
||||
if (authOpts.length > 0) {
|
||||
node['driver-opts'] = [...(node['driver-opts'] || []), ...authOpts];
|
||||
await core.group(`Appending node(s) to builder`, async () => {
|
||||
let nodeIndex = 1;
|
||||
const nodes = yaml.load(inputs.append) as Node[];
|
||||
for (const node of nodes) {
|
||||
const certsDriverOpts = Buildx.resolveCertsDriverOpts(inputs.driver, `${node.endpoint}`, {
|
||||
cacert: process.env[`${context.builderNodeEnvPrefix}_${nodeIndex}_AUTH_TLS_CACERT`],
|
||||
cert: process.env[`${context.builderNodeEnvPrefix}_${nodeIndex}_AUTH_TLS_CERT`],
|
||||
key: process.env[`${context.builderNodeEnvPrefix}_${nodeIndex}_AUTH_TLS_KEY`]
|
||||
});
|
||||
if (certsDriverOpts.length > 0) {
|
||||
node['driver-opts'] = [...(node['driver-opts'] || []), ...certsDriverOpts];
|
||||
}
|
||||
const appendCmd = await toolkit.buildx.getCommand(await context.getAppendArgs(inputs, node, toolkit));
|
||||
await Exec.getExecOutput(appendCmd.command, appendCmd.args, {
|
||||
ignoreReturnCode: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(`Failed to append node ${node.name}: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
|
||||
}
|
||||
});
|
||||
nodeIndex++;
|
||||
}
|
||||
const appendCmd = buildx.getCommand(await context.getAppendArgs(inputs, node, buildxVersion), standalone);
|
||||
await exec.exec(appendCmd.commandLine, appendCmd.args);
|
||||
nodeIndex++;
|
||||
}
|
||||
core.endGroup();
|
||||
});
|
||||
}
|
||||
|
||||
core.startGroup(`Booting builder`);
|
||||
const inspectCmd = buildx.getCommand(await context.getInspectArgs(inputs, buildxVersion), standalone);
|
||||
await exec.exec(inspectCmd.commandLine, inspectCmd.args);
|
||||
core.endGroup();
|
||||
await core.group(`Booting builder`, async () => {
|
||||
const inspectCmd = await toolkit.buildx.getCommand(await context.getInspectArgs(inputs, toolkit));
|
||||
await Exec.getExecOutput(inspectCmd.command, inspectCmd.args, {
|
||||
ignoreReturnCode: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (inputs.install) {
|
||||
if (standalone) {
|
||||
throw new Error(`Cannot set buildx as default builder without the Docker CLI`);
|
||||
}
|
||||
core.startGroup(`Setting buildx as default builder`);
|
||||
await exec.exec('docker', ['buildx', 'install']);
|
||||
core.endGroup();
|
||||
await core.group(`Setting buildx as default builder`, async () => {
|
||||
stateHelper.setBuildxIsDefaultBuilder(true);
|
||||
const installCmd = await toolkit.buildx.getCommand(['install']);
|
||||
await Exec.getExecOutput(installCmd.command, installCmd.args, {
|
||||
ignoreReturnCode: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
core.startGroup(`Inspect builder`);
|
||||
const builder = await buildx.inspect(inputs.name, standalone);
|
||||
const firstNode = builder.nodes[0];
|
||||
const reducedPlatforms: Array<string> = [];
|
||||
for (const node of builder.nodes) {
|
||||
for (const platform of node.platforms?.split(',') || []) {
|
||||
if (reducedPlatforms.indexOf(platform) > -1) {
|
||||
continue;
|
||||
const builderInspect = await toolkit.builder.inspect(inputs.name);
|
||||
const firstNode = builderInspect.nodes[0];
|
||||
|
||||
await core.group(`Inspect builder`, async () => {
|
||||
const reducedPlatforms: Array<string> = [];
|
||||
for (const node of builderInspect.nodes) {
|
||||
for (const platform of node.platforms?.split(',') || []) {
|
||||
if (reducedPlatforms.indexOf(platform) > -1) {
|
||||
continue;
|
||||
}
|
||||
reducedPlatforms.push(platform);
|
||||
}
|
||||
reducedPlatforms.push(platform);
|
||||
}
|
||||
}
|
||||
core.info(JSON.stringify(builder, undefined, 2));
|
||||
core.setOutput('driver', builder.driver);
|
||||
core.setOutput('platforms', reducedPlatforms.join(','));
|
||||
core.setOutput('nodes', JSON.stringify(builder.nodes, undefined, 2));
|
||||
core.setOutput('endpoint', firstNode.endpoint); // TODO: deprecated, to be removed in a later version
|
||||
core.setOutput('status', firstNode.status); // TODO: deprecated, to be removed in a later version
|
||||
core.setOutput('flags', firstNode['buildkitd-flags']); // TODO: deprecated, to be removed in a later version
|
||||
core.endGroup();
|
||||
core.info(JSON.stringify(builderInspect, undefined, 2));
|
||||
core.setOutput('driver', builderInspect.driver);
|
||||
core.setOutput('platforms', reducedPlatforms.join(','));
|
||||
core.setOutput('nodes', JSON.stringify(builderInspect.nodes, undefined, 2));
|
||||
core.setOutput('endpoint', firstNode.endpoint); // TODO: deprecated, to be removed in a later version
|
||||
core.setOutput('status', firstNode.status); // TODO: deprecated, to be removed in a later version
|
||||
core.setOutput('flags', firstNode['buildkitd-flags']); // TODO: deprecated, to be removed in a later version
|
||||
});
|
||||
|
||||
if (!standalone && builder.driver == 'docker-container') {
|
||||
stateHelper.setContainerName(`buildx_buildkit_${firstNode.name}`);
|
||||
core.startGroup(`BuildKit version`);
|
||||
for (const node of builder.nodes) {
|
||||
const bkvers = await buildx.getBuildKitVersion(`buildx_buildkit_${node.name}`);
|
||||
core.info(`${node.name}: ${bkvers}`);
|
||||
}
|
||||
core.endGroup();
|
||||
if (!standalone && builderInspect.driver == 'docker-container') {
|
||||
stateHelper.setContainerName(`${Buildx.containerNamePrefix}${firstNode.name}`);
|
||||
await core.group(`BuildKit version`, async () => {
|
||||
for (const node of builderInspect.nodes) {
|
||||
const buildkitVersion = await toolkit.buildkit.getVersion(node);
|
||||
core.info(`${node.name}: ${buildkitVersion}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (core.isDebug() || firstNode['buildkitd-flags']?.includes('--debug')) {
|
||||
stateHelper.setDebug('true');
|
||||
}
|
||||
} catch (error) {
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
}
|
||||
},
|
||||
// post
|
||||
async () => {
|
||||
if (stateHelper.IsDebug && stateHelper.containerName.length > 0) {
|
||||
await core.group(`BuildKit container logs`, async () => {
|
||||
await Docker.getExecOutput(['logs', `${stateHelper.containerName}`], {
|
||||
ignoreReturnCode: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
core.warning(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function cleanup(): Promise<void> {
|
||||
if (stateHelper.IsDebug && stateHelper.containerName.length > 0) {
|
||||
core.startGroup(`BuildKit container logs`);
|
||||
await exec
|
||||
.getExecOutput('docker', ['logs', `${stateHelper.containerName}`], {
|
||||
ignoreReturnCode: true
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
core.warning(res.stderr.trim());
|
||||
if (!stateHelper.cleanup) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stateHelper.builderDriver != 'docker' && stateHelper.builderName.length > 0) {
|
||||
await core.group(`Removing builder`, async () => {
|
||||
const buildx = new Buildx({standalone: stateHelper.standalone});
|
||||
const builder = new Builder({buildx: buildx});
|
||||
if (await builder.exists(stateHelper.builderName)) {
|
||||
const rmCmd = await buildx.getCommand(['rm', stateHelper.builderName, ...(stateHelper.keepState ? ['--keep-state'] : [])]);
|
||||
await Exec.getExecOutput(rmCmd.command, rmCmd.args, {
|
||||
ignoreReturnCode: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
core.warning(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
core.info(`${stateHelper.builderName} does not exist`);
|
||||
}
|
||||
});
|
||||
core.endGroup();
|
||||
}
|
||||
}
|
||||
|
||||
if (stateHelper.builderName.length > 0) {
|
||||
core.startGroup(`Removing builder`);
|
||||
const rmCmd = buildx.getCommand(['rm', stateHelper.builderName], /true/i.test(stateHelper.standalone));
|
||||
await exec
|
||||
.getExecOutput(rmCmd.commandLine, rmCmd.args, {
|
||||
ignoreReturnCode: true
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
core.warning(res.stderr.trim());
|
||||
}
|
||||
if (stateHelper.tmpDockerContext) {
|
||||
await core.group(`Removing temp docker context`, async () => {
|
||||
await Exec.getExecOutput('docker', ['context', 'rm', '-f', stateHelper.tmpDockerContext], {
|
||||
ignoreReturnCode: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
core.warning(`${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
core.endGroup();
|
||||
}
|
||||
}
|
||||
|
||||
if (stateHelper.credsDir.length > 0 && fs.existsSync(stateHelper.credsDir)) {
|
||||
core.info(`Cleaning up credentials`);
|
||||
fs.rmSync(stateHelper.credsDir, {recursive: true});
|
||||
}
|
||||
}
|
||||
if (stateHelper.certsDir.length > 0 && fs.existsSync(stateHelper.certsDir)) {
|
||||
await core.group(`Cleaning up certificates`, async () => {
|
||||
fs.rmSync(stateHelper.certsDir, {recursive: true});
|
||||
});
|
||||
}
|
||||
|
||||
if (!stateHelper.IsPost) {
|
||||
run();
|
||||
} else {
|
||||
cleanup();
|
||||
}
|
||||
if (stateHelper.buildxIsDefaultBuilder) {
|
||||
await core.group(`Restoring default builder`, async () => {
|
||||
await Exec.getExecOutput('docker', ['buildx', 'uninstall'], {
|
||||
ignoreReturnCode: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
core.warning(`${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
13
src/nodes.ts
13
src/nodes.ts
@@ -1,13 +0,0 @@
|
||||
import * as yaml from 'js-yaml';
|
||||
|
||||
export type Node = {
|
||||
name?: string;
|
||||
endpoint?: string;
|
||||
'driver-opts'?: Array<string>;
|
||||
'buildkitd-flags'?: string;
|
||||
platforms?: string;
|
||||
};
|
||||
|
||||
export function Parse(data: string): Node[] {
|
||||
return yaml.load(data) as Node[];
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
import * as core from '@actions/core';
|
||||
|
||||
export const IsPost = !!process.env['STATE_isPost'];
|
||||
export const IsDebug = !!process.env['STATE_isDebug'];
|
||||
export const standalone = process.env['STATE_standalone'] || '';
|
||||
export const standalone = /true/i.test(process.env['STATE_standalone'] || '');
|
||||
export const builderName = process.env['STATE_builderName'] || '';
|
||||
export const builderDriver = process.env['STATE_builderDriver'] || '';
|
||||
export const containerName = process.env['STATE_containerName'] || '';
|
||||
export const credsDir = process.env['STATE_credsDir'] || '';
|
||||
export const certsDir = process.env['STATE_certsDir'] || '';
|
||||
export const tmpDockerContext = process.env['STATE_tmpDockerContext'] || '';
|
||||
export const cleanup = /true/i.test(process.env['STATE_cleanup'] || '');
|
||||
export const buildxIsDefaultBuilder = /true/i.test(process.env['STATE_buildxIsDefaultBuilder'] || '');
|
||||
export const keepState = /true/i.test(process.env['STATE_keepState'] || '');
|
||||
|
||||
export function setDebug(debug: string) {
|
||||
core.saveState('isDebug', debug);
|
||||
@@ -19,14 +23,30 @@ export function setBuilderName(builderName: string) {
|
||||
core.saveState('builderName', builderName);
|
||||
}
|
||||
|
||||
export function setBuilderDriver(builderDriver: string) {
|
||||
core.saveState('builderDriver', builderDriver);
|
||||
}
|
||||
|
||||
export function setContainerName(containerName: string) {
|
||||
core.saveState('containerName', containerName);
|
||||
}
|
||||
|
||||
export function setCredsDir(credsDir: string) {
|
||||
core.saveState('credsDir', credsDir);
|
||||
export function setCertsDir(certsDir: string) {
|
||||
core.saveState('certsDir', certsDir);
|
||||
}
|
||||
|
||||
if (!IsPost) {
|
||||
core.saveState('isPost', 'true');
|
||||
export function setTmpDockerContext(tmpDockerContext: string) {
|
||||
core.saveState('tmpDockerContext', tmpDockerContext);
|
||||
}
|
||||
|
||||
export function setCleanup(cleanup: boolean) {
|
||||
core.saveState('cleanup', cleanup);
|
||||
}
|
||||
|
||||
export function setBuildxIsDefaultBuilder(buildxIsDefaultBuilder: boolean) {
|
||||
core.saveState('buildxIsDefaultBuilder', buildxIsDefaultBuilder);
|
||||
}
|
||||
|
||||
export function setKeepState(keepState: boolean) {
|
||||
core.saveState('keepState', keepState);
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
export function isValidUrl(url: string): boolean {
|
||||
try {
|
||||
new URL(url);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1,19 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"module": "nodenext",
|
||||
"moduleResolution": "nodenext",
|
||||
"esModuleInterop": true,
|
||||
"newLine": "lf",
|
||||
"outDir": "./lib",
|
||||
"rootDir": "./src",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitAny": false,
|
||||
"resolveJsonModule": true,
|
||||
"useUnknownInCatchVariables": false,
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/*.test.ts",
|
||||
"jest.config.ts"
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
]
|
||||
}
|
||||
|
||||
16
vitest.config.ts
Normal file
16
vitest.config.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import {defineConfig} from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
clearMocks: true,
|
||||
environment: 'node',
|
||||
setupFiles: ['./__tests__/setup.unit.ts'],
|
||||
include: ['**/*.test.ts'],
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
reporter: ['clover'],
|
||||
include: ['src/**/*.ts'],
|
||||
exclude: ['src/**/main.ts']
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user