Compare commits

..

No commits in common. "master" and "v1.1.1" have entirely different histories.

53 changed files with 14019 additions and 13217 deletions

View File

@ -1,12 +0,0 @@
/coverage
# Dependency directories
node_modules/
jspm_packages/
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

View File

@ -1,3 +0,0 @@
/dist/**
/coverage/**
/node_modules/**

View File

@ -1,24 +0,0 @@
{
"env": {
"node": true,
"es6": true,
"jest": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/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
View File

@ -1,4 +1,2 @@
/.yarn/releases/** binary
/.yarn/plugins/** binary
/dist/** linguist-generated=true /dist/** linguist-generated=true
/lib/** linguist-generated=true /lib/** linguist-generated=true

1
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1 @@
* @crazy-max

View File

@ -1,3 +0,0 @@
# Code of conduct
- [Moby community guidelines](https://github.com/moby/moby/blob/master/CONTRIBUTING.md#moby-community-guidelines)

View File

@ -2,24 +2,35 @@
Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great.
Contributions to this project are [released](https://docs.github.com/en/github/site-policy/github-terms-of-service#6-contributions-under-repository-license) Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE).
to the public under the [project's open source license](LICENSE).
## Submitting a pull request ## Submitting a pull request
1. [Fork](https://github.com/docker/setup-buildx-action/fork) and clone the repository 1. [Fork](https://github.com/docker/setup-buildx-action/fork) and clone the repository
2. Configure and install the dependencies: `yarn install` 2. Configure and install the dependencies: `yarn install`
3. Create a new branch: `git checkout -b my-branch-name` 3. Create a new branch: `git checkout -b my-branch-name`
4. Make your changes 4. Make your change, add tests, and make sure the tests still pass
5. Make sure the tests pass: `docker buildx bake test` 5. Run pre-checkin: `yarn run pre-checkin`
6. Format code and build javascript artifacts: `docker buildx bake pre-checkin` 6. Push to your fork and [submit a pull request](https://github.com/docker/setup-buildx-action/compare)
7. Validate all code has correctly formatted and built: `docker buildx bake validate` 7. Pat yourself on the back and wait for your pull request to be reviewed and merged.
8. Push to your fork and [submit a pull request](https://github.com/docker/setup-buildx-action/compare)
9. Pat your self on the back and wait for your pull request to be reviewed and merged. ## Container based developer flow
If you don't want to maintain a Node developer environment that fits this project you can use containerized commands instead of invoking yarn directly.
```
# format code and build javascript artifacts
docker buildx bake pre-checkin
# validate all code has correctly formatted and built
docker buildx bake validate
# run tests
docker buildx bake test
```
Here are a few things you can do that will increase the likelihood of your pull request being accepted: Here are a few things you can do that will increase the likelihood of your pull request being accepted:
- Write tests.
- Make sure the `README.md` and any other relevant **documentation are kept up-to-date**. - Make sure the `README.md` and any other relevant **documentation are kept up-to-date**.
- We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option.
- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as **separate pull requests**. - Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as **separate pull requests**.
@ -28,5 +39,5 @@ Here are a few things you can do that will increase the likelihood of your pull
## Resources ## Resources
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
- [Using Pull Requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) - [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)
- [GitHub Help](https://docs.github.com/en) - [GitHub Help](https://help.github.com)

View File

@ -1,101 +0,0 @@
# 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.

33
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,33 @@
---
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://help.github.com/en/actions/configuring-and-managing-workflows/managing-a-workflow-run#downloading-logs) and [attach it](https://help.github.com/en/github/managing-your-work-on-github/file-attachments-on-issues-and-pull-requests) to this issue.

View File

@ -1,9 +0,0 @@
# 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.

View File

@ -1,15 +0,0 @@
# 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
View File

@ -1,12 +0,0 @@
# 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&mdash;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 Normal file
View File

@ -0,0 +1,31 @@
# Support [![](https://isitmaintained.com/badge/resolution/docker/setup-buildx-action.svg)](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.

View File

@ -4,16 +4,19 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
time: "06:00"
timezone: "Europe/Paris"
labels: labels:
- "dependencies" - ":game_die: dependencies"
- "bot" - ":robot: bot"
- package-ecosystem: "npm" - package-ecosystem: "npm"
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
versioning-strategy: "increase" time: "06:00"
timezone: "Europe/Paris"
allow: allow:
- dependency-type: "production" - dependency-type: "production"
labels: labels:
- "dependencies" - ":game_die: dependencies"
- "bot" - ":robot: bot"

77
.github/labels.yml vendored Normal file
View File

@ -0,0 +1,77 @@
## more info https://github.com/crazy-max/ghaction-github-labeler
- # automerge
name: ":bell: automerge"
color: "8f4fbc"
description: ""
- # bot
name: ":robot: bot"
color: "69cde9"
description: ""
- # bug
name: ":bug: bug"
color: "b60205"
description: ""
- # dependencies
name: ":game_die: dependencies"
color: "0366d6"
description: ""
- # documentation
name: ":memo: documentation"
color: "c5def5"
description: ""
- # duplicate
name: ":busts_in_silhouette: duplicate"
color: "cccccc"
description: ""
- # enhancement
name: ":sparkles: enhancement"
color: "0054ca"
description: ""
- # feature request
name: ":bulb: feature request"
color: "0e8a16"
description: ""
- # feedback
name: ":mega: feedback"
color: "03a9f4"
description: ""
- # future maybe
name: ":rocket: future maybe"
color: "fef2c0"
description: ""
- # good first issue
name: ":hatching_chick: good first issue"
color: "7057ff"
description: ""
- # help wanted
name: ":pray: help wanted"
color: "4caf50"
description: ""
- # hold
name: ":hand: hold"
color: "24292f"
description: ""
- # invalid
name: ":no_entry_sign: invalid"
color: "e6e6e6"
description: ""
- # maybe bug
name: ":interrobang: maybe bug"
color: "ff5722"
description: ""
- # needs more info
name: ":thinking: needs more info"
color: "795548"
description: ""
- # question
name: ":question: question"
color: "3f51b5"
description: ""
- # upstream
name: ":eyes: upstream"
color: "fbca04"
description: ""
- # wontfix
name: ":coffin: wontfix"
color: "ffffff"
description: ""

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -1,20 +1,18 @@
name: ci name: ci
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: on:
workflow_dispatch:
schedule:
- cron: '0 10 * * *'
push: push:
branches: branches:
- 'master' - master
- 'releases/v*' - releases/v*
tags: paths-ignore:
- 'v*' - "**.md"
pull_request: pull_request:
branches:
- master
- releases/v*
paths-ignore:
- "**.md"
jobs: jobs:
main: main:
@ -23,16 +21,13 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
buildx-version: buildx-version:
- latest
- v0.4.1
- "" - ""
- "latest"
- "v0.4.1"
- "cloud:latest"
- "cloud:v0.11.2-desktop.2"
- "lab:latest"
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
- -
name: Set up Docker Buildx name: Set up Docker Buildx
id: buildx id: buildx
@ -40,87 +35,42 @@ jobs:
with: with:
version: ${{ matrix.buildx-version }} version: ${{ matrix.buildx-version }}
- -
name: Nodes output name: Builder instance name
run: | run: echo ${{ steps.buildx.outputs.name }}
cat << EOF -
${{ steps.buildx.outputs.nodes }} name: Available platforms
EOF run: echo ${{ steps.buildx.outputs.platforms }}
-
name: Dump context
uses: crazy-max/ghaction-dump-context@v1
multi: multi:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
- -
name: Set up Docker Buildx 1 name: Set up Docker Buildx 1
id: buildx1
uses: ./ uses: ./
-
name: Builder 1 instance name
run: echo ${{ steps.buildx1.outputs.name }}
- -
name: Set up Docker Buildx 2 name: Set up Docker Buildx 2
uses: ./ id: buildx2
error:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Stop docker
run: |
sudo systemctl stop docker docker.socket
-
name: Set up Docker Buildx
id: buildx
continue-on-error: true
uses: ./ uses: ./
- -
name: Check name: Builder 2 instance name
run: | run: echo ${{ steps.buildx2.outputs.name }}
echo "${{ toJson(steps.buildx) }}"
if [ "${{ steps.buildx.outcome }}" != "failure" ] || [ "${{ steps.buildx.conclusion }}" != "success" ]; then
echo "::error::Should have failed"
exit 1
fi
-
name: Dump context
if: always()
uses: crazy-max/ghaction-dump-context@v2
debug:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Create Dockerfile
run: |
cat > ./Dockerfile <<EOL
FROM alpine
RUN uname -a
EOL
-
name: Set up QEMU
uses: docker/setup-qemu-action@v3
-
name: Set up Docker Buildx
uses: ./
with:
buildkitd-flags: --debug
-
name: Build
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64,linux/ppc64le
install: install:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: ./ uses: ./
@ -142,7 +92,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: ./ uses: ./
@ -165,7 +115,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: ./ uses: ./
@ -178,7 +128,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: ./ uses: ./
@ -211,7 +161,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
- -
name: Create context name: Create context
run: | run: |
@ -225,67 +175,6 @@ jobs:
uses: ./ uses: ./
with: with:
endpoint: mycontext endpoint: mycontext
env:
DOCKER_CONTEXT: mycontext
config:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Create buildkitd conf
run: |
cat > /tmp/buildkitd.toml <<EOL
debug = true
[registry."docker.io"]
mirrors = ["mirror.gcr.io"]
EOL
-
name: Create Dockerfile
run: |
cat > ./Dockerfile <<EOL
FROM alpine
EOL
-
name: Set up Docker Buildx
uses: ./
with:
buildkitd-flags: --debug
buildkitd-config: /tmp/buildkitd.toml
-
name: Build
uses: docker/build-push-action@v6
with:
context: .
config-inline:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Create Dockerfile
run: |
cat > ./Dockerfile <<EOL
FROM alpine
EOL
-
name: Set up Docker Buildx
uses: ./
with:
buildkitd-flags: --debug
buildkitd-config-inline: |
debug = true
[registry."docker.io"]
mirrors = ["mirror.gcr.io"]
-
name: Build
uses: docker/build-push-action@v6
with:
context: .
with-qemu: with-qemu:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -293,7 +182,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
buildx-version: buildx-version:
- v0.9.1 - latest
- v0.4.1
- "" - ""
qemu-platforms: qemu-platforms:
- all - all
@ -301,10 +191,10 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
- -
name: Set up QEMU name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v1
with: with:
platforms: ${{ matrix.qemu-platforms }} platforms: ${{ matrix.qemu-platforms }}
- -
@ -314,292 +204,8 @@ jobs:
with: with:
version: ${{ matrix.buildx-version }} version: ${{ matrix.buildx-version }}
- -
name: List builder platforms name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }} run: echo ${{ steps.buildx.outputs.platforms }}
build-ref:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ref:
- master
- refs/tags/v0.5.1
- refs/pull/731/head
- cb185f095fd3d9444e0aa605d3789e9e05f2a1e7
steps:
- -
name: Checkout name: Builder instance name
uses: actions/checkout@v4 run: echo ${{ steps.buildx.outputs.name }}
-
name: Set up Docker Buildx
uses: ./
with:
version: https://github.com/docker/buildx.git#${{ matrix.ref }}
-
name: Create Dockerfile
run: |
cat > ./Dockerfile <<EOL
FROM alpine
EOL
-
name: Build
uses: docker/build-push-action@master
with:
context: .
standalone-cmd:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Uninstall docker cli
run: |
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: ./
-
name: Create Dockerfile
run: |
cat > ./Dockerfile <<EOL
FROM alpine
EOL
-
name: Build
run: |
buildx build .
standalone-action:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Uninstall docker cli
run: |
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: ./
with:
version: ${{ matrix.buildx-version }}
-
name: Create Dockerfile
run: |
cat > ./Dockerfile <<EOL
FROM alpine
EOL
-
name: Build
uses: docker/build-push-action@master
with:
context: .
standalone-install-error:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Uninstall docker cli
run: |
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
continue-on-error: true
uses: ./
with:
install: 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
append:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Create dummy contexts
run: |
docker context create ctxbuilder2
docker context create ctxbuilder3
-
name: Set up Docker Buildx
id: buildx
uses: ./
with:
append: |
- name: builder2
endpoint: ctxbuilder2
platforms: linux/amd64
driver-opts:
- image=moby/buildkit:master
- network=host
- endpoint: ctxbuilder3
platforms: linux/arm64
-
name: List builder platforms
run: echo ${{ steps.buildx.outputs.platforms }}
platforms:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Set up QEMU
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@v4
-
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@v4
-
name: Set up Docker Buildx
uses: ./
with:
cleanup: ${{ matrix.cleanup }}
k3s:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
version:
- v0.11.0
- v0.10.5
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Install k3s
uses: crazy-max/.github/.github/actions/install-k3s@f5cb4a109b7a3b466a2ac293ef4bb13f1571acd7
-
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@v4
-
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@v4
-
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

20
.github/workflows/labels.yml vendored Normal file
View File

@ -0,0 +1,20 @@
name: labels
on:
push:
branches:
- 'master'
paths:
- '.github/labels.yml'
- '.github/workflows/labels.yml'
jobs:
labeler:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Run Labeler
uses: crazy-max/ghaction-github-labeler@v3

View File

@ -1,21 +0,0 @@
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@v4
-
name: Publish
uses: actions/publish-immutable-action@v0.0.4

View File

@ -1,34 +1,46 @@
name: test name: test
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: on:
push: push:
branches: branches:
- 'master' - master
- 'releases/v*' - releases/v*
paths-ignore:
- "**.md"
pull_request: pull_request:
paths-ignore:
- "**.md"
jobs: jobs:
test-containerized:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Validate
run: docker buildx bake validate
-
name: Test
run: docker buildx bake test
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
- -
name: Set up Docker Buildx name: Install
uses: ./ run: yarn install
- -
name: Test name: Test
uses: docker/bake-action@v6 run: yarn run test
with:
targets: test
- -
name: Upload coverage name: Upload coverage
uses: codecov/codecov-action@v5 uses: codecov/codecov-action@v1
if: success()
with: with:
files: ./coverage/clover.xml
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage/clover.xml

View File

@ -1,43 +0,0 @@
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@v4
-
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
View File

@ -1,5 +1,12 @@
# https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore /.dev
node_modules
lib
# Jetbrains
/.idea
/*.iml
# Rest of the file pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
# Logs # Logs
logs logs
*.log *.log
@ -7,7 +14,6 @@ npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
lerna-debug.log* lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html) # Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
@ -18,14 +24,34 @@ pids
*.seed *.seed
*.pid.lock *.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul # Coverage directory used by tools like istanbul
coverage coverage
*.lcov *.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 # Dependency directories
node_modules/
jspm_packages/ jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache # TypeScript cache
*.tsbuildinfo *.tsbuildinfo
@ -35,19 +61,36 @@ jspm_packages/
# Optional eslint cache # Optional eslint cache
.eslintcache .eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file # Yarn Integrity file
.yarn-integrity .yarn-integrity
# dotenv environment variable files # dotenv environment variables file
.env .env
.env.development.local .env.test
.env.test.local
.env.production.local
.env.local
# yarn v2 # parcel-bundler cache (https://parceljs.org/)
.yarn/cache .cache
.yarn/unplugged
.yarn/build-state.yml # next.js build output
.yarn/install-state.gz .next
.pnp.*
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/

View File

@ -1,6 +0,0 @@
# Dependency directories
node_modules/
jspm_packages/
# yarn v2
.yarn/

View File

@ -1,5 +1,5 @@
{ {
"printWidth": 240, "printWidth": 120,
"tabWidth": 2, "tabWidth": 2,
"useTabs": false, "useTabs": false,
"semi": true, "semi": true,

File diff suppressed because one or more lines are too long

View File

@ -1,13 +0,0 @@
logFilters:
- code: YN0013
level: discard
- code: YN0019
level: discard
- code: YN0076
level: discard
nodeLinker: node-modules
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
spec: "@yarnpkg/plugin-interactive-tools"

52
Dockerfile Normal file
View File

@ -0,0 +1,52 @@
#syntax=docker/dockerfile:1.1-experimental
FROM node:14 AS deps
WORKDIR /src
COPY package.json yarn.lock ./
RUN --mount=type=cache,target=/usr/local/share/.cache/yarn \
yarn install
FROM scratch AS update-yarn
COPY --from=deps /src/yarn.lock /
FROM deps AS validate-yarn
COPY .git .git
RUN status=$(git status --porcelain -- yarn.lock); if [ -n "$status" ]; then echo $status; exit 1; fi
FROM deps AS base
COPY . .
FROM base AS build
RUN yarn build
FROM deps AS test
COPY --from=docker /usr/local/bin/docker /usr/bin/
ARG TARGETOS
ARG TARGETARCH
ARG BUILDX_VERSION=v0.4.2
ENV RUNNER_TEMP=/tmp/github_runner
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
RUN mkdir -p /usr/local/lib/docker/cli-plugins && \
curl -fsSL https://github.com/docker/buildx/releases/download/$BUILDX_VERSION/buildx-$BUILDX_VERSION.$TARGETOS-$TARGETARCH > /usr/local/lib/docker/cli-plugins/docker-buildx && \
chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx && \
docker buildx version
COPY . .
RUN yarn run test
FROM base AS run-format
RUN yarn run format
FROM scratch AS format
COPY --from=run-format /src/src/*.ts /src/
FROM base AS validate-format
RUN yarn run format-check
FROM scratch AS dist
COPY --from=build /src/dist/ /dist/
FROM build AS validate-build
RUN status=$(git status --porcelain -- dist); if [ -n "$status" ]; then echo $status; exit 1; fi
FROM base AS dev
ENTRYPOINT ["bash"]

209
README.md
View File

@ -1,35 +1,37 @@
[![GitHub release](https://img.shields.io/github/release/docker/setup-buildx-action.svg?style=flat-square)](https://github.com/docker/setup-buildx-action/releases/latest) [![GitHub release](https://img.shields.io/github/release/docker/setup-buildx-action.svg?style=flat-square)](https://github.com/docker/setup-buildx-action/releases/latest)
[![GitHub marketplace](https://img.shields.io/badge/marketplace-docker--setup--buildx-blue?logo=github&style=flat-square)](https://github.com/marketplace/actions/docker-setup-buildx) [![GitHub marketplace](https://img.shields.io/badge/marketplace-docker--setup--buildx-blue?logo=github&style=flat-square)](https://github.com/marketplace/actions/docker-setup-buildx)
[![CI workflow](https://img.shields.io/github/actions/workflow/status/docker/setup-buildx-action/ci.yml?branch=master&label=ci&logo=github&style=flat-square)](https://github.com/docker/setup-buildx-action/actions?workflow=ci) [![CI workflow](https://img.shields.io/github/workflow/status/docker/setup-buildx-action/ci?label=ci&logo=github&style=flat-square)](https://github.com/docker/setup-buildx-action/actions?workflow=ci)
[![Test workflow](https://img.shields.io/github/actions/workflow/status/docker/setup-buildx-action/test.yml?branch=master&label=test&logo=github&style=flat-square)](https://github.com/docker/setup-buildx-action/actions?workflow=test) [![Test workflow](https://img.shields.io/github/workflow/status/docker/setup-buildx-action/test?label=test&logo=github&style=flat-square)](https://github.com/docker/setup-buildx-action/actions?workflow=test)
[![Codecov](https://img.shields.io/codecov/c/github/docker/setup-buildx-action?logo=codecov&style=flat-square)](https://codecov.io/gh/docker/setup-buildx-action) [![Codecov](https://img.shields.io/codecov/c/github/docker/setup-buildx-action?logo=codecov&style=flat-square)](https://codecov.io/gh/docker/setup-buildx-action)
## About ## About
GitHub Action to set up Docker [Buildx](https://github.com/docker/buildx). GitHub Action to set up Docker [Buildx](https://github.com/docker/buildx).
This action will create and boot a builder that can be used in the following > :bulb: See also:
steps of your workflow if you're using Buildx or the [`build-push` action](https://github.com/docker/build-push-action/). > * [login](https://github.com/docker/login-action) action
By default, the [`docker-container` driver](https://docs.docker.com/build/building/drivers/docker-container/) > * [setup-qemu](https://github.com/docker/setup-qemu-action) action
will be used to be able to build multi-platform images and export cache using > * [build-push](https://github.com/docker/build-push-action) action
a [BuildKit](https://github.com/moby/buildkit) container.
![Screenshot](.github/setup-buildx-action.png) ![Screenshot](.github/setup-buildx-action.png)
___ ___
* [Usage](#usage) * [Usage](#usage)
* [Configuring your builder](#configuring-your-builder) * [Quick start](#quick-start)
* [With QEMU](#with-qemu)
* [Install by default](#install-by-default)
* [Customizing](#customizing) * [Customizing](#customizing)
* [inputs](#inputs) * [inputs](#inputs)
* [outputs](#outputs) * [outputs](#outputs)
* [environment variables](#environment-variables) * [environment variables](#environment-variables)
* [Notes](#notes) * [Keep up-to-date with GitHub Dependabot](#keep-up-to-date-with-github-dependabot)
* [`nodes` output](#nodes-output) * [Limitation](#limitation)
* [Contributing](#contributing)
## Usage ## Usage
### Quick start
```yaml ```yaml
name: ci name: ci
@ -42,124 +44,135 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
-
# Add support for more platforms with QEMU (optional)
# https://github.com/docker/setup-qemu-action
name: Set up QEMU
uses: docker/setup-qemu-action@v3
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 id: buildx
uses: docker/setup-buildx-action@v1
-
name: Builder instance name
run: echo ${{ steps.buildx.outputs.name }}
-
name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
``` ```
## Configuring your builder ### With QEMU
* [Version pinning](https://docs.docker.com/build/ci/github-actions/configure-builder/#version-pinning): Pin to a specific Buildx or BuildKit version If you want support for more platforms you can use our [setup-qemu](https://github.com/docker/setup-qemu-action) action:
* [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) ```yaml
* [Registry mirror](https://docs.docker.com/build/ci/github-actions/configure-builder/#registry-mirror): Configure a registry mirror for your builds name: ci
* [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 on:
* [Authentication for remote builders](https://docs.docker.com/build/ci/github-actions/configure-builder/#authentication-for-remote-builders) push:
* [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 jobs:
* [Standalone mode](https://docs.docker.com/build/ci/github-actions/configure-builder/#standalone-mode): Use Buildx as a standalone binary (without the Docker CLI) buildx:
* [Isolated builders](https://docs.docker.com/build/ci/github-actions/configure-builder/#isolated-builders): Create isolated builders for your builds runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
-
name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
```
### Install by default
Implemented with https://github.com/docker/buildx#setting-buildx-as-default-builder-in-docker-1903
```yaml
name: ci
on:
push:
jobs:
buildx:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
uses: docker/setup-buildx-action@v1
id: buildx
with:
install: true
-
name: Build
run: |
docker build . # will run buildx
```
## Customizing ## Customizing
### inputs ### inputs
The following inputs can be used as `step.with` keys: Following inputs can be used as `step.with` keys
> `List` type is a newline-delimited string | Name | Type | Description |
|--------------------|---------|-----------------------------------|
| `version` | String | [Buildx](https://github.com/docker/buildx) version. (eg. `v0.3.0`, `latest`) |
| `driver` | String | Sets the [builder driver](https://github.com/docker/buildx#--driver-driver) to be used (default `docker-container`) |
| `driver-opts` | CSV | List of additional [driver-specific options](https://github.com/docker/buildx#--driver-opt-options) (eg. `image=moby/buildkit:master`) |
| `buildkitd-flags` | String | [Flags for buildkitd](https://github.com/moby/buildkit/blob/master/docs/buildkitd.toml.md) 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://github.com/docker/buildx#buildx-create-options-contextendpoint) or context from `docker context ls` |
> `CSV` type must be a newline-delimited string
> ```yaml
> driver-opts: image=moby/buildkit:master
> ```
> ```yaml > ```yaml
> driver-opts: | > driver-opts: |
> image=moby/buildkit:master > image=moby/buildkit:master
> network=host > network=host
> ``` > ```
> `CSV` type must be a comma-delimited string
> ```yaml
> platforms: linux/amd64,linux/arm64
> ```
| 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`) |
| `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 |
| `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 |
> [!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.
### outputs ### outputs
The following outputs are available: Following outputs are available
| Name | Type | Description | | Name | Type | Description |
|-------------|--------|-----------------------------------------------------| |---------------|---------|---------------------------------------|
| `name` | String | Builder name | | `name` | String | Builder instance name |
| `driver` | String | Builder driver | | `platforms` | String | Available platforms (comma separated) |
| `platforms` | String | Builder node platforms (preferred and/or available) |
| `nodes` | JSON | Builder [nodes metadata](#nodes-output) |
### environment variables ### environment variables
The following [official docker environment variables](https://docs.docker.com/engine/reference/commandline/cli/#environment-variables) are supported: The following [official docker environment variables](https://docs.docker.com/engine/reference/commandline/cli/#environment-variables) are supported:
| Name | Type | Default | Description | | Name | Type | Default | Description |
|-----------------|--------|-------------|-------------------------------------------------| |-----------------|---------|-------------|-------------------------------------------------|
| `DOCKER_CONFIG` | String | `~/.docker` | The location of your client configuration files | | `DOCKER_CONFIG` | String | `~/.docker` | The location of your client configuration files |
## Notes ## Keep up-to-date with GitHub Dependabot
### `nodes` output 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:
```json ```yaml
[ version: 2
{ updates:
"name": "builder-3820d274-502c-4498-ae24-d4c32b3023d90", # Maintain dependencies for GitHub Actions
"endpoint": "unix:///var/run/docker.sock", - package-ecosystem: "github-actions"
"driver-opts": [ directory: "/"
"network=host", schedule:
"image=moby/buildkit:master" interval: "daily"
],
"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 | Type | Description | ## Limitation
|-------------------|--------|----------------------------|
| `name` | String | Node name |
| `endpoint` | String | Node endpoint |
| `driver-opts` | List | Options for the driver |
| `status` | String | Node status |
| `buildkitd-flags` | String | Flags for buildkitd daemon |
| `buildkit` | String | BuildKit version |
| `platforms` | String | Platforms available |
## Contributing This action is only available for Linux [virtual environments](https://docs.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners#supported-virtual-environments-and-hardware-resources).
Want to contribute? Awesome! You can find information about contributing to
this project in the [CONTRIBUTING.md](/.github/CONTRIBUTING.md)

56
__tests__/buildx.test.ts Normal file
View File

@ -0,0 +1,56 @@
import fs = require('fs');
import * as docker from '../src/docker';
import * as buildx from '../src/buildx';
import * as path from 'path';
import * as os from 'os';
import * as semver from 'semver';
import * as exec from '@actions/exec';
describe('getVersion', () => {
it('valid', async () => {
await exec.exec('docker', ['buildx', 'version']);
const version = await buildx.getVersion();
console.log(`version: ${version}`);
expect(semver.valid(version)).not.toBeNull();
}, 100000);
});
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']
])('given %p', async (stdout, expected) => {
expect(await buildx.parseVersion(stdout)).toEqual(expected);
});
});
describe('platforms', () => {
async function isDaemonRunning() {
return await docker.isDaemonRunning();
}
(isDaemonRunning() ? it : it.skip)(
'valid',
async () => {
const platforms = buildx.platforms();
console.log(`platforms: ${platforms}`);
expect(platforms).not.toBeUndefined();
expect(platforms).not.toEqual('');
},
100000
);
});
describe('install', () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-buildx-'));
it('acquires v0.4.1 version of buildx', async () => {
const buildxBin = await buildx.install('v0.4.1', tmpDir);
console.log(buildxBin);
expect(fs.existsSync(buildxBin)).toBe(true);
}, 100000);
it('acquires latest version of buildx', async () => {
const buildxBin = await buildx.install('latest', tmpDir);
console.log(buildxBin);
expect(fs.existsSync(buildxBin)).toBe(true);
}, 100000);
});

View File

@ -1,460 +1,81 @@
import {beforeEach, describe, expect, jest, test} from '@jest/globals';
import * as fs from 'fs';
import * as path from 'path';
import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx';
import {Context} from '@docker/actions-toolkit/lib/context';
import {Docker} from '@docker/actions-toolkit/lib/docker/docker';
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit';
import {Node} from '@docker/actions-toolkit/lib/types/buildx/builder';
import * as context from '../src/context'; import * as context from '../src/context';
const fixturesDir = path.join(__dirname, 'fixtures'); describe('getInputList', () => {
// prettier-ignore it('handles single line correctly', async () => {
const tmpDir = path.join(process.env.TEMP || '/tmp', 'setup-buildx-jest'); await setInput('foo', 'bar');
const tmpName = path.join(tmpDir, '.tmpname-jest'); const res = await context.getInputList('foo');
console.log(res);
expect(res).toEqual(['bar']);
});
jest.spyOn(Context, 'tmpDir').mockImplementation((): string => { it('handles multiple lines correctly', async () => {
if (!fs.existsSync(tmpDir)) { setInput('foo', 'bar\nbaz');
fs.mkdirSync(tmpDir, {recursive: true}); const res = await context.getInputList('foo');
} console.log(res);
return tmpDir; expect(res).toEqual(['bar', 'baz']);
});
it('remove empty lines correctly', async () => {
setInput('foo', 'bar\n\nbaz');
const res = await context.getInputList('foo');
console.log(res);
expect(res).toEqual(['bar', 'baz']);
});
it('handles comma correctly', async () => {
setInput('foo', 'bar,baz');
const res = await context.getInputList('foo');
console.log(res);
expect(res).toEqual(['bar', 'baz']);
});
it('remove empty result correctly', async () => {
setInput('foo', 'bar,baz,');
const res = await context.getInputList('foo');
console.log(res);
expect(res).toEqual(['bar', 'baz']);
});
it('handles different new lines correctly', async () => {
setInput('foo', 'bar\r\nbaz');
const res = await context.getInputList('foo');
console.log(res);
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');
console.log(res);
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);
console.log(res);
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);
console.log(res);
expect(res).toEqual(['image=moby/buildkit:master', 'network=host']);
});
}); });
jest.spyOn(Context, 'tmpName').mockImplementation((): string => { describe('asyncForEach', () => {
return tmpName; it('executes async tasks sequentially', async () => {
}); const testValues = [1, 2, 3, 4, 5];
const results: number[] = [];
jest.mock('crypto', () => { await context.asyncForEach(testValues, async value => {
return { results.push(value);
...(jest.requireActual('crypto') as object),
randomUUID: jest.fn(() => '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d')
};
});
jest.spyOn(Docker, 'context').mockImplementation((): Promise<string> => {
return Promise.resolve('default');
});
describe('getCreateArgs', () => {
beforeEach(() => {
process.env = Object.keys(process.env).reduce((object, key) => {
if (!key.startsWith('INPUT_')) {
object[key] = process.env[key];
}
return object;
}, {});
}); });
// prettier-ignore expect(results).toEqual(testValues);
test.each([
[
0,
'v0.10.3',
new Map<string, string>([
['install', 'false'],
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true'],
]),
[
'create',
'--name', 'builder-9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d',
'--driver', 'docker-container',
'--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
'--use'
]
],
[
1,
'v0.10.3',
new Map<string, string>([
['driver', 'docker'],
['install', 'false'],
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true'],
]),
[
'create',
'--name', 'default',
'--driver', 'docker',
'--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
'--use'
]
],
[
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'],
]),
[
'create',
'--name', 'builder-9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d',
'--driver', 'docker-container',
'--driver-opt', 'image=moby/buildkit:master',
'--driver-opt', 'network=host',
'--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host'
]
],
[
3,
'v0.10.3',
new Map<string, string>([
['driver', 'remote'],
['endpoint', 'tls://foo:1234'],
['install', 'false'],
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true'],
]),
[
'create',
'--name', 'builder-9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d',
'--driver', 'remote',
'--use',
'tls://foo:1234'
]
],
[
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'],
]),
[
'create',
'--name', 'builder-9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d',
'--driver', 'remote',
'--platform', 'linux/arm64,linux/arm/v7',
'--use',
'tls://foo:1234'
]
],
[
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'],
]),
[
'create',
'--name', 'builder-9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d',
'--driver', 'docker-container',
'--driver-opt', '"env.no_proxy=localhost,127.0.0.1,.mydomain"',
'--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host'
]
],
[
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'],
]),
[
'create',
'--name', 'builder-9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d',
'--driver', 'docker-container',
'--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
'--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'],
]),
[
'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'],
]),
[
'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'],
]),
[
'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'],
]),
[
'create',
'--name', 'builder-9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d',
'--driver', 'cloud',
'--buildkitd-flags', '--allow-insecure-entitlement network.host',
]
]
])(
'[%d] given buildx %s and %p as inputs, returns %p',
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();
jest.spyOn(Buildx.prototype, 'version').mockImplementation(async (): Promise<string> => {
return buildxVersion;
});
const inp = await context.getInputs();
const res = await context.getCreateArgs(inp, toolkit);
expect(res).toEqual(expected);
}
);
});
describe('getAppendArgs', () => {
beforeEach(() => {
process.env = Object.keys(process.env).reduce((object, key) => {
if (!key.startsWith('INPUT_')) {
object[key] = process.env[key];
}
return object;
}, {});
});
// prettier-ignore
test.each([
[
0,
'v0.10.3',
new Map<string, string>([
['install', 'false'],
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true'],
]),
{
"name": "aws_graviton2",
"endpoint": "ssh://me@graviton2",
"driver-opts": [
"image=moby/buildkit:latest"
],
"buildkitd-flags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
"platforms": "linux/arm64"
},
[
'create',
'--name', 'builder-9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d',
'--append',
'--node', 'aws_graviton2',
'--driver-opt', 'image=moby/buildkit:latest',
'--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
'--platform', 'linux/arm64',
'ssh://me@graviton2'
]
]
])(
'[%d] given buildx %s and %p as inputs, returns %p',
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();
jest.spyOn(Buildx.prototype, 'version').mockImplementation(async (): Promise<string> => {
return buildxVersion;
});
const inp = await context.getInputs();
const res = await context.getAppendArgs(inp, node, toolkit);
expect(res).toEqual(expected);
}
);
});
describe('getVersion', () => {
beforeEach(() => {
process.env = Object.keys(process.env).reduce((object, key) => {
if (!key.startsWith('INPUT_')) {
object[key] = process.env[key];
}
return object;
}, {});
});
// prettier-ignore
test.each([
[
0,
new Map<string, string>([
// defaults
['install', 'false'],
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true'],
]),
''
],
[
1,
new Map<string, string>([
['version', 'latest'],
// defaults
['install', 'false'],
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true']
]),
'latest'
],
[
2,
new Map<string, string>([
['version', 'edge'],
// defaults
['install', 'false'],
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true']
]),
'edge'
],
[
3,
new Map<string, string>([
['version', 'v0.19.2'],
// defaults
['install', 'false'],
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true']
]),
'v0.19.2'
],
[
4,
new Map<string, string>([
['version', 'latest'],
['driver', 'cloud'],
// defaults
['install', 'false'],
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true']
]),
'cloud:latest'
],
[
5,
new Map<string, string>([
['version', 'edge'],
['driver', 'cloud'],
// defaults
['install', 'false'],
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true']
]),
'cloud:edge'
],
[
6,
new Map<string, string>([
['driver', 'cloud'],
// defaults
['install', 'false'],
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true'],
]),
'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'],
]),
'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'],
]),
'cloud:v0.11.2-desktop.2'
],
])(
'[%d] given %p as inputs, returns version %p',
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 // See: https://github.com/actions/toolkit/blob/master/packages/core/src/core.ts#L67

View File

@ -1 +0,0 @@
debug = true

17
__tests__/github.test.ts Normal file
View File

@ -0,0 +1,17 @@
import * as github from '../src/github';
describe('github', () => {
it('returns latest buildx GitHub release', async () => {
const release = await github.getRelease('latest');
console.log(release);
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');
console.log(release);
expect(release).not.toBeNull();
expect(release?.tag_name).toEqual('v0.2.2');
});
});

View File

@ -18,16 +18,11 @@ inputs:
description: 'List of additional driver-specific options. (eg. image=moby/buildkit:master)' description: 'List of additional driver-specific options. (eg. image=moby/buildkit:master)'
required: false required: false
buildkitd-flags: buildkitd-flags:
description: 'BuildKit daemon flags' description: 'Flags for buildkitd daemon'
required: false default: '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host'
buildkitd-config:
description: 'BuildKit daemon config file'
required: false
buildkitd-config-inline:
description: 'Inline BuildKit daemon config'
required: false required: false
install: install:
description: 'Sets up docker build command as an alias to docker buildx build' description: 'Sets up docker build command as an alias to docker buildx'
default: 'false' default: 'false'
required: false required: false
use: use:
@ -37,47 +32,14 @@ inputs:
endpoint: endpoint:
description: 'Optional address for docker socket or context from `docker context ls`' description: 'Optional address for docker socket or context from `docker context ls`'
required: false required: false
platforms:
description: 'Fixed platforms for current node. If not empty, values take priority over the detected ones'
required: false
append:
description: 'Append additional nodes to the builder'
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 and config-inline 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
outputs: outputs:
name: name:
description: 'Builder name' description: 'Builder instance name'
driver:
description: 'Builder driver'
platforms: platforms:
description: 'Builder node platforms (preferred or available)' description: 'Available platforms (comma separated)'
nodes:
description: 'Builder nodes metadata'
endpoint:
description: 'Builder node endpoint (deprecated, use nodes output instead)'
status:
description: 'Builder node status (deprecated, use nodes output instead)'
flags:
description: 'Builder node flags (deprecated, use nodes output instead)'
runs: runs:
using: 'node20' using: 'node12'
main: 'dist/index.js' main: 'dist/index.js'
post: 'dist/index.js' post: 'dist/index.js'

View File

@ -1,3 +0,0 @@
comment: false
github_checks:
annotations: false

View File

@ -1,80 +0,0 @@
# syntax=docker/dockerfile:1
ARG NODE_VERSION=20
FROM node:${NODE_VERSION}-alpine AS base
RUN apk add --no-cache cpio findutils git
WORKDIR /src
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/.yarn/cache <<EOT
corepack enable
yarn --version
yarn config set --home enableTelemetry 0
EOT
FROM base AS deps
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/.yarn/cache \
--mount=type=cache,target=/src/node_modules \
yarn install && mkdir /vendor && cp yarn.lock /vendor
FROM scratch AS vendor-update
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"'
git status --porcelain -- yarn.lock
exit 1
fi
EOT
FROM deps AS build
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/.yarn/cache \
--mount=type=cache,target=/src/node_modules \
yarn run build && mkdir /out && cp -Rf dist /out/
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
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/*' -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 deps AS test
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/.yarn/cache \
--mount=type=cache,target=/src/node_modules \
yarn run test --coverage --coverageDirectory=/tmp/coverage
FROM scratch AS test-coverage
COPY --from=test /tmp/coverage /

9300
dist/index.js generated vendored

File diff suppressed because one or more lines are too long

1
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

3869
dist/licenses.txt generated vendored

File diff suppressed because it is too large Load Diff

1
dist/sourcemap-register.js generated vendored

File diff suppressed because one or more lines are too long

View File

@ -1,66 +1,42 @@
target "_common" {
args = {
BUILDKIT_CONTEXT_KEEP_GIT_DIR = 1
}
}
group "default" { group "default" {
targets = ["build"] targets = ["build"]
} }
group "pre-checkin" { group "pre-checkin" {
targets = ["vendor", "format", "build"] targets = ["update-yarn", "format", "build"]
} }
group "validate" { group "validate" {
targets = ["lint", "build-validate", "vendor-validate"] targets = ["validate-format", "validate-build", "validate-yarn"]
}
target "update-yarn" {
target = "update-yarn"
output = ["."]
} }
target "build" { target "build" {
inherits = ["_common"] target = "dist"
dockerfile = "dev.Dockerfile"
target = "build-update"
output = ["."] 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" {
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" { target "test" {
inherits = ["_common"] target = "test"
dockerfile = "dev.Dockerfile" }
target = "test-coverage"
output = ["./coverage"] target "format" {
target = "format"
output = ["."]
}
target "validate-format" {
target = "validate-format"
}
target "validate-build" {
target = "validate-build"
}
target "validate-yarn" {
target = "validate-yarn"
} }

6
hack/shell Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
iidfile=$(mktemp -t docker-iidfile.XXXXXXXXXX)
DOCKER_BUILDKIT=1 docker build --iidfile $iidfile --progress=plain .
docker run -it --rm $(cat $iidfile)
docker rmi $(cat $iidfile)

12
jest.config.js Normal file
View File

@ -0,0 +1,12 @@
module.exports = {
clearMocks: true,
moduleFileExtensions: ['js', 'ts'],
setupFiles: ["dotenv/config"],
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
testRunner: 'jest-circus/runner',
transform: {
'^.+\\.ts$': 'ts-jest'
},
verbose: false
}

View File

@ -1,29 +0,0 @@
import fs from 'fs';
import os from 'os';
import path from 'path';
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-setup-buildx-action-')).split(path.sep).join(path.posix.sep);
process.env = Object.assign({}, process.env, {
TEMP: tmpDir,
GITHUB_REPOSITORY: 'docker/setup-buildx-action',
RUNNER_TEMP: path.join(tmpDir, 'runner-temp').split(path.sep).join(path.posix.sep),
RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache').split(path.sep).join(path.posix.sep)
}) as {
[key: string]: string;
};
module.exports = {
clearMocks: true,
moduleFileExtensions: ['js', 'ts'],
testMatch: ['**/*.test.ts'],
transform: {
'^.+\\.ts$': 'ts-jest'
},
moduleNameMapper: {
'^csv-parse/sync': '<rootDir>/node_modules/csv-parse/dist/cjs/sync.cjs'
},
collectCoverageFrom: ['src/**/{!(main.ts),}.ts'],
coveragePathIgnorePatterns: ['lib/', 'node_modules/', '__tests__/'],
verbose: true
};

View File

@ -1,16 +1,13 @@
{ {
"name": "docker-setup-buildx", "name": "docker-setup-buildx",
"description": "Set up Docker Buildx", "description": "Set up Docker Buildx",
"main": "src/main.ts", "main": "lib/main.js",
"scripts": { "scripts": {
"build": "ncc build --source-map --minify --license licenses.txt", "build": "tsc && ncc build",
"lint": "yarn run prettier && yarn run eslint", "format": "prettier --write **/*.ts",
"format": "yarn run prettier:fix && yarn run eslint:fix", "format-check": "prettier --check **/*.ts",
"eslint": "eslint --max-warnings=0 .", "test": "jest --coverage",
"eslint:fix": "eslint --fix .", "pre-checkin": "yarn run format && yarn run build"
"prettier": "prettier --check \"./**/*.ts\"",
"prettier:fix": "prettier --write \"./**/*.ts\"",
"test": "jest"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -21,29 +18,33 @@
"docker", "docker",
"buildx" "buildx"
], ],
"author": "Docker Inc.", "author": "Docker",
"contributors": [
{
"name": "CrazyMax",
"url": "https://crazymax.dev"
}
],
"license": "Apache-2.0", "license": "Apache-2.0",
"packageManager": "yarn@3.6.3",
"dependencies": { "dependencies": {
"@actions/core": "^1.11.1", "@actions/core": "^1.2.6",
"@docker/actions-toolkit": "^0.56.0", "@actions/exec": "^1.0.4",
"js-yaml": "^4.1.0" "@actions/http-client": "^1.0.9",
"@actions/tool-cache": "^1.6.1",
"semver": "^7.3.4",
"uuid": "^8.3.2"
}, },
"devDependencies": { "devDependencies": {
"@types/js-yaml": "^4.0.9", "@types/jest": "^26.0.3",
"@types/node": "^20.12.12", "@types/node": "^14.0.14",
"@types/uuid": "^10.0.0", "@vercel/ncc": "^0.23.0",
"@typescript-eslint/eslint-plugin": "^7.9.0", "dotenv": "^8.2.0",
"@typescript-eslint/parser": "^7.9.0", "jest": "^26.1.0",
"@vercel/ncc": "^0.38.1", "jest-circus": "^26.1.0",
"eslint": "^8.57.0", "jest-runtime": "^26.1.0",
"eslint-config-prettier": "^9.1.0", "prettier": "^2.0.5",
"eslint-plugin-jest": "^28.5.0", "ts-jest": "^26.1.1",
"eslint-plugin-prettier": "^5.1.3", "typescript": "^3.9.5",
"jest": "^29.7.0", "typescript-formatter": "^7.2.2"
"prettier": "^3.2.5",
"ts-jest": "^29.1.2",
"ts-node": "^10.9.2",
"typescript": "^5.4.5"
} }
} }

129
src/buildx.ts Normal file
View File

@ -0,0 +1,129 @@
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 exec from './exec';
import * as github from './github';
import * as core from '@actions/core';
import * as tc from '@actions/tool-cache';
export async function getVersion(): Promise<string> {
return await exec.exec(`docker`, ['buildx', 'version'], true).then(res => {
if (res.stderr != '' && !res.success) {
throw new Error(res.stderr);
}
return parseVersion(res.stdout);
});
}
export async function parseVersion(stdout: string): Promise<string> {
const matches = /\sv?([0-9.]+)/.exec(stdout);
if (!matches) {
throw new Error(`Cannot parse Buildx version`);
}
return semver.clean(matches[1]);
}
export async function isAvailable(): Promise<Boolean> {
return await exec.exec(`docker`, ['buildx'], true).then(res => {
if (res.stderr != '' && !res.success) {
return false;
}
return res.success;
});
}
export async function platforms(): Promise<String | undefined> {
return await exec.exec(`docker`, ['buildx', 'inspect'], true).then(res => {
if (res.stderr != '' && !res.success) {
throw new Error(res.stderr);
}
for (const line of res.stdout.trim().split(`\n`)) {
if (line.startsWith('Platforms')) {
return line.replace('Platforms: ', '').replace(/\s/g, '').trim();
}
}
});
}
export async function install(inputVersion: string, dockerConfigHome: string): Promise<string> {
const release: github.GitHubRelease | null = await github.getRelease(inputVersion);
if (!release) {
throw new Error(`Cannot find buildx ${inputVersion} release`);
}
core.debug(`Release found: ${release.tag_name}`);
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);
}
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(path.join(toolPath, filename), 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)
);
let downloadPath: string;
try {
core.info(`⬇️ Downloading ${downloadUrl}...`);
downloadPath = await tc.downloadTool(downloadUrl);
core.debug(`Downloaded to ${downloadPath}`);
} catch (error) {
throw error;
}
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': {
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);
}

View File

@ -1,132 +1,49 @@
import * as crypto from 'crypto'; import * as os from 'os';
import * as core from '@actions/core'; import * as core from '@actions/core';
import {Docker} from '@docker/actions-toolkit/lib/docker/docker'; export const osPlat: string = os.platform();
import {Util} from '@docker/actions-toolkit/lib/util'; export const osArch: string = os.arch();
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit';
import {Node} from '@docker/actions-toolkit/lib/types/buildx/builder';
export const builderNodeEnvPrefix = 'BUILDER_NODE';
const defaultBuildkitdFlags = '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host';
export interface Inputs { export interface Inputs {
version: string; version: string;
name: string;
driver: string; driver: string;
driverOpts: string[]; driverOpts: string[];
buildkitdFlags: string; buildkitdFlags: string;
buildkitdConfig: string;
buildkitdConfigInline: string;
platforms: string[];
install: boolean; install: boolean;
use: boolean; use: boolean;
endpoint: string; endpoint: string;
append: string;
cacheBinary: boolean;
cleanup: boolean;
} }
export async function getInputs(): Promise<Inputs> { export async function getInputs(): Promise<Inputs> {
return { return {
version: core.getInput('version'), version: core.getInput('version'),
name: await getBuilderName(core.getInput('driver') || 'docker-container'),
driver: core.getInput('driver') || 'docker-container', driver: core.getInput('driver') || 'docker-container',
driverOpts: Util.getInputList('driver-opts', {ignoreComma: true, quote: false}), driverOpts: await getInputList('driver-opts', true),
buildkitdFlags: core.getInput('buildkitd-flags'), buildkitdFlags:
platforms: Util.getInputList('platforms'), core.getInput('buildkitd-flags') ||
install: core.getBooleanInput('install'), '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
use: core.getBooleanInput('use'), install: /true/i.test(core.getInput('install')),
endpoint: core.getInput('endpoint'), use: /true/i.test(core.getInput('use')),
buildkitdConfig: core.getInput('buildkitd-config') || core.getInput('config'), endpoint: core.getInput('endpoint')
buildkitdConfigInline: core.getInput('buildkitd-config-inline') || core.getInput('config-inline'),
append: core.getInput('append'),
cacheBinary: core.getBooleanInput('cache-binary'),
cleanup: core.getBooleanInput('cleanup')
}; };
} }
export async function getBuilderName(driver: string): Promise<string> { export async function getInputList(name: string, ignoreComma?: boolean): Promise<string[]> {
return driver == 'docker' ? await Docker.context() : `builder-${crypto.randomUUID()}`; const items = core.getInput(name);
if (items == '') {
return [];
}
return items
.split(/\r?\n/)
.filter(x => x)
.reduce<string[]>(
(acc, line) => acc.concat(!ignoreComma ? line.split(',').filter(x => x) : line).map(pat => pat.trim()),
[]
);
} }
export async function getCreateArgs(inputs: Inputs, toolkit: Toolkit): Promise<Array<string>> { export const asyncForEach = async (array, callback) => {
const args: Array<string> = ['create', '--name', inputs.name, '--driver', inputs.driver]; for (let index = 0; index < array.length; index++) {
if (await toolkit.buildx.versionSatisfies('>=0.3.0')) { await callback(array[index], index, array);
await Util.asyncForEach(inputs.driverOpts, async (driverOpt: string) => {
args.push('--driver-opt', driverOpt);
});
if (inputs.buildkitdFlags) {
args.push('--buildkitd-flags', inputs.buildkitdFlags);
} else if (driverSupportsBuildkitdFlags(inputs.driver)) {
args.push('--buildkitd-flags', defaultBuildkitdFlags);
} }
} };
if (inputs.platforms.length > 0) {
args.push('--platform', inputs.platforms.join(','));
}
if (inputs.use) {
args.push('--use');
}
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);
}
return args;
}
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'] && (await toolkit.buildx.versionSatisfies('>=0.3.0'))) {
await Util.asyncForEach(node['driver-opts'], async (driverOpt: string) => {
args.push('--driver-opt', driverOpt);
});
if (node['buildkitd-flags']) {
args.push('--buildkitd-flags', node['buildkitd-flags']);
} else if (driverSupportsBuildkitdFlags(inputs.driver)) {
args.push('--buildkitd-flags', defaultBuildkitdFlags);
}
}
if (node.platforms) {
args.push('--platform', node.platforms);
}
if (node.endpoint) {
args.push(node.endpoint);
}
return args;
}
export async function getInspectArgs(inputs: Inputs, toolkit: Toolkit): Promise<Array<string>> {
const args: Array<string> = ['inspect', '--bootstrap'];
if (await toolkit.buildx.versionSatisfies('>=0.4.0')) {
args.push('--builder', inputs.name);
}
return args;
}
function driverSupportsBuildkitdFlags(driver: string): boolean {
return driver == '' || driver == 'docker-container' || driver == 'docker' || driver == 'kubernetes';
}
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;
}

7
src/docker.ts Normal file
View File

@ -0,0 +1,7 @@
import * as exec from './exec';
export async function isDaemonRunning(): Promise<boolean> {
return await exec.exec(`docker`, ['version', '--format', '{{.Server.Os}}'], true).then(res => {
return !res.stdout.includes(' ') && res.success;
});
}

34
src/exec.ts Normal file
View File

@ -0,0 +1,34 @@
import * as aexec from '@actions/exec';
import {ExecOptions} from '@actions/exec';
export interface ExecResult {
success: boolean;
stdout: string;
stderr: string;
}
export const exec = async (command: string, args: string[] = [], silent: boolean): Promise<ExecResult> => {
let stdout: string = '';
let stderr: string = '';
const options: ExecOptions = {
silent: silent,
ignoreReturnCode: true
};
options.listeners = {
stdout: (data: Buffer) => {
stdout += data.toString();
},
stderr: (data: Buffer) => {
stderr += data.toString();
}
};
const returnCode: number = await aexec.exec(command, args, options);
return {
success: returnCode === 0,
stdout: stdout.trim(),
stderr: stderr.trim()
};
};

12
src/github.ts Normal file
View File

@ -0,0 +1,12 @@
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: string = `https://github.com/docker/buildx/releases/${version}`;
const http: httpm.HttpClient = new httpm.HttpClient('setup-buildx');
return (await http.getJson<GitHubRelease>(url)).result;
};

View File

@ -1,283 +1,94 @@
import * as crypto from 'crypto';
import * as fs from 'fs';
import * as yaml from 'js-yaml';
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as actionsToolkit from '@docker/actions-toolkit'; import * as exec from '@actions/exec';
import * as os from 'os';
import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx'; import * as path from 'path';
import {Builder} from '@docker/actions-toolkit/lib/buildx/builder'; import * as semver from 'semver';
import {Docker} from '@docker/actions-toolkit/lib/docker/docker'; import * as buildx from './buildx';
import {Exec} from '@docker/actions-toolkit/lib/exec';
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit';
import {Util} from '@docker/actions-toolkit/lib/util';
import {Node} from '@docker/actions-toolkit/lib/types/buildx/builder';
import {ContextInfo} from '@docker/actions-toolkit/lib/types/docker/docker';
import * as context from './context'; import * as context from './context';
import * as mexec from './exec';
import * as stateHelper from './state-helper'; import * as stateHelper from './state-helper';
actionsToolkit.run( async function run(): Promise<void> {
// main
async () => {
const inputs: context.Inputs = await context.getInputs();
stateHelper.setCleanup(inputs.cleanup);
const version = context.getVersion(inputs);
const toolkit = new Toolkit();
const standalone = await toolkit.buildx.isStandalone();
stateHelper.setStandalone(standalone);
await core.group(`Docker info`, async () => {
try { try {
await Docker.printVersion(); if (os.platform() !== 'linux') {
await Docker.printInfo(); core.setFailed('Only supported on linux platform');
} 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`);
}
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 || 'latest', !inputs.cacheBinary);
});
}
if (toolPath) {
await core.group(`Install buildx`, async () => {
if (standalone) {
await toolkit.buildxInstall.installStandalone(toolPath);
} else {
await toolkit.buildxInstall.installPlugin(toolPath);
}
});
}
await core.group(`Buildx version`, async () => {
await toolkit.buildx.printVersion();
});
core.setOutput('name', inputs.name);
stateHelper.setBuilderName(inputs.name);
stateHelper.setBuilderDriver(inputs.driver);
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') {
await core.group(`Creating a new builder instance`, async () => {
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) {
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++;
}
});
}
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`);
}
await core.group(`Setting buildx as default builder`, async () => {
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');
}
});
});
}
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);
}
}
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 && 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');
}
},
// 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');
}
});
});
}
if (!stateHelper.cleanup) {
return; return;
} }
if (stateHelper.builderDriver != 'docker' && stateHelper.builderName.length > 0) { const inputs: context.Inputs = await context.getInputs();
await core.group(`Removing builder`, async () => { const dockerConfigHome: string = process.env.DOCKER_CONFIG || path.join(os.homedir(), '.docker');
const buildx = new Buildx({standalone: stateHelper.standalone});
const builder = new Builder({buildx: buildx}); if (!(await buildx.isAvailable()) || inputs.version) {
if (await builder.exists(stateHelper.builderName)) { core.startGroup(`👉 Installing Buildx`);
const rmCmd = await buildx.getCommand(['rm', stateHelper.builderName]); await buildx.install(inputs.version || 'latest', dockerConfigHome);
await Exec.getExecOutput(rmCmd.command, rmCmd.args, { core.endGroup();
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`);
}
});
} }
if (stateHelper.tmpDockerContext) { const buildxVersion = await buildx.getVersion();
await core.group(`Removing temp docker context`, async () => { core.info(`📣 Buildx version: ${buildxVersion}`);
await Exec.getExecOutput('docker', ['context', 'rm', '-f', stateHelper.tmpDockerContext], {
ignoreReturnCode: true const builderName: string = inputs.driver == 'docker' ? 'default' : `builder-${require('uuid').v4()}`;
}).then(res => { core.setOutput('name', builderName);
if (res.stderr.length > 0 && res.exitCode != 0) { stateHelper.setBuilderName(builderName);
core.warning(`${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
if (inputs.driver !== 'docker') {
core.startGroup(`🔨 Creating a new builder instance`);
let createArgs: Array<string> = ['buildx', 'create', '--name', builderName, '--driver', inputs.driver];
if (semver.satisfies(buildxVersion, '>=0.3.0')) {
await context.asyncForEach(inputs.driverOpts, async driverOpt => {
createArgs.push('--driver-opt', driverOpt);
});
if (inputs.buildkitdFlags) {
createArgs.push('--buildkitd-flags', inputs.buildkitdFlags);
} }
}); }
}); if (inputs.use) {
createArgs.push('--use');
}
if (inputs.endpoint) {
createArgs.push(inputs.endpoint);
}
await exec.exec('docker', createArgs);
core.endGroup();
core.startGroup(`🏃 Booting builder`);
let bootstrapArgs: Array<string> = ['buildx', 'inspect', '--bootstrap'];
if (semver.satisfies(buildxVersion, '>=0.4.0')) {
bootstrapArgs.push('--builder', builderName);
}
await exec.exec('docker', bootstrapArgs);
core.endGroup();
} }
if (stateHelper.certsDir.length > 0 && fs.existsSync(stateHelper.certsDir)) { if (inputs.install) {
await core.group(`Cleaning up certificates`, async () => { core.startGroup(`🤝 Setting buildx as default builder`);
fs.rmSync(stateHelper.certsDir, {recursive: true}); await exec.exec('docker', ['buildx', 'install']);
core.endGroup();
}
core.startGroup(`🛒 Extracting available platforms`);
const platforms = await buildx.platforms();
core.info(`${platforms}`);
core.setOutput('platforms', platforms);
core.endGroup();
} catch (error) {
core.setFailed(error.message);
}
}
async function cleanup(): Promise<void> {
if (stateHelper.builderName.length == 0) {
return;
}
await mexec.exec('docker', ['buildx', 'rm', `${stateHelper.builderName}`], false).then(res => {
if (res.stderr != '' && !res.success) {
core.warning(res.stderr);
}
}); });
} }
}
); if (!stateHelper.IsPost) {
run();
} else {
cleanup();
}

View File

@ -1,42 +1,12 @@
import * as core from '@actions/core'; import * as core from '@actions/core';
export const IsDebug = !!process.env['STATE_isDebug']; export const IsPost = !!process.env['STATE_isPost'];
export const standalone = /true/i.test(process.env['STATE_standalone'] || '');
export const builderName = process.env['STATE_builderName'] || ''; export const builderName = process.env['STATE_builderName'] || '';
export const builderDriver = process.env['STATE_builderDriver'] || '';
export const containerName = process.env['STATE_containerName'] || '';
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 function setDebug(debug: string) {
core.saveState('isDebug', debug);
}
export function setStandalone(standalone: boolean) {
core.saveState('standalone', standalone);
}
export function setBuilderName(builderName: string) { export function setBuilderName(builderName: string) {
core.saveState('builderName', builderName); core.saveState('builderName', builderName);
} }
export function setBuilderDriver(builderDriver: string) { if (!IsPost) {
core.saveState('builderDriver', builderDriver); core.saveState('isPost', 'true');
}
export function setContainerName(containerName: string) {
core.saveState('containerName', containerName);
}
export function setCertsDir(certsDir: string) {
core.saveState('certsDir', certsDir);
}
export function setTmpDockerContext(tmpDockerContext: string) {
core.saveState('tmpDockerContext', tmpDockerContext);
}
export function setCleanup(cleanup: boolean) {
core.saveState('cleanup', cleanup);
} }

View File

@ -1,21 +1,18 @@
{ {
"compilerOptions": { "compilerOptions": {
"esModuleInterop": true,
"target": "es6", "target": "es6",
"module": "commonjs", "module": "commonjs",
"strict": true, "lib": [
"es6",
"dom"
],
"newLine": "lf", "newLine": "lf",
"outDir": "./lib", "outDir": "./lib",
"rootDir": "./src", "rootDir": "./src",
"forceConsistentCasingInFileNames": true, "strict": true,
"noImplicitAny": false, "noImplicitAny": false,
"resolveJsonModule": true, "esModuleInterop": true,
"useUnknownInCatchVariables": false, "sourceMap": true
}, },
"exclude": [ "exclude": ["node_modules", "**/*.test.ts"]
"./__tests__/**/*",
"./lib/**/*",
"node_modules",
"jest.config.ts"
]
} }

10569
yarn.lock

File diff suppressed because it is too large Load Diff