Compare commits

..

No commits in common. "master" and "v3.2.0" have entirely different histories.

41 changed files with 6493 additions and 6025 deletions

View File

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

3
.eslintignore Normal file
View File

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

24
.eslintrc.json Normal file
View File

@ -0,0 +1,24 @@
{
"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

View File

@ -4,12 +4,6 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
cooldown:
default-days: 2
groups:
crazy-max-dot-github:
patterns:
- "crazy-max/.github/*"
labels: labels:
- "dependencies" - "dependencies"
- "bot" - "bot"
@ -17,8 +11,6 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
cooldown:
default-days: 2
versioning-strategy: "increase" versioning-strategy: "increase"
allow: allow:
- dependency-type: "production" - dependency-type: "production"

View File

@ -1,14 +1,10 @@
name: ci name: ci
permissions:
contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
on: on:
workflow_dispatch:
schedule: schedule:
- cron: '0 10 * * *' - cron: '0 10 * * *'
push: push:
@ -29,13 +25,12 @@ jobs:
- "" - ""
- "latest" - "latest"
- "v0.4.1" - "v0.4.1"
- "cloud:latest"
- "cloud:v0.11.2-desktop.2"
- "lab:latest" - "lab:latest"
- "lab:v0.11.2-desktop.2"
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Set up Docker Buildx name: Set up Docker Buildx
id: buildx id: buildx
@ -54,7 +49,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Set up Docker Buildx 1 name: Set up Docker Buildx 1
uses: ./ uses: ./
@ -67,7 +62,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Stop docker name: Stop docker
run: | run: |
@ -88,14 +83,14 @@ jobs:
- -
name: Dump context name: Dump context
if: always() if: always()
uses: crazy-max/ghaction-dump-context@5d2753e7076f4568c7729971e25231f32147e2d8 # v3.0.0 uses: crazy-max/ghaction-dump-context@v2
debug: debug:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Create Dockerfile name: Create Dockerfile
run: | run: |
@ -105,7 +100,7 @@ jobs:
EOL EOL
- -
name: Set up QEMU name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 uses: docker/setup-qemu-action@v3
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: ./ uses: ./
@ -113,11 +108,27 @@ jobs:
buildkitd-flags: --debug buildkitd-flags: --debug
- -
name: Build name: Build
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 uses: docker/build-push-action@v5
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64,linux/ppc64le platforms: linux/amd64,linux/arm64,linux/ppc64le
install:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: ./
with:
install: true
-
name: Check cmd
run: |
docker build --help
use: use:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@ -129,7 +140,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: ./ uses: ./
@ -152,7 +163,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: ./ uses: ./
@ -165,7 +176,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: ./ uses: ./
@ -184,7 +195,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
services: services:
dind: dind:
image: docker:29.3-dind@sha256:4d90f1f6c400315c2dba96d3ec93c01e64198395cbba04f79d12adce4f737029 image: docker:dind
options: >- options: >-
--privileged --privileged
--health-cmd "docker info" --health-cmd "docker info"
@ -198,7 +209,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Create context name: Create context
run: | run: |
@ -215,12 +226,12 @@ jobs:
env: env:
DOCKER_CONTEXT: mycontext DOCKER_CONTEXT: mycontext
buildkitd-config: config:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Create buildkitd conf name: Create buildkitd conf
run: | run: |
@ -243,16 +254,16 @@ jobs:
buildkitd-config: /tmp/buildkitd.toml buildkitd-config: /tmp/buildkitd.toml
- -
name: Build name: Build
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 uses: docker/build-push-action@v5
with: with:
context: . context: .
buildkitd-config-inline: config-inline:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Create Dockerfile name: Create Dockerfile
run: | run: |
@ -270,7 +281,7 @@ jobs:
mirrors = ["mirror.gcr.io"] mirrors = ["mirror.gcr.io"]
- -
name: Build name: Build
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 uses: docker/build-push-action@v5
with: with:
context: . context: .
@ -288,10 +299,10 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Set up QEMU name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 uses: docker/setup-qemu-action@v3
with: with:
platforms: ${{ matrix.qemu-platforms }} platforms: ${{ matrix.qemu-platforms }}
- -
@ -317,7 +328,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: ./ uses: ./
@ -331,7 +342,7 @@ jobs:
EOL EOL
- -
name: Build name: Build
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 uses: docker/build-push-action@master
with: with:
context: . context: .
@ -340,7 +351,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Uninstall docker cli name: Uninstall docker cli
run: | run: |
@ -368,7 +379,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Uninstall docker cli name: Uninstall docker cli
run: | run: |
@ -390,16 +401,46 @@ jobs:
EOL EOL
- -
name: Build name: Build
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 uses: docker/build-push-action@master
with: with:
context: . 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: append:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Create dummy contexts name: Create dummy contexts
run: | run: |
@ -428,10 +469,10 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Set up QEMU name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 uses: docker/setup-qemu-action@v3
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: ./ uses: ./
@ -443,7 +484,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Create Docker context name: Create Docker context
run: | run: |
@ -466,7 +507,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: ./ uses: ./
@ -474,21 +515,22 @@ jobs:
cleanup: ${{ matrix.cleanup }} cleanup: ${{ matrix.cleanup }}
k3s: k3s:
runs-on: ubuntu-latest runs-on: ubuntu-20.04
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
version: version:
- latest
- v0.11.0 - v0.11.0
- v0.10.5 - v0.10.5
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Install k3s name: Install k3s
uses: crazy-max/.github/.github/actions/install-k3s@bb328ea508cd6a89d0865555ddbeb148e5724aed # v1.3.0 uses: crazy-max/.github/.github/actions/install-k3s@605d30d5ae97f6680578ace4b56645af79343e60
with:
version: "v1.21.2-k3s1"
- -
name: Set up Docker Buildx name: Set up Docker Buildx
id: buildx id: buildx
@ -518,7 +560,7 @@ jobs:
EOL EOL
- -
name: Build name: Build
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 uses: docker/build-push-action@master
with: with:
context: . context: .
@ -533,73 +575,10 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: ./ uses: ./
with: with:
version: v0.11.2 version: v0.11.2
cache-binary: ${{ matrix.cache }} cache-binary: ${{ matrix.cache }}
windows-error:
runs-on: windows-latest
steps:
-
name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
-
name: Set up Docker Buildx
id: buildx
continue-on-error: true
uses: ./
-
name: Check
run: |
echo "${{ toJson(steps.buildx) }}"
if [ "${{ steps.buildx.outcome }}" != "failure" ] || [ "${{ steps.buildx.conclusion }}" != "success" ]; then
echo "::error::Should have failed"
exit 1
fi
shell: bash
keep-state:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
-
name: Set up Docker Buildx
uses: ./
with:
name: foo
keep-state: true
-
name: Set up Docker Buildx
uses: ./
with:
name: foo
keep-state: true
keep-state-error:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
-
name: Set up Docker Buildx
id: buildx
continue-on-error: true
uses: ./
with:
driver: docker
keep-state: true
-
name: Check
run: |
echo "${{ toJson(steps.buildx) }}"
if [ "${{ steps.buildx.outcome }}" != "failure" ] || [ "${{ steps.buildx.conclusion }}" != "success" ]; then
echo "::error::Should have failed"
exit 1
fi

View File

@ -1,46 +0,0 @@
name: codeql
permissions:
contents: read
on:
push:
branches:
- 'master'
- 'releases/v*'
pull_request:
env:
NODE_VERSION: "24"
jobs:
analyze:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
-
name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
-
name: Enable corepack
run: |
corepack enable
yarn --version
-
name: Set up Node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: ${{ env.NODE_VERSION }}
-
name: Initialize CodeQL
uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
with:
languages: javascript-typescript
build-mode: none
-
name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
with:
category: "/language:javascript-typescript"

View File

@ -1,17 +0,0 @@
name: pr-assign-author
permissions:
contents: read
on:
pull_request_target: # zizmor: ignore[dangerous-triggers] safe to use without checkout
types:
- opened
- reopened
jobs:
run:
uses: crazy-max/.github/.github/workflows/pr-assign-author.yml@bb328ea508cd6a89d0865555ddbeb148e5724aed # v1.3.0
permissions:
contents: read
pull-requests: write

View File

@ -1,28 +0,0 @@
name: publish
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
release:
types:
- published
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
packages: write
steps:
-
name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
-
name: Publish
uses: actions/publish-immutable-action@4bc8754ffc40f27910afb20287dbbbb675a4e978 # v0.0.4

View File

@ -1,8 +1,5 @@
name: test name: test
permissions:
contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
@ -20,19 +17,18 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: ./ uses: ./
- -
name: Test name: Test
uses: docker/bake-action@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0 uses: docker/bake-action@v4
with: with:
source: .
targets: test targets: test
- -
name: Upload coverage name: Upload coverage
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 uses: codecov/codecov-action@v4
with: with:
files: ./coverage/clover.xml file: ./coverage/clover.xml
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}

View File

@ -1,56 +0,0 @@
name: update-dist
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
pull_request:
types:
- opened
- synchronize
jobs:
update-dist:
if: github.actor == 'dependabot[bot]' && github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == github.event.pull_request.head.repo.full_name
runs-on: ubuntu-latest
steps:
-
name: GitHub auth token from GitHub App
id: docker-read-app
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
with:
app-id: ${{ secrets.GHACTIONS_REPO_WRITE_APP_ID }}
private-key: ${{ secrets.GHACTIONS_REPO_WRITE_APP_PRIVATE_KEY }}
owner: docker
-
name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
token: ${{ steps.docker-read-app.outputs.token }}
-
name: Build
uses: docker/bake-action@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0
with:
source: .
targets: build
-
name: Commit and push dist
run: |
if [ -n "$(git status --porcelain -- dist)" ]; then
(
set -x
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add dist
git commit -m "chore: update generated content"
git push
)
else
echo "No changes in dist"
fi

View File

@ -1,8 +1,5 @@
name: validate name: validate
permissions:
contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
@ -18,17 +15,16 @@ jobs:
prepare: prepare:
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
matrix: ${{ steps.generate.outputs.matrix }} targets: ${{ steps.targets.outputs.matrix }}
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Generate matrix name: Targets matrix
id: generate id: targets
uses: docker/bake-action/subaction/matrix@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0 run: |
with: echo "matrix=$(docker buildx bake validate --print | jq -cr '.group.validate.targets')" >> $GITHUB_OUTPUT
target: validate
validate: validate:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -37,10 +33,13 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
include: ${{ fromJson(needs.prepare.outputs.matrix) }} target: ${{ fromJson(needs.prepare.outputs.targets) }}
steps: steps:
-
name: Checkout
uses: actions/checkout@v4
- -
name: Validate name: Validate
uses: docker/bake-action@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0 uses: docker/bake-action@v4
with: with:
targets: ${{ matrix.target }} targets: ${{ matrix.target }}

View File

@ -1,29 +0,0 @@
name: zizmor
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
workflow_dispatch:
push:
branches:
- 'master'
- 'releases/v*'
tags:
- 'v*'
pull_request:
jobs:
zizmor:
uses: crazy-max/.github/.github/workflows/zizmor.yml@bb328ea508cd6a89d0865555ddbeb148e5724aed # v1.3.0
permissions:
contents: read
security-events: write
with:
min-severity: medium
min-confidence: medium
persona: pedantic

3
.github/zizmor.yml vendored
View File

@ -1,3 +0,0 @@
rules:
secrets-outside-env: # FIXME: remove this rule when zizmor 1.24.0 is released, fixing the right persona attached to this rule: https://github.com/zizmorcore/zizmor/pull/1783
disable: true

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

@ -6,5 +6,6 @@
"singleQuote": true, "singleQuote": true,
"trailingComma": "none", "trailingComma": "none",
"bracketSpacing": false, "bracketSpacing": false,
"arrowParens": "avoid" "arrowParens": "avoid",
"parser": "typescript"
} }

View File

@ -1,17 +0,0 @@
# https://yarnpkg.com/configuration/yarnrc
compressionLevel: mixed
enableGlobalCache: false
enableHardenedMode: true
logFilters:
- code: YN0013
level: discard
- code: YN0019
level: discard
- code: YN0076
level: discard
- code: YN0086
level: discard
nodeLinker: node-modules

View File

@ -40,14 +40,17 @@ jobs:
buildx: buildx:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
-
name: Checkout
uses: actions/checkout@v4
- -
# Add support for more platforms with QEMU (optional) # Add support for more platforms with QEMU (optional)
# https://github.com/docker/setup-qemu-action # https://github.com/docker/setup-qemu-action
name: Set up QEMU name: Set up QEMU
uses: docker/setup-qemu-action@v4 uses: docker/setup-qemu-action@v3
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@v3
``` ```
## Configuring your builder ## Configuring your builder
@ -83,29 +86,22 @@ The following inputs can be used as `step.with` keys:
> ``` > ```
| Name | Type | Default | Description | | 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`) | | `version` | String | | [Buildx](https://github.com/docker/buildx) version. (eg. `v0.3.0`, `latest`, `https://github.com/docker/buildx.git#master`) |
| `name` | String | | Name of the builder. If not specified, one will be generated or if it already exists, it will be used instead of creating a new one |
| `driver` | String | `docker-container` | Sets the [builder driver](https://docs.docker.com/engine/reference/commandline/buildx_create/#driver) to be used | | `driver` | 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`) | | `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-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` \* | 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 | | `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 | | `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` | | `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 | | `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 | | `append` | YAML | | [Append additional nodes](https://docs.docker.com/build/ci/github-actions/configure-builder/#append-additional-nodes-to-the-builder) to the builder |
| `keep-state` | Bool | `false` | Keep BuildKit state on `cleanup`. This is only useful on persistent self-hosted runners |
| `cache-binary` | Bool | `true` | Cache buildx binary to GitHub Actions cache backend | | `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 | | `cleanup` | Bool | `true` | Cleanup temp files and remove builder at the end of a job |
> [!IMPORTANT] _\* `buildkitd-config` and `buildkitd-config-inline` are mutually exclusive_
> 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
@ -130,6 +126,23 @@ The following [official docker environment variables](https://docs.docker.com/en
### `nodes` output ### `nodes` output
```json
[
{
"name": "builder-3820d274-502c-4498-ae24-d4c32b3023d90",
"endpoint": "unix:///var/run/docker.sock",
"driver-opts": [
"network=host",
"image=moby/buildkit:master"
],
"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 | | Name | Type | Description |
|-------------------|--------|----------------------------| |-------------------|--------|----------------------------|
| `name` | String | Node name | | `name` | String | Node name |
@ -140,21 +153,6 @@ The following [official docker environment variables](https://docs.docker.com/en
| `buildkit` | String | BuildKit version | | `buildkit` | String | BuildKit version |
| `platforms` | String | Platforms available | | `platforms` | String | Platforms available |
Example:
```json
[
{
"name": "builder-8fa135e1-9bce-4a29-9368-46a09a1d750d0",
"endpoint": "unix:///var/run/docker.sock",
"status": "running",
"buildkitd-flags": "--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host",
"buildkit": "v0.27.1",
"platforms": "linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/386"
}
]
```
## Contributing ## Contributing
Want to contribute? Awesome! You can find information about contributing to Want to contribute? Awesome! You can find information about contributing to

View File

@ -1,40 +1,35 @@
import {beforeEach, describe, expect, test, vi} from 'vitest'; import {beforeEach, describe, expect, jest, test} from '@jest/globals';
import * as fs from 'fs'; import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
import * as uuid from 'uuid';
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/builder';
import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx.js'; import * as context from '../src/context';
import {Context} from '@docker/actions-toolkit/lib/context.js';
import {Docker} from '@docker/actions-toolkit/lib/docker/docker.js';
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit.js';
import {Node} from '@docker/actions-toolkit/lib/types/buildx/builder.js';
import * as context from '../src/context.js';
const fixturesDir = path.join(__dirname, 'fixtures'); const fixturesDir = path.join(__dirname, 'fixtures');
const tmpDir = fs.mkdtempSync(path.join(process.env.TEMP || os.tmpdir(), 'context-')); // prettier-ignore
const tmpName = path.join(tmpDir, '.tmpname-vi'); const tmpDir = path.join(process.env.TEMP || '/tmp', 'setup-buildx-jest');
const tmpName = path.join(tmpDir, '.tmpname-jest');
vi.spyOn(Context, 'tmpDir').mockImplementation((): string => { jest.spyOn(Context, 'tmpDir').mockImplementation((): string => {
if (!fs.existsSync(tmpDir)) { if (!fs.existsSync(tmpDir)) {
fs.mkdirSync(tmpDir, {recursive: true}); fs.mkdirSync(tmpDir, {recursive: true});
} }
return tmpDir; return tmpDir;
}); });
vi.spyOn(Context, 'tmpName').mockImplementation((): string => { jest.spyOn(Context, 'tmpName').mockImplementation((): string => {
return tmpName; return tmpName;
}); });
vi.mock('crypto', async () => { jest.mock('uuid');
return { jest.spyOn(uuid, 'v4').mockReturnValue('9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d');
...(await vi.importActual('crypto')),
randomUUID: vi.fn(() => '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d')
};
});
vi.spyOn(Docker, 'context').mockImplementation((): Promise<string> => { jest.spyOn(Docker, 'context').mockImplementation((): Promise<string> => {
return Promise.resolve('default'); return Promise.resolve('default');
}); });
@ -54,10 +49,10 @@ describe('getCreateArgs', () => {
0, 0,
'v0.10.3', 'v0.10.3',
new Map<string, string>([ new Map<string, string>([
['install', 'false'],
['use', 'true'], ['use', 'true'],
['cache-binary', 'true'], ['cache-binary', 'true'],
['cleanup', 'true'], ['cleanup', 'true'],
['keep-state', 'false']
]), ]),
[ [
'create', 'create',
@ -72,10 +67,10 @@ describe('getCreateArgs', () => {
'v0.10.3', 'v0.10.3',
new Map<string, string>([ new Map<string, string>([
['driver', 'docker'], ['driver', 'docker'],
['install', 'false'],
['use', 'true'], ['use', 'true'],
['cache-binary', 'true'], ['cache-binary', 'true'],
['cleanup', 'true'], ['cleanup', 'true'],
['keep-state', 'false']
]), ]),
[ [
'create', 'create',
@ -89,11 +84,11 @@ describe('getCreateArgs', () => {
2, 2,
'v0.10.3', 'v0.10.3',
new Map<string, string>([ new Map<string, string>([
['install', 'false'],
['use', 'false'], ['use', 'false'],
['driver-opts', 'image=moby/buildkit:master\nnetwork=host'], ['driver-opts', 'image=moby/buildkit:master\nnetwork=host'],
['cache-binary', 'true'], ['cache-binary', 'true'],
['cleanup', 'true'], ['cleanup', 'true'],
['keep-state', 'false']
]), ]),
[ [
'create', 'create',
@ -110,10 +105,10 @@ describe('getCreateArgs', () => {
new Map<string, string>([ new Map<string, string>([
['driver', 'remote'], ['driver', 'remote'],
['endpoint', 'tls://foo:1234'], ['endpoint', 'tls://foo:1234'],
['install', 'false'],
['use', 'true'], ['use', 'true'],
['cache-binary', 'true'], ['cache-binary', 'true'],
['cleanup', 'true'], ['cleanup', 'true'],
['keep-state', 'false']
]), ]),
[ [
'create', 'create',
@ -130,10 +125,10 @@ describe('getCreateArgs', () => {
['driver', 'remote'], ['driver', 'remote'],
['platforms', 'linux/arm64,linux/arm/v7'], ['platforms', 'linux/arm64,linux/arm/v7'],
['endpoint', 'tls://foo:1234'], ['endpoint', 'tls://foo:1234'],
['install', 'false'],
['use', 'true'], ['use', 'true'],
['cache-binary', 'true'], ['cache-binary', 'true'],
['cleanup', 'true'], ['cleanup', 'true'],
['keep-state', 'false']
]), ]),
[ [
'create', 'create',
@ -148,11 +143,11 @@ describe('getCreateArgs', () => {
5, 5,
'v0.10.3', 'v0.10.3',
new Map<string, string>([ new Map<string, string>([
['install', 'false'],
['use', 'false'], ['use', 'false'],
['driver-opts', `"env.no_proxy=localhost,127.0.0.1,.mydomain"`], ['driver-opts', `"env.no_proxy=localhost,127.0.0.1,.mydomain"`],
['cache-binary', 'true'], ['cache-binary', 'true'],
['cleanup', 'true'], ['cleanup', 'true'],
['keep-state', 'false'],
]), ]),
[ [
'create', 'create',
@ -166,11 +161,11 @@ describe('getCreateArgs', () => {
6, 6,
'v0.10.3', 'v0.10.3',
new Map<string, string>([ new Map<string, string>([
['install', 'false'],
['use', 'false'], ['use', 'false'],
['platforms', 'linux/amd64\n"linux/arm64,linux/arm/v7"'], ['platforms', 'linux/amd64\n"linux/arm64,linux/arm/v7"'],
['cache-binary', 'true'], ['cache-binary', 'true'],
['cleanup', 'true'], ['cleanup', 'true'],
['keep-state', 'false'],
]), ]),
[ [
'create', 'create',
@ -184,11 +179,11 @@ describe('getCreateArgs', () => {
7, 7,
'v0.10.3', 'v0.10.3',
new Map<string, string>([ new Map<string, string>([
['install', 'false'],
['use', 'false'], ['use', 'false'],
['driver', 'unknown'], ['driver', 'unknown'],
['cache-binary', 'true'], ['cache-binary', 'true'],
['cleanup', 'true'], ['cleanup', 'true'],
['keep-state', 'false'],
]), ]),
[ [
'create', 'create',
@ -200,11 +195,11 @@ describe('getCreateArgs', () => {
8, 8,
'v0.10.3', 'v0.10.3',
new Map<string, string>([ new Map<string, string>([
['install', 'false'],
['use', 'false'], ['use', 'false'],
['buildkitd-config', path.join(fixturesDir, 'buildkitd.toml')], ['buildkitd-config', path.join(fixturesDir, 'buildkitd.toml')],
['cache-binary', 'true'], ['cache-binary', 'true'],
['cleanup', 'true'], ['cleanup', 'true'],
['keep-state', 'false'],
]), ]),
[ [
'create', 'create',
@ -218,11 +213,11 @@ describe('getCreateArgs', () => {
9, 9,
'v0.10.3', 'v0.10.3',
new Map<string, string>([ new Map<string, string>([
['install', 'false'],
['use', 'false'], ['use', 'false'],
['buildkitd-config-inline', 'debug = true'], ['buildkitd-config-inline', 'debug = true'],
['cache-binary', 'true'], ['cache-binary', 'true'],
['cleanup', 'true'], ['cleanup', 'true'],
['keep-state', 'false'],
]), ]),
[ [
'create', 'create',
@ -231,69 +226,15 @@ describe('getCreateArgs', () => {
'--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host', '--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
'--config', tmpName, '--config', tmpName,
] ]
],
[
10,
'v0.10.3',
new Map<string, string>([
['use', 'false'],
['driver', 'cloud'],
['buildkitd-flags', '--allow-insecure-entitlement network.host'],
['cache-binary', 'true'],
['cleanup', 'true'],
['keep-state', 'false'],
]),
[
'create',
'--name', 'builder-9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d',
'--driver', 'cloud',
'--buildkitd-flags', '--allow-insecure-entitlement network.host',
] ]
],
[
11,
'v0.10.3',
new Map<string, string>([
['use', 'true'],
['cleanup', 'true'],
['cache-binary', 'true'],
['keep-state', 'false'],
['name', 'test-builder-name'],
]),
[
'create',
'--name', 'test-builder-name',
'--driver', 'docker-container',
'--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
'--use'
]
],
[
12,
'v0.10.3',
new Map<string, string>([
['use', 'true'],
['cleanup', 'true'],
['cache-binary', 'true'],
['keep-state', 'true'],
['name', 'test-builder-name'],
]),
[
'create',
'--name', 'test-builder-name',
'--driver', 'docker-container',
'--buildkitd-flags', '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
'--use',
]
],
])( ])(
'[%d] given buildx %o and %o as inputs, returns %o', '[%d] given buildx %s and %p as inputs, returns %p',
async (num: number, buildxVersion: string, inputs: Map<string, string>, expected: Array<string>) => { async (num: number, buildxVersion: string, inputs: Map<string, string>, expected: Array<string>) => {
inputs.forEach((value: string, name: string) => { inputs.forEach((value: string, name: string) => {
setInput(name, value); setInput(name, value);
}); });
const toolkit = new Toolkit(); const toolkit = new Toolkit();
vi.spyOn(Buildx.prototype, 'version').mockImplementation(async (): Promise<string> => { jest.spyOn(Buildx.prototype, 'version').mockImplementation(async (): Promise<string> => {
return buildxVersion; return buildxVersion;
}); });
const inp = await context.getInputs(); const inp = await context.getInputs();
@ -319,10 +260,10 @@ describe('getAppendArgs', () => {
0, 0,
'v0.10.3', 'v0.10.3',
new Map<string, string>([ new Map<string, string>([
['install', 'false'],
['use', 'true'], ['use', 'true'],
['cache-binary', 'true'], ['cache-binary', 'true'],
['cleanup', 'true'], ['cleanup', 'true'],
['keep-state', 'false']
]), ]),
{ {
"name": "aws_graviton2", "name": "aws_graviton2",
@ -345,13 +286,13 @@ describe('getAppendArgs', () => {
] ]
] ]
])( ])(
'[%d] given buildx %o and %o as inputs, returns %o', '[%d] given buildx %s and %p as inputs, returns %p',
async (num: number, buildxVersion: string, inputs: Map<string, string>, node: Node, expected: Array<string>) => { async (num: number, buildxVersion: string, inputs: Map<string, string>, node: Node, expected: Array<string>) => {
inputs.forEach((value: string, name: string) => { inputs.forEach((value: string, name: string) => {
setInput(name, value); setInput(name, value);
}); });
const toolkit = new Toolkit(); const toolkit = new Toolkit();
vi.spyOn(Buildx.prototype, 'version').mockImplementation(async (): Promise<string> => { jest.spyOn(Buildx.prototype, 'version').mockImplementation(async (): Promise<string> => {
return buildxVersion; return buildxVersion;
}); });
const inp = await context.getInputs(); const inp = await context.getInputs();
@ -361,140 +302,6 @@ describe('getAppendArgs', () => {
); );
}); });
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
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true'],
['keep-state', 'false']
]),
''
],
[
1,
new Map<string, string>([
['version', 'latest'],
// defaults
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true'],
['keep-state', 'false']
]),
'latest'
],
[
2,
new Map<string, string>([
['version', 'edge'],
// defaults
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true'],
['keep-state', 'false']
]),
'edge'
],
[
3,
new Map<string, string>([
['version', 'v0.19.2'],
// defaults
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true'],
['keep-state', 'false']
]),
'v0.19.2'
],
[
4,
new Map<string, string>([
['version', 'latest'],
['driver', 'cloud'],
// defaults
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true'],
['keep-state', 'false']
]),
'cloud:latest'
],
[
5,
new Map<string, string>([
['version', 'edge'],
['driver', 'cloud'],
// defaults
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true'],
['keep-state', 'false']
]),
'cloud:edge'
],
[
6,
new Map<string, string>([
['driver', 'cloud'],
// defaults
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true'],
['keep-state', 'false']
]),
'cloud:latest'
],
[
7,
new Map<string, string>([
['version', 'cloud:v0.11.2-desktop.2'],
['driver', 'cloud'],
// defaults
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true'],
['keep-state', 'false']
]),
'cloud:v0.11.2-desktop.2'
],
[
8,
new Map<string, string>([
['version', 'cloud:v0.11.2-desktop.2'],
// defaults
['use', 'true'],
['cache-binary', 'true'],
['cleanup', 'true'],
['keep-state', 'false']
]),
'cloud:v0.11.2-desktop.2'
],
])(
'[%d] given %o as inputs, returns version %o',
async (num: number, inputs: Map<string, string>, expected: string) => {
inputs.forEach((value: string, name: string) => {
setInput(name, value);
});
const inp = await context.getInputs();
expect(context.getVersion(inp)).toEqual(expected);
}
);
});
// See: https://github.com/actions/toolkit/blob/master/packages/core/src/core.ts#L67 // See: https://github.com/actions/toolkit/blob/master/packages/core/src/core.ts#L67
function getInputName(name: string): string { function getInputName(name: string): string {
return `INPUT_${name.replace(/ /g, '_').toUpperCase()}`; return `INPUT_${name.replace(/ /g, '_').toUpperCase()}`;

View File

@ -1,12 +0,0 @@
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-setup-buildx-action-'));
process.env = Object.assign({}, process.env, {
TEMP: tmpDir,
GITHUB_REPOSITORY: 'docker/setup-buildx-action',
RUNNER_TEMP: path.join(tmpDir, 'runner-temp'),
RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache')
});

View File

@ -19,6 +19,7 @@ inputs:
required: false required: false
buildkitd-flags: buildkitd-flags:
description: 'BuildKit daemon flags' description: 'BuildKit daemon flags'
default: '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host'
required: false required: false
buildkitd-config: buildkitd-config:
description: 'BuildKit daemon config file' description: 'BuildKit daemon config file'
@ -26,13 +27,14 @@ inputs:
buildkitd-config-inline: buildkitd-config-inline:
description: 'Inline BuildKit daemon config' description: 'Inline BuildKit daemon config'
required: false required: false
install:
description: 'Sets up docker build command as an alias to docker buildx build'
default: 'false'
required: false
use: use:
description: 'Switch to this builder instance' description: 'Switch to this builder instance'
default: 'true' default: 'true'
required: false required: false
name:
description: 'Name of the builder. If not specified, one will be generated or if it already exists, it will be used instead of creating a new one.'
required: false
endpoint: 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
@ -42,10 +44,6 @@ inputs:
append: append:
description: 'Append additional nodes to the builder' description: 'Append additional nodes to the builder'
required: false required: false
keep-state:
description: 'Keep BuildKit state on cleanup. This is only useful on persistent self-hosted runners.'
default: 'false'
required: false
cache-binary: cache-binary:
description: 'Cache buildx binary to GitHub Actions cache backend' description: 'Cache buildx binary to GitHub Actions cache backend'
default: 'true' default: 'true'
@ -54,6 +52,15 @@ inputs:
description: 'Cleanup temp files and remove builder at the end of a job' description: 'Cleanup temp files and remove builder at the end of a job'
default: 'true' default: 'true'
required: false required: false
# deprecated 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:
@ -72,6 +79,6 @@ outputs:
description: 'Builder node flags (deprecated, use nodes output instead)' description: 'Builder node flags (deprecated, use nodes output instead)'
runs: runs:
using: 'node24' using: 'node20'
main: 'dist/index.js' main: 'dist/index.js'
post: 'dist/index.js' post: 'dist/index.js'

View File

@ -1,21 +1,13 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
ARG NODE_VERSION=24 ARG NODE_VERSION=20
FROM node:${NODE_VERSION}-alpine AS base FROM node:${NODE_VERSION}-alpine AS base
RUN apk add --no-cache cpio findutils git rsync RUN apk add --no-cache cpio findutils git
WORKDIR /src WORKDIR /src
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/.yarn/cache <<EOT
set -e
corepack enable
yarn --version
yarn config set --home enableTelemetry 0
EOT
FROM base AS deps FROM base AS deps
RUN --mount=type=bind,target=.,rw \ RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/.yarn/cache \
--mount=type=cache,target=/src/node_modules \ --mount=type=cache,target=/src/node_modules \
yarn install && mkdir /vendor && cp yarn.lock /vendor yarn install && mkdir /vendor && cp yarn.lock /vendor
@ -24,66 +16,56 @@ COPY --from=deps /vendor /
FROM deps AS vendor-validate FROM deps AS vendor-validate
RUN --mount=type=bind,target=.,rw <<EOT RUN --mount=type=bind,target=.,rw <<EOT
set -e set -e
git add -A git add -A
cp -rf /vendor/* . cp -rf /vendor/* .
if [ -n "$(git status --porcelain -- yarn.lock)" ]; then if [ -n "$(git status --porcelain -- yarn.lock)" ]; then
echo >&2 'ERROR: Vendor result differs. Please vendor your package with "docker buildx bake vendor"' echo >&2 'ERROR: Vendor result differs. Please vendor your package with "docker buildx bake vendor-update"'
git status --porcelain -- yarn.lock git status --porcelain -- yarn.lock
exit 1 exit 1
fi fi
EOT EOT
FROM deps AS build FROM deps AS build
RUN --mount=target=/context \ RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/.yarn/cache \ --mount=type=cache,target=/src/node_modules \
--mount=type=cache,target=/src/node_modules <<EOT yarn run build && mkdir /out && cp -Rf dist /out/
set -e
rsync -a /context/. .
rm -rf dist
yarn run build
mkdir /out
cp -r dist /out
EOT
FROM scratch AS build-update FROM scratch AS build-update
COPY --from=build /out / COPY --from=build /out /
FROM build AS build-validate FROM build AS build-validate
RUN --mount=target=/context \ RUN --mount=type=bind,target=.,rw <<EOT
--mount=target=.,type=tmpfs <<EOT set -e
set -e git add -A
rsync -a /context/. . cp -rf /out/* .
git add -A if [ -n "$(git status --porcelain -- dist)" ]; then
rm -rf dist
cp -rf /out/* .
if [ -n "$(git status --porcelain -- dist)" ]; then
echo >&2 'ERROR: Build result differs. Please build first with "docker buildx bake build"' echo >&2 'ERROR: Build result differs. Please build first with "docker buildx bake build"'
git status --porcelain -- dist git status --porcelain -- dist
exit 1 exit 1
fi fi
EOT EOT
FROM deps AS format FROM deps AS format
RUN --mount=type=bind,target=.,rw \ RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/.yarn/cache \
--mount=type=cache,target=/src/node_modules \ --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 yarn run format \
&& mkdir /out && find . -name '*.ts' -not -path './node_modules/*' | cpio -pdm /out
FROM scratch AS format-update FROM scratch AS format-update
COPY --from=format /out / COPY --from=format /out /
FROM deps AS lint FROM deps AS lint
RUN --mount=type=bind,target=.,rw \ RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/.yarn/cache \
--mount=type=cache,target=/src/node_modules \ --mount=type=cache,target=/src/node_modules \
yarn run lint yarn run lint
FROM deps AS test FROM deps AS test
ENV RUNNER_TEMP=/tmp/github_runner
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
RUN --mount=type=bind,target=.,rw \ RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/.yarn/cache \
--mount=type=cache,target=/src/node_modules \ --mount=type=cache,target=/src/node_modules \
yarn run test --coverage --coverage.reportsDirectory=/tmp/coverage yarn run test --coverage --coverageDirectory=/tmp/coverage
FROM scratch AS test-coverage FROM scratch AS test-coverage
COPY --from=test /tmp/coverage / COPY --from=test /tmp/coverage /

301
dist/606.index.js generated vendored
View File

@ -1,301 +0,0 @@
export const id = 606;
export const ids = [606];
export const modules = {
/***/ 606:
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ pMap)
/* harmony export */ });
/* unused harmony exports pMapIterable, pMapSkip */
async function pMap(
iterable,
mapper,
{
concurrency = Number.POSITIVE_INFINITY,
stopOnError = true,
signal,
} = {},
) {
return new Promise((resolve_, reject_) => {
if (iterable[Symbol.iterator] === undefined && iterable[Symbol.asyncIterator] === undefined) {
throw new TypeError(`Expected \`input\` to be either an \`Iterable\` or \`AsyncIterable\`, got (${typeof iterable})`);
}
if (typeof mapper !== 'function') {
throw new TypeError('Mapper function is required');
}
if (!((Number.isSafeInteger(concurrency) && concurrency >= 1) || concurrency === Number.POSITIVE_INFINITY)) {
throw new TypeError(`Expected \`concurrency\` to be an integer from 1 and up or \`Infinity\`, got \`${concurrency}\` (${typeof concurrency})`);
}
const result = [];
const errors = [];
const skippedIndexesMap = new Map();
let isRejected = false;
let isResolved = false;
let isIterableDone = false;
let resolvingCount = 0;
let currentIndex = 0;
const iterator = iterable[Symbol.iterator] === undefined ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator]();
const signalListener = () => {
reject(signal.reason);
};
const cleanup = () => {
signal?.removeEventListener('abort', signalListener);
};
const resolve = value => {
resolve_(value);
cleanup();
};
const reject = reason => {
isRejected = true;
isResolved = true;
reject_(reason);
cleanup();
};
if (signal) {
if (signal.aborted) {
reject(signal.reason);
}
signal.addEventListener('abort', signalListener, {once: true});
}
const next = async () => {
if (isResolved) {
return;
}
const nextItem = await iterator.next();
const index = currentIndex;
currentIndex++;
// Note: `iterator.next()` can be called many times in parallel.
// This can cause multiple calls to this `next()` function to
// receive a `nextItem` with `done === true`.
// The shutdown logic that rejects/resolves must be protected
// so it runs only one time as the `skippedIndex` logic is
// non-idempotent.
if (nextItem.done) {
isIterableDone = true;
if (resolvingCount === 0 && !isResolved) {
if (!stopOnError && errors.length > 0) {
reject(new AggregateError(errors)); // eslint-disable-line unicorn/error-message
return;
}
isResolved = true;
if (skippedIndexesMap.size === 0) {
resolve(result);
return;
}
const pureResult = [];
// Support multiple `pMapSkip`'s.
for (const [index, value] of result.entries()) {
if (skippedIndexesMap.get(index) === pMapSkip) {
continue;
}
pureResult.push(value);
}
resolve(pureResult);
}
return;
}
resolvingCount++;
// Intentionally detached
(async () => {
try {
const element = await nextItem.value;
if (isResolved) {
return;
}
const value = await mapper(element, index);
// Use Map to stage the index of the element.
if (value === pMapSkip) {
skippedIndexesMap.set(index, value);
}
result[index] = value;
resolvingCount--;
await next();
} catch (error) {
if (stopOnError) {
reject(error);
} else {
errors.push(error);
resolvingCount--;
// In that case we can't really continue regardless of `stopOnError` state
// since an iterable is likely to continue throwing after it throws once.
// If we continue calling `next()` indefinitely we will likely end up
// in an infinite loop of failed iteration.
try {
await next();
} catch (error) {
reject(error);
}
}
}
})();
};
// Create the concurrent runners in a detached (non-awaited)
// promise. We need this so we can await the `next()` calls
// to stop creating runners before hitting the concurrency limit
// if the iterable has already been marked as done.
// NOTE: We *must* do this for async iterators otherwise we'll spin up
// infinite `next()` calls by default and never start the event loop.
(async () => {
for (let index = 0; index < concurrency; index++) {
try {
// eslint-disable-next-line no-await-in-loop
await next();
} catch (error) {
reject(error);
break;
}
if (isIterableDone || isRejected) {
break;
}
}
})();
});
}
function pMapIterable(
iterable,
mapper,
{
concurrency = Number.POSITIVE_INFINITY,
backpressure = concurrency,
} = {},
) {
if (iterable[Symbol.iterator] === undefined && iterable[Symbol.asyncIterator] === undefined) {
throw new TypeError(`Expected \`input\` to be either an \`Iterable\` or \`AsyncIterable\`, got (${typeof iterable})`);
}
if (typeof mapper !== 'function') {
throw new TypeError('Mapper function is required');
}
if (!((Number.isSafeInteger(concurrency) && concurrency >= 1) || concurrency === Number.POSITIVE_INFINITY)) {
throw new TypeError(`Expected \`concurrency\` to be an integer from 1 and up or \`Infinity\`, got \`${concurrency}\` (${typeof concurrency})`);
}
if (!((Number.isSafeInteger(backpressure) && backpressure >= concurrency) || backpressure === Number.POSITIVE_INFINITY)) {
throw new TypeError(`Expected \`backpressure\` to be an integer from \`concurrency\` (${concurrency}) and up or \`Infinity\`, got \`${backpressure}\` (${typeof backpressure})`);
}
return {
async * [Symbol.asyncIterator]() {
const iterator = iterable[Symbol.asyncIterator] === undefined ? iterable[Symbol.iterator]() : iterable[Symbol.asyncIterator]();
const promises = [];
let pendingPromisesCount = 0;
let isDone = false;
let index = 0;
function trySpawn() {
if (isDone || !(pendingPromisesCount < concurrency && promises.length < backpressure)) {
return;
}
pendingPromisesCount++;
const promise = (async () => {
const {done, value} = await iterator.next();
if (done) {
pendingPromisesCount--;
return {done: true};
}
// Spawn if still below concurrency and backpressure limit
trySpawn();
try {
const returnValue = await mapper(await value, index++);
pendingPromisesCount--;
if (returnValue === pMapSkip) {
const index = promises.indexOf(promise);
if (index > 0) {
promises.splice(index, 1);
}
}
// Spawn if still below backpressure limit and just dropped below concurrency limit
trySpawn();
return {done: false, value: returnValue};
} catch (error) {
pendingPromisesCount--;
isDone = true;
return {error};
}
})();
promises.push(promise);
}
trySpawn();
while (promises.length > 0) {
const {error, done, value} = await promises[0]; // eslint-disable-line no-await-in-loop
promises.shift();
if (error) {
throw error;
}
if (done) {
return;
}
// Spawn if just dropped below backpressure limit and below the concurrency limit
trySpawn();
if (value === pMapSkip) {
continue;
}
yield value;
}
},
};
}
const pMapSkip = Symbol('skip');
/***/ })
};
//# sourceMappingURL=606.index.js.map

1
dist/606.index.js.map generated vendored

File diff suppressed because one or more lines are too long

63
dist/index.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

1866
dist/licenses.txt generated vendored

File diff suppressed because it is too large Load Diff

3
dist/package.json generated vendored
View File

@ -1,3 +0,0 @@
{
"type": "module"
}

1
dist/sourcemap-register.cjs generated vendored

File diff suppressed because one or more lines are too long

1
dist/sourcemap-register.js generated vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,15 +1,9 @@
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 = ["vendor-update", "format", "build"]
} }
group "validate" { group "validate" {
@ -17,49 +11,42 @@ group "validate" {
} }
target "build" { target "build" {
inherits = ["_common"]
dockerfile = "dev.Dockerfile" dockerfile = "dev.Dockerfile"
target = "build-update" target = "build-update"
output = ["."] output = ["."]
} }
target "build-validate" { target "build-validate" {
inherits = ["_common"]
dockerfile = "dev.Dockerfile" dockerfile = "dev.Dockerfile"
target = "build-validate" target = "build-validate"
output = ["type=cacheonly"] output = ["type=cacheonly"]
} }
target "format" { target "format" {
inherits = ["_common"]
dockerfile = "dev.Dockerfile" dockerfile = "dev.Dockerfile"
target = "format-update" target = "format-update"
output = ["."] output = ["."]
} }
target "lint" { target "lint" {
inherits = ["_common"]
dockerfile = "dev.Dockerfile" dockerfile = "dev.Dockerfile"
target = "lint" target = "lint"
output = ["type=cacheonly"] output = ["type=cacheonly"]
} }
target "vendor" { target "vendor-update" {
inherits = ["_common"]
dockerfile = "dev.Dockerfile" dockerfile = "dev.Dockerfile"
target = "vendor-update" target = "vendor-update"
output = ["."] output = ["."]
} }
target "vendor-validate" { target "vendor-validate" {
inherits = ["_common"]
dockerfile = "dev.Dockerfile" dockerfile = "dev.Dockerfile"
target = "vendor-validate" target = "vendor-validate"
output = ["type=cacheonly"] output = ["type=cacheonly"]
} }
target "test" { target "test" {
inherits = ["_common"]
dockerfile = "dev.Dockerfile" dockerfile = "dev.Dockerfile"
target = "test-coverage" target = "test-coverage"
output = ["./coverage"] output = ["./coverage"]

View File

@ -1,52 +0,0 @@
import {defineConfig} from 'eslint/config';
import js from '@eslint/js';
import tseslint from '@typescript-eslint/eslint-plugin';
import vitest from '@vitest/eslint-plugin';
import globals from 'globals';
import eslintConfigPrettier from 'eslint-config-prettier/flat';
import eslintPluginPrettier from 'eslint-plugin-prettier';
export default defineConfig([
{
ignores: ['.yarn/**/*', 'coverage/**/*', 'dist/**/*']
},
js.configs.recommended,
...tseslint.configs['flat/recommended'],
eslintConfigPrettier,
{
languageOptions: {
globals: {
...globals.node
}
}
},
{
files: ['__tests__/**'],
...vitest.configs.recommended,
languageOptions: {
globals: {
...globals.node,
...vitest.environments.env.globals
}
},
rules: {
...vitest.configs.recommended.rules,
'vitest/no-conditional-expect': 'error',
'vitest/no-disabled-tests': 0
}
},
{
plugins: {
prettier: eslintPluginPrettier
},
rules: {
'prettier/prettier': 'error',
'@typescript-eslint/no-require-imports': [
'error',
{
allowAsImport: true
}
]
}
}
]);

29
jest.config.ts Normal file
View File

@ -0,0 +1,29 @@
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,13 +1,17 @@
{ {
"name": "docker-setup-buildx", "name": "docker-setup-buildx",
"description": "Set up Docker Buildx", "description": "Set up Docker Buildx",
"type": "module", "main": "lib/main.js",
"main": "src/main.ts",
"scripts": { "scripts": {
"build": "ncc build --source-map --minify --license licenses.txt", "build": "ncc build src/main.ts --source-map --minify --license licenses.txt",
"lint": "eslint --max-warnings=0 .", "lint": "yarn run prettier && yarn run eslint",
"format": "eslint --fix .", "format": "yarn run prettier:fix && yarn run eslint:fix",
"test": "vitest run" "eslint": "eslint --max-warnings=0 .",
"eslint:fix": "eslint --fix .",
"prettier": "prettier --check \"./**/*.ts\"",
"prettier:fix": "prettier --write \"./**/*.ts\"",
"test": "jest",
"all": "yarn run build && yarn run format && yarn test"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -20,27 +24,26 @@
], ],
"author": "Docker Inc.", "author": "Docker Inc.",
"license": "Apache-2.0", "license": "Apache-2.0",
"packageManager": "yarn@4.9.2",
"dependencies": { "dependencies": {
"@actions/core": "^3.0.0", "@actions/core": "^1.10.1",
"@docker/actions-toolkit": "^0.79.0", "@actions/exec": "^1.1.1",
"js-yaml": "^4.1.1" "@docker/actions-toolkit": "^0.19.0",
"js-yaml": "^4.1.0",
"uuid": "^9.0.1"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.39.3", "@types/node": "^20.5.9",
"@types/js-yaml": "^4.0.9", "@typescript-eslint/eslint-plugin": "^6.6.0",
"@types/node": "^24.11.0", "@typescript-eslint/parser": "^6.6.0",
"@typescript-eslint/eslint-plugin": "^8.56.1", "@vercel/ncc": "^0.38.0",
"@typescript-eslint/parser": "^8.56.1", "eslint": "^8.48.0",
"@vercel/ncc": "^0.38.4", "eslint-config-prettier": "^9.0.0",
"@vitest/coverage-v8": "^4.0.18", "eslint-plugin-jest": "^27.2.3",
"@vitest/eslint-plugin": "^1.6.9", "eslint-plugin-prettier": "^5.0.0",
"eslint": "^9.39.3", "jest": "^29.6.4",
"eslint-config-prettier": "^10.1.8", "prettier": "^3.0.3",
"eslint-plugin-prettier": "^5.5.5", "ts-jest": "^29.1.1",
"globals": "^17.3.0", "ts-node": "^10.9.1",
"prettier": "^3.8.1", "typescript": "^5.2.2"
"typescript": "^5.9.3",
"vitest": "^4.0.18"
} }
} }

View File

@ -1,14 +1,11 @@
import * as crypto from 'crypto'; import * as uuid from 'uuid';
import * as core from '@actions/core'; import * as core from '@actions/core';
import {Docker} from '@docker/actions-toolkit/lib/docker/docker';
import {Docker} from '@docker/actions-toolkit/lib/docker/docker.js'; import {Util} from '@docker/actions-toolkit/lib/util';
import {Util} from '@docker/actions-toolkit/lib/util.js'; import {Toolkit} from '@docker/actions-toolkit/lib/toolkit';
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit.js'; import {Node} from '@docker/actions-toolkit/lib/types/builder';
import {Node} from '@docker/actions-toolkit/lib/types/buildx/builder.js';
export const builderNodeEnvPrefix = 'BUILDER_NODE'; 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;
@ -19,47 +16,45 @@ export interface Inputs {
buildkitdConfig: string; buildkitdConfig: string;
buildkitdConfigInline: string; buildkitdConfigInline: string;
platforms: string[]; platforms: string[];
install: boolean;
use: boolean; use: boolean;
endpoint: string; endpoint: string;
append: string; append: string;
cacheBinary: boolean; cacheBinary: boolean;
cleanup: boolean; cleanup: boolean;
keepState: 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('name'), core.getInput('driver') || 'docker-container'), 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: Util.getInputList('driver-opts', {ignoreComma: true, quote: false}),
buildkitdFlags: core.getInput('buildkitd-flags'), buildkitdFlags: core.getInput('buildkitd-flags') || '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
platforms: Util.getInputList('platforms'), platforms: Util.getInputList('platforms'),
install: core.getBooleanInput('install'),
use: core.getBooleanInput('use'), use: core.getBooleanInput('use'),
endpoint: core.getInput('endpoint'), endpoint: core.getInput('endpoint'),
buildkitdConfig: core.getInput('buildkitd-config'), buildkitdConfig: core.getInput('buildkitd-config') || core.getInput('config'),
buildkitdConfigInline: core.getInput('buildkitd-config-inline'), buildkitdConfigInline: core.getInput('buildkitd-config-inline') || core.getInput('config-inline'),
append: core.getInput('append'), append: core.getInput('append'),
keepState: core.getBooleanInput('keep-state'),
cacheBinary: core.getBooleanInput('cache-binary'), cacheBinary: core.getBooleanInput('cache-binary'),
cleanup: core.getBooleanInput('cleanup') cleanup: core.getBooleanInput('cleanup')
}; };
} }
export async function getBuilderName(name: string, driver: string): Promise<string> { export async function getBuilderName(driver: string): Promise<string> {
return driver == 'docker' ? await Docker.context() : name || `builder-${crypto.randomUUID()}`; return driver == 'docker' ? await Docker.context() : `builder-${uuid.v4()}`;
} }
export async function getCreateArgs(inputs: Inputs, toolkit: Toolkit): Promise<Array<string>> { export async function getCreateArgs(inputs: Inputs, toolkit: Toolkit): Promise<Array<string>> {
const args: Array<string> = ['create', '--name', inputs.name, '--driver', inputs.driver]; const args: Array<string> = ['create', '--name', inputs.name, '--driver', inputs.driver];
if (await toolkit.buildx.versionSatisfies('>=0.3.0')) { if (await toolkit.buildx.versionSatisfies('>=0.3.0')) {
await Util.asyncForEach(inputs.driverOpts, async (driverOpt: string) => { await Util.asyncForEach(inputs.driverOpts, async driverOpt => {
args.push('--driver-opt', driverOpt); args.push('--driver-opt', driverOpt);
}); });
if (inputs.buildkitdFlags) { if (driverSupportsFlags(inputs.driver) && inputs.buildkitdFlags) {
args.push('--buildkitd-flags', inputs.buildkitdFlags); args.push('--buildkitd-flags', inputs.buildkitdFlags);
} else if (driverSupportsBuildkitdFlags(inputs.driver)) {
args.push('--buildkitd-flags', defaultBuildkitdFlags);
} }
} }
if (inputs.platforms.length > 0) { if (inputs.platforms.length > 0) {
@ -68,11 +63,13 @@ export async function getCreateArgs(inputs: Inputs, toolkit: Toolkit): Promise<A
if (inputs.use) { if (inputs.use) {
args.push('--use'); args.push('--use');
} }
if (driverSupportsFlags(inputs.driver)) {
if (inputs.buildkitdConfig) { if (inputs.buildkitdConfig) {
args.push('--config', toolkit.buildkit.config.resolveFromFile(inputs.buildkitdConfig)); args.push('--config', toolkit.buildkit.config.resolveFromFile(inputs.buildkitdConfig));
} else if (inputs.buildkitdConfigInline) { } else if (inputs.buildkitdConfigInline) {
args.push('--config', toolkit.buildkit.config.resolveFromString(inputs.buildkitdConfigInline)); args.push('--config', toolkit.buildkit.config.resolveFromString(inputs.buildkitdConfigInline));
} }
}
if (inputs.endpoint) { if (inputs.endpoint) {
args.push(inputs.endpoint); args.push(inputs.endpoint);
} }
@ -84,16 +81,14 @@ export async function getAppendArgs(inputs: Inputs, node: Node, toolkit: Toolkit
if (node.name) { if (node.name) {
args.push('--node', node.name); args.push('--node', node.name);
} else if (inputs.driver == 'kubernetes' && (await toolkit.buildx.versionSatisfies('<0.11.0'))) { } else if (inputs.driver == 'kubernetes' && (await toolkit.buildx.versionSatisfies('<0.11.0'))) {
args.push('--node', `node-${crypto.randomUUID()}`); args.push('--node', `node-${uuid.v4()}`);
} }
if (node['driver-opts'] && (await toolkit.buildx.versionSatisfies('>=0.3.0'))) { if (node['driver-opts'] && (await toolkit.buildx.versionSatisfies('>=0.3.0'))) {
await Util.asyncForEach(node['driver-opts'], async (driverOpt: string) => { await Util.asyncForEach(node['driver-opts'], async driverOpt => {
args.push('--driver-opt', driverOpt); args.push('--driver-opt', driverOpt);
}); });
if (node['buildkitd-flags']) { if (driverSupportsFlags(inputs.driver) && node['buildkitd-flags']) {
args.push('--buildkitd-flags', node['buildkitd-flags']); args.push('--buildkitd-flags', node['buildkitd-flags']);
} else if (driverSupportsBuildkitdFlags(inputs.driver)) {
args.push('--buildkitd-flags', defaultBuildkitdFlags);
} }
} }
if (node.platforms) { if (node.platforms) {
@ -113,20 +108,6 @@ export async function getInspectArgs(inputs: Inputs, toolkit: Toolkit): Promise<
return args; return args;
} }
function driverSupportsBuildkitdFlags(driver: string): boolean { function driverSupportsFlags(driver: string): boolean {
return driver == '' || driver == 'docker-container' || driver == 'docker' || driver == 'kubernetes'; 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;
}

View File

@ -1,39 +1,28 @@
import * as crypto from 'crypto';
import * as fs from 'fs'; import * as fs from 'fs';
import * as yaml from 'js-yaml'; import * as yaml from 'js-yaml';
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as exec from '@actions/exec';
import * as actionsToolkit from '@docker/actions-toolkit'; import * as actionsToolkit from '@docker/actions-toolkit';
import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx';
import {Builder} from '@docker/actions-toolkit/lib/buildx/builder';
import {Docker} from '@docker/actions-toolkit/lib/docker/docker';
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit';
import {Util} from '@docker/actions-toolkit/lib/util';
import {Node} from '@docker/actions-toolkit/lib/types/builder';
import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx.js'; import * as context from './context';
import {Builder} from '@docker/actions-toolkit/lib/buildx/builder.js'; import * as stateHelper from './state-helper';
import {Docker} from '@docker/actions-toolkit/lib/docker/docker.js';
import {Exec} from '@docker/actions-toolkit/lib/exec.js';
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit.js';
import {Util} from '@docker/actions-toolkit/lib/util.js';
import {Node} from '@docker/actions-toolkit/lib/types/buildx/builder.js';
import {ContextInfo} from '@docker/actions-toolkit/lib/types/docker/docker.js';
import * as context from './context.js';
import * as stateHelper from './state-helper.js';
actionsToolkit.run( actionsToolkit.run(
// main // main
async () => { async () => {
const inputs: context.Inputs = await context.getInputs(); const inputs: context.Inputs = await context.getInputs();
stateHelper.setCleanup(inputs.cleanup); stateHelper.setCleanup(inputs.cleanup);
const version = context.getVersion(inputs);
const toolkit = new Toolkit(); const toolkit = new Toolkit();
const standalone = await toolkit.buildx.isStandalone(); const standalone = await toolkit.buildx.isStandalone();
stateHelper.setStandalone(standalone); stateHelper.setStandalone(standalone);
if (inputs.keepState && inputs.driver !== 'docker-container') {
// https://docs.docker.com/reference/cli/docker/buildx/rm/#keep-state
throw new Error(`Cannot use keep-state with ${inputs.driver} driver`);
}
stateHelper.setKeepState(inputs.keepState);
await core.group(`Docker info`, async () => { await core.group(`Docker info`, async () => {
try { try {
await Docker.printVersion(); await Docker.printVersion();
@ -44,19 +33,16 @@ actionsToolkit.run(
}); });
let toolPath; let toolPath;
if (Util.isValidRef(version)) { if (Util.isValidRef(inputs.version)) {
if (standalone) { if (standalone) {
throw new Error(`Cannot build from source without the Docker CLI`); throw new Error(`Cannot build from source without the Docker CLI`);
} }
await core.group(`Build buildx from source`, async () => { await core.group(`Build buildx from source`, async () => {
toolPath = await toolkit.buildxInstall.build(version, !inputs.cacheBinary); toolPath = await toolkit.buildxInstall.build(inputs.version, !inputs.cacheBinary);
}); });
} else if (!(await toolkit.buildx.isAvailable()) || version) { } else if (!(await toolkit.buildx.isAvailable()) || inputs.version) {
await core.group(`Download buildx from GitHub Releases`, async () => { await core.group(`Download buildx from GitHub Releases`, async () => {
toolPath = await toolkit.buildxInstall.download({ toolPath = await toolkit.buildxInstall.download(inputs.version || 'latest', !inputs.cacheBinary);
version: version || 'latest',
ghaNoCache: !inputs.cacheBinary
});
}); });
} }
if (toolPath) { if (toolPath) {
@ -80,56 +66,8 @@ actionsToolkit.run(
fs.mkdirSync(Buildx.certsDir, {recursive: true}); fs.mkdirSync(Buildx.certsDir, {recursive: true});
stateHelper.setCertsDir(Buildx.certsDir); 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') { if (inputs.driver !== 'docker') {
await core.group(`Creating a new builder instance`, async () => { await core.group(`Creating a new builder instance`, async () => {
if (await toolkit.builder.exists(inputs.name)) {
core.info(`Builder ${inputs.name} already exists, skipping creation`);
} else {
const certsDriverOpts = Buildx.resolveCertsDriverOpts(inputs.driver, inputs.endpoint, { const certsDriverOpts = Buildx.resolveCertsDriverOpts(inputs.driver, inputs.endpoint, {
cacert: process.env[`${context.builderNodeEnvPrefix}_0_AUTH_TLS_CACERT`], cacert: process.env[`${context.builderNodeEnvPrefix}_0_AUTH_TLS_CACERT`],
cert: process.env[`${context.builderNodeEnvPrefix}_0_AUTH_TLS_CERT`], cert: process.env[`${context.builderNodeEnvPrefix}_0_AUTH_TLS_CERT`],
@ -139,14 +77,7 @@ actionsToolkit.run(
inputs.driverOpts = [...inputs.driverOpts, ...certsDriverOpts]; inputs.driverOpts = [...inputs.driverOpts, ...certsDriverOpts];
} }
const createCmd = await toolkit.buildx.getCommand(await context.getCreateArgs(inputs, toolkit)); const createCmd = await toolkit.buildx.getCommand(await context.getCreateArgs(inputs, toolkit));
await Exec.getExecOutput(createCmd.command, createCmd.args, { await exec.exec(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');
}
});
}
}); });
} }
@ -164,13 +95,7 @@ actionsToolkit.run(
node['driver-opts'] = [...(node['driver-opts'] || []), ...certsDriverOpts]; node['driver-opts'] = [...(node['driver-opts'] || []), ...certsDriverOpts];
} }
const appendCmd = await toolkit.buildx.getCommand(await context.getAppendArgs(inputs, node, toolkit)); const appendCmd = await toolkit.buildx.getCommand(await context.getAppendArgs(inputs, node, toolkit));
await Exec.getExecOutput(appendCmd.command, appendCmd.args, { await exec.exec(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++; nodeIndex++;
} }
}); });
@ -178,14 +103,18 @@ actionsToolkit.run(
await core.group(`Booting builder`, async () => { await core.group(`Booting builder`, async () => {
const inspectCmd = await toolkit.buildx.getCommand(await context.getInspectArgs(inputs, toolkit)); const inspectCmd = await toolkit.buildx.getCommand(await context.getInspectArgs(inputs, toolkit));
await Exec.getExecOutput(inspectCmd.command, inspectCmd.args, { await exec.exec(inspectCmd.command, inspectCmd.args);
ignoreReturnCode: true });
}).then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) { if (inputs.install) {
throw new Error(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'); 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.exec(installCmd.command, installCmd.args);
}); });
}); }
const builderInspect = await toolkit.builder.inspect(inputs.name); const builderInspect = await toolkit.builder.inspect(inputs.name);
const firstNode = builderInspect.nodes[0]; const firstNode = builderInspect.nodes[0];
@ -204,6 +133,9 @@ actionsToolkit.run(
core.setOutput('driver', builderInspect.driver); core.setOutput('driver', builderInspect.driver);
core.setOutput('platforms', reducedPlatforms.join(',')); core.setOutput('platforms', reducedPlatforms.join(','));
core.setOutput('nodes', JSON.stringify(builderInspect.nodes, undefined, 2)); 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') { if (!standalone && builderInspect.driver == 'docker-container') {
@ -223,11 +155,13 @@ actionsToolkit.run(
async () => { async () => {
if (stateHelper.IsDebug && stateHelper.containerName.length > 0) { if (stateHelper.IsDebug && stateHelper.containerName.length > 0) {
await core.group(`BuildKit container logs`, async () => { await core.group(`BuildKit container logs`, async () => {
await Docker.getExecOutput(['logs', `${stateHelper.containerName}`], { await exec
.getExecOutput('docker', ['logs', `${stateHelper.containerName}`], {
ignoreReturnCode: true ignoreReturnCode: true
}).then(res => { })
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) { if (res.stderr.length > 0 && res.exitCode != 0) {
core.warning(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'); core.warning(res.stderr.trim());
} }
}); });
}); });
@ -242,12 +176,14 @@ actionsToolkit.run(
const buildx = new Buildx({standalone: stateHelper.standalone}); const buildx = new Buildx({standalone: stateHelper.standalone});
const builder = new Builder({buildx: buildx}); const builder = new Builder({buildx: buildx});
if (await builder.exists(stateHelper.builderName)) { if (await builder.exists(stateHelper.builderName)) {
const rmCmd = await buildx.getCommand(['rm', stateHelper.builderName, ...(stateHelper.keepState ? ['--keep-state'] : [])]); const rmCmd = await buildx.getCommand(['rm', stateHelper.builderName]);
await Exec.getExecOutput(rmCmd.command, rmCmd.args, { await exec
.getExecOutput(rmCmd.command, rmCmd.args, {
ignoreReturnCode: true ignoreReturnCode: true
}).then(res => { })
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) { if (res.stderr.length > 0 && res.exitCode != 0) {
core.warning(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'); core.warning(res.stderr.trim());
} }
}); });
} else { } else {
@ -256,18 +192,6 @@ actionsToolkit.run(
}); });
} }
if (stateHelper.tmpDockerContext) {
await core.group(`Removing temp docker context`, async () => {
await Exec.getExecOutput('docker', ['context', 'rm', '-f', stateHelper.tmpDockerContext], {
ignoreReturnCode: true
}).then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
core.warning(`${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
}
});
});
}
if (stateHelper.certsDir.length > 0 && fs.existsSync(stateHelper.certsDir)) { if (stateHelper.certsDir.length > 0 && fs.existsSync(stateHelper.certsDir)) {
await core.group(`Cleaning up certificates`, async () => { await core.group(`Cleaning up certificates`, async () => {
fs.rmSync(stateHelper.certsDir, {recursive: true}); fs.rmSync(stateHelper.certsDir, {recursive: true});

View File

@ -6,9 +6,7 @@ export const builderName = process.env['STATE_builderName'] || '';
export const builderDriver = process.env['STATE_builderDriver'] || ''; export const builderDriver = process.env['STATE_builderDriver'] || '';
export const containerName = process.env['STATE_containerName'] || ''; export const containerName = process.env['STATE_containerName'] || '';
export const certsDir = process.env['STATE_certsDir'] || ''; export const certsDir = process.env['STATE_certsDir'] || '';
export const tmpDockerContext = process.env['STATE_tmpDockerContext'] || '';
export const cleanup = /true/i.test(process.env['STATE_cleanup'] || ''); export const cleanup = /true/i.test(process.env['STATE_cleanup'] || '');
export const keepState = /true/i.test(process.env['STATE_keepState'] || '');
export function setDebug(debug: string) { export function setDebug(debug: string) {
core.saveState('isDebug', debug); core.saveState('isDebug', debug);
@ -34,14 +32,6 @@ export function setCertsDir(certsDir: string) {
core.saveState('certsDir', certsDir); core.saveState('certsDir', certsDir);
} }
export function setTmpDockerContext(tmpDockerContext: string) {
core.saveState('tmpDockerContext', tmpDockerContext);
}
export function setCleanup(cleanup: boolean) { export function setCleanup(cleanup: boolean) {
core.saveState('cleanup', cleanup); core.saveState('cleanup', cleanup);
} }
export function setKeepState(keepState: boolean) {
core.saveState('keepState', keepState);
}

View File

@ -1,8 +1,9 @@
{ {
"compilerOptions": { "compilerOptions": {
"module": "nodenext",
"moduleResolution": "nodenext",
"esModuleInterop": true, "esModuleInterop": true,
"target": "es6",
"module": "commonjs",
"strict": true,
"newLine": "lf", "newLine": "lf",
"outDir": "./lib", "outDir": "./lib",
"rootDir": "./src", "rootDir": "./src",
@ -11,7 +12,10 @@
"resolveJsonModule": true, "resolveJsonModule": true,
"useUnknownInCatchVariables": false, "useUnknownInCatchVariables": false,
}, },
"include": [ "exclude": [
"src/**/*.ts" "./__tests__/**/*",
"./lib/**/*",
"node_modules",
"jest.config.ts"
] ]
} }

View File

@ -1,16 +0,0 @@
import {defineConfig} from 'vitest/config';
export default defineConfig({
test: {
clearMocks: true,
environment: 'node',
setupFiles: ['./__tests__/setup.unit.ts'],
include: ['**/*.test.ts'],
coverage: {
provider: 'v8',
reporter: ['clover'],
include: ['src/**/*.ts'],
exclude: ['src/**/main.ts']
}
}
});

8843
yarn.lock

File diff suppressed because it is too large Load Diff