├── .github ├── CODEOWNERS ├── build-push-action.png ├── e2e │ ├── distribution │ │ ├── env │ │ └── install.sh │ ├── nexus │ │ ├── docker-compose.yml │ │ ├── env │ │ └── install.sh │ └── harbor │ │ ├── env │ │ └── install.sh ├── dependabot.yml ├── workflows │ ├── test.yml │ ├── validate.yml │ ├── e2e.yml │ └── ci.yml ├── ISSUE_TEMPLATE │ └── bug_report.md ├── SUPPORT.md └── CONTRIBUTING.md ├── __tests__ ├── fixtures │ ├── secret.txt │ └── github-repo.json └── context.test.ts ├── .dockerignore ├── codecov.yml ├── .gitattributes ├── test ├── go │ ├── go.mod │ ├── main.go │ └── Dockerfile ├── Dockerfile ├── ulimit.Dockerfile ├── addhost.Dockerfile ├── cgroup.Dockerfile ├── shmsize.Dockerfile ├── named-context.Dockerfile ├── named-context-base.Dockerfile ├── secret.Dockerfile ├── nocachefilter.Dockerfile ├── multi.Dockerfile └── multi-sudo.Dockerfile ├── docs └── advanced │ ├── cache.md │ ├── secrets.md │ ├── local-registry.md │ ├── named-contexts.md │ ├── export-docker.md │ ├── multi-platform.md │ ├── tags-labels.md │ ├── share-image-jobs.md │ ├── dockerhub-desc.md │ ├── isolated-builders.md │ ├── push-multi-registries.md │ ├── test-before-push.md │ └── copy-between-registries.md ├── src ├── state-helper.ts ├── main.ts └── context.ts ├── .prettierrc.json ├── .editorconfig ├── .eslintrc.json ├── tsconfig.json ├── jest.config.ts ├── docker-bake.hcl ├── package.json ├── .gitignore ├── dev.Dockerfile ├── action.yml ├── TROUBLESHOOTING.md ├── __mocks__ └── @actions │ └── github.ts ├── LICENSE ├── README.md └── dist └── sourcemap-register.js /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @crazy-max 2 | -------------------------------------------------------------------------------- /__tests__/fixtures/secret.txt: -------------------------------------------------------------------------------- 1 | bar 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | /coverage 2 | /node_modules 3 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | github_checks: 3 | annotations: false 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | /dist/** linguist-generated=true 2 | /lib/** linguist-generated=true 3 | -------------------------------------------------------------------------------- /test/go/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/docker/build-push-action/test/go 2 | 3 | go 1.18 4 | -------------------------------------------------------------------------------- /test/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | FROM alpine 3 | RUN echo "Hello world!" 4 | -------------------------------------------------------------------------------- /test/ulimit.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | FROM busybox 3 | RUN ulimit -a 4 | -------------------------------------------------------------------------------- /test/addhost.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | FROM busybox 3 | RUN cat /etc/hosts 4 | -------------------------------------------------------------------------------- /test/cgroup.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | FROM alpine 3 | RUN cat /proc/self/cgroup 4 | -------------------------------------------------------------------------------- /test/shmsize.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | FROM busybox 3 | RUN mount | grep /dev/shm 4 | -------------------------------------------------------------------------------- /test/named-context.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | FROM alpine 4 | RUN cat /etc/*release 5 | -------------------------------------------------------------------------------- /test/named-context-base.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | FROM debian 4 | RUN echo "Hello debian!" 5 | -------------------------------------------------------------------------------- /.github/build-push-action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zendesk/build-push-action/master/.github/build-push-action.png -------------------------------------------------------------------------------- /docs/advanced/cache.md: -------------------------------------------------------------------------------- 1 | # Cache 2 | 3 | This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/cache/) 4 | -------------------------------------------------------------------------------- /docs/advanced/secrets.md: -------------------------------------------------------------------------------- 1 | # Secrets 2 | 3 | This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/secrets/) 4 | -------------------------------------------------------------------------------- /test/secret.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | FROM busybox 3 | RUN --mount=type=secret,id=MYSECRET \ 4 | echo "MYSECRET=$(cat /run/secrets/MYSECRET)" 5 | -------------------------------------------------------------------------------- /.github/e2e/distribution/env: -------------------------------------------------------------------------------- 1 | REGISTRY_FQDN=localhost:8080 2 | REGISTRY_SLUG=localhost:8080/test-docker-action 3 | 4 | DISTRIBUTION_HOST=localhost 5 | DISTRIBUTION_PORT=8080 -------------------------------------------------------------------------------- /docs/advanced/local-registry.md: -------------------------------------------------------------------------------- 1 | # Local registry 2 | 3 | This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/local-registry/) 4 | -------------------------------------------------------------------------------- /docs/advanced/named-contexts.md: -------------------------------------------------------------------------------- 1 | # Named contexts 2 | 3 | This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/named-contexts/) 4 | -------------------------------------------------------------------------------- /docs/advanced/export-docker.md: -------------------------------------------------------------------------------- 1 | # Export image to Docker 2 | 3 | This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/export-docker/) 4 | -------------------------------------------------------------------------------- /docs/advanced/multi-platform.md: -------------------------------------------------------------------------------- 1 | # Multi-platform image 2 | 3 | This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/multi-platform/) 4 | -------------------------------------------------------------------------------- /docs/advanced/tags-labels.md: -------------------------------------------------------------------------------- 1 | # Handle tags and labels 2 | 3 | This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/manage-tags-labels/) 4 | -------------------------------------------------------------------------------- /docs/advanced/share-image-jobs.md: -------------------------------------------------------------------------------- 1 | # Share built image between jobs 2 | 3 | This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/share-image-jobs/) 4 | -------------------------------------------------------------------------------- /docs/advanced/dockerhub-desc.md: -------------------------------------------------------------------------------- 1 | # Update Docker Hub repo description 2 | 3 | This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/update-dockerhub-desc/) 4 | -------------------------------------------------------------------------------- /docs/advanced/isolated-builders.md: -------------------------------------------------------------------------------- 1 | # Isolated builders 2 | 3 | This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/configure-builder/#isolated-builders) 4 | -------------------------------------------------------------------------------- /docs/advanced/push-multi-registries.md: -------------------------------------------------------------------------------- 1 | # Push to multi-registries 2 | 3 | This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/push-multi-registries/) 4 | -------------------------------------------------------------------------------- /docs/advanced/test-before-push.md: -------------------------------------------------------------------------------- 1 | # Test your image before pushing it 2 | 3 | This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/test-before-push/) 4 | -------------------------------------------------------------------------------- /docs/advanced/copy-between-registries.md: -------------------------------------------------------------------------------- 1 | # Copy images between registries 2 | 3 | This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/copy-image-registries/) 4 | -------------------------------------------------------------------------------- /src/state-helper.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core'; 2 | 3 | export const tmpDir = process.env['STATE_tmpDir'] || ''; 4 | 5 | export function setTmpDir(tmpDir: string) { 6 | core.saveState('tmpDir', tmpDir); 7 | } 8 | -------------------------------------------------------------------------------- /.github/e2e/nexus/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | nexus: 3 | image: sonatype/nexus3:${NEXUS_VERSION:-latest} 4 | volumes: 5 | - "./data:/nexus-data" 6 | ports: 7 | - "8081:8081" 8 | - "8082:8082" 9 | -------------------------------------------------------------------------------- /test/nocachefilter.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | FROM busybox AS base 3 | RUN echo "Hello world!" > /hello 4 | 5 | FROM alpine AS build 6 | COPY --from=base /hello /hello 7 | RUN uname -a 8 | 9 | FROM build 10 | -------------------------------------------------------------------------------- /.github/e2e/harbor/env: -------------------------------------------------------------------------------- 1 | REGISTRY_FQDN=localhost:8081 2 | REGISTRY_USER=admin 3 | REGISTRY_PASSWORD=Harbor12345 4 | REGISTRY_SLUG=localhost:8081/test-docker-action/test-docker-action 5 | 6 | HARBOR_HOST=localhost 7 | HARBOR_PORT=8081 8 | HARBOR_PROJECT=test-docker-action 9 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 240, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": true, 7 | "trailingComma": "none", 8 | "bracketSpacing": false, 9 | "arrowParens": "avoid", 10 | "parser": "typescript" 11 | } 12 | -------------------------------------------------------------------------------- /.github/e2e/nexus/env: -------------------------------------------------------------------------------- 1 | REGISTRY_FQDN=localhost:8082 2 | REGISTRY_USER=admin 3 | REGISTRY_PASSWORD=Nexus12345 4 | REGISTRY_SLUG=localhost:8082/test-docker-action 5 | 6 | NEXUS_HOST=localhost 7 | NEXUS_PORT=8081 8 | NEXUS_REGISTRY_PORT=8082 9 | NEXUS_REPO=test-docker-action 10 | -------------------------------------------------------------------------------- /test/go/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 11 | fmt.Fprintf(w, "Hello, Go!") 12 | }) 13 | log.Fatal(http.ListenAndServe(":8080", nil)) 14 | } 15 | -------------------------------------------------------------------------------- /test/multi.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | FROM --platform=$BUILDPLATFORM golang:alpine AS build 3 | 4 | ARG TARGETPLATFORM 5 | ARG BUILDPLATFORM 6 | RUN echo "I am running on $BUILDPLATFORM, building for $TARGETPLATFORM" > /log 7 | 8 | FROM alpine 9 | COPY --from=build /log /log 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs. 2 | # More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.github/e2e/distribution/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eu 3 | 4 | : "${DISTRIBUTION_VERSION:=2}" 5 | : "${DISTRIBUTION_HOST:=localhost}" 6 | : "${DISTRIBUTION_PORT:=8080}" 7 | 8 | echo "::group::Starting registry:${DISTRIBUTION_VERSION}" 9 | ( 10 | set -x 11 | docker run -d --name registry -p "${DISTRIBUTION_PORT}:5000" "registry:${DISTRIBUTION_VERSION}" 12 | ) 13 | echo "::endgroup::" -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | labels: 8 | - "dependencies" 9 | - "bot" 10 | - package-ecosystem: "npm" 11 | directory: "/" 12 | schedule: 13 | interval: "daily" 14 | allow: 15 | - dependency-type: "production" 16 | labels: 17 | - "dependencies" 18 | - "bot" 19 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true, 4 | "es2021": true, 5 | "jest": true 6 | }, 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:@typescript-eslint/recommended", 10 | "plugin:jest/recommended", 11 | "plugin:prettier/recommended" 12 | ], 13 | "parser": "@typescript-eslint/parser", 14 | "parserOptions": { 15 | "ecmaVersion": "latest", 16 | "sourceType": "module" 17 | }, 18 | "plugins": [ 19 | "@typescript-eslint", 20 | "jest", 21 | "prettier" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /test/go/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | FROM golang:alpine AS base 4 | ENV CGO_ENABLED=0 5 | RUN apk add --no-cache file git 6 | WORKDIR /src 7 | 8 | FROM base AS build 9 | RUN --mount=type=bind,target=/src \ 10 | --mount=type=cache,target=/root/.cache/go-build \ 11 | go build -ldflags "-s -w" -o /usr/bin/app . 12 | 13 | FROM scratch AS binary 14 | COPY --from=build /usr/bin/app /bin/app 15 | 16 | FROM alpine AS image 17 | COPY --from=build /usr/bin/app /bin/app 18 | EXPOSE 8080 19 | ENTRYPOINT ["/bin/app"] 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "target": "es6", 5 | "module": "commonjs", 6 | "strict": true, 7 | "newLine": "lf", 8 | "outDir": "./lib", 9 | "rootDir": "./src", 10 | "forceConsistentCasingInFileNames": true, 11 | "noImplicitAny": false, 12 | "resolveJsonModule": true, 13 | "useUnknownInCatchVariables": false, 14 | }, 15 | "exclude": [ 16 | "./__mocks__/**/*", 17 | "./__tests__/**/*", 18 | "./lib/**/*", 19 | "node_modules", 20 | "jest.config.ts" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | - 'releases/v*' 8 | pull_request: 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - 15 | name: Checkout 16 | uses: actions/checkout@v3 17 | - 18 | name: Test 19 | uses: docker/bake-action@v3 20 | with: 21 | targets: test 22 | - 23 | name: Upload coverage 24 | uses: codecov/codecov-action@v3 25 | with: 26 | file: ./coverage/clover.xml 27 | -------------------------------------------------------------------------------- /test/multi-sudo.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | FROM --platform=$BUILDPLATFORM golang:alpine AS build 3 | ARG TARGETPLATFORM 4 | ARG BUILDPLATFORM 5 | RUN echo "I am running on $BUILDPLATFORM, building for $TARGETPLATFORM" > /log 6 | RUN apk --update --no-cache add \ 7 | shadow \ 8 | sudo \ 9 | && addgroup -g 1200 buildx \ 10 | && adduser -u 1200 -G buildx -s /sbin/nologin -D buildx \ 11 | && echo 'buildx ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers \ 12 | && rm -rf /tmp/* /var/cache/apk/* 13 | 14 | USER buildx 15 | RUN sudo chown buildx. /log 16 | USER root 17 | 18 | FROM alpine 19 | COPY --from=build /log /log 20 | RUN ls -al /log 21 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import os from 'os'; 3 | import path from 'path'; 4 | 5 | const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-build-push-action-')); 6 | 7 | process.env = Object.assign({}, process.env, { 8 | TEMP: tmpDir, 9 | GITHUB_REPOSITORY: 'docker/build-push-action', 10 | RUNNER_TEMP: path.join(tmpDir, 'runner-temp'), 11 | RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache') 12 | }) as { 13 | [key: string]: string; 14 | }; 15 | 16 | module.exports = { 17 | clearMocks: false, 18 | testEnvironment: 'node', 19 | moduleFileExtensions: ['js', 'ts'], 20 | testMatch: ['**/*.test.ts'], 21 | transform: { 22 | '^.+\\.ts$': 'ts-jest' 23 | }, 24 | moduleNameMapper: { 25 | '^csv-parse/sync': '/node_modules/csv-parse/dist/cjs/sync.cjs' 26 | }, 27 | collectCoverageFrom: ['src/**/{!(main.ts),}.ts'], 28 | coveragePathIgnorePatterns: ['lib/', 'node_modules/', '__mocks__/', '__tests__/'], 29 | verbose: true 30 | }; 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | --- 5 | 6 | ### Troubleshooting 7 | 8 | Before submitting a bug report please read the [Troubleshooting doc](https://github.com/docker/build-push-action/blob/master/TROUBLESHOOTING.md). 9 | 10 | ### Behaviour 11 | 12 | #### Steps to reproduce this issue 13 | 14 | 1. 15 | 2. 16 | 3. 17 | 18 | #### Expected behaviour 19 | 20 | > Tell us what should happen 21 | 22 | #### Actual behaviour 23 | 24 | > Tell us what happens instead 25 | 26 | ### Configuration 27 | 28 | * Repository URL (if public): 29 | * Build URL (if public): 30 | 31 | ```yml 32 | # paste your YAML workflow file here and remove sensitive data 33 | ``` 34 | 35 | ### Logs 36 | 37 | > Download the [log file of your build](https://docs.github.com/en/actions/managing-workflow-runs/using-workflow-run-logs#downloading-logs) and [attach it](https://docs.github.com/en/github/managing-your-work-on-github/file-attachments-on-issues-and-pull-requests) to this issue. 38 | -------------------------------------------------------------------------------- /.github/workflows/validate.yml: -------------------------------------------------------------------------------- 1 | name: validate 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | - 'releases/v*' 8 | pull_request: 9 | 10 | jobs: 11 | prepare: 12 | runs-on: ubuntu-latest 13 | outputs: 14 | targets: ${{ steps.targets.outputs.matrix }} 15 | steps: 16 | - 17 | name: Checkout 18 | uses: actions/checkout@v3 19 | - 20 | name: Targets matrix 21 | id: targets 22 | run: | 23 | echo "matrix=$(docker buildx bake validate --print | jq -cr '.group.validate.targets')" >> $GITHUB_OUTPUT 24 | 25 | validate: 26 | runs-on: ubuntu-latest 27 | needs: 28 | - prepare 29 | strategy: 30 | fail-fast: false 31 | matrix: 32 | target: ${{ fromJson(needs.prepare.outputs.targets) }} 33 | steps: 34 | - 35 | name: Checkout 36 | uses: actions/checkout@v3 37 | - 38 | name: Validate 39 | uses: docker/bake-action@v3 40 | with: 41 | targets: ${{ matrix.target }} 42 | -------------------------------------------------------------------------------- /docker-bake.hcl: -------------------------------------------------------------------------------- 1 | group "default" { 2 | targets = ["build"] 3 | } 4 | 5 | group "pre-checkin" { 6 | targets = ["vendor-update", "format", "build"] 7 | } 8 | 9 | group "validate" { 10 | targets = ["lint", "build-validate", "vendor-validate"] 11 | } 12 | 13 | target "build" { 14 | dockerfile = "dev.Dockerfile" 15 | target = "build-update" 16 | output = ["."] 17 | } 18 | 19 | target "build-validate" { 20 | dockerfile = "dev.Dockerfile" 21 | target = "build-validate" 22 | output = ["type=cacheonly"] 23 | } 24 | 25 | target "format" { 26 | dockerfile = "dev.Dockerfile" 27 | target = "format-update" 28 | output = ["."] 29 | } 30 | 31 | target "lint" { 32 | dockerfile = "dev.Dockerfile" 33 | target = "lint" 34 | output = ["type=cacheonly"] 35 | } 36 | 37 | target "vendor-update" { 38 | dockerfile = "dev.Dockerfile" 39 | target = "vendor-update" 40 | output = ["."] 41 | } 42 | 43 | target "vendor-validate" { 44 | dockerfile = "dev.Dockerfile" 45 | target = "vendor-validate" 46 | output = ["type=cacheonly"] 47 | } 48 | 49 | target "test" { 50 | dockerfile = "dev.Dockerfile" 51 | target = "test-coverage" 52 | output = ["./coverage"] 53 | } 54 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docker-build-push", 3 | "description": "Build and push Docker images", 4 | "main": "lib/main.js", 5 | "scripts": { 6 | "build": "ncc build src/main.ts --source-map --minify --license licenses.txt", 7 | "lint": "eslint src/**/*.ts __tests__/**/*.ts", 8 | "format": "eslint --fix src/**/*.ts __tests__/**/*.ts", 9 | "test": "jest --coverage", 10 | "all": "yarn run build && yarn run format && yarn test" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/docker/build-push-action.git" 15 | }, 16 | "keywords": [ 17 | "actions", 18 | "docker", 19 | "build", 20 | "push" 21 | ], 22 | "author": "Docker", 23 | "contributors": [ 24 | { 25 | "name": "CrazyMax", 26 | "url": "https://crazymax.dev" 27 | } 28 | ], 29 | "license": "Apache-2.0", 30 | "dependencies": { 31 | "@actions/core": "^1.10.0", 32 | "@docker/actions-toolkit": "^0.1.0", 33 | "handlebars": "^4.7.7" 34 | }, 35 | "devDependencies": { 36 | "@types/csv-parse": "^1.2.2", 37 | "@types/node": "^16.18.21", 38 | "@typescript-eslint/eslint-plugin": "^5.56.0", 39 | "@typescript-eslint/parser": "^5.56.0", 40 | "@vercel/ncc": "^0.36.1", 41 | "eslint": "^8.36.0", 42 | "eslint-config-prettier": "^8.8.0", 43 | "eslint-plugin-jest": "^27.2.1", 44 | "eslint-plugin-prettier": "^4.2.1", 45 | "jest": "^29.5.0", 46 | "prettier": "^2.8.7", 47 | "ts-jest": "^29.0.5", 48 | "ts-node": "^10.9.1", 49 | "typescript": "^4.9.5" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /.github/SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support [![](https://isitmaintained.com/badge/resolution/docker/build-push-action.svg)](https://isitmaintained.com/project/docker/build-push-action) 2 | 3 | First, [be a good guy](https://github.com/kossnocorp/etiquette/blob/master/README.md). 4 | 5 | ## Reporting an issue 6 | 7 | Please do a search in [open issues](https://github.com/docker/build-push-action/issues?utf8=%E2%9C%93&q=) to see if the issue or feature request has already been filed. 8 | 9 | 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. 10 | 11 | :+1: - upvote 12 | 13 | :-1: - downvote 14 | 15 | If you cannot find an existing issue that describes your bug or feature, submit an issue using the guidelines below. 16 | 17 | ## Writing good bug reports and feature requests 18 | 19 | File a single issue per problem and feature request. 20 | 21 | * Do not enumerate multiple bugs or feature requests in the same issue. 22 | * 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. 23 | 24 | The more information you can provide, the more likely someone will be successful reproducing the issue and finding a fix. 25 | 26 | You are now ready to [create a new issue](https://github.com/docker/build-push-action/issues/new/choose)! 27 | 28 | ## Closure policy 29 | 30 | * Issues that don't have the information requested above (when applicable) will be closed immediately and the poster directed to the support guidelines. 31 | * Issues that go a week without a response from original poster are subject to closure at our discretion. 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib 3 | 4 | # Rest of the file pulled from https://github.com/github/gitignore/blob/master/Node.gitignore 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | *.lcov 28 | 29 | # nyc test coverage 30 | .nyc_output 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | jspm_packages/ 46 | 47 | # TypeScript v1 declaration files 48 | typings/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Optional REPL history 60 | .node_repl_history 61 | 62 | # Output of 'npm pack' 63 | *.tgz 64 | 65 | # Yarn Integrity file 66 | .yarn-integrity 67 | 68 | # dotenv environment variables file 69 | .env 70 | .env.test 71 | 72 | # parcel-bundler cache (https://parceljs.org/) 73 | .cache 74 | 75 | # next.js build output 76 | .next 77 | 78 | # nuxt.js build output 79 | .nuxt 80 | 81 | # vuepress build output 82 | .vuepress/dist 83 | 84 | # Serverless directories 85 | .serverless/ 86 | 87 | # FuseBox cache 88 | .fusebox/ 89 | 90 | # DynamoDB Local files 91 | .dynamodb/ 92 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. 4 | 5 | Contributions to this project are [released](https://docs.github.com/en/github/site-policy/github-terms-of-service#6-contributions-under-repository-license) 6 | to the public under the [project's open source license](LICENSE). 7 | 8 | ## Submitting a pull request 9 | 10 | 1. [Fork](https://github.com/docker/build-push-action/fork) and clone the repository 11 | 2. Configure and install the dependencies: `yarn install` 12 | 3. Create a new branch: `git checkout -b my-branch-name` 13 | 4. Make your changes 14 | 5. Make sure the tests pass: `docker buildx bake test` 15 | 6. Format code and build javascript artifacts: `docker buildx bake pre-checkin` 16 | 7. Validate all code has correctly formatted and built: `docker buildx bake validate` 17 | 8. Push to your fork and [submit a pull request](https://github.com/docker/build-push-action/compare) 18 | 9. Pat your self on the back and wait for your pull request to be reviewed and merged. 19 | 20 | Here are a few things you can do that will increase the likelihood of your pull request being accepted: 21 | 22 | - Make sure the `README.md` and any other relevant **documentation are kept up-to-date**. 23 | - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. 24 | - 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**. 25 | - Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). 26 | 27 | ## Resources 28 | 29 | - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) 30 | - [Using Pull Requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) 31 | - [GitHub Help](https://docs.github.com/en) 32 | -------------------------------------------------------------------------------- /.github/e2e/harbor/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eu 3 | 4 | : "${HARBOR_VERSION:=v2.7.0}" 5 | : "${HARBOR_HOST:=localhost}" 6 | : "${HARBOR_PORT:=49154}" 7 | : "${REGISTRY_USER:=admin}" 8 | : "${REGISTRY_PASSWORD:=Harbor12345}" 9 | 10 | : "${HARBOR_PROJECT:=test-docker-action}" 11 | 12 | project_post_data() { 13 | cat </dev/null 41 | yq --no-colors harbor.yml 42 | ) 43 | echo "::endgroup::" 44 | 45 | # install and start 46 | echo "::group::Installing Harbor" 47 | ( 48 | cd /tmp/harbor 49 | set -x 50 | ./install.sh 51 | sleep 10 52 | netstat -aptn 53 | ) 54 | echo "::endgroup::" 55 | 56 | # compose config 57 | echo "::group::Compose config" 58 | ( 59 | cd /tmp/harbor 60 | set -x 61 | docker compose config 62 | ) 63 | echo "::endgroup::" 64 | 65 | # create project 66 | echo "::group::Creating project" 67 | ( 68 | set -x 69 | curl --fail -v -k --max-time 10 -u "$REGISTRY_USER:$REGISTRY_PASSWORD" -X POST -H "Content-Type: application/json" -d "$(project_post_data)" "http://$HARBOR_HOST:$HARBOR_PORT/api/v2.0/projects" 70 | ) 71 | echo "::endgroup::" 72 | 73 | # list projects 74 | echo "::group::List projects" 75 | ( 76 | set -x 77 | curl --fail -s -k --max-time 10 -u "$REGISTRY_USER:$REGISTRY_PASSWORD" -H "Content-Type: application/json" "http://$HARBOR_HOST:$HARBOR_PORT/api/v2.0/projects" | jq 78 | ) 79 | echo "::endgroup::" 80 | -------------------------------------------------------------------------------- /dev.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | ARG NODE_VERSION=16 4 | ARG DOCKER_VERSION=20.10.13 5 | ARG BUILDX_VERSION=0.8.0 6 | 7 | FROM node:${NODE_VERSION}-alpine AS base 8 | RUN apk add --no-cache cpio findutils git 9 | WORKDIR /src 10 | 11 | FROM base AS deps 12 | RUN --mount=type=bind,target=.,rw \ 13 | --mount=type=cache,target=/src/node_modules \ 14 | yarn install && mkdir /vendor && cp yarn.lock /vendor 15 | 16 | FROM scratch AS vendor-update 17 | COPY --from=deps /vendor / 18 | 19 | FROM deps AS vendor-validate 20 | RUN --mount=type=bind,target=.,rw <&2 'ERROR: Vendor result differs. Please vendor your package with "docker buildx bake vendor-update"' 26 | git status --porcelain -- yarn.lock 27 | exit 1 28 | fi 29 | EOT 30 | 31 | FROM deps AS build 32 | RUN --mount=type=bind,target=.,rw \ 33 | --mount=type=cache,target=/src/node_modules \ 34 | yarn run build && mkdir /out && cp -Rf dist /out/ 35 | 36 | FROM scratch AS build-update 37 | COPY --from=build /out / 38 | 39 | FROM build AS build-validate 40 | RUN --mount=type=bind,target=.,rw <&2 'ERROR: Build result differs. Please build first with "docker buildx bake build"' 46 | git status --porcelain -- dist 47 | exit 1 48 | fi 49 | EOT 50 | 51 | FROM deps AS format 52 | RUN --mount=type=bind,target=.,rw \ 53 | --mount=type=cache,target=/src/node_modules \ 54 | yarn run format \ 55 | && mkdir /out && find . -name '*.ts' -not -path './node_modules/*' | cpio -pdm /out 56 | 57 | FROM scratch AS format-update 58 | COPY --from=format /out / 59 | 60 | FROM deps AS lint 61 | RUN --mount=type=bind,target=.,rw \ 62 | --mount=type=cache,target=/src/node_modules \ 63 | yarn run lint 64 | 65 | FROM docker:${DOCKER_VERSION} as docker 66 | FROM docker/buildx-bin:${BUILDX_VERSION} as buildx 67 | 68 | FROM deps AS test 69 | RUN --mount=type=bind,target=.,rw \ 70 | --mount=type=cache,target=/src/node_modules \ 71 | --mount=type=bind,from=docker,source=/usr/local/bin/docker,target=/usr/bin/docker \ 72 | --mount=type=bind,from=buildx,source=/buildx,target=/usr/libexec/docker/cli-plugins/docker-buildx \ 73 | yarn run test --coverageDirectory=/tmp/coverage 74 | 75 | FROM scratch AS test-coverage 76 | COPY --from=test /tmp/coverage / 77 | -------------------------------------------------------------------------------- /.github/e2e/nexus/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eu 3 | 4 | SCRIPT_DIR=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) 5 | 6 | : "${NEXUS_VERSION:=3.47.1}" 7 | : "${NEXUS_HOST:=localhost}" 8 | : "${NEXUS_PORT:=8081}" 9 | : "${NEXUS_REGISTRY_PORT:=8082}" 10 | : "${REGISTRY_USER:=admin}" 11 | : "${REGISTRY_PASSWORD:=Nexus12345}" 12 | 13 | : "${NEXUS_REPO:=test-docker-action}" 14 | 15 | createrepo_post_data() { 16 | cat < { 17 | const inputs: context.Inputs = await context.getInputs(); 18 | const toolkit = new Toolkit(); 19 | 20 | await core.group(`GitHub Actions runtime token ACs`, async () => { 21 | try { 22 | await GitHub.printActionsRuntimeTokenACs(); 23 | } catch (e) { 24 | core.warning(e.message); 25 | } 26 | }); 27 | 28 | await core.group(`Docker info`, async () => { 29 | try { 30 | await Docker.printVersion(); 31 | await Docker.printInfo(); 32 | } catch (e) { 33 | core.info(e.message); 34 | } 35 | }); 36 | 37 | if (!(await toolkit.buildx.isAvailable())) { 38 | core.setFailed(`Docker buildx is required. See https://github.com/docker/setup-buildx-action to set up buildx.`); 39 | return; 40 | } 41 | 42 | stateHelper.setTmpDir(Context.tmpDir()); 43 | 44 | await core.group(`Buildx version`, async () => { 45 | await toolkit.buildx.printVersion(); 46 | }); 47 | 48 | const args: string[] = await context.getArgs(inputs, toolkit); 49 | const buildCmd = await toolkit.buildx.getCommand(args); 50 | await Exec.getExecOutput(buildCmd.command, buildCmd.args, { 51 | ignoreReturnCode: true 52 | }).then(res => { 53 | if (res.stderr.length > 0 && res.exitCode != 0) { 54 | throw new Error(`buildx failed with: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`); 55 | } 56 | }); 57 | 58 | const imageID = BuildxInputs.resolveBuildImageID(); 59 | const metadata = BuildxInputs.resolveBuildMetadata(); 60 | const digest = BuildxInputs.resolveDigest(); 61 | 62 | if (imageID) { 63 | await core.group(`ImageID`, async () => { 64 | core.info(imageID); 65 | core.setOutput('imageid', imageID); 66 | }); 67 | } 68 | if (digest) { 69 | await core.group(`Digest`, async () => { 70 | core.info(digest); 71 | core.setOutput('digest', digest); 72 | }); 73 | } 74 | if (metadata) { 75 | await core.group(`Metadata`, async () => { 76 | core.info(metadata); 77 | core.setOutput('metadata', metadata); 78 | }); 79 | } 80 | }, 81 | // post 82 | async () => { 83 | if (stateHelper.tmpDir.length > 0) { 84 | await core.group(`Removing temp folder ${stateHelper.tmpDir}`, async () => { 85 | fs.rmSync(stateHelper.tmpDir, {recursive: true}); 86 | }); 87 | } 88 | } 89 | ); 90 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | # https://help.github.com/en/articles/metadata-syntax-for-github-actions 2 | name: Build and push Docker images 3 | description: Build and push Docker images with Buildx 4 | author: docker 5 | branding: 6 | icon: 'anchor' 7 | color: 'blue' 8 | 9 | inputs: 10 | add-hosts: 11 | description: "List of a customs host-to-IP mapping (e.g., docker:10.180.0.1)" 12 | required: false 13 | allow: 14 | description: "List of extra privileged entitlement (e.g., network.host,security.insecure)" 15 | required: false 16 | attests: 17 | description: "List of attestation parameters (e.g., type=sbom,generator=image)" 18 | required: false 19 | build-args: 20 | description: "List of build-time variables" 21 | required: false 22 | build-contexts: 23 | description: "List of additional build contexts (e.g., name=path)" 24 | required: false 25 | builder: 26 | description: "Builder instance" 27 | required: false 28 | cache-from: 29 | description: "List of external cache sources for buildx (e.g., user/app:cache, type=local,src=path/to/dir)" 30 | required: false 31 | cache-to: 32 | description: "List of cache export destinations for buildx (e.g., user/app:cache, type=local,dest=path/to/dir)" 33 | required: false 34 | cgroup-parent: 35 | description: "Optional parent cgroup for the container used in the build" 36 | required: false 37 | context: 38 | description: "Build's context is the set of files located in the specified PATH or URL" 39 | required: false 40 | file: 41 | description: "Path to the Dockerfile" 42 | required: false 43 | labels: 44 | description: "List of metadata for an image" 45 | required: false 46 | load: 47 | description: "Load is a shorthand for --output=type=docker" 48 | required: false 49 | default: 'false' 50 | network: 51 | description: "Set the networking mode for the RUN instructions during build" 52 | required: false 53 | no-cache: 54 | description: "Do not use cache when building the image" 55 | required: false 56 | default: 'false' 57 | no-cache-filters: 58 | description: "Do not cache specified stages" 59 | required: false 60 | outputs: 61 | description: "List of output destinations (format: type=local,dest=path)" 62 | required: false 63 | platforms: 64 | description: "List of target platforms for build" 65 | required: false 66 | provenance: 67 | description: "Generate provenance attestation for the build (shorthand for --attest=type=provenance)" 68 | required: false 69 | pull: 70 | description: "Always attempt to pull all referenced images" 71 | required: false 72 | default: 'false' 73 | push: 74 | description: "Push is a shorthand for --output=type=registry" 75 | required: false 76 | default: 'false' 77 | sbom: 78 | description: "Generate SBOM attestation for the build (shorthand for --attest=type=sbom)" 79 | required: false 80 | secrets: 81 | description: "List of secrets to expose to the build (e.g., key=string, GIT_AUTH_TOKEN=mytoken)" 82 | required: false 83 | secret-files: 84 | description: "List of secret files to expose to the build (e.g., key=filename, MY_SECRET=./secret.txt)" 85 | required: false 86 | shm-size: 87 | description: "Size of /dev/shm (e.g., 2g)" 88 | required: false 89 | ssh: 90 | description: "List of SSH agent socket or keys to expose to the build" 91 | required: false 92 | tags: 93 | description: "List of tags" 94 | required: false 95 | target: 96 | description: "Sets the target stage to build" 97 | required: false 98 | ulimit: 99 | description: "Ulimit options (e.g., nofile=1024:1024)" 100 | required: false 101 | github-token: 102 | description: "GitHub Token used to authenticate against a repository for Git context" 103 | default: ${{ github.token }} 104 | required: false 105 | 106 | outputs: 107 | imageid: 108 | description: 'Image ID' 109 | digest: 110 | description: 'Image digest' 111 | metadata: 112 | description: 'Build result metadata' 113 | 114 | runs: 115 | using: 'node16' 116 | main: 'dist/index.js' 117 | post: 'dist/index.js' 118 | -------------------------------------------------------------------------------- /TROUBLESHOOTING.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | * [Cannot push to a registry](#cannot-push-to-a-registry) 4 | * [BuildKit container logs](#buildkit-container-logs) 5 | * [With containerd](#with-containerd) 6 | * [`repository name must be lowercase`](#repository-name-must-be-lowercase) 7 | 8 | ## Cannot push to a registry 9 | 10 | While pushing to a registry, you may encounter these kinds of issues: 11 | 12 | * `failed commit on ref "layer-sha256:...": invalid content digest in response: invalid checksum digest format` 13 | * `failed commit on ref "layer-sha256:...": no response` 14 | * `failed commit on ref "manifest-sha256:...": unexpected status: 400 Bad Request` 15 | * `failed commit on ref "manifest-sha256:...": unexpected status: 401 Unauthorized` 16 | * `unexpected response: 401 Unauthorized` 17 | 18 | These issues are not directly related to this action but are rather linked to 19 | [Buildx](https://github.com/docker/buildx), [BuildKit](https://github.com/moby/buildkit), 20 | [containerd](https://github.com/containerd/containerd) or the registry on which 21 | you're pushing your image. The quality of error message depends on the registry 22 | and are usually not very informative. 23 | 24 | ### BuildKit container logs 25 | 26 | To help you solve this, you have to [enable debugging in the setup-buildx](https://github.com/docker/setup-buildx-action#buildkit-container-logs) 27 | action step and attach BuildKit container logs to your issue. 28 | 29 | ### With containerd 30 | 31 | Next you can test pushing with [containerd action](https://github.com/crazy-max/ghaction-setup-containerd) 32 | using the following workflow. If it works then open an issue on [BuildKit](https://github.com/moby/buildkit) 33 | repository. 34 | 35 | ```yaml 36 | name: containerd 37 | 38 | on: 39 | push: 40 | 41 | jobs: 42 | containerd: 43 | runs-on: ubuntu-latest 44 | steps: 45 | - 46 | name: Checkout 47 | uses: actions/checkout@v3 48 | - 49 | name: Set up QEMU 50 | uses: docker/setup-qemu-action@v2 51 | - 52 | name: Set up Docker Buildx 53 | uses: docker/setup-buildx-action@v2 54 | with: 55 | buildkitd-flags: --debug 56 | - 57 | name: Set up containerd 58 | uses: crazy-max/ghaction-setup-containerd@v2 59 | - 60 | name: Build Docker image 61 | uses: docker/build-push-action@v4 62 | with: 63 | context: . 64 | platforms: linux/amd64,linux/arm64 65 | tags: docker.io/user/app:latest 66 | outputs: type=oci,dest=/tmp/image.tar 67 | - 68 | name: Import image in containerd 69 | run: | 70 | sudo ctr i import --base-name docker.io/user/app --digests --all-platforms /tmp/image.tar 71 | - 72 | name: Push image with containerd 73 | run: | 74 | sudo ctr --debug i push --user "${{ secrets.DOCKER_USERNAME }}:${{ secrets.DOCKER_PASSWORD }}" docker.io/user/app:latest 75 | ``` 76 | 77 | ## `repository name must be lowercase` 78 | 79 | You may encounter this issue if you're using `github.repository` as a repo slug 80 | in your tag: 81 | 82 | ``` 83 | #6 exporting to image 84 | #6 exporting layers 85 | #6 exporting layers 1.2s done 86 | #6 exporting manifest sha256:b47f7dfb97b89ccd5de553af3c8cd94c4795884cbe5693e93946b1d95a7b1d12 0.0s done 87 | #6 exporting config sha256:995e93fab8196893192f08a38deea6769dc4d98f86cf705eccc24ec96a3e271c 0.0s done 88 | #6 ERROR: invalid reference format: repository name must be lowercase 89 | ------ 90 | > exporting to image: 91 | ------ 92 | error: failed to solve: invalid reference format: repository name must be lowercase 93 | ``` 94 | 95 | or a cache reference: 96 | 97 | ``` 98 | #10 importing cache manifest from ghcr.io/My-Org/repo:main 99 | #10 ERROR: invalid reference format: repository name must be lowercase 100 | ``` 101 | 102 | To fix this issue you can use our [metadata action](https://github.com/docker/metadata-action) 103 | to generate sanitized tags: 104 | 105 | ```yaml 106 | - name: Docker meta 107 | id: meta 108 | uses: docker/metadata-action@v4 109 | with: 110 | images: ghcr.io/${{ github.repository }} 111 | tags: latest 112 | 113 | - name: Build and push 114 | uses: docker/build-push-action@v4 115 | with: 116 | context: . 117 | push: true 118 | tags: ${{ steps.meta.outputs.tags }} 119 | ``` 120 | 121 | Or a dedicated step to sanitize the slug: 122 | 123 | ```yaml 124 | - name: Sanitize repo slug 125 | uses: actions/github-script@v6 126 | id: repo_slug 127 | with: 128 | result-encoding: string 129 | script: return 'ghcr.io/${{ github.repository }}'.toLowerCase() 130 | 131 | - name: Build and push 132 | uses: docker/build-push-action@v4 133 | with: 134 | context: . 135 | push: true 136 | tags: ${{ steps.repo_slug.outputs.result }}:latest 137 | ``` 138 | -------------------------------------------------------------------------------- /.github/workflows/e2e.yml: -------------------------------------------------------------------------------- 1 | name: e2e 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | buildx-version: 7 | description: 'Buildx version or Git context' 8 | default: 'latest' 9 | required: false 10 | buildkit-image: 11 | description: 'BuildKit image' 12 | default: 'moby/buildkit:buildx-stable-1' 13 | required: false 14 | tag: 15 | description: 'Additional tag to push' 16 | required: false 17 | schedule: 18 | - cron: '0 10 * * *' 19 | push: 20 | branches: 21 | - 'master' 22 | tags: 23 | - 'v*' 24 | 25 | env: 26 | BUILDX_VERSION: latest 27 | BUILDKIT_IMAGE: moby/buildkit:buildx-stable-1 28 | HARBOR_VERSION: v2.7.0 29 | NEXUS_VERSION: 3.47.1 30 | DISTRIBUTION_VERSION: 2.8.1 31 | 32 | jobs: 33 | build: 34 | runs-on: ubuntu-latest 35 | strategy: 36 | fail-fast: false 37 | matrix: 38 | include: 39 | - 40 | name: Distribution 41 | id: distribution 42 | type: local 43 | - 44 | name: Docker Hub 45 | registry: '' 46 | slug: ghactionstest/ghactionstest 47 | username_secret: DOCKERHUB_USERNAME 48 | password_secret: DOCKERHUB_TOKEN 49 | type: remote 50 | - 51 | name: GitHub 52 | registry: ghcr.io 53 | slug: ghcr.io/docker-ghactiontest/test 54 | username_secret: GHCR_USERNAME 55 | password_secret: GHCR_PAT 56 | type: remote 57 | - 58 | name: GitLab 59 | registry: registry.gitlab.com 60 | slug: registry.gitlab.com/test1716/test 61 | username_secret: GITLAB_USERNAME 62 | password_secret: GITLAB_TOKEN 63 | type: remote 64 | - 65 | name: AWS ECR 66 | registry: 175142243308.dkr.ecr.us-east-2.amazonaws.com 67 | slug: 175142243308.dkr.ecr.us-east-2.amazonaws.com/sandbox/test-docker-action 68 | username_secret: AWS_ACCESS_KEY_ID 69 | password_secret: AWS_SECRET_ACCESS_KEY 70 | type: remote 71 | - 72 | name: AWS ECR Public 73 | registry: public.ecr.aws 74 | slug: public.ecr.aws/q3b5f1u4/test-docker-action 75 | username_secret: AWS_ACCESS_KEY_ID 76 | password_secret: AWS_SECRET_ACCESS_KEY 77 | type: remote 78 | - 79 | name: Google Artifact Registry 80 | registry: us-east4-docker.pkg.dev 81 | slug: us-east4-docker.pkg.dev/sandbox-298914/docker-official-github-actions/test-docker-action 82 | username_secret: GAR_USERNAME 83 | password_secret: GAR_JSON_KEY 84 | type: remote 85 | - 86 | name: Google Container Registry 87 | registry: gcr.io 88 | slug: gcr.io/sandbox-298914/test-docker-action 89 | username_secret: GCR_USERNAME 90 | password_secret: GCR_JSON_KEY 91 | type: remote 92 | - 93 | name: Azure Container Registry 94 | registry: officialgithubactions.azurecr.io 95 | slug: officialgithubactions.azurecr.io/test-docker-action 96 | username_secret: AZURE_CLIENT_ID 97 | password_secret: AZURE_CLIENT_SECRET 98 | type: remote 99 | - 100 | name: Quay 101 | registry: quay.io 102 | slug: quay.io/docker_build_team/ghactiontest 103 | username_secret: QUAY_USERNAME 104 | password_secret: QUAY_TOKEN 105 | type: remote 106 | - 107 | name: Artifactory 108 | registry: buildkitghactiontests.jfrog.io 109 | slug: buildkitghactiontests.jfrog.io/ghactiontest/test-docker-action 110 | username_secret: ARTIFACTORY_USERNAME 111 | password_secret: ARTIFACTORY_TOKEN 112 | type: remote 113 | - 114 | name: Harbor 115 | id: harbor 116 | type: local 117 | - 118 | name: Nexus 119 | id: nexus 120 | type: local 121 | steps: 122 | - 123 | name: Checkout 124 | uses: actions/checkout@v3 125 | - 126 | name: Set up env 127 | if: matrix.type == 'local' 128 | run: | 129 | cat ./.github/e2e/${{ matrix.id }}/env >> $GITHUB_ENV 130 | - 131 | name: Set up BuildKit config 132 | run: | 133 | touch /tmp/buildkitd.toml 134 | if [ "${{ matrix.type }}" = "local" ]; then 135 | echo -e "[registry.\"${{ env.REGISTRY_FQDN }}\"]\nhttp = true\ninsecure = true" > /tmp/buildkitd.toml 136 | fi 137 | - 138 | name: Set up Docker daemon 139 | if: matrix.type == 'local' 140 | run: | 141 | if [ ! -e /etc/docker/daemon.json ]; then 142 | echo '{}' | tee /etc/docker/daemon.json >/dev/null 143 | fi 144 | DOCKERD_CONFIG=$(jq '.+{"insecure-registries":["http://${{ env.REGISTRY_FQDN }}"]}' /etc/docker/daemon.json) 145 | sudo tee /etc/docker/daemon.json <<<"$DOCKERD_CONFIG" >/dev/null 146 | sudo service docker restart 147 | - 148 | name: Install ${{ matrix.name }} 149 | if: matrix.type == 'local' 150 | run: | 151 | sudo -E bash ./.github/e2e/${{ matrix.id }}/install.sh 152 | - 153 | name: Docker meta 154 | id: meta 155 | uses: docker/metadata-action@v4 156 | with: 157 | images: ${{ env.REGISTRY_SLUG || matrix.slug }} 158 | tags: | 159 | type=ref,event=branch 160 | type=ref,event=tag 161 | type=raw,value=${{ inputs.tag }},enable=${{ inputs.tag != '' }} 162 | - 163 | name: Set up QEMU 164 | uses: docker/setup-qemu-action@v2 165 | - 166 | name: Set up Docker Buildx 167 | uses: docker/setup-buildx-action@v2 168 | with: 169 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 170 | config: /tmp/buildkitd.toml 171 | buildkitd-flags: --debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host 172 | driver-opts: | 173 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 174 | network=host 175 | - 176 | name: Login to Registry 177 | if: github.event_name != 'pull_request' && (env.REGISTRY_USER || matrix.username_secret) != '' 178 | uses: docker/login-action@v2 179 | with: 180 | registry: ${{ env.REGISTRY_FQDN || matrix.registry }} 181 | username: ${{ env.REGISTRY_USER || secrets[matrix.username_secret] }} 182 | password: ${{ env.REGISTRY_PASSWORD || secrets[matrix.password_secret] }} 183 | - 184 | name: Build and push 185 | uses: ./ 186 | with: 187 | context: ./test 188 | file: ./test/multi.Dockerfile 189 | platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x 190 | push: ${{ github.event_name != 'pull_request' }} 191 | tags: ${{ steps.meta.outputs.tags }} 192 | labels: ${{ steps.meta.outputs.labels }} 193 | cache-from: type=registry,ref=${{ env.REGISTRY_SLUG || matrix.slug }}:master 194 | cache-to: type=inline 195 | - 196 | name: Inspect image 197 | run: | 198 | docker pull ${{ env.REGISTRY_SLUG || matrix.slug }}:${{ steps.meta.outputs.version }} 199 | docker image inspect ${{ env.REGISTRY_SLUG || matrix.slug }}:${{ steps.meta.outputs.version }} 200 | - 201 | name: Check manifest 202 | run: | 203 | docker buildx imagetools inspect ${{ env.REGISTRY_SLUG || matrix.slug }}:${{ steps.meta.outputs.version }} --format '{{json .}}' 204 | -------------------------------------------------------------------------------- /src/context.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core'; 2 | import * as handlebars from 'handlebars'; 3 | import {Context} from '@docker/actions-toolkit/lib/context'; 4 | import {GitHub} from '@docker/actions-toolkit/lib/github'; 5 | import {Inputs as BuildxInputs} from '@docker/actions-toolkit/lib/buildx/inputs'; 6 | import {Toolkit} from '@docker/actions-toolkit/lib/toolkit'; 7 | import {Util} from '@docker/actions-toolkit/lib/util'; 8 | 9 | export interface Inputs { 10 | addHosts: string[]; 11 | allow: string[]; 12 | attests: string[]; 13 | buildArgs: string[]; 14 | buildContexts: string[]; 15 | builder: string; 16 | cacheFrom: string[]; 17 | cacheTo: string[]; 18 | cgroupParent: string; 19 | context: string; 20 | file: string; 21 | labels: string[]; 22 | load: boolean; 23 | network: string; 24 | noCache: boolean; 25 | noCacheFilters: string[]; 26 | outputs: string[]; 27 | platforms: string[]; 28 | provenance: string; 29 | pull: boolean; 30 | push: boolean; 31 | sbom: string; 32 | secrets: string[]; 33 | secretFiles: string[]; 34 | shmSize: string; 35 | ssh: string[]; 36 | tags: string[]; 37 | target: string; 38 | ulimit: string[]; 39 | githubToken: string; 40 | } 41 | 42 | export async function getInputs(): Promise { 43 | return { 44 | addHosts: Util.getInputList('add-hosts'), 45 | allow: Util.getInputList('allow'), 46 | attests: Util.getInputList('attests', {ignoreComma: true}), 47 | buildArgs: Util.getInputList('build-args', {ignoreComma: true}), 48 | buildContexts: Util.getInputList('build-contexts', {ignoreComma: true}), 49 | builder: core.getInput('builder'), 50 | cacheFrom: Util.getInputList('cache-from', {ignoreComma: true}), 51 | cacheTo: Util.getInputList('cache-to', {ignoreComma: true}), 52 | cgroupParent: core.getInput('cgroup-parent'), 53 | context: core.getInput('context') || Context.gitContext(), 54 | file: core.getInput('file'), 55 | labels: Util.getInputList('labels', {ignoreComma: true}), 56 | load: core.getBooleanInput('load'), 57 | network: core.getInput('network'), 58 | noCache: core.getBooleanInput('no-cache'), 59 | noCacheFilters: Util.getInputList('no-cache-filters'), 60 | outputs: Util.getInputList('outputs', {ignoreComma: true}), 61 | platforms: Util.getInputList('platforms'), 62 | provenance: BuildxInputs.getProvenanceInput('provenance'), 63 | pull: core.getBooleanInput('pull'), 64 | push: core.getBooleanInput('push'), 65 | sbom: core.getInput('sbom'), 66 | secrets: Util.getInputList('secrets', {ignoreComma: true}), 67 | secretFiles: Util.getInputList('secret-files', {ignoreComma: true}), 68 | shmSize: core.getInput('shm-size'), 69 | ssh: Util.getInputList('ssh'), 70 | tags: Util.getInputList('tags'), 71 | target: core.getInput('target'), 72 | ulimit: Util.getInputList('ulimit', {ignoreComma: true}), 73 | githubToken: core.getInput('github-token') 74 | }; 75 | } 76 | 77 | export async function getArgs(inputs: Inputs, toolkit: Toolkit): Promise> { 78 | const context = handlebars.compile(inputs.context)({ 79 | defaultContext: Context.gitContext() 80 | }); 81 | // prettier-ignore 82 | return [ 83 | ...await getBuildArgs(inputs, context, toolkit), 84 | ...await getCommonArgs(inputs, toolkit), 85 | context 86 | ]; 87 | } 88 | 89 | async function getBuildArgs(inputs: Inputs, context: string, toolkit: Toolkit): Promise> { 90 | const args: Array = ['build']; 91 | await Util.asyncForEach(inputs.addHosts, async addHost => { 92 | args.push('--add-host', addHost); 93 | }); 94 | if (inputs.allow.length > 0) { 95 | args.push('--allow', inputs.allow.join(',')); 96 | } 97 | if (await toolkit.buildx.versionSatisfies('>=0.10.0')) { 98 | await Util.asyncForEach(inputs.attests, async attest => { 99 | args.push('--attest', attest); 100 | }); 101 | } 102 | await Util.asyncForEach(inputs.buildArgs, async buildArg => { 103 | args.push('--build-arg', buildArg); 104 | }); 105 | if (await toolkit.buildx.versionSatisfies('>=0.8.0')) { 106 | await Util.asyncForEach(inputs.buildContexts, async buildContext => { 107 | args.push('--build-context', buildContext); 108 | }); 109 | } 110 | await Util.asyncForEach(inputs.cacheFrom, async cacheFrom => { 111 | args.push('--cache-from', cacheFrom); 112 | }); 113 | await Util.asyncForEach(inputs.cacheTo, async cacheTo => { 114 | args.push('--cache-to', cacheTo); 115 | }); 116 | if (inputs.cgroupParent) { 117 | args.push('--cgroup-parent', inputs.cgroupParent); 118 | } 119 | if (inputs.file) { 120 | args.push('--file', inputs.file); 121 | } 122 | if (!BuildxInputs.hasLocalExporter(inputs.outputs) && !BuildxInputs.hasTarExporter(inputs.outputs) && (inputs.platforms.length == 0 || (await toolkit.buildx.versionSatisfies('>=0.4.2')))) { 123 | args.push('--iidfile', BuildxInputs.getBuildImageIDFilePath()); 124 | } 125 | await Util.asyncForEach(inputs.labels, async label => { 126 | args.push('--label', label); 127 | }); 128 | await Util.asyncForEach(inputs.noCacheFilters, async noCacheFilter => { 129 | args.push('--no-cache-filter', noCacheFilter); 130 | }); 131 | await Util.asyncForEach(inputs.outputs, async output => { 132 | args.push('--output', output); 133 | }); 134 | if (inputs.platforms.length > 0) { 135 | args.push('--platform', inputs.platforms.join(',')); 136 | } 137 | if (await toolkit.buildx.versionSatisfies('>=0.10.0')) { 138 | if (inputs.provenance) { 139 | args.push('--provenance', inputs.provenance); 140 | } else if ((await toolkit.buildkit.versionSatisfies(inputs.builder, '>=0.11.0')) && !BuildxInputs.hasDockerExporter(inputs.outputs, inputs.load)) { 141 | // if provenance not specified and BuildKit version compatible for 142 | // attestation, set default provenance. Also needs to make sure user 143 | // doesn't want to explicitly load the image to docker. 144 | if (GitHub.context.payload.repository?.private ?? false) { 145 | // if this is a private repository, we set the default provenance 146 | // attributes being set in buildx: https://github.com/docker/buildx/blob/fb27e3f919dcbf614d7126b10c2bc2d0b1927eb6/build/build.go#L603 147 | args.push('--provenance', BuildxInputs.resolveProvenanceAttrs(`mode=min,inline-only=true`)); 148 | } else { 149 | // for a public repository, we set max provenance mode. 150 | args.push('--provenance', BuildxInputs.resolveProvenanceAttrs(`mode=max`)); 151 | } 152 | } 153 | if (inputs.sbom) { 154 | args.push('--sbom', inputs.sbom); 155 | } 156 | } 157 | await Util.asyncForEach(inputs.secrets, async secret => { 158 | try { 159 | args.push('--secret', BuildxInputs.resolveBuildSecretString(secret)); 160 | } catch (err) { 161 | core.warning(err.message); 162 | } 163 | }); 164 | await Util.asyncForEach(inputs.secretFiles, async secretFile => { 165 | try { 166 | args.push('--secret', BuildxInputs.resolveBuildSecretFile(secretFile)); 167 | } catch (err) { 168 | core.warning(err.message); 169 | } 170 | }); 171 | if (inputs.githubToken && !BuildxInputs.hasGitAuthTokenSecret(inputs.secrets) && context.startsWith(Context.gitContext())) { 172 | args.push('--secret', BuildxInputs.resolveBuildSecretString(`GIT_AUTH_TOKEN=${inputs.githubToken}`)); 173 | } 174 | if (inputs.shmSize) { 175 | args.push('--shm-size', inputs.shmSize); 176 | } 177 | await Util.asyncForEach(inputs.ssh, async ssh => { 178 | args.push('--ssh', ssh); 179 | }); 180 | await Util.asyncForEach(inputs.tags, async tag => { 181 | args.push('--tag', tag); 182 | }); 183 | if (inputs.target) { 184 | args.push('--target', inputs.target); 185 | } 186 | await Util.asyncForEach(inputs.ulimit, async ulimit => { 187 | args.push('--ulimit', ulimit); 188 | }); 189 | return args; 190 | } 191 | 192 | async function getCommonArgs(inputs: Inputs, toolkit: Toolkit): Promise> { 193 | const args: Array = []; 194 | if (inputs.builder) { 195 | args.push('--builder', inputs.builder); 196 | } 197 | if (inputs.load) { 198 | args.push('--load'); 199 | } 200 | if (await toolkit.buildx.versionSatisfies('>=0.6.0')) { 201 | args.push('--metadata-file', BuildxInputs.getBuildMetadataFilePath()); 202 | } 203 | if (inputs.network) { 204 | args.push('--network', inputs.network); 205 | } 206 | if (inputs.noCache) { 207 | args.push('--no-cache'); 208 | } 209 | if (inputs.pull) { 210 | args.push('--pull'); 211 | } 212 | if (inputs.push) { 213 | args.push('--push'); 214 | } 215 | return args; 216 | } 217 | -------------------------------------------------------------------------------- /__mocks__/@actions/github.ts: -------------------------------------------------------------------------------- 1 | import {jest} from '@jest/globals'; 2 | 3 | export const context = { 4 | repo: { 5 | owner: 'docker', 6 | repo: 'build-push-action' 7 | }, 8 | ref: 'refs/heads/master', 9 | runId: 123456789, 10 | payload: { 11 | after: '860c1904a1ce19322e91ac35af1ab07466440c37', 12 | base_ref: null, 13 | before: '5f3331d7f7044c18ca9f12c77d961c4d7cf3276a', 14 | commits: [ 15 | { 16 | author: { 17 | email: 'crazy-max@users.noreply.github.com', 18 | name: 'CrazyMax', 19 | username: 'crazy-max' 20 | }, 21 | committer: { 22 | email: 'crazy-max@users.noreply.github.com', 23 | name: 'CrazyMax', 24 | username: 'crazy-max' 25 | }, 26 | distinct: true, 27 | id: '860c1904a1ce19322e91ac35af1ab07466440c37', 28 | message: 'hello dev', 29 | timestamp: '2022-04-19T11:27:24+02:00', 30 | tree_id: 'd2c60af597e863787d2d27f569e30495b0b92820', 31 | url: 'https://github.com/docker/test-docker-action/commit/860c1904a1ce19322e91ac35af1ab07466440c37' 32 | } 33 | ], 34 | compare: 'https://github.com/docker/test-docker-action/compare/5f3331d7f704...860c1904a1ce', 35 | created: false, 36 | deleted: false, 37 | forced: false, 38 | head_commit: { 39 | author: { 40 | email: 'crazy-max@users.noreply.github.com', 41 | name: 'CrazyMax', 42 | username: 'crazy-max' 43 | }, 44 | committer: { 45 | email: 'crazy-max@users.noreply.github.com', 46 | name: 'CrazyMax', 47 | username: 'crazy-max' 48 | }, 49 | distinct: true, 50 | id: '860c1904a1ce19322e91ac35af1ab07466440c37', 51 | message: 'hello dev', 52 | timestamp: '2022-04-19T11:27:24+02:00', 53 | tree_id: 'd2c60af597e863787d2d27f569e30495b0b92820', 54 | url: 'https://github.com/docker/test-docker-action/commit/860c1904a1ce19322e91ac35af1ab07466440c37' 55 | }, 56 | organization: { 57 | avatar_url: 'https://avatars.githubusercontent.com/u/5429470?v=4', 58 | description: 'Docker helps developers bring their ideas to life by conquering the complexity of app development.', 59 | events_url: 'https://api.github.com/orgs/docker/events', 60 | hooks_url: 'https://api.github.com/orgs/docker/hooks', 61 | id: 5429470, 62 | issues_url: 'https://api.github.com/orgs/docker/issues', 63 | login: 'docker', 64 | members_url: 'https://api.github.com/orgs/docker/members{/member}', 65 | node_id: 'MDEyOk9yZ2FuaXphdGlvbjU0Mjk0NzA=', 66 | public_members_url: 'https://api.github.com/orgs/docker/public_members{/member}', 67 | repos_url: 'https://api.github.com/orgs/docker/repos', 68 | url: 'https://api.github.com/orgs/docker' 69 | }, 70 | pusher: { 71 | email: 'github@crazymax.dev', 72 | name: 'crazy-max' 73 | }, 74 | ref: 'refs/heads/dev', 75 | repository: { 76 | allow_forking: true, 77 | archive_url: 'https://api.github.com/repos/docker/test-docker-action/{archive_format}{/ref}', 78 | archived: false, 79 | assignees_url: 'https://api.github.com/repos/docker/test-docker-action/assignees{/user}', 80 | blobs_url: 'https://api.github.com/repos/docker/test-docker-action/git/blobs{/sha}', 81 | branches_url: 'https://api.github.com/repos/docker/test-docker-action/branches{/branch}', 82 | clone_url: 'https://github.com/docker/test-docker-action.git', 83 | collaborators_url: 'https://api.github.com/repos/docker/test-docker-action/collaborators{/collaborator}', 84 | comments_url: 'https://api.github.com/repos/docker/test-docker-action/comments{/number}', 85 | commits_url: 'https://api.github.com/repos/docker/test-docker-action/commits{/sha}', 86 | compare_url: 'https://api.github.com/repos/docker/test-docker-action/compare/{base}...{head}', 87 | contents_url: 'https://api.github.com/repos/docker/test-docker-action/contents/{+path}', 88 | contributors_url: 'https://api.github.com/repos/docker/test-docker-action/contributors', 89 | created_at: 1596792180, 90 | default_branch: 'master', 91 | deployments_url: 'https://api.github.com/repos/docker/test-docker-action/deployments', 92 | description: 'Test "Docker" Actions', 93 | disabled: false, 94 | downloads_url: 'https://api.github.com/repos/docker/test-docker-action/downloads', 95 | events_url: 'https://api.github.com/repos/docker/test-docker-action/events', 96 | fork: false, 97 | forks: 1, 98 | forks_count: 1, 99 | forks_url: 'https://api.github.com/repos/docker/test-docker-action/forks', 100 | full_name: 'docker/test-docker-action', 101 | git_commits_url: 'https://api.github.com/repos/docker/test-docker-action/git/commits{/sha}', 102 | git_refs_url: 'https://api.github.com/repos/docker/test-docker-action/git/refs{/sha}', 103 | git_tags_url: 'https://api.github.com/repos/docker/test-docker-action/git/tags{/sha}', 104 | git_url: 'git://github.com/docker/test-docker-action.git', 105 | has_downloads: true, 106 | has_issues: true, 107 | has_pages: false, 108 | has_projects: true, 109 | has_wiki: true, 110 | homepage: '', 111 | hooks_url: 'https://api.github.com/repos/docker/test-docker-action/hooks', 112 | html_url: 'https://github.com/docker/test-docker-action', 113 | id: 285789493, 114 | is_template: false, 115 | issue_comment_url: 'https://api.github.com/repos/docker/test-docker-action/issues/comments{/number}', 116 | issue_events_url: 'https://api.github.com/repos/docker/test-docker-action/issues/events{/number}', 117 | issues_url: 'https://api.github.com/repos/docker/test-docker-action/issues{/number}', 118 | keys_url: 'https://api.github.com/repos/docker/test-docker-action/keys{/key_id}', 119 | labels_url: 'https://api.github.com/repos/docker/test-docker-action/labels{/name}', 120 | language: 'JavaScript', 121 | languages_url: 'https://api.github.com/repos/docker/test-docker-action/languages', 122 | license: { 123 | key: 'mit', 124 | name: 'MIT License', 125 | node_id: 'MDc6TGljZW5zZTEz', 126 | spdx_id: 'MIT', 127 | url: 'https://api.github.com/licenses/mit' 128 | }, 129 | master_branch: 'master', 130 | merges_url: 'https://api.github.com/repos/docker/test-docker-action/merges', 131 | milestones_url: 'https://api.github.com/repos/docker/test-docker-action/milestones{/number}', 132 | mirror_url: null, 133 | name: 'test-docker-action', 134 | node_id: 'MDEwOlJlcG9zaXRvcnkyODU3ODk0OTM=', 135 | notifications_url: 'https://api.github.com/repos/docker/test-docker-action/notifications{?since,all,participating}', 136 | open_issues: 6, 137 | open_issues_count: 6, 138 | organization: 'docker', 139 | owner: { 140 | avatar_url: 'https://avatars.githubusercontent.com/u/5429470?v=4', 141 | email: 'info@docker.com', 142 | events_url: 'https://api.github.com/users/docker/events{/privacy}', 143 | followers_url: 'https://api.github.com/users/docker/followers', 144 | following_url: 'https://api.github.com/users/docker/following{/other_user}', 145 | gists_url: 'https://api.github.com/users/docker/gists{/gist_id}', 146 | gravatar_id: '', 147 | html_url: 'https://github.com/docker', 148 | id: 5429470, 149 | login: 'docker', 150 | name: 'docker', 151 | node_id: 'MDEyOk9yZ2FuaXphdGlvbjU0Mjk0NzA=', 152 | organizations_url: 'https://api.github.com/users/docker/orgs', 153 | received_events_url: 'https://api.github.com/users/docker/received_events', 154 | repos_url: 'https://api.github.com/users/docker/repos', 155 | site_admin: false, 156 | starred_url: 'https://api.github.com/users/docker/starred{/owner}{/repo}', 157 | subscriptions_url: 'https://api.github.com/users/docker/subscriptions', 158 | type: 'Organization', 159 | url: 'https://api.github.com/users/docker' 160 | }, 161 | private: true, 162 | pulls_url: 'https://api.github.com/repos/docker/test-docker-action/pulls{/number}', 163 | pushed_at: 1650360446, 164 | releases_url: 'https://api.github.com/repos/docker/test-docker-action/releases{/id}', 165 | size: 796, 166 | ssh_url: 'git@github.com:docker/test-docker-action.git', 167 | stargazers: 0, 168 | stargazers_count: 0, 169 | stargazers_url: 'https://api.github.com/repos/docker/test-docker-action/stargazers', 170 | statuses_url: 'https://api.github.com/repos/docker/test-docker-action/statuses/{sha}', 171 | subscribers_url: 'https://api.github.com/repos/docker/test-docker-action/subscribers', 172 | subscription_url: 'https://api.github.com/repos/docker/test-docker-action/subscription', 173 | svn_url: 'https://github.com/docker/test-docker-action', 174 | tags_url: 'https://api.github.com/repos/docker/test-docker-action/tags', 175 | teams_url: 'https://api.github.com/repos/docker/test-docker-action/teams', 176 | topics: [], 177 | trees_url: 'https://api.github.com/repos/docker/test-docker-action/git/trees{/sha}', 178 | updated_at: '2022-04-19T09:05:09Z', 179 | url: 'https://github.com/docker/test-docker-action', 180 | visibility: 'private', 181 | watchers: 0, 182 | watchers_count: 0 183 | }, 184 | sender: { 185 | avatar_url: 'https://avatars.githubusercontent.com/u/1951866?v=4', 186 | events_url: 'https://api.github.com/users/crazy-max/events{/privacy}', 187 | followers_url: 'https://api.github.com/users/crazy-max/followers', 188 | following_url: 'https://api.github.com/users/crazy-max/following{/other_user}', 189 | gists_url: 'https://api.github.com/users/crazy-max/gists{/gist_id}', 190 | gravatar_id: '', 191 | html_url: 'https://github.com/crazy-max', 192 | id: 1951866, 193 | login: 'crazy-max', 194 | node_id: 'MDQ6VXNlcjE5NTE4NjY=', 195 | organizations_url: 'https://api.github.com/users/crazy-max/orgs', 196 | received_events_url: 'https://api.github.com/users/crazy-max/received_events', 197 | repos_url: 'https://api.github.com/users/crazy-max/repos', 198 | site_admin: false, 199 | starred_url: 'https://api.github.com/users/crazy-max/starred{/owner}{/repo}', 200 | subscriptions_url: 'https://api.github.com/users/crazy-max/subscriptions', 201 | type: 'User', 202 | url: 'https://api.github.com/users/crazy-max' 203 | } 204 | } 205 | }; 206 | 207 | export const getOctokit = jest.fn(); 208 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | https://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | Copyright 2013-2018 Docker, Inc. 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | https://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![GitHub release](https://img.shields.io/github/release/docker/build-push-action.svg?style=flat-square)](https://github.com/docker/build-push-action/releases/latest) 2 | [![GitHub marketplace](https://img.shields.io/badge/marketplace-build--and--push--docker--images-blue?logo=github&style=flat-square)](https://github.com/marketplace/actions/build-and-push-docker-images) 3 | [![CI workflow](https://img.shields.io/github/actions/workflow/status/docker/build-push-action/ci.yml?branch=master&label=ci&logo=github&style=flat-square)](https://github.com/docker/build-push-action/actions?workflow=ci) 4 | [![Test workflow](https://img.shields.io/github/actions/workflow/status/docker/build-push-action/test.yml?branch=master&label=test&logo=github&style=flat-square)](https://github.com/docker/build-push-action/actions?workflow=test) 5 | [![Codecov](https://img.shields.io/codecov/c/github/docker/build-push-action?logo=codecov&style=flat-square)](https://codecov.io/gh/docker/build-push-action) 6 | 7 | ## About 8 | 9 | GitHub Action to build and push Docker images with [Buildx](https://github.com/docker/buildx) 10 | with full support of the features provided by [Moby BuildKit](https://github.com/moby/buildkit) 11 | builder toolkit. This includes multi-platform build, secrets, remote cache, etc. 12 | and different builder deployment/namespacing options. 13 | 14 | ![Screenshot](.github/build-push-action.png) 15 | 16 | ___ 17 | 18 | * [Usage](#usage) 19 | * [Git context](#git-context) 20 | * [Path context](#path-context) 21 | * [Examples](#examples) 22 | * [Multi-platform image](https://docs.docker.com/build/ci/github-actions/multi-platform/) 23 | * [Secrets](https://docs.docker.com/build/ci/github-actions/secrets/) 24 | * [Push to multi-registries](https://docs.docker.com/build/ci/github-actions/push-multi-registries/) 25 | * [Manage tags and labels](https://docs.docker.com/build/ci/github-actions/manage-tags-labels/) 26 | * [Cache management](https://docs.docker.com/build/ci/github-actions/cache/) 27 | * [Export to Docker](https://docs.docker.com/build/ci/github-actions/export-docker/) 28 | * [Test before push](https://docs.docker.com/build/ci/github-actions/test-before-push/) 29 | * [Local registry](https://docs.docker.com/build/ci/github-actions/local-registry/) 30 | * [Share built image between jobs](https://docs.docker.com/build/ci/github-actions/share-image-jobs/) 31 | * [Named contexts](https://docs.docker.com/build/ci/github-actions/named-contexts/) 32 | * [Copy image between registries](https://docs.docker.com/build/ci/github-actions/copy-image-registries/) 33 | * [Update Docker Hub repo description](https://docs.docker.com/build/ci/github-actions/update-dockerhub-desc/) 34 | * [Customizing](#customizing) 35 | * [inputs](#inputs) 36 | * [outputs](#outputs) 37 | * [Troubleshooting](#troubleshooting) 38 | * [Contributing](#contributing) 39 | 40 | ## Usage 41 | 42 | In the examples below we are also using 3 other actions: 43 | 44 | * [`setup-buildx`](https://github.com/docker/setup-buildx-action) action will 45 | create and boot a builder using by default the [`docker-container` driver](https://docs.docker.com/build/building/drivers/docker-container/). 46 | This is **not required but recommended** using it to be able to build 47 | multi-platform images, export cache, etc. 48 | * [`setup-qemu`](https://github.com/docker/setup-qemu-action) action can be 49 | useful if you want to add emulation support with QEMU to be able to build 50 | against more platforms. 51 | * [`login`](https://github.com/docker/login-action) action will take care to 52 | log in against a Docker registry. 53 | 54 | ### Git context 55 | 56 | By default, this action uses the [Git context](https://docs.docker.com/engine/reference/commandline/build/#git-repositories), 57 | so you don't need to use the [`actions/checkout`](https://github.com/actions/checkout/) 58 | action to check out the repository as this will be done directly by [BuildKit](https://github.com/moby/buildkit). 59 | 60 | The git reference will be based on the [event that triggered your workflow](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows) 61 | and will result in the following context: `https://github.com//.git#`. 62 | 63 | ```yaml 64 | name: ci 65 | 66 | on: 67 | push: 68 | branches: 69 | - 'main' 70 | 71 | jobs: 72 | docker: 73 | runs-on: ubuntu-latest 74 | steps: 75 | - 76 | name: Set up QEMU 77 | uses: docker/setup-qemu-action@v2 78 | - 79 | name: Set up Docker Buildx 80 | uses: docker/setup-buildx-action@v2 81 | - 82 | name: Login to Docker Hub 83 | uses: docker/login-action@v2 84 | with: 85 | username: ${{ secrets.DOCKERHUB_USERNAME }} 86 | password: ${{ secrets.DOCKERHUB_TOKEN }} 87 | - 88 | name: Build and push 89 | uses: docker/build-push-action@v4 90 | with: 91 | push: true 92 | tags: user/app:latest 93 | ``` 94 | 95 | Be careful because **any file mutation in the steps that precede the build step 96 | will be ignored, including processing of the `.dockerignore` file** since 97 | the context is based on the Git reference. However, you can use the 98 | [Path context](#path-context) using the [`context` input](#inputs) alongside 99 | the [`actions/checkout`](https://github.com/actions/checkout/) action to remove 100 | this restriction. 101 | 102 | Default Git context can also be provided using the [Handlebars template](https://handlebarsjs.com/guide/) 103 | expression `{{defaultContext}}`. Here we can use it to provide a subdirectory 104 | to the default Git context: 105 | 106 | ```yaml 107 | - 108 | # Setting up Docker Buildx with docker-container driver is required 109 | # at the moment to be able to use a subdirectory with Git context 110 | name: Set up Docker Buildx 111 | uses: docker/setup-buildx-action@v2 112 | - 113 | name: Build and push 114 | uses: docker/build-push-action@v4 115 | with: 116 | context: "{{defaultContext}}:mysubdir" 117 | push: true 118 | tags: user/app:latest 119 | ``` 120 | 121 | > **Warning** 122 | > 123 | > Subdirectory for Git context is available from [BuildKit v0.9.0](https://github.com/moby/buildkit/releases/tag/v0.9.0). 124 | > If you're using the `docker` builder (default if `setup-buildx-action` not used), 125 | > then BuildKit in Docker Engine will be used. As Docker Engine < v22.x.x embeds 126 | > Buildkit 0.8.2 at the moment, it does not support this feature. It's therefore 127 | > required to use the `setup-buildx-action` at the moment. 128 | 129 | Building from the current repository automatically uses the [GitHub Token](https://docs.github.com/en/actions/security-guides/automatic-token-authentication), 130 | so it does not need to be passed. If you want to authenticate against another 131 | private repository, you have to use a [secret](https://docs.docker.com/build/ci/github-actions/examples/#secrets) 132 | named `GIT_AUTH_TOKEN` to be able to authenticate against it with Buildx: 133 | 134 | ```yaml 135 | - 136 | name: Build and push 137 | uses: docker/build-push-action@v4 138 | with: 139 | push: true 140 | tags: user/app:latest 141 | secrets: | 142 | GIT_AUTH_TOKEN=${{ secrets.MYTOKEN }} 143 | ``` 144 | 145 | ### Path context 146 | 147 | ```yaml 148 | name: ci 149 | 150 | on: 151 | push: 152 | branches: 153 | - 'main' 154 | 155 | jobs: 156 | docker: 157 | runs-on: ubuntu-latest 158 | steps: 159 | - 160 | name: Checkout 161 | uses: actions/checkout@v3 162 | - 163 | name: Set up QEMU 164 | uses: docker/setup-qemu-action@v2 165 | - 166 | name: Set up Docker Buildx 167 | uses: docker/setup-buildx-action@v2 168 | - 169 | name: Login to Docker Hub 170 | uses: docker/login-action@v2 171 | with: 172 | username: ${{ secrets.DOCKERHUB_USERNAME }} 173 | password: ${{ secrets.DOCKERHUB_TOKEN }} 174 | - 175 | name: Build and push 176 | uses: docker/build-push-action@v4 177 | with: 178 | context: . 179 | push: true 180 | tags: user/app:latest 181 | ``` 182 | 183 | ## Examples 184 | 185 | * [Multi-platform image](https://docs.docker.com/build/ci/github-actions/multi-platform/) 186 | * [Secrets](https://docs.docker.com/build/ci/github-actions/secrets/) 187 | * [Push to multi-registries](https://docs.docker.com/build/ci/github-actions/push-multi-registries/) 188 | * [Manage tags and labels](https://docs.docker.com/build/ci/github-actions/manage-tags-labels/) 189 | * [Cache management](https://docs.docker.com/build/ci/github-actions/cache/) 190 | * [Export to Docker](https://docs.docker.com/build/ci/github-actions/export-docker/) 191 | * [Test before push](https://docs.docker.com/build/ci/github-actions/test-before-push/) 192 | * [Local registry](https://docs.docker.com/build/ci/github-actions/local-registry/) 193 | * [Share built image between jobs](https://docs.docker.com/build/ci/github-actions/share-image-jobs/) 194 | * [Named contexts](https://docs.docker.com/build/ci/github-actions/named-contexts/) 195 | * [Copy image between registries](https://docs.docker.com/build/ci/github-actions/copy-image-registries/) 196 | * [Update Docker Hub repo description](https://docs.docker.com/build/ci/github-actions/update-dockerhub-desc/) 197 | 198 | ## Customizing 199 | 200 | ### inputs 201 | 202 | Following inputs can be used as `step.with` keys 203 | 204 | > `List` type is a newline-delimited string 205 | > ```yaml 206 | > cache-from: | 207 | > user/app:cache 208 | > type=local,src=path/to/dir 209 | > ``` 210 | 211 | > `CSV` type is a comma-delimited string 212 | > ```yaml 213 | > tags: name/app:latest,name/app:1.0.0 214 | > ``` 215 | 216 | | Name | Type | Description | 217 | |--------------------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 218 | | `add-hosts` | List/CSV | List of [customs host-to-IP mapping](https://docs.docker.com/engine/reference/commandline/build/#add-entries-to-container-hosts-file---add-host) (e.g., `docker:10.180.0.1`) | 219 | | `allow` | List/CSV | List of [extra privileged entitlement](https://docs.docker.com/engine/reference/commandline/buildx_build/#allow) (e.g., `network.host,security.insecure`) | 220 | | `attests` | List | List of [attestation](https://docs.docker.com/build/attestations/) parameters (e.g., `type=sbom,generator=image`) | 221 | | `builder` | String | Builder instance (see [setup-buildx](https://github.com/docker/setup-buildx-action) action) | 222 | | `build-args` | List | List of [build-time variables](https://docs.docker.com/engine/reference/commandline/buildx_build/#build-arg) | 223 | | `build-contexts` | List | List of additional [build contexts](https://docs.docker.com/engine/reference/commandline/buildx_build/#build-context) (e.g., `name=path`) | 224 | | `cache-from` | List | List of [external cache sources](https://docs.docker.com/engine/reference/commandline/buildx_build/#cache-from) (e.g., `type=local,src=path/to/dir`) | 225 | | `cache-to` | List | List of [cache export destinations](https://docs.docker.com/engine/reference/commandline/buildx_build/#cache-to) (e.g., `type=local,dest=path/to/dir`) | 226 | | `cgroup-parent` | String | Optional [parent cgroup](https://docs.docker.com/engine/reference/commandline/build/#use-a-custom-parent-cgroup---cgroup-parent) for the container used in the build | 227 | | `context` | String | Build's context is the set of files located in the specified [`PATH` or `URL`](https://docs.docker.com/engine/reference/commandline/build/) (default [Git context](#git-context)) | 228 | | `file` | String | Path to the Dockerfile. (default `{context}/Dockerfile`) | 229 | | `labels` | List | List of metadata for an image | 230 | | `load` | Bool | [Load](https://docs.docker.com/engine/reference/commandline/buildx_build/#load) is a shorthand for `--output=type=docker` (default `false`) | 231 | | `network` | String | Set the networking mode for the `RUN` instructions during build | 232 | | `no-cache` | Bool | Do not use cache when building the image (default `false`) | 233 | | `no-cache-filters` | List/CSV | Do not cache specified stages | 234 | | `outputs`¹ | List | List of [output destinations](https://docs.docker.com/engine/reference/commandline/buildx_build/#output) (format: `type=local,dest=path`) | 235 | | `platforms` | List/CSV | List of [target platforms](https://docs.docker.com/engine/reference/commandline/buildx_build/#platform) for build | 236 | | `provenance` | Bool/String | Generate [provenance](https://docs.docker.com/build/attestations/slsa-provenance/) attestation for the build (shorthand for `--attest=type=provenance`) | 237 | | `pull` | Bool | Always attempt to pull all referenced images (default `false`) | 238 | | `push` | Bool | [Push](https://docs.docker.com/engine/reference/commandline/buildx_build/#push) is a shorthand for `--output=type=registry` (default `false`) | 239 | | `sbom` | Bool/String | Generate [SBOM](https://docs.docker.com/build/attestations/sbom/) attestation for the build (shorthand for `--attest=type=sbom`) | 240 | | `secrets` | List | List of [secrets](https://docs.docker.com/engine/reference/commandline/buildx_build/#secret) to expose to the build (e.g., `key=string`, `GIT_AUTH_TOKEN=mytoken`) | 241 | | `secret-files` | List | List of [secret files](https://docs.docker.com/engine/reference/commandline/buildx_build/#secret) to expose to the build (e.g., `key=filename`, `MY_SECRET=./secret.txt`) | 242 | | `shm-size` | String | Size of [`/dev/shm`](https://docs.docker.com/engine/reference/commandline/buildx_build/#shm-size) (e.g., `2g`) | 243 | | `ssh` | List | List of [SSH agent socket or keys](https://docs.docker.com/engine/reference/commandline/buildx_build/#ssh) to expose to the build | 244 | | `tags` | List/CSV | List of tags | 245 | | `target` | String | Sets the target stage to build | 246 | | `ulimit` | List | [Ulimit](https://docs.docker.com/engine/reference/commandline/buildx_build/#ulimit) options (e.g., `nofile=1024:1024`) | 247 | | `github-token` | String | GitHub Token used to authenticate against a repository for [Git context](#git-context) (default `${{ github.token }}`) | 248 | 249 | > **Note** 250 | > 251 | > * ¹ multiple `outputs` are [not yet supported](https://github.com/moby/buildkit/issues/1555) 252 | 253 | ### outputs 254 | 255 | Following outputs are available 256 | 257 | | Name | Type | Description | 258 | |------------|---------|-----------------------| 259 | | `imageid` | String | Image ID | 260 | | `digest` | String | Image digest | 261 | | `metadata` | JSON | Build result metadata | 262 | 263 | ## Troubleshooting 264 | 265 | See [TROUBLESHOOTING.md](TROUBLESHOOTING.md) 266 | 267 | ## Contributing 268 | 269 | Want to contribute? Awesome! You can find information about contributing to 270 | this project in the [CONTRIBUTING.md](/.github/CONTRIBUTING.md) 271 | -------------------------------------------------------------------------------- /__tests__/fixtures/github-repo.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1296269, 3 | "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", 4 | "name": "Hello-World", 5 | "full_name": "octocat/Hello-World", 6 | "owner": { 7 | "login": "octocat", 8 | "id": 1, 9 | "node_id": "MDQ6VXNlcjE=", 10 | "avatar_url": "https://github.com/images/error/octocat_happy.gif", 11 | "gravatar_id": "", 12 | "url": "https://api.github.com/users/octocat", 13 | "html_url": "https://github.com/octocat", 14 | "followers_url": "https://api.github.com/users/octocat/followers", 15 | "following_url": "https://api.github.com/users/octocat/following{/other_user}", 16 | "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", 17 | "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", 18 | "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", 19 | "organizations_url": "https://api.github.com/users/octocat/orgs", 20 | "repos_url": "https://api.github.com/users/octocat/repos", 21 | "events_url": "https://api.github.com/users/octocat/events{/privacy}", 22 | "received_events_url": "https://api.github.com/users/octocat/received_events", 23 | "type": "User", 24 | "site_admin": false 25 | }, 26 | "private": false, 27 | "html_url": "https://github.com/octocat/Hello-World", 28 | "description": "This your first repo!", 29 | "fork": false, 30 | "url": "https://api.github.com/repos/octocat/Hello-World", 31 | "archive_url": "http://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", 32 | "assignees_url": "http://api.github.com/repos/octocat/Hello-World/assignees{/user}", 33 | "blobs_url": "http://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", 34 | "branches_url": "http://api.github.com/repos/octocat/Hello-World/branches{/branch}", 35 | "collaborators_url": "http://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", 36 | "comments_url": "http://api.github.com/repos/octocat/Hello-World/comments{/number}", 37 | "commits_url": "http://api.github.com/repos/octocat/Hello-World/commits{/sha}", 38 | "compare_url": "http://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", 39 | "contents_url": "http://api.github.com/repos/octocat/Hello-World/contents/{+path}", 40 | "contributors_url": "http://api.github.com/repos/octocat/Hello-World/contributors", 41 | "deployments_url": "http://api.github.com/repos/octocat/Hello-World/deployments", 42 | "downloads_url": "http://api.github.com/repos/octocat/Hello-World/downloads", 43 | "events_url": "http://api.github.com/repos/octocat/Hello-World/events", 44 | "forks_url": "http://api.github.com/repos/octocat/Hello-World/forks", 45 | "git_commits_url": "http://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", 46 | "git_refs_url": "http://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", 47 | "git_tags_url": "http://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", 48 | "git_url": "git:github.com/octocat/Hello-World.git", 49 | "issue_comment_url": "http://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", 50 | "issue_events_url": "http://api.github.com/repos/octocat/Hello-World/issues/events{/number}", 51 | "issues_url": "http://api.github.com/repos/octocat/Hello-World/issues{/number}", 52 | "keys_url": "http://api.github.com/repos/octocat/Hello-World/keys{/key_id}", 53 | "labels_url": "http://api.github.com/repos/octocat/Hello-World/labels{/name}", 54 | "languages_url": "http://api.github.com/repos/octocat/Hello-World/languages", 55 | "merges_url": "http://api.github.com/repos/octocat/Hello-World/merges", 56 | "milestones_url": "http://api.github.com/repos/octocat/Hello-World/milestones{/number}", 57 | "notifications_url": "http://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", 58 | "pulls_url": "http://api.github.com/repos/octocat/Hello-World/pulls{/number}", 59 | "releases_url": "http://api.github.com/repos/octocat/Hello-World/releases{/id}", 60 | "ssh_url": "git@github.com:octocat/Hello-World.git", 61 | "stargazers_url": "http://api.github.com/repos/octocat/Hello-World/stargazers", 62 | "statuses_url": "http://api.github.com/repos/octocat/Hello-World/statuses/{sha}", 63 | "subscribers_url": "http://api.github.com/repos/octocat/Hello-World/subscribers", 64 | "subscription_url": "http://api.github.com/repos/octocat/Hello-World/subscription", 65 | "tags_url": "http://api.github.com/repos/octocat/Hello-World/tags", 66 | "teams_url": "http://api.github.com/repos/octocat/Hello-World/teams", 67 | "trees_url": "http://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", 68 | "clone_url": "https://github.com/octocat/Hello-World.git", 69 | "mirror_url": "git:git.example.com/octocat/Hello-World", 70 | "hooks_url": "http://api.github.com/repos/octocat/Hello-World/hooks", 71 | "svn_url": "https://svn.github.com/octocat/Hello-World", 72 | "homepage": "https://github.com", 73 | "language": null, 74 | "forks_count": 9, 75 | "stargazers_count": 80, 76 | "watchers_count": 80, 77 | "size": 108, 78 | "default_branch": "master", 79 | "open_issues_count": 0, 80 | "is_template": true, 81 | "topics": [ 82 | "octocat", 83 | "atom", 84 | "electron", 85 | "api" 86 | ], 87 | "has_issues": true, 88 | "has_projects": true, 89 | "has_wiki": true, 90 | "has_pages": false, 91 | "has_downloads": true, 92 | "archived": false, 93 | "disabled": false, 94 | "visibility": "public", 95 | "pushed_at": "2011-01-26T19:06:43Z", 96 | "created_at": "2011-01-26T19:01:12Z", 97 | "updated_at": "2011-01-26T19:14:43Z", 98 | "permissions": { 99 | "pull": true, 100 | "triage": true, 101 | "push": false, 102 | "maintain": false, 103 | "admin": false 104 | }, 105 | "allow_rebase_merge": true, 106 | "template_repository": null, 107 | "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O", 108 | "allow_squash_merge": true, 109 | "delete_branch_on_merge": true, 110 | "allow_merge_commit": true, 111 | "subscribers_count": 42, 112 | "network_count": 0, 113 | "license": { 114 | "key": "mit", 115 | "name": "MIT License", 116 | "spdx_id": "MIT", 117 | "url": "https://api.github.com/licenses/mit", 118 | "node_id": "MDc6TGljZW5zZW1pdA==" 119 | }, 120 | "organization": { 121 | "login": "octocat", 122 | "id": 1, 123 | "node_id": "MDQ6VXNlcjE=", 124 | "avatar_url": "https://github.com/images/error/octocat_happy.gif", 125 | "gravatar_id": "", 126 | "url": "https://api.github.com/users/octocat", 127 | "html_url": "https://github.com/octocat", 128 | "followers_url": "https://api.github.com/users/octocat/followers", 129 | "following_url": "https://api.github.com/users/octocat/following{/other_user}", 130 | "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", 131 | "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", 132 | "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", 133 | "organizations_url": "https://api.github.com/users/octocat/orgs", 134 | "repos_url": "https://api.github.com/users/octocat/repos", 135 | "events_url": "https://api.github.com/users/octocat/events{/privacy}", 136 | "received_events_url": "https://api.github.com/users/octocat/received_events", 137 | "type": "Organization", 138 | "site_admin": false 139 | }, 140 | "parent": { 141 | "id": 1296269, 142 | "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", 143 | "name": "Hello-World", 144 | "full_name": "octocat/Hello-World", 145 | "owner": { 146 | "login": "octocat", 147 | "id": 1, 148 | "node_id": "MDQ6VXNlcjE=", 149 | "avatar_url": "https://github.com/images/error/octocat_happy.gif", 150 | "gravatar_id": "", 151 | "url": "https://api.github.com/users/octocat", 152 | "html_url": "https://github.com/octocat", 153 | "followers_url": "https://api.github.com/users/octocat/followers", 154 | "following_url": "https://api.github.com/users/octocat/following{/other_user}", 155 | "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", 156 | "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", 157 | "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", 158 | "organizations_url": "https://api.github.com/users/octocat/orgs", 159 | "repos_url": "https://api.github.com/users/octocat/repos", 160 | "events_url": "https://api.github.com/users/octocat/events{/privacy}", 161 | "received_events_url": "https://api.github.com/users/octocat/received_events", 162 | "type": "User", 163 | "site_admin": false 164 | }, 165 | "private": false, 166 | "html_url": "https://github.com/octocat/Hello-World", 167 | "description": "This your first repo!", 168 | "fork": false, 169 | "url": "https://api.github.com/repos/octocat/Hello-World", 170 | "archive_url": "http://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", 171 | "assignees_url": "http://api.github.com/repos/octocat/Hello-World/assignees{/user}", 172 | "blobs_url": "http://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", 173 | "branches_url": "http://api.github.com/repos/octocat/Hello-World/branches{/branch}", 174 | "collaborators_url": "http://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", 175 | "comments_url": "http://api.github.com/repos/octocat/Hello-World/comments{/number}", 176 | "commits_url": "http://api.github.com/repos/octocat/Hello-World/commits{/sha}", 177 | "compare_url": "http://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", 178 | "contents_url": "http://api.github.com/repos/octocat/Hello-World/contents/{+path}", 179 | "contributors_url": "http://api.github.com/repos/octocat/Hello-World/contributors", 180 | "deployments_url": "http://api.github.com/repos/octocat/Hello-World/deployments", 181 | "downloads_url": "http://api.github.com/repos/octocat/Hello-World/downloads", 182 | "events_url": "http://api.github.com/repos/octocat/Hello-World/events", 183 | "forks_url": "http://api.github.com/repos/octocat/Hello-World/forks", 184 | "git_commits_url": "http://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", 185 | "git_refs_url": "http://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", 186 | "git_tags_url": "http://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", 187 | "git_url": "git:github.com/octocat/Hello-World.git", 188 | "issue_comment_url": "http://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", 189 | "issue_events_url": "http://api.github.com/repos/octocat/Hello-World/issues/events{/number}", 190 | "issues_url": "http://api.github.com/repos/octocat/Hello-World/issues{/number}", 191 | "keys_url": "http://api.github.com/repos/octocat/Hello-World/keys{/key_id}", 192 | "labels_url": "http://api.github.com/repos/octocat/Hello-World/labels{/name}", 193 | "languages_url": "http://api.github.com/repos/octocat/Hello-World/languages", 194 | "merges_url": "http://api.github.com/repos/octocat/Hello-World/merges", 195 | "milestones_url": "http://api.github.com/repos/octocat/Hello-World/milestones{/number}", 196 | "notifications_url": "http://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", 197 | "pulls_url": "http://api.github.com/repos/octocat/Hello-World/pulls{/number}", 198 | "releases_url": "http://api.github.com/repos/octocat/Hello-World/releases{/id}", 199 | "ssh_url": "git@github.com:octocat/Hello-World.git", 200 | "stargazers_url": "http://api.github.com/repos/octocat/Hello-World/stargazers", 201 | "statuses_url": "http://api.github.com/repos/octocat/Hello-World/statuses/{sha}", 202 | "subscribers_url": "http://api.github.com/repos/octocat/Hello-World/subscribers", 203 | "subscription_url": "http://api.github.com/repos/octocat/Hello-World/subscription", 204 | "tags_url": "http://api.github.com/repos/octocat/Hello-World/tags", 205 | "teams_url": "http://api.github.com/repos/octocat/Hello-World/teams", 206 | "trees_url": "http://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", 207 | "clone_url": "https://github.com/octocat/Hello-World.git", 208 | "mirror_url": "git:git.example.com/octocat/Hello-World", 209 | "hooks_url": "http://api.github.com/repos/octocat/Hello-World/hooks", 210 | "svn_url": "https://svn.github.com/octocat/Hello-World", 211 | "homepage": "https://github.com", 212 | "language": null, 213 | "forks_count": 9, 214 | "stargazers_count": 80, 215 | "watchers_count": 80, 216 | "size": 108, 217 | "default_branch": "master", 218 | "open_issues_count": 0, 219 | "is_template": true, 220 | "topics": [ 221 | "octocat", 222 | "atom", 223 | "electron", 224 | "api" 225 | ], 226 | "has_issues": true, 227 | "has_projects": true, 228 | "has_wiki": true, 229 | "has_pages": false, 230 | "has_downloads": true, 231 | "archived": false, 232 | "disabled": false, 233 | "visibility": "public", 234 | "pushed_at": "2011-01-26T19:06:43Z", 235 | "created_at": "2011-01-26T19:01:12Z", 236 | "updated_at": "2011-01-26T19:14:43Z", 237 | "permissions": { 238 | "admin": false, 239 | "push": false, 240 | "pull": true 241 | }, 242 | "allow_rebase_merge": true, 243 | "template_repository": null, 244 | "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O", 245 | "allow_squash_merge": true, 246 | "delete_branch_on_merge": true, 247 | "allow_merge_commit": true, 248 | "subscribers_count": 42, 249 | "network_count": 0 250 | }, 251 | "source": { 252 | "id": 1296269, 253 | "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", 254 | "name": "Hello-World", 255 | "full_name": "octocat/Hello-World", 256 | "owner": { 257 | "login": "octocat", 258 | "id": 1, 259 | "node_id": "MDQ6VXNlcjE=", 260 | "avatar_url": "https://github.com/images/error/octocat_happy.gif", 261 | "gravatar_id": "", 262 | "url": "https://api.github.com/users/octocat", 263 | "html_url": "https://github.com/octocat", 264 | "followers_url": "https://api.github.com/users/octocat/followers", 265 | "following_url": "https://api.github.com/users/octocat/following{/other_user}", 266 | "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", 267 | "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", 268 | "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", 269 | "organizations_url": "https://api.github.com/users/octocat/orgs", 270 | "repos_url": "https://api.github.com/users/octocat/repos", 271 | "events_url": "https://api.github.com/users/octocat/events{/privacy}", 272 | "received_events_url": "https://api.github.com/users/octocat/received_events", 273 | "type": "User", 274 | "site_admin": false 275 | }, 276 | "private": false, 277 | "html_url": "https://github.com/octocat/Hello-World", 278 | "description": "This your first repo!", 279 | "fork": false, 280 | "url": "https://api.github.com/repos/octocat/Hello-World", 281 | "archive_url": "http://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", 282 | "assignees_url": "http://api.github.com/repos/octocat/Hello-World/assignees{/user}", 283 | "blobs_url": "http://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", 284 | "branches_url": "http://api.github.com/repos/octocat/Hello-World/branches{/branch}", 285 | "collaborators_url": "http://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", 286 | "comments_url": "http://api.github.com/repos/octocat/Hello-World/comments{/number}", 287 | "commits_url": "http://api.github.com/repos/octocat/Hello-World/commits{/sha}", 288 | "compare_url": "http://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", 289 | "contents_url": "http://api.github.com/repos/octocat/Hello-World/contents/{+path}", 290 | "contributors_url": "http://api.github.com/repos/octocat/Hello-World/contributors", 291 | "deployments_url": "http://api.github.com/repos/octocat/Hello-World/deployments", 292 | "downloads_url": "http://api.github.com/repos/octocat/Hello-World/downloads", 293 | "events_url": "http://api.github.com/repos/octocat/Hello-World/events", 294 | "forks_url": "http://api.github.com/repos/octocat/Hello-World/forks", 295 | "git_commits_url": "http://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", 296 | "git_refs_url": "http://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", 297 | "git_tags_url": "http://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", 298 | "git_url": "git:github.com/octocat/Hello-World.git", 299 | "issue_comment_url": "http://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", 300 | "issue_events_url": "http://api.github.com/repos/octocat/Hello-World/issues/events{/number}", 301 | "issues_url": "http://api.github.com/repos/octocat/Hello-World/issues{/number}", 302 | "keys_url": "http://api.github.com/repos/octocat/Hello-World/keys{/key_id}", 303 | "labels_url": "http://api.github.com/repos/octocat/Hello-World/labels{/name}", 304 | "languages_url": "http://api.github.com/repos/octocat/Hello-World/languages", 305 | "merges_url": "http://api.github.com/repos/octocat/Hello-World/merges", 306 | "milestones_url": "http://api.github.com/repos/octocat/Hello-World/milestones{/number}", 307 | "notifications_url": "http://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", 308 | "pulls_url": "http://api.github.com/repos/octocat/Hello-World/pulls{/number}", 309 | "releases_url": "http://api.github.com/repos/octocat/Hello-World/releases{/id}", 310 | "ssh_url": "git@github.com:octocat/Hello-World.git", 311 | "stargazers_url": "http://api.github.com/repos/octocat/Hello-World/stargazers", 312 | "statuses_url": "http://api.github.com/repos/octocat/Hello-World/statuses/{sha}", 313 | "subscribers_url": "http://api.github.com/repos/octocat/Hello-World/subscribers", 314 | "subscription_url": "http://api.github.com/repos/octocat/Hello-World/subscription", 315 | "tags_url": "http://api.github.com/repos/octocat/Hello-World/tags", 316 | "teams_url": "http://api.github.com/repos/octocat/Hello-World/teams", 317 | "trees_url": "http://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", 318 | "clone_url": "https://github.com/octocat/Hello-World.git", 319 | "mirror_url": "git:git.example.com/octocat/Hello-World", 320 | "hooks_url": "http://api.github.com/repos/octocat/Hello-World/hooks", 321 | "svn_url": "https://svn.github.com/octocat/Hello-World", 322 | "homepage": "https://github.com", 323 | "language": null, 324 | "forks_count": 9, 325 | "stargazers_count": 80, 326 | "watchers_count": 80, 327 | "size": 108, 328 | "default_branch": "master", 329 | "open_issues_count": 0, 330 | "is_template": true, 331 | "topics": [ 332 | "octocat", 333 | "atom", 334 | "electron", 335 | "api" 336 | ], 337 | "has_issues": true, 338 | "has_projects": true, 339 | "has_wiki": true, 340 | "has_pages": false, 341 | "has_downloads": true, 342 | "archived": false, 343 | "disabled": false, 344 | "visibility": "public", 345 | "pushed_at": "2011-01-26T19:06:43Z", 346 | "created_at": "2011-01-26T19:01:12Z", 347 | "updated_at": "2011-01-26T19:14:43Z", 348 | "permissions": { 349 | "admin": false, 350 | "push": false, 351 | "pull": true 352 | }, 353 | "allow_rebase_merge": true, 354 | "template_repository": null, 355 | "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O", 356 | "allow_squash_merge": true, 357 | "delete_branch_on_merge": true, 358 | "allow_merge_commit": true, 359 | "subscribers_count": 42, 360 | "network_count": 0 361 | } 362 | } 363 | -------------------------------------------------------------------------------- /__tests__/context.test.ts: -------------------------------------------------------------------------------- 1 | import {beforeEach, describe, expect, jest, test} from '@jest/globals'; 2 | import * as fs from 'fs'; 3 | import * as path from 'path'; 4 | import {Builder} from '@docker/actions-toolkit/lib/buildx/builder'; 5 | import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx'; 6 | import {Context} from '@docker/actions-toolkit/lib/context'; 7 | import {Docker} from '@docker/actions-toolkit/lib/docker/docker'; 8 | import {GitHub} from '@docker/actions-toolkit/lib/github'; 9 | import {Toolkit} from '@docker/actions-toolkit/lib/toolkit'; 10 | import {BuilderInfo} from '@docker/actions-toolkit/lib/types/builder'; 11 | import {GitHubRepo} from '@docker/actions-toolkit/lib/types/github'; 12 | 13 | import * as context from '../src/context'; 14 | 15 | const tmpDir = path.join('/tmp', '.docker-build-push-jest'); 16 | const tmpName = path.join(tmpDir, '.tmpname-jest'); 17 | 18 | import repoFixture from './fixtures/github-repo.json'; 19 | jest.spyOn(GitHub.prototype, 'repoData').mockImplementation((): Promise => { 20 | return >(repoFixture as unknown); 21 | }); 22 | 23 | jest.spyOn(Context, 'tmpDir').mockImplementation((): string => { 24 | if (!fs.existsSync(tmpDir)) { 25 | fs.mkdirSync(tmpDir, {recursive: true}); 26 | } 27 | return tmpDir; 28 | }); 29 | 30 | jest.spyOn(Context, 'tmpName').mockImplementation((): string => { 31 | return tmpName; 32 | }); 33 | 34 | jest.spyOn(Docker, 'isAvailable').mockImplementation(async (): Promise => { 35 | return true; 36 | }); 37 | 38 | jest.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise => { 39 | return { 40 | name: 'builder2', 41 | driver: 'docker-container', 42 | lastActivity: new Date('2023-01-16 09:45:23 +0000 UTC'), 43 | nodes: [ 44 | { 45 | buildkit: 'v0.11.0', 46 | 'buildkitd-flags': '--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host', 47 | 'driver-opts': ['BUILDKIT_STEP_LOG_MAX_SIZE=10485760', 'BUILDKIT_STEP_LOG_MAX_SPEED=10485760', 'JAEGER_TRACE=localhost:6831', 'image=moby/buildkit:latest', 'network=host'], 48 | endpoint: 'unix:///var/run/docker.sock', 49 | name: 'builder20', 50 | platforms: 'linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6', 51 | status: 'running' 52 | } 53 | ] 54 | }; 55 | }); 56 | 57 | describe('getArgs', () => { 58 | beforeEach(() => { 59 | process.env = Object.keys(process.env).reduce((object, key) => { 60 | if (!key.startsWith('INPUT_')) { 61 | object[key] = process.env[key]; 62 | } 63 | return object; 64 | }, {}); 65 | }); 66 | 67 | // prettier-ignore 68 | test.each([ 69 | [ 70 | 0, 71 | '0.4.1', 72 | new Map([ 73 | ['context', '.'], 74 | ['load', 'false'], 75 | ['no-cache', 'false'], 76 | ['push', 'false'], 77 | ['pull', 'false'], 78 | ]), 79 | [ 80 | 'build', 81 | '--iidfile', path.join(tmpDir, 'iidfile'), 82 | '.' 83 | ] 84 | ], 85 | [ 86 | 1, 87 | '0.4.2', 88 | new Map([ 89 | ['build-args', `MY_ARG=val1,val2,val3 90 | ARG=val 91 | "MULTILINE=aaaa 92 | bbbb 93 | ccc"`], 94 | ['load', 'false'], 95 | ['no-cache', 'false'], 96 | ['push', 'false'], 97 | ['pull', 'false'], 98 | ]), 99 | [ 100 | 'build', 101 | '--build-arg', 'MY_ARG=val1,val2,val3', 102 | '--build-arg', 'ARG=val', 103 | '--build-arg', `MULTILINE=aaaa\nbbbb\nccc`, 104 | '--iidfile', path.join(tmpDir, 'iidfile'), 105 | 'https://github.com/docker/build-push-action.git#refs/heads/master' 106 | ] 107 | ], 108 | [ 109 | 2, 110 | '0.4.2', 111 | new Map([ 112 | ['tags', 'name/app:7.4, name/app:latest'], 113 | ['load', 'false'], 114 | ['no-cache', 'false'], 115 | ['push', 'false'], 116 | ['pull', 'false'], 117 | ]), 118 | [ 119 | 'build', 120 | '--iidfile', path.join(tmpDir, 'iidfile'), 121 | '--tag', 'name/app:7.4', 122 | '--tag', 'name/app:latest', 123 | 'https://github.com/docker/build-push-action.git#refs/heads/master' 124 | ] 125 | ], 126 | [ 127 | 3, 128 | '0.4.2', 129 | new Map([ 130 | ['context', '.'], 131 | ['labels', 'org.opencontainers.image.title=buildkit\norg.opencontainers.image.description=concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit'], 132 | ['outputs', 'type=local,dest=./release-out'], 133 | ['load', 'false'], 134 | ['no-cache', 'false'], 135 | ['push', 'false'], 136 | ['pull', 'false'], 137 | ]), 138 | [ 139 | 'build', 140 | '--label', 'org.opencontainers.image.title=buildkit', 141 | '--label', 'org.opencontainers.image.description=concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit', 142 | '--output', 'type=local,dest=./release-out', 143 | '.' 144 | ] 145 | ], 146 | [ 147 | 4, 148 | '0.4.1', 149 | new Map([ 150 | ['context', '.'], 151 | ['platforms', 'linux/amd64,linux/arm64'], 152 | ['load', 'false'], 153 | ['no-cache', 'false'], 154 | ['push', 'false'], 155 | ['pull', 'false'], 156 | ]), 157 | [ 158 | 'build', 159 | '--platform', 'linux/amd64,linux/arm64', 160 | '.' 161 | ] 162 | ], 163 | [ 164 | 5, 165 | '0.4.1', 166 | new Map([ 167 | ['context', '.'], 168 | ['load', 'false'], 169 | ['no-cache', 'false'], 170 | ['push', 'false'], 171 | ['pull', 'false'], 172 | ]), 173 | [ 174 | 'build', 175 | '--iidfile', path.join(tmpDir, 'iidfile'), 176 | '.' 177 | ] 178 | ], 179 | [ 180 | 6, 181 | '0.4.2', 182 | new Map([ 183 | ['context', '.'], 184 | ['secrets', 'GIT_AUTH_TOKEN=abcdefghijklmno=0123456789'], 185 | ['load', 'false'], 186 | ['no-cache', 'false'], 187 | ['push', 'false'], 188 | ['pull', 'false'], 189 | ]), 190 | [ 191 | 'build', 192 | '--iidfile', path.join(tmpDir, 'iidfile'), 193 | '--secret', `id=GIT_AUTH_TOKEN,src=${tmpName}`, 194 | '.' 195 | ] 196 | ], 197 | [ 198 | 7, 199 | '0.4.2', 200 | new Map([ 201 | ['github-token', 'abcdefghijklmno0123456789'], 202 | ['outputs', '.'], 203 | ['load', 'false'], 204 | ['no-cache', 'false'], 205 | ['push', 'false'], 206 | ['pull', 'false'], 207 | ]), 208 | [ 209 | 'build', 210 | '--output', '.', 211 | '--secret', `id=GIT_AUTH_TOKEN,src=${tmpName}`, 212 | 'https://github.com/docker/build-push-action.git#refs/heads/master' 213 | ] 214 | ], 215 | [ 216 | 8, 217 | '0.4.2', 218 | new Map([ 219 | ['context', 'https://github.com/docker/build-push-action.git#refs/heads/master'], 220 | ['tag', 'localhost:5000/name/app:latest'], 221 | ['platforms', 'linux/amd64,linux/arm64'], 222 | ['secrets', 'GIT_AUTH_TOKEN=abcdefghijklmno=0123456789'], 223 | ['file', './test/Dockerfile'], 224 | ['builder', 'builder-git-context-2'], 225 | ['load', 'false'], 226 | ['no-cache', 'false'], 227 | ['push', 'true'], 228 | ['pull', 'false'], 229 | ]), 230 | [ 231 | 'build', 232 | '--file', './test/Dockerfile', 233 | '--iidfile', path.join(tmpDir, 'iidfile'), 234 | '--platform', 'linux/amd64,linux/arm64', 235 | '--secret', `id=GIT_AUTH_TOKEN,src=${tmpName}`, 236 | '--builder', 'builder-git-context-2', 237 | '--push', 238 | 'https://github.com/docker/build-push-action.git#refs/heads/master' 239 | ] 240 | ], 241 | [ 242 | 9, 243 | '0.4.2', 244 | new Map([ 245 | ['context', 'https://github.com/docker/build-push-action.git#refs/heads/master'], 246 | ['tag', 'localhost:5000/name/app:latest'], 247 | ['platforms', 'linux/amd64,linux/arm64'], 248 | ['secrets', `GIT_AUTH_TOKEN=abcdefghi,jklmno=0123456789 249 | "MYSECRET=aaaaaaaa 250 | bbbbbbb 251 | ccccccccc" 252 | FOO=bar 253 | "EMPTYLINE=aaaa 254 | 255 | bbbb 256 | ccc"`], 257 | ['file', './test/Dockerfile'], 258 | ['builder', 'builder-git-context-2'], 259 | ['load', 'false'], 260 | ['no-cache', 'false'], 261 | ['push', 'true'], 262 | ['pull', 'false'], 263 | ]), 264 | [ 265 | 'build', 266 | '--file', './test/Dockerfile', 267 | '--iidfile', path.join(tmpDir, 'iidfile'), 268 | '--platform', 'linux/amd64,linux/arm64', 269 | '--secret', `id=GIT_AUTH_TOKEN,src=${tmpName}`, 270 | '--secret', `id=MYSECRET,src=${tmpName}`, 271 | '--secret', `id=FOO,src=${tmpName}`, 272 | '--secret', `id=EMPTYLINE,src=${tmpName}`, 273 | '--builder', 'builder-git-context-2', 274 | '--push', 275 | 'https://github.com/docker/build-push-action.git#refs/heads/master' 276 | ] 277 | ], 278 | [ 279 | 10, 280 | '0.4.2', 281 | new Map([ 282 | ['context', 'https://github.com/docker/build-push-action.git#refs/heads/master'], 283 | ['tag', 'localhost:5000/name/app:latest'], 284 | ['platforms', 'linux/amd64,linux/arm64'], 285 | ['secrets', `GIT_AUTH_TOKEN=abcdefghi,jklmno=0123456789 286 | MYSECRET=aaaaaaaa 287 | bbbbbbb 288 | ccccccccc 289 | FOO=bar 290 | EMPTYLINE=aaaa 291 | 292 | bbbb 293 | ccc`], 294 | ['file', './test/Dockerfile'], 295 | ['builder', 'builder-git-context-2'], 296 | ['load', 'false'], 297 | ['no-cache', 'false'], 298 | ['push', 'true'], 299 | ['pull', 'false'], 300 | ]), 301 | [ 302 | 'build', 303 | '--file', './test/Dockerfile', 304 | '--iidfile', path.join(tmpDir, 'iidfile'), 305 | '--platform', 'linux/amd64,linux/arm64', 306 | '--secret', `id=GIT_AUTH_TOKEN,src=${tmpName}`, 307 | '--secret', `id=MYSECRET,src=${tmpName}`, 308 | '--secret', `id=FOO,src=${tmpName}`, 309 | '--secret', `id=EMPTYLINE,src=${tmpName}`, 310 | '--builder', 'builder-git-context-2', 311 | '--push', 312 | 'https://github.com/docker/build-push-action.git#refs/heads/master' 313 | ] 314 | ], 315 | [ 316 | 11, 317 | '0.5.1', 318 | new Map([ 319 | ['context', 'https://github.com/docker/build-push-action.git#refs/heads/master'], 320 | ['tag', 'localhost:5000/name/app:latest'], 321 | ['secret-files', `MY_SECRET=${path.join(__dirname, 'fixtures', 'secret.txt')}`], 322 | ['file', './test/Dockerfile'], 323 | ['builder', 'builder-git-context-2'], 324 | ['network', 'host'], 325 | ['load', 'false'], 326 | ['no-cache', 'false'], 327 | ['push', 'true'], 328 | ['pull', 'false'], 329 | ]), 330 | [ 331 | 'build', 332 | '--file', './test/Dockerfile', 333 | '--iidfile', path.join(tmpDir, 'iidfile'), 334 | '--secret', `id=MY_SECRET,src=${tmpName}`, 335 | '--builder', 'builder-git-context-2', 336 | '--network', 'host', 337 | '--push', 338 | 'https://github.com/docker/build-push-action.git#refs/heads/master' 339 | ] 340 | ], 341 | [ 342 | 12, 343 | '0.4.2', 344 | new Map([ 345 | ['context', '.'], 346 | ['labels', 'org.opencontainers.image.title=filter_results_top_n\norg.opencontainers.image.description=Reference implementation of operation "filter results (top-n)"'], 347 | ['outputs', 'type=local,dest=./release-out'], 348 | ['load', 'false'], 349 | ['no-cache', 'false'], 350 | ['push', 'false'], 351 | ['pull', 'false'], 352 | ]), 353 | [ 354 | 'build', 355 | '--label', 'org.opencontainers.image.title=filter_results_top_n', 356 | '--label', 'org.opencontainers.image.description=Reference implementation of operation "filter results (top-n)"', 357 | '--output', 'type=local,dest=./release-out', 358 | '.' 359 | ] 360 | ], 361 | [ 362 | 13, 363 | '0.6.0', 364 | new Map([ 365 | ['context', '.'], 366 | ['tag', 'localhost:5000/name/app:latest'], 367 | ['file', './test/Dockerfile'], 368 | ['add-hosts', 'docker:10.180.0.1,foo:10.0.0.1'], 369 | ['network', 'host'], 370 | ['load', 'false'], 371 | ['no-cache', 'false'], 372 | ['push', 'true'], 373 | ['pull', 'false'], 374 | ]), 375 | [ 376 | 'build', 377 | '--add-host', 'docker:10.180.0.1', 378 | '--add-host', 'foo:10.0.0.1', 379 | '--file', './test/Dockerfile', 380 | '--iidfile', path.join(tmpDir, 'iidfile'), 381 | '--metadata-file', path.join(tmpDir, 'metadata-file'), 382 | '--network', 'host', 383 | '--push', 384 | '.' 385 | ] 386 | ], 387 | [ 388 | 14, 389 | '0.7.0', 390 | new Map([ 391 | ['context', '.'], 392 | ['file', './test/Dockerfile'], 393 | ['add-hosts', 'docker:10.180.0.1\nfoo:10.0.0.1'], 394 | ['cgroup-parent', 'foo'], 395 | ['shm-size', '2g'], 396 | ['ulimit', `nofile=1024:1024 397 | nproc=3`], 398 | ['load', 'false'], 399 | ['no-cache', 'false'], 400 | ['push', 'false'], 401 | ['pull', 'false'], 402 | ]), 403 | [ 404 | 'build', 405 | '--add-host', 'docker:10.180.0.1', 406 | '--add-host', 'foo:10.0.0.1', 407 | '--cgroup-parent', 'foo', 408 | '--file', './test/Dockerfile', 409 | '--iidfile', path.join(tmpDir, 'iidfile'), 410 | '--shm-size', '2g', 411 | '--ulimit', 'nofile=1024:1024', 412 | '--ulimit', 'nproc=3', 413 | '--metadata-file', path.join(tmpDir, 'metadata-file'), 414 | '.' 415 | ] 416 | ], 417 | [ 418 | 15, 419 | '0.7.0', 420 | new Map([ 421 | ['context', '{{defaultContext}}:docker'], 422 | ['load', 'false'], 423 | ['no-cache', 'false'], 424 | ['push', 'false'], 425 | ['pull', 'false'], 426 | ]), 427 | [ 428 | 'build', 429 | '--iidfile', path.join(tmpDir, 'iidfile'), 430 | '--metadata-file', path.join(tmpDir, 'metadata-file'), 431 | 'https://github.com/docker/build-push-action.git#refs/heads/master:docker' 432 | ] 433 | ], 434 | [ 435 | 16, 436 | '0.8.2', 437 | new Map([ 438 | ['github-token', 'abcdefghijklmno0123456789'], 439 | ['context', '{{defaultContext}}:subdir'], 440 | ['load', 'false'], 441 | ['no-cache', 'false'], 442 | ['push', 'false'], 443 | ['pull', 'false'], 444 | ]), 445 | [ 446 | 'build', 447 | '--iidfile', path.join(tmpDir, 'iidfile'), 448 | '--secret', `id=GIT_AUTH_TOKEN,src=${tmpName}`, 449 | '--metadata-file', path.join(tmpDir, 'metadata-file'), 450 | 'https://github.com/docker/build-push-action.git#refs/heads/master:subdir' 451 | ] 452 | ], 453 | [ 454 | 17, 455 | '0.8.2', 456 | new Map([ 457 | ['context', '.'], 458 | ['load', 'false'], 459 | ['no-cache', 'false'], 460 | ['push', 'false'], 461 | ['pull', 'false'], 462 | ['provenance', 'true'], 463 | ]), 464 | [ 465 | 'build', 466 | '--iidfile', path.join(tmpDir, 'iidfile'), 467 | '--metadata-file', path.join(tmpDir, 'metadata-file'), 468 | '.' 469 | ] 470 | ], 471 | [ 472 | 18, 473 | '0.10.0', 474 | new Map([ 475 | ['context', '.'], 476 | ['load', 'false'], 477 | ['no-cache', 'false'], 478 | ['push', 'false'], 479 | ['pull', 'false'], 480 | ]), 481 | [ 482 | 'build', 483 | '--iidfile', path.join(tmpDir, 'iidfile'), 484 | "--provenance", `mode=min,inline-only=true,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`, 485 | '--metadata-file', path.join(tmpDir, 'metadata-file'), 486 | '.' 487 | ] 488 | ], 489 | [ 490 | 19, 491 | '0.10.0', 492 | new Map([ 493 | ['context', '.'], 494 | ['load', 'false'], 495 | ['no-cache', 'false'], 496 | ['push', 'false'], 497 | ['pull', 'false'], 498 | ['provenance', 'true'], 499 | ]), 500 | [ 501 | 'build', 502 | '--iidfile', path.join(tmpDir, 'iidfile'), 503 | "--provenance", `builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`, 504 | '--metadata-file', path.join(tmpDir, 'metadata-file'), 505 | '.' 506 | ] 507 | ], 508 | [ 509 | 20, 510 | '0.10.0', 511 | new Map([ 512 | ['context', '.'], 513 | ['load', 'false'], 514 | ['no-cache', 'false'], 515 | ['push', 'false'], 516 | ['pull', 'false'], 517 | ['provenance', 'mode=max'], 518 | ]), 519 | [ 520 | 'build', 521 | '--iidfile', path.join(tmpDir, 'iidfile'), 522 | "--provenance", `mode=max,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`, 523 | '--metadata-file', path.join(tmpDir, 'metadata-file'), 524 | '.' 525 | ] 526 | ], 527 | [ 528 | 21, 529 | '0.10.0', 530 | new Map([ 531 | ['context', '.'], 532 | ['load', 'false'], 533 | ['no-cache', 'false'], 534 | ['push', 'false'], 535 | ['pull', 'false'], 536 | ['provenance', 'false'], 537 | ]), 538 | [ 539 | 'build', 540 | '--iidfile', path.join(tmpDir, 'iidfile'), 541 | "--provenance", 'false', 542 | '--metadata-file', path.join(tmpDir, 'metadata-file'), 543 | '.' 544 | ] 545 | ], 546 | [ 547 | 22, 548 | '0.10.0', 549 | new Map([ 550 | ['context', '.'], 551 | ['load', 'false'], 552 | ['no-cache', 'false'], 553 | ['push', 'false'], 554 | ['pull', 'false'], 555 | ['provenance', 'builder-id=foo'], 556 | ]), 557 | [ 558 | 'build', 559 | '--iidfile', path.join(tmpDir, 'iidfile'), 560 | "--provenance", 'builder-id=foo', 561 | '--metadata-file', path.join(tmpDir, 'metadata-file'), 562 | '.' 563 | ] 564 | ], 565 | [ 566 | 23, 567 | '0.10.0', 568 | new Map([ 569 | ['context', '.'], 570 | ['load', 'false'], 571 | ['no-cache', 'false'], 572 | ['push', 'false'], 573 | ['pull', 'false'], 574 | ['outputs', 'type=docker'], 575 | ]), 576 | [ 577 | 'build', 578 | '--iidfile', path.join(tmpDir, 'iidfile'), 579 | "--output", 'type=docker', 580 | '--metadata-file', path.join(tmpDir, 'metadata-file'), 581 | '.' 582 | ] 583 | ], 584 | [ 585 | 24, 586 | '0.10.0', 587 | new Map([ 588 | ['context', '.'], 589 | ['load', 'true'], 590 | ['no-cache', 'false'], 591 | ['push', 'false'], 592 | ['pull', 'false'], 593 | ]), 594 | [ 595 | 'build', 596 | '--iidfile', path.join(tmpDir, 'iidfile'), 597 | '--load', 598 | '--metadata-file', path.join(tmpDir, 'metadata-file'), 599 | '.' 600 | ] 601 | ], 602 | ])( 603 | '[%d] given %p with %p as inputs, returns %p', 604 | async (num: number, buildxVersion: string, inputs: Map, expected: Array) => { 605 | inputs.forEach((value: string, name: string) => { 606 | setInput(name, value); 607 | }); 608 | const toolkit = new Toolkit(); 609 | jest.spyOn(Buildx.prototype, 'version').mockImplementation(async (): Promise => { 610 | return buildxVersion; 611 | }); 612 | const inp = await context.getInputs(); 613 | const res = await context.getArgs(inp, toolkit); 614 | expect(res).toEqual(expected); 615 | } 616 | ); 617 | }); 618 | 619 | // See: https://github.com/actions/toolkit/blob/a1b068ec31a042ff1e10a522d8fdf0b8869d53ca/packages/core/src/core.ts#L89 620 | function getInputName(name: string): string { 621 | return `INPUT_${name.replace(/ /g, '_').toUpperCase()}`; 622 | } 623 | 624 | function setInput(name: string, value: string): void { 625 | process.env[getInputName(name)] = value; 626 | } 627 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | buildx-version: 7 | description: 'Buildx version or Git context' 8 | default: 'latest' 9 | required: false 10 | buildkit-image: 11 | description: 'BuildKit image' 12 | default: 'moby/buildkit:buildx-stable-1' 13 | required: false 14 | schedule: 15 | - cron: '0 10 * * *' 16 | push: 17 | branches: 18 | - 'master' 19 | - 'releases/v*' 20 | pull_request: 21 | 22 | env: 23 | BUILDX_VERSION: latest 24 | BUILDKIT_IMAGE: moby/buildkit:buildx-stable-1 25 | 26 | jobs: 27 | minimal: 28 | runs-on: ubuntu-latest 29 | steps: 30 | - 31 | name: Checkout 32 | uses: actions/checkout@v3 33 | with: 34 | path: action 35 | - 36 | name: Set up Docker Buildx 37 | uses: docker/setup-buildx-action@v2 38 | with: 39 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 40 | driver-opts: | 41 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 42 | - 43 | name: Build 44 | uses: ./action 45 | with: 46 | file: ./test/Dockerfile 47 | 48 | git-context: 49 | runs-on: ubuntu-latest 50 | services: 51 | registry: 52 | image: registry:2 53 | ports: 54 | - 5000:5000 55 | steps: 56 | - 57 | name: Checkout 58 | uses: actions/checkout@v3 59 | with: 60 | path: action 61 | - 62 | name: Set up QEMU 63 | uses: docker/setup-qemu-action@v2 64 | - 65 | name: Set up Docker Buildx 66 | id: buildx 67 | uses: docker/setup-buildx-action@v2 68 | with: 69 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 70 | driver-opts: | 71 | network=host 72 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 73 | - 74 | name: Build and push 75 | id: docker_build 76 | uses: ./action 77 | with: 78 | file: ./test/Dockerfile 79 | builder: ${{ steps.buildx.outputs.name }} 80 | platforms: linux/amd64,linux/arm64 81 | push: true 82 | tags: | 83 | localhost:5000/name/app:latest 84 | localhost:5000/name/app:1.0.0 85 | - 86 | name: Inspect 87 | run: | 88 | docker buildx imagetools inspect localhost:5000/name/app:1.0.0 --format '{{json .}}' 89 | - 90 | name: Check digest 91 | run: | 92 | if [ -z "${{ steps.docker_build.outputs.digest }}" ]; then 93 | echo "::error::Digest should not be empty" 94 | exit 1 95 | fi 96 | 97 | git-context-secret: 98 | runs-on: ubuntu-latest 99 | services: 100 | registry: 101 | image: registry:2 102 | ports: 103 | - 5000:5000 104 | steps: 105 | - 106 | name: Checkout 107 | uses: actions/checkout@v3 108 | with: 109 | path: action 110 | - 111 | name: Set up QEMU 112 | uses: docker/setup-qemu-action@v2 113 | - 114 | name: Set up Docker Buildx 115 | id: buildx 116 | uses: docker/setup-buildx-action@v2 117 | with: 118 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 119 | driver-opts: | 120 | network=host 121 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 122 | - 123 | name: Build and push 124 | id: docker_build 125 | uses: ./action 126 | with: 127 | file: ./test/Dockerfile 128 | builder: ${{ steps.buildx.outputs.name }} 129 | platforms: linux/amd64,linux/arm64 130 | push: true 131 | tags: | 132 | localhost:5000/name/app:latest 133 | localhost:5000/name/app:1.0.0 134 | secrets: | 135 | GIT_AUTH_TOKEN=${{ github.token }} 136 | "MYSECRET=aaaaaaaa 137 | bbbbbbb 138 | ccccccccc" 139 | FOO=bar 140 | "EMPTYLINE=aaaa 141 | 142 | bbbb 143 | ccc" 144 | - 145 | name: Inspect 146 | run: | 147 | docker buildx imagetools inspect localhost:5000/name/app:1.0.0 --format '{{json .}}' 148 | - 149 | name: Check digest 150 | run: | 151 | if [ -z "${{ steps.docker_build.outputs.digest }}" ]; then 152 | echo "::error::Digest should not be empty" 153 | exit 1 154 | fi 155 | 156 | path-context: 157 | runs-on: ubuntu-latest 158 | services: 159 | registry: 160 | image: registry:2 161 | ports: 162 | - 5000:5000 163 | steps: 164 | - 165 | name: Checkout 166 | uses: actions/checkout@v3 167 | - 168 | name: Set up QEMU 169 | uses: docker/setup-qemu-action@v2 170 | - 171 | name: Set up Docker Buildx 172 | id: buildx 173 | uses: docker/setup-buildx-action@v2 174 | with: 175 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 176 | driver-opts: | 177 | network=host 178 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 179 | - 180 | name: Build and push 181 | id: docker_build 182 | uses: ./ 183 | with: 184 | context: ./test 185 | file: ./test/Dockerfile 186 | builder: ${{ steps.buildx.outputs.name }} 187 | push: true 188 | tags: | 189 | localhost:5000/name/app:latest 190 | localhost:5000/name/app:1.0.0 191 | - 192 | name: Inspect 193 | run: | 194 | docker buildx imagetools inspect localhost:5000/name/app:1.0.0 --format '{{json .}}' 195 | - 196 | name: Check digest 197 | run: | 198 | if [ -z "${{ steps.docker_build.outputs.digest }}" ]; then 199 | echo "::error::Digest should not be empty" 200 | exit 1 201 | fi 202 | 203 | example: 204 | runs-on: ubuntu-latest 205 | env: 206 | DOCKER_IMAGE: localhost:5000/name/app 207 | services: 208 | registry: 209 | image: registry:2 210 | ports: 211 | - 5000:5000 212 | steps: 213 | - 214 | name: Checkout 215 | uses: actions/checkout@v3 216 | - 217 | name: Docker meta 218 | id: meta 219 | uses: docker/metadata-action@v4 220 | with: 221 | images: ${{ env.DOCKER_IMAGE }} 222 | tags: | 223 | type=schedule 224 | type=ref,event=branch 225 | type=ref,event=pr 226 | type=semver,pattern={{version}} 227 | type=semver,pattern={{major}}.{{minor}} 228 | type=semver,pattern={{major}} 229 | type=sha 230 | - 231 | name: Set up Docker Buildx 232 | uses: docker/setup-buildx-action@v2 233 | with: 234 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 235 | driver-opts: | 236 | network=host 237 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 238 | - 239 | name: Build and export to Docker client 240 | uses: ./ 241 | with: 242 | context: ./test 243 | file: ./test/Dockerfile 244 | load: true 245 | tags: ${{ steps.meta.outputs.tags }} 246 | labels: ${{ steps.meta.outputs.labels }} 247 | - 248 | name: Build and push to local registry 249 | uses: ./ 250 | with: 251 | context: ./test 252 | file: ./test/Dockerfile 253 | push: ${{ github.event_name != 'pull_request' }} 254 | tags: ${{ steps.meta.outputs.tags }} 255 | labels: ${{ steps.meta.outputs.labels }} 256 | - 257 | name: Inspect image 258 | run: | 259 | docker image inspect ${{ env.DOCKER_IMAGE }}:${{ steps.meta.outputs.version }} 260 | - 261 | name: Check manifest 262 | if: github.event_name != 'pull_request' 263 | run: | 264 | docker buildx imagetools inspect ${{ env.DOCKER_IMAGE }}:${{ steps.meta.outputs.version }} --format '{{json .}}' 265 | 266 | error: 267 | runs-on: ubuntu-latest 268 | steps: 269 | - 270 | name: Checkout 271 | uses: actions/checkout@v3 272 | - 273 | name: Stop docker 274 | run: | 275 | sudo systemctl stop docker 276 | - 277 | name: Build 278 | id: docker_build 279 | continue-on-error: true 280 | uses: ./ 281 | with: 282 | context: ./test 283 | file: ./test/Dockerfile 284 | - 285 | name: Check 286 | run: | 287 | echo "${{ toJson(steps.docker_build) }}" 288 | if [ "${{ steps.docker_build.outcome }}" != "failure" ] || [ "${{ steps.docker_build.conclusion }}" != "success" ]; then 289 | echo "::error::Should have failed" 290 | exit 1 291 | fi 292 | 293 | error-buildx: 294 | runs-on: ubuntu-latest 295 | steps: 296 | - 297 | name: Checkout 298 | uses: actions/checkout@v3 299 | - 300 | name: Set up QEMU 301 | uses: docker/setup-qemu-action@v2 302 | - 303 | name: Set up Docker Buildx 304 | uses: docker/setup-buildx-action@v2 305 | with: 306 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 307 | driver-opts: | 308 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 309 | - 310 | name: Build 311 | id: docker_build 312 | continue-on-error: true 313 | uses: ./ 314 | with: 315 | context: ./test 316 | file: ./test/Dockerfile 317 | platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x 318 | push: true 319 | tags: localhost:5000/name/app:latest 320 | - 321 | name: Check 322 | run: | 323 | echo "${{ toJson(steps.docker_build) }}" 324 | if [ "${{ steps.docker_build.outcome }}" != "failure" ] || [ "${{ steps.docker_build.conclusion }}" != "success" ]; then 325 | echo "::error::Should have failed" 326 | exit 1 327 | fi 328 | 329 | docker-driver: 330 | runs-on: ubuntu-latest 331 | services: 332 | registry: 333 | image: registry:2 334 | ports: 335 | - 5000:5000 336 | steps: 337 | - 338 | name: Checkout 339 | uses: actions/checkout@v3 340 | - 341 | name: Build 342 | id: docker_build 343 | uses: ./ 344 | with: 345 | context: ./test 346 | file: ./test/Dockerfile 347 | push: true 348 | tags: localhost:5000/name/app:latest 349 | 350 | export-docker: 351 | runs-on: ubuntu-latest 352 | steps: 353 | - 354 | name: Checkout 355 | uses: actions/checkout@v3 356 | - 357 | name: Build 358 | uses: ./ 359 | with: 360 | context: ./test 361 | file: ./test/Dockerfile 362 | load: true 363 | tags: myimage:latest 364 | - 365 | name: Inspect 366 | run: | 367 | docker image inspect myimage:latest 368 | 369 | secret: 370 | runs-on: ubuntu-latest 371 | steps: 372 | - 373 | name: Checkout 374 | uses: actions/checkout@v3 375 | - 376 | name: Set up Docker Buildx 377 | uses: docker/setup-buildx-action@v2 378 | with: 379 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 380 | driver-opts: | 381 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 382 | - 383 | name: Build 384 | uses: ./ 385 | with: 386 | context: . 387 | file: ./test/secret.Dockerfile 388 | secrets: | 389 | MYSECRET=foo 390 | INVALID_SECRET= 391 | 392 | network: 393 | runs-on: ubuntu-latest 394 | steps: 395 | - 396 | name: Checkout 397 | uses: actions/checkout@v3 398 | - 399 | name: Set up Docker Buildx 400 | uses: docker/setup-buildx-action@v2 401 | with: 402 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 403 | driver-opts: | 404 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 405 | - 406 | name: List networks 407 | run: docker network ls 408 | - 409 | name: Build 410 | uses: ./ 411 | with: 412 | context: ./test 413 | tags: name/app:latest 414 | network: host 415 | 416 | shm-size: 417 | runs-on: ubuntu-latest 418 | steps: 419 | - 420 | name: Checkout 421 | uses: actions/checkout@v3 422 | - 423 | name: Set up Docker Buildx 424 | uses: docker/setup-buildx-action@v2 425 | with: 426 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 427 | driver-opts: | 428 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 429 | - 430 | name: Build 431 | uses: ./ 432 | with: 433 | context: ./test 434 | file: ./test/shmsize.Dockerfile 435 | tags: name/app:latest 436 | shm-size: 2g 437 | 438 | ulimit: 439 | runs-on: ubuntu-latest 440 | steps: 441 | - 442 | name: Checkout 443 | uses: actions/checkout@v3 444 | - 445 | name: Set up Docker Buildx 446 | uses: docker/setup-buildx-action@v2 447 | with: 448 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 449 | driver-opts: | 450 | network=host 451 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 452 | - 453 | name: Build 454 | uses: ./ 455 | with: 456 | context: ./test 457 | file: ./test/ulimit.Dockerfile 458 | tags: name/app:latest 459 | ulimit: | 460 | nofile=1024:1024 461 | nproc=3 462 | 463 | cgroup-parent: 464 | runs-on: ubuntu-latest 465 | steps: 466 | - 467 | name: Checkout 468 | uses: actions/checkout@v3 469 | - 470 | name: Set up Docker Buildx 471 | uses: docker/setup-buildx-action@v2 472 | with: 473 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 474 | driver-opts: | 475 | network=host 476 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 477 | - 478 | name: Build 479 | uses: ./ 480 | with: 481 | context: ./test 482 | file: ./test/cgroup.Dockerfile 483 | tags: name/app:latest 484 | cgroup-parent: foo 485 | 486 | add-hosts: 487 | runs-on: ubuntu-latest 488 | steps: 489 | - 490 | name: Checkout 491 | uses: actions/checkout@v3 492 | - 493 | name: Set up Docker Buildx 494 | uses: docker/setup-buildx-action@v2 495 | with: 496 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 497 | driver-opts: | 498 | network=host 499 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 500 | - 501 | name: Build 502 | uses: ./ 503 | with: 504 | context: ./test 505 | file: ./test/addhost.Dockerfile 506 | tags: name/app:latest 507 | add-hosts: | 508 | docker:10.180.0.1 509 | foo:10.0.0.1 510 | 511 | no-cache-filters: 512 | runs-on: ubuntu-latest 513 | steps: 514 | - 515 | name: Checkout 516 | uses: actions/checkout@v3 517 | - 518 | name: Set up Docker Buildx 519 | uses: docker/setup-buildx-action@v2 520 | with: 521 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 522 | driver-opts: | 523 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 524 | - 525 | name: Build 526 | uses: ./ 527 | with: 528 | context: ./test 529 | file: ./test/nocachefilter.Dockerfile 530 | no-cache-filters: build 531 | tags: name/app:latest 532 | cache-from: type=gha,scope=nocachefilter 533 | cache-to: type=gha,scope=nocachefilter,mode=max 534 | 535 | attests-compat: 536 | runs-on: ubuntu-latest 537 | strategy: 538 | fail-fast: false 539 | matrix: 540 | include: 541 | - buildx: latest 542 | buildkit: moby/buildkit:buildx-stable-1 543 | - buildx: latest 544 | buildkit: moby/buildkit:v0.10.6 545 | - buildx: v0.9.1 546 | buildkit: moby/buildkit:buildx-stable-1 547 | steps: 548 | - 549 | name: Checkout 550 | uses: actions/checkout@v3 551 | - 552 | name: Set up Docker Buildx 553 | uses: docker/setup-buildx-action@v2 554 | with: 555 | version: ${{ matrix.buildx }} 556 | driver-opts: | 557 | network=host 558 | image=${{ matrix.buildkit }} 559 | - 560 | name: Build 561 | uses: ./ 562 | with: 563 | context: ./test/go 564 | file: ./test/go/Dockerfile 565 | outputs: type=cacheonly 566 | 567 | provenance: 568 | runs-on: ubuntu-latest 569 | strategy: 570 | fail-fast: false 571 | matrix: 572 | attrs: 573 | - '' 574 | - mode=max 575 | - builder-id=foo 576 | - false 577 | - true 578 | steps: 579 | - 580 | name: Checkout 581 | uses: actions/checkout@v3 582 | - 583 | name: Set up Docker Buildx 584 | uses: docker/setup-buildx-action@v2 585 | with: 586 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 587 | driver-opts: | 588 | network=host 589 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 590 | - 591 | name: Build 592 | uses: ./ 593 | with: 594 | context: ./test/go 595 | file: ./test/go/Dockerfile 596 | target: binary 597 | outputs: type=oci,dest=/tmp/build.tar 598 | provenance: ${{ matrix.attrs }} 599 | cache-from: type=gha,scope=provenance 600 | cache-to: type=gha,scope=provenance,mode=max 601 | 602 | sbom: 603 | runs-on: ubuntu-latest 604 | strategy: 605 | fail-fast: false 606 | matrix: 607 | include: 608 | - target: image 609 | output: type=image,name=localhost:5000/name/app:latest,push=true 610 | - target: binary 611 | output: /tmp/buildx-build 612 | services: 613 | registry: 614 | image: registry:2 615 | ports: 616 | - 5000:5000 617 | steps: 618 | - 619 | name: Checkout 620 | uses: actions/checkout@v3 621 | - 622 | name: Set up Docker Buildx 623 | uses: docker/setup-buildx-action@v2 624 | with: 625 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 626 | driver-opts: | 627 | network=host 628 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 629 | - 630 | name: Build 631 | uses: ./ 632 | with: 633 | context: ./test/go 634 | file: ./test/go/Dockerfile 635 | target: ${{ matrix.target }} 636 | outputs: ${{ matrix.output }} 637 | sbom: true 638 | cache-from: type=gha,scope=attests-${{ matrix.target }} 639 | cache-to: type=gha,scope=attests-${{ matrix.target }},mode=max 640 | - 641 | name: Inspect image 642 | if: matrix.target == 'image' 643 | run: | 644 | docker buildx imagetools inspect localhost:5000/name/app:latest --format '{{json .}}' 645 | - 646 | name: Check output folder 647 | if: matrix.target == 'binary' 648 | run: | 649 | tree /tmp/buildx-build 650 | - 651 | name: Print provenance 652 | if: matrix.target == 'binary' 653 | run: | 654 | cat /tmp/buildx-build/provenance.json | jq 655 | - 656 | name: Print SBOM 657 | if: matrix.target == 'binary' 658 | run: | 659 | cat /tmp/buildx-build/sbom.spdx.json | jq 660 | 661 | multi: 662 | runs-on: ubuntu-latest 663 | strategy: 664 | fail-fast: false 665 | matrix: 666 | dockerfile: 667 | - multi 668 | - multi-sudo 669 | services: 670 | registry: 671 | image: registry:2 672 | ports: 673 | - 5000:5000 674 | steps: 675 | - 676 | name: Checkout 677 | uses: actions/checkout@v3 678 | - 679 | name: Set up QEMU 680 | uses: docker/setup-qemu-action@v2 681 | - 682 | name: Set up Docker Buildx 683 | id: buildx 684 | uses: docker/setup-buildx-action@v2 685 | with: 686 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 687 | driver-opts: | 688 | network=host 689 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 690 | - 691 | name: Build and push 692 | id: docker_build 693 | uses: ./ 694 | with: 695 | context: ./test 696 | file: ./test/${{ matrix.dockerfile }}.Dockerfile 697 | builder: ${{ steps.buildx.outputs.name }} 698 | platforms: linux/amd64,linux/arm64 699 | push: true 700 | tags: | 701 | localhost:5000/name/app:latest 702 | localhost:5000/name/app:1.0.0 703 | - 704 | name: Inspect 705 | run: | 706 | docker buildx imagetools inspect localhost:5000/name/app:1.0.0 --format '{{json .}}' 707 | - 708 | name: Check digest 709 | run: | 710 | if [ -z "${{ steps.docker_build.outputs.digest }}" ]; then 711 | echo "::error::Digest should not be empty" 712 | exit 1 713 | fi 714 | 715 | digest: 716 | runs-on: ubuntu-latest 717 | env: 718 | DOCKER_IMAGE: localhost:5000/name/app 719 | strategy: 720 | fail-fast: false 721 | matrix: 722 | driver: 723 | - docker 724 | - docker-container 725 | load: 726 | - true 727 | - false 728 | push: 729 | - true 730 | - false 731 | exclude: 732 | - driver: docker 733 | load: true 734 | push: true 735 | - driver: docker-container 736 | load: true 737 | push: true 738 | - driver: docker 739 | load: false 740 | push: false 741 | - driver: docker-container 742 | load: false 743 | push: false 744 | services: 745 | registry: 746 | image: registry:2 747 | ports: 748 | - 5000:5000 749 | steps: 750 | - 751 | name: Checkout 752 | uses: actions/checkout@v3 753 | - 754 | name: Set up Docker Buildx 755 | uses: docker/setup-buildx-action@v2 756 | with: 757 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 758 | driver: ${{ matrix.driver }} 759 | driver-opts: | 760 | network=host 761 | - 762 | name: Build 763 | id: docker_build 764 | uses: ./ 765 | with: 766 | context: ./test 767 | load: ${{ matrix.load }} 768 | push: ${{ matrix.push }} 769 | tags: ${{ env.DOCKER_IMAGE }}:latest 770 | platforms: ${{ matrix.platforms }} 771 | - 772 | name: Docker images 773 | run: | 774 | docker image ls --no-trunc 775 | - 776 | name: Check digest 777 | if: ${{ matrix.push }} 778 | run: | 779 | if [ -z "${{ steps.docker_build.outputs.digest }}" ]; then 780 | echo "::error::Digest should not be empty" 781 | exit 1 782 | fi 783 | - 784 | name: Check manifest 785 | if: ${{ matrix.push }} 786 | run: | 787 | set -x 788 | docker buildx imagetools inspect ${{ env.DOCKER_IMAGE }}@${{ steps.docker_build.outputs.digest }} --format '{{json .}}' 789 | - 790 | name: Check image ID 791 | run: | 792 | if [ -z "${{ steps.docker_build.outputs.imageid }}" ]; then 793 | echo "::error::Image ID should not be empty" 794 | exit 1 795 | fi 796 | - 797 | name: Inspect image 798 | if: ${{ matrix.load }} 799 | run: | 800 | set -x 801 | docker image inspect ${{ steps.docker_build.outputs.imageid }} 802 | 803 | registry-cache: 804 | runs-on: ubuntu-latest 805 | services: 806 | registry: 807 | image: registry:2 808 | ports: 809 | - 5000:5000 810 | steps: 811 | - 812 | name: Checkout 813 | uses: actions/checkout@v3 814 | - 815 | name: Set up QEMU 816 | uses: docker/setup-qemu-action@v2 817 | - 818 | name: Set up Docker Buildx 819 | uses: docker/setup-buildx-action@v2 820 | with: 821 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 822 | driver-opts: | 823 | network=host 824 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 825 | - 826 | name: Build and push 827 | id: docker_build 828 | uses: ./ 829 | with: 830 | context: ./test 831 | file: ./test/multi.Dockerfile 832 | builder: ${{ steps.buildx.outputs.name }} 833 | platforms: linux/amd64,linux/arm64 834 | push: true 835 | tags: | 836 | localhost:5000/name/app:latest 837 | localhost:5000/name/app:1.0.0 838 | cache-from: type=registry,ref=localhost:5000/name/app 839 | cache-to: type=inline 840 | - 841 | name: Inspect 842 | run: | 843 | docker buildx imagetools inspect localhost:5000/name/app:latest --format '{{json .}}' 844 | - 845 | name: Check digest 846 | run: | 847 | if [ -z "${{ steps.docker_build.outputs.digest }}" ]; then 848 | echo "::error::Digest should not be empty" 849 | exit 1 850 | fi 851 | 852 | github-cache: 853 | runs-on: ubuntu-latest 854 | services: 855 | registry: 856 | image: registry:2 857 | ports: 858 | - 5000:5000 859 | steps: 860 | - 861 | name: Checkout 862 | uses: actions/checkout@v3 863 | - 864 | name: Set up QEMU 865 | uses: docker/setup-qemu-action@v2 866 | - 867 | name: Set up Docker Buildx 868 | uses: docker/setup-buildx-action@v2 869 | with: 870 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 871 | driver-opts: | 872 | network=host 873 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 874 | buildkitd-flags: --debug 875 | - 876 | name: Build and push 877 | uses: ./ 878 | with: 879 | context: ./test 880 | file: ./test/multi.Dockerfile 881 | platforms: linux/amd64,linux/arm64 882 | push: true 883 | tags: | 884 | localhost:5000/name/app:latest 885 | localhost:5000/name/app:1.0.0 886 | cache-from: type=gha,scope=ci-${{ matrix.buildx_version }} 887 | cache-to: type=gha,scope=ci-${{ matrix.buildx_version }} 888 | - 889 | name: Inspect 890 | run: | 891 | docker buildx imagetools inspect localhost:5000/name/app:1.0.0 --format '{{json .}}' 892 | 893 | standalone: 894 | runs-on: ubuntu-latest 895 | steps: 896 | - 897 | name: Checkout 898 | uses: actions/checkout@v3 899 | - 900 | name: Uninstall moby cli 901 | run: | 902 | sudo apt-get purge -y moby-cli moby-buildx 903 | - 904 | name: Set up Docker Buildx 905 | uses: docker/setup-buildx-action@v2 906 | with: 907 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 908 | driver-opts: | 909 | network=host 910 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 911 | - 912 | name: Build 913 | uses: ./ 914 | with: 915 | context: ./test 916 | file: ./test/Dockerfile 917 | 918 | named-context-pin: 919 | runs-on: ubuntu-latest 920 | steps: 921 | - 922 | name: Checkout 923 | uses: actions/checkout@v3 924 | - 925 | name: Set up Docker Buildx 926 | uses: docker/setup-buildx-action@v2 927 | with: 928 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 929 | driver-opts: | 930 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 931 | - 932 | name: Build base image 933 | uses: ./ 934 | with: 935 | context: ./test 936 | file: ./test/named-context.Dockerfile 937 | build-contexts: | 938 | alpine=docker-image://alpine:edge 939 | 940 | named-context-docker: 941 | runs-on: ubuntu-latest 942 | steps: 943 | - 944 | name: Checkout 945 | uses: actions/checkout@v3 946 | - 947 | name: Set up Docker Buildx 948 | uses: docker/setup-buildx-action@v2 949 | with: 950 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 951 | driver: docker 952 | - 953 | name: Build base image 954 | uses: ./ 955 | with: 956 | context: ./test 957 | file: ./test/named-context-base.Dockerfile 958 | load: true 959 | tags: my-base-image:local 960 | - 961 | name: Build 962 | uses: ./ 963 | with: 964 | context: ./test 965 | file: ./test/named-context.Dockerfile 966 | build-contexts: | 967 | base=docker-image://my-base-image:local 968 | 969 | named-context-container: 970 | runs-on: ubuntu-latest 971 | services: 972 | registry: 973 | image: registry:2 974 | ports: 975 | - 5000:5000 976 | steps: 977 | - 978 | name: Checkout 979 | uses: actions/checkout@v3 980 | - 981 | name: Set up Docker Buildx 982 | uses: docker/setup-buildx-action@v2 983 | with: 984 | version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} 985 | driver-opts: | 986 | image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} 987 | network=host 988 | - 989 | name: Build base image 990 | uses: ./ 991 | with: 992 | context: ./test 993 | file: ./test/named-context-base.Dockerfile 994 | tags: localhost:5000/my-base-image:latest 995 | push: true 996 | - 997 | name: Build 998 | uses: ./ 999 | with: 1000 | context: ./test 1001 | file: ./test/named-context.Dockerfile 1002 | build-contexts: | 1003 | alpine=docker-image://localhost:5000/my-base-image:latest 1004 | -------------------------------------------------------------------------------- /dist/sourcemap-register.js: -------------------------------------------------------------------------------- 1 | (()=>{var e={650:e=>{var r=Object.prototype.toString;var n=typeof Buffer.alloc==="function"&&typeof Buffer.allocUnsafe==="function"&&typeof Buffer.from==="function";function isArrayBuffer(e){return r.call(e).slice(8,-1)==="ArrayBuffer"}function fromArrayBuffer(e,r,t){r>>>=0;var o=e.byteLength-r;if(o<0){throw new RangeError("'offset' is out of bounds")}if(t===undefined){t=o}else{t>>>=0;if(t>o){throw new RangeError("'length' is out of bounds")}}return n?Buffer.from(e.slice(r,r+t)):new Buffer(new Uint8Array(e.slice(r,r+t)))}function fromString(e,r){if(typeof r!=="string"||r===""){r="utf8"}if(!Buffer.isEncoding(r)){throw new TypeError('"encoding" must be a valid string encoding')}return n?Buffer.from(e,r):new Buffer(e,r)}function bufferFrom(e,r,t){if(typeof e==="number"){throw new TypeError('"value" argument must not be a number')}if(isArrayBuffer(e)){return fromArrayBuffer(e,r,t)}if(typeof e==="string"){return fromString(e,r)}return n?Buffer.from(e):new Buffer(e)}e.exports=bufferFrom},274:(e,r,n)=>{var t=n(339);var o=Object.prototype.hasOwnProperty;var i=typeof Map!=="undefined";function ArraySet(){this._array=[];this._set=i?new Map:Object.create(null)}ArraySet.fromArray=function ArraySet_fromArray(e,r){var n=new ArraySet;for(var t=0,o=e.length;t=0){return r}}else{var n=t.toSetString(e);if(o.call(this._set,n)){return this._set[n]}}throw new Error('"'+e+'" is not in the set.')};ArraySet.prototype.at=function ArraySet_at(e){if(e>=0&&e{var t=n(190);var o=5;var i=1<>1;return r?-n:n}r.encode=function base64VLQ_encode(e){var r="";var n;var i=toVLQSigned(e);do{n=i&a;i>>>=o;if(i>0){n|=u}r+=t.encode(n)}while(i>0);return r};r.decode=function base64VLQ_decode(e,r,n){var i=e.length;var s=0;var l=0;var c,p;do{if(r>=i){throw new Error("Expected more digits in base 64 VLQ value.")}p=t.decode(e.charCodeAt(r++));if(p===-1){throw new Error("Invalid base64 digit: "+e.charAt(r-1))}c=!!(p&u);p&=a;s=s+(p<{var n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");r.encode=function(e){if(0<=e&&e{r.GREATEST_LOWER_BOUND=1;r.LEAST_UPPER_BOUND=2;function recursiveSearch(e,n,t,o,i,a){var u=Math.floor((n-e)/2)+e;var s=i(t,o[u],true);if(s===0){return u}else if(s>0){if(n-u>1){return recursiveSearch(u,n,t,o,i,a)}if(a==r.LEAST_UPPER_BOUND){return n1){return recursiveSearch(e,u,t,o,i,a)}if(a==r.LEAST_UPPER_BOUND){return u}else{return e<0?-1:e}}}r.search=function search(e,n,t,o){if(n.length===0){return-1}var i=recursiveSearch(-1,n.length,e,n,t,o||r.GREATEST_LOWER_BOUND);if(i<0){return-1}while(i-1>=0){if(t(n[i],n[i-1],true)!==0){break}--i}return i}},680:(e,r,n)=>{var t=n(339);function generatedPositionAfter(e,r){var n=e.generatedLine;var o=r.generatedLine;var i=e.generatedColumn;var a=r.generatedColumn;return o>n||o==n&&a>=i||t.compareByGeneratedPositionsInflated(e,r)<=0}function MappingList(){this._array=[];this._sorted=true;this._last={generatedLine:-1,generatedColumn:0}}MappingList.prototype.unsortedForEach=function MappingList_forEach(e,r){this._array.forEach(e,r)};MappingList.prototype.add=function MappingList_add(e){if(generatedPositionAfter(this._last,e)){this._last=e;this._array.push(e)}else{this._sorted=false;this._array.push(e)}};MappingList.prototype.toArray=function MappingList_toArray(){if(!this._sorted){this._array.sort(t.compareByGeneratedPositionsInflated);this._sorted=true}return this._array};r.H=MappingList},758:(e,r)=>{function swap(e,r,n){var t=e[r];e[r]=e[n];e[n]=t}function randomIntInRange(e,r){return Math.round(e+Math.random()*(r-e))}function doQuickSort(e,r,n,t){if(n{var t;var o=n(339);var i=n(345);var a=n(274).I;var u=n(449);var s=n(758).U;function SourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}return n.sections!=null?new IndexedSourceMapConsumer(n,r):new BasicSourceMapConsumer(n,r)}SourceMapConsumer.fromSourceMap=function(e,r){return BasicSourceMapConsumer.fromSourceMap(e,r)};SourceMapConsumer.prototype._version=3;SourceMapConsumer.prototype.__generatedMappings=null;Object.defineProperty(SourceMapConsumer.prototype,"_generatedMappings",{configurable:true,enumerable:true,get:function(){if(!this.__generatedMappings){this._parseMappings(this._mappings,this.sourceRoot)}return this.__generatedMappings}});SourceMapConsumer.prototype.__originalMappings=null;Object.defineProperty(SourceMapConsumer.prototype,"_originalMappings",{configurable:true,enumerable:true,get:function(){if(!this.__originalMappings){this._parseMappings(this._mappings,this.sourceRoot)}return this.__originalMappings}});SourceMapConsumer.prototype._charIsMappingSeparator=function SourceMapConsumer_charIsMappingSeparator(e,r){var n=e.charAt(r);return n===";"||n===","};SourceMapConsumer.prototype._parseMappings=function SourceMapConsumer_parseMappings(e,r){throw new Error("Subclasses must implement _parseMappings")};SourceMapConsumer.GENERATED_ORDER=1;SourceMapConsumer.ORIGINAL_ORDER=2;SourceMapConsumer.GREATEST_LOWER_BOUND=1;SourceMapConsumer.LEAST_UPPER_BOUND=2;SourceMapConsumer.prototype.eachMapping=function SourceMapConsumer_eachMapping(e,r,n){var t=r||null;var i=n||SourceMapConsumer.GENERATED_ORDER;var a;switch(i){case SourceMapConsumer.GENERATED_ORDER:a=this._generatedMappings;break;case SourceMapConsumer.ORIGINAL_ORDER:a=this._originalMappings;break;default:throw new Error("Unknown order of iteration.")}var u=this.sourceRoot;a.map((function(e){var r=e.source===null?null:this._sources.at(e.source);r=o.computeSourceURL(u,r,this._sourceMapURL);return{source:r,generatedLine:e.generatedLine,generatedColumn:e.generatedColumn,originalLine:e.originalLine,originalColumn:e.originalColumn,name:e.name===null?null:this._names.at(e.name)}}),this).forEach(e,t)};SourceMapConsumer.prototype.allGeneratedPositionsFor=function SourceMapConsumer_allGeneratedPositionsFor(e){var r=o.getArg(e,"line");var n={source:o.getArg(e,"source"),originalLine:r,originalColumn:o.getArg(e,"column",0)};n.source=this._findSourceIndex(n.source);if(n.source<0){return[]}var t=[];var a=this._findMapping(n,this._originalMappings,"originalLine","originalColumn",o.compareByOriginalPositions,i.LEAST_UPPER_BOUND);if(a>=0){var u=this._originalMappings[a];if(e.column===undefined){var s=u.originalLine;while(u&&u.originalLine===s){t.push({line:o.getArg(u,"generatedLine",null),column:o.getArg(u,"generatedColumn",null),lastColumn:o.getArg(u,"lastGeneratedColumn",null)});u=this._originalMappings[++a]}}else{var l=u.originalColumn;while(u&&u.originalLine===r&&u.originalColumn==l){t.push({line:o.getArg(u,"generatedLine",null),column:o.getArg(u,"generatedColumn",null),lastColumn:o.getArg(u,"lastGeneratedColumn",null)});u=this._originalMappings[++a]}}}return t};r.SourceMapConsumer=SourceMapConsumer;function BasicSourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}var t=o.getArg(n,"version");var i=o.getArg(n,"sources");var u=o.getArg(n,"names",[]);var s=o.getArg(n,"sourceRoot",null);var l=o.getArg(n,"sourcesContent",null);var c=o.getArg(n,"mappings");var p=o.getArg(n,"file",null);if(t!=this._version){throw new Error("Unsupported version: "+t)}if(s){s=o.normalize(s)}i=i.map(String).map(o.normalize).map((function(e){return s&&o.isAbsolute(s)&&o.isAbsolute(e)?o.relative(s,e):e}));this._names=a.fromArray(u.map(String),true);this._sources=a.fromArray(i,true);this._absoluteSources=this._sources.toArray().map((function(e){return o.computeSourceURL(s,e,r)}));this.sourceRoot=s;this.sourcesContent=l;this._mappings=c;this._sourceMapURL=r;this.file=p}BasicSourceMapConsumer.prototype=Object.create(SourceMapConsumer.prototype);BasicSourceMapConsumer.prototype.consumer=SourceMapConsumer;BasicSourceMapConsumer.prototype._findSourceIndex=function(e){var r=e;if(this.sourceRoot!=null){r=o.relative(this.sourceRoot,r)}if(this._sources.has(r)){return this._sources.indexOf(r)}var n;for(n=0;n1){v.source=l+_[1];l+=_[1];v.originalLine=i+_[2];i=v.originalLine;v.originalLine+=1;v.originalColumn=a+_[3];a=v.originalColumn;if(_.length>4){v.name=c+_[4];c+=_[4]}}m.push(v);if(typeof v.originalLine==="number"){d.push(v)}}}s(m,o.compareByGeneratedPositionsDeflated);this.__generatedMappings=m;s(d,o.compareByOriginalPositions);this.__originalMappings=d};BasicSourceMapConsumer.prototype._findMapping=function SourceMapConsumer_findMapping(e,r,n,t,o,a){if(e[n]<=0){throw new TypeError("Line must be greater than or equal to 1, got "+e[n])}if(e[t]<0){throw new TypeError("Column must be greater than or equal to 0, got "+e[t])}return i.search(e,r,o,a)};BasicSourceMapConsumer.prototype.computeColumnSpans=function SourceMapConsumer_computeColumnSpans(){for(var e=0;e=0){var t=this._generatedMappings[n];if(t.generatedLine===r.generatedLine){var i=o.getArg(t,"source",null);if(i!==null){i=this._sources.at(i);i=o.computeSourceURL(this.sourceRoot,i,this._sourceMapURL)}var a=o.getArg(t,"name",null);if(a!==null){a=this._names.at(a)}return{source:i,line:o.getArg(t,"originalLine",null),column:o.getArg(t,"originalColumn",null),name:a}}}return{source:null,line:null,column:null,name:null}};BasicSourceMapConsumer.prototype.hasContentsOfAllSources=function BasicSourceMapConsumer_hasContentsOfAllSources(){if(!this.sourcesContent){return false}return this.sourcesContent.length>=this._sources.size()&&!this.sourcesContent.some((function(e){return e==null}))};BasicSourceMapConsumer.prototype.sourceContentFor=function SourceMapConsumer_sourceContentFor(e,r){if(!this.sourcesContent){return null}var n=this._findSourceIndex(e);if(n>=0){return this.sourcesContent[n]}var t=e;if(this.sourceRoot!=null){t=o.relative(this.sourceRoot,t)}var i;if(this.sourceRoot!=null&&(i=o.urlParse(this.sourceRoot))){var a=t.replace(/^file:\/\//,"");if(i.scheme=="file"&&this._sources.has(a)){return this.sourcesContent[this._sources.indexOf(a)]}if((!i.path||i.path=="/")&&this._sources.has("/"+t)){return this.sourcesContent[this._sources.indexOf("/"+t)]}}if(r){return null}else{throw new Error('"'+t+'" is not in the SourceMap.')}};BasicSourceMapConsumer.prototype.generatedPositionFor=function SourceMapConsumer_generatedPositionFor(e){var r=o.getArg(e,"source");r=this._findSourceIndex(r);if(r<0){return{line:null,column:null,lastColumn:null}}var n={source:r,originalLine:o.getArg(e,"line"),originalColumn:o.getArg(e,"column")};var t=this._findMapping(n,this._originalMappings,"originalLine","originalColumn",o.compareByOriginalPositions,o.getArg(e,"bias",SourceMapConsumer.GREATEST_LOWER_BOUND));if(t>=0){var i=this._originalMappings[t];if(i.source===n.source){return{line:o.getArg(i,"generatedLine",null),column:o.getArg(i,"generatedColumn",null),lastColumn:o.getArg(i,"lastGeneratedColumn",null)}}}return{line:null,column:null,lastColumn:null}};t=BasicSourceMapConsumer;function IndexedSourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}var t=o.getArg(n,"version");var i=o.getArg(n,"sections");if(t!=this._version){throw new Error("Unsupported version: "+t)}this._sources=new a;this._names=new a;var u={line:-1,column:0};this._sections=i.map((function(e){if(e.url){throw new Error("Support for url field in sections not implemented.")}var n=o.getArg(e,"offset");var t=o.getArg(n,"line");var i=o.getArg(n,"column");if(t{var t=n(449);var o=n(339);var i=n(274).I;var a=n(680).H;function SourceMapGenerator(e){if(!e){e={}}this._file=o.getArg(e,"file",null);this._sourceRoot=o.getArg(e,"sourceRoot",null);this._skipValidation=o.getArg(e,"skipValidation",false);this._sources=new i;this._names=new i;this._mappings=new a;this._sourcesContents=null}SourceMapGenerator.prototype._version=3;SourceMapGenerator.fromSourceMap=function SourceMapGenerator_fromSourceMap(e){var r=e.sourceRoot;var n=new SourceMapGenerator({file:e.file,sourceRoot:r});e.eachMapping((function(e){var t={generated:{line:e.generatedLine,column:e.generatedColumn}};if(e.source!=null){t.source=e.source;if(r!=null){t.source=o.relative(r,t.source)}t.original={line:e.originalLine,column:e.originalColumn};if(e.name!=null){t.name=e.name}}n.addMapping(t)}));e.sources.forEach((function(t){var i=t;if(r!==null){i=o.relative(r,t)}if(!n._sources.has(i)){n._sources.add(i)}var a=e.sourceContentFor(t);if(a!=null){n.setSourceContent(t,a)}}));return n};SourceMapGenerator.prototype.addMapping=function SourceMapGenerator_addMapping(e){var r=o.getArg(e,"generated");var n=o.getArg(e,"original",null);var t=o.getArg(e,"source",null);var i=o.getArg(e,"name",null);if(!this._skipValidation){this._validateMapping(r,n,t,i)}if(t!=null){t=String(t);if(!this._sources.has(t)){this._sources.add(t)}}if(i!=null){i=String(i);if(!this._names.has(i)){this._names.add(i)}}this._mappings.add({generatedLine:r.line,generatedColumn:r.column,originalLine:n!=null&&n.line,originalColumn:n!=null&&n.column,source:t,name:i})};SourceMapGenerator.prototype.setSourceContent=function SourceMapGenerator_setSourceContent(e,r){var n=e;if(this._sourceRoot!=null){n=o.relative(this._sourceRoot,n)}if(r!=null){if(!this._sourcesContents){this._sourcesContents=Object.create(null)}this._sourcesContents[o.toSetString(n)]=r}else if(this._sourcesContents){delete this._sourcesContents[o.toSetString(n)];if(Object.keys(this._sourcesContents).length===0){this._sourcesContents=null}}};SourceMapGenerator.prototype.applySourceMap=function SourceMapGenerator_applySourceMap(e,r,n){var t=r;if(r==null){if(e.file==null){throw new Error("SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, "+'or the source map\'s "file" property. Both were omitted.')}t=e.file}var a=this._sourceRoot;if(a!=null){t=o.relative(a,t)}var u=new i;var s=new i;this._mappings.unsortedForEach((function(r){if(r.source===t&&r.originalLine!=null){var i=e.originalPositionFor({line:r.originalLine,column:r.originalColumn});if(i.source!=null){r.source=i.source;if(n!=null){r.source=o.join(n,r.source)}if(a!=null){r.source=o.relative(a,r.source)}r.originalLine=i.line;r.originalColumn=i.column;if(i.name!=null){r.name=i.name}}}var l=r.source;if(l!=null&&!u.has(l)){u.add(l)}var c=r.name;if(c!=null&&!s.has(c)){s.add(c)}}),this);this._sources=u;this._names=s;e.sources.forEach((function(r){var t=e.sourceContentFor(r);if(t!=null){if(n!=null){r=o.join(n,r)}if(a!=null){r=o.relative(a,r)}this.setSourceContent(r,t)}}),this)};SourceMapGenerator.prototype._validateMapping=function SourceMapGenerator_validateMapping(e,r,n,t){if(r&&typeof r.line!=="number"&&typeof r.column!=="number"){throw new Error("original.line and original.column are not numbers -- you probably meant to omit "+"the original mapping entirely and only map the generated position. If so, pass "+"null for the original mapping instead of an object with empty or null values.")}if(e&&"line"in e&&"column"in e&&e.line>0&&e.column>=0&&!r&&!n&&!t){return}else if(e&&"line"in e&&"column"in e&&r&&"line"in r&&"column"in r&&e.line>0&&e.column>=0&&r.line>0&&r.column>=0&&n){return}else{throw new Error("Invalid mapping: "+JSON.stringify({generated:e,source:n,original:r,name:t}))}};SourceMapGenerator.prototype._serializeMappings=function SourceMapGenerator_serializeMappings(){var e=0;var r=1;var n=0;var i=0;var a=0;var u=0;var s="";var l;var c;var p;var f;var g=this._mappings.toArray();for(var h=0,d=g.length;h0){if(!o.compareByGeneratedPositionsInflated(c,g[h-1])){continue}l+=","}}l+=t.encode(c.generatedColumn-e);e=c.generatedColumn;if(c.source!=null){f=this._sources.indexOf(c.source);l+=t.encode(f-u);u=f;l+=t.encode(c.originalLine-1-i);i=c.originalLine-1;l+=t.encode(c.originalColumn-n);n=c.originalColumn;if(c.name!=null){p=this._names.indexOf(c.name);l+=t.encode(p-a);a=p}}s+=l}return s};SourceMapGenerator.prototype._generateSourcesContent=function SourceMapGenerator_generateSourcesContent(e,r){return e.map((function(e){if(!this._sourcesContents){return null}if(r!=null){e=o.relative(r,e)}var n=o.toSetString(e);return Object.prototype.hasOwnProperty.call(this._sourcesContents,n)?this._sourcesContents[n]:null}),this)};SourceMapGenerator.prototype.toJSON=function SourceMapGenerator_toJSON(){var e={version:this._version,sources:this._sources.toArray(),names:this._names.toArray(),mappings:this._serializeMappings()};if(this._file!=null){e.file=this._file}if(this._sourceRoot!=null){e.sourceRoot=this._sourceRoot}if(this._sourcesContents){e.sourcesContent=this._generateSourcesContent(e.sources,e.sourceRoot)}return e};SourceMapGenerator.prototype.toString=function SourceMapGenerator_toString(){return JSON.stringify(this.toJSON())};r.h=SourceMapGenerator},351:(e,r,n)=>{var t;var o=n(591).h;var i=n(339);var a=/(\r?\n)/;var u=10;var s="$$$isSourceNode$$$";function SourceNode(e,r,n,t,o){this.children=[];this.sourceContents={};this.line=e==null?null:e;this.column=r==null?null:r;this.source=n==null?null:n;this.name=o==null?null:o;this[s]=true;if(t!=null)this.add(t)}SourceNode.fromStringWithSourceMap=function SourceNode_fromStringWithSourceMap(e,r,n){var t=new SourceNode;var o=e.split(a);var u=0;var shiftNextLine=function(){var e=getNextLine();var r=getNextLine()||"";return e+r;function getNextLine(){return u=0;r--){this.prepend(e[r])}}else if(e[s]||typeof e==="string"){this.children.unshift(e)}else{throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e)}return this};SourceNode.prototype.walk=function SourceNode_walk(e){var r;for(var n=0,t=this.children.length;n0){r=[];for(n=0;n{function getArg(e,r,n){if(r in e){return e[r]}else if(arguments.length===3){return n}else{throw new Error('"'+r+'" is a required argument.')}}r.getArg=getArg;var n=/^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/;var t=/^data:.+\,.+$/;function urlParse(e){var r=e.match(n);if(!r){return null}return{scheme:r[1],auth:r[2],host:r[3],port:r[4],path:r[5]}}r.urlParse=urlParse;function urlGenerate(e){var r="";if(e.scheme){r+=e.scheme+":"}r+="//";if(e.auth){r+=e.auth+"@"}if(e.host){r+=e.host}if(e.port){r+=":"+e.port}if(e.path){r+=e.path}return r}r.urlGenerate=urlGenerate;function normalize(e){var n=e;var t=urlParse(e);if(t){if(!t.path){return e}n=t.path}var o=r.isAbsolute(n);var i=n.split(/\/+/);for(var a,u=0,s=i.length-1;s>=0;s--){a=i[s];if(a==="."){i.splice(s,1)}else if(a===".."){u++}else if(u>0){if(a===""){i.splice(s+1,u);u=0}else{i.splice(s,2);u--}}}n=i.join("/");if(n===""){n=o?"/":"."}if(t){t.path=n;return urlGenerate(t)}return n}r.normalize=normalize;function join(e,r){if(e===""){e="."}if(r===""){r="."}var n=urlParse(r);var o=urlParse(e);if(o){e=o.path||"/"}if(n&&!n.scheme){if(o){n.scheme=o.scheme}return urlGenerate(n)}if(n||r.match(t)){return r}if(o&&!o.host&&!o.path){o.host=r;return urlGenerate(o)}var i=r.charAt(0)==="/"?r:normalize(e.replace(/\/+$/,"")+"/"+r);if(o){o.path=i;return urlGenerate(o)}return i}r.join=join;r.isAbsolute=function(e){return e.charAt(0)==="/"||n.test(e)};function relative(e,r){if(e===""){e="."}e=e.replace(/\/$/,"");var n=0;while(r.indexOf(e+"/")!==0){var t=e.lastIndexOf("/");if(t<0){return r}e=e.slice(0,t);if(e.match(/^([^\/]+:\/)?\/*$/)){return r}++n}return Array(n+1).join("../")+r.substr(e.length+1)}r.relative=relative;var o=function(){var e=Object.create(null);return!("__proto__"in e)}();function identity(e){return e}function toSetString(e){if(isProtoString(e)){return"$"+e}return e}r.toSetString=o?identity:toSetString;function fromSetString(e){if(isProtoString(e)){return e.slice(1)}return e}r.fromSetString=o?identity:fromSetString;function isProtoString(e){if(!e){return false}var r=e.length;if(r<9){return false}if(e.charCodeAt(r-1)!==95||e.charCodeAt(r-2)!==95||e.charCodeAt(r-3)!==111||e.charCodeAt(r-4)!==116||e.charCodeAt(r-5)!==111||e.charCodeAt(r-6)!==114||e.charCodeAt(r-7)!==112||e.charCodeAt(r-8)!==95||e.charCodeAt(r-9)!==95){return false}for(var n=r-10;n>=0;n--){if(e.charCodeAt(n)!==36){return false}}return true}function compareByOriginalPositions(e,r,n){var t=strcmp(e.source,r.source);if(t!==0){return t}t=e.originalLine-r.originalLine;if(t!==0){return t}t=e.originalColumn-r.originalColumn;if(t!==0||n){return t}t=e.generatedColumn-r.generatedColumn;if(t!==0){return t}t=e.generatedLine-r.generatedLine;if(t!==0){return t}return strcmp(e.name,r.name)}r.compareByOriginalPositions=compareByOriginalPositions;function compareByGeneratedPositionsDeflated(e,r,n){var t=e.generatedLine-r.generatedLine;if(t!==0){return t}t=e.generatedColumn-r.generatedColumn;if(t!==0||n){return t}t=strcmp(e.source,r.source);if(t!==0){return t}t=e.originalLine-r.originalLine;if(t!==0){return t}t=e.originalColumn-r.originalColumn;if(t!==0){return t}return strcmp(e.name,r.name)}r.compareByGeneratedPositionsDeflated=compareByGeneratedPositionsDeflated;function strcmp(e,r){if(e===r){return 0}if(e===null){return 1}if(r===null){return-1}if(e>r){return 1}return-1}function compareByGeneratedPositionsInflated(e,r){var n=e.generatedLine-r.generatedLine;if(n!==0){return n}n=e.generatedColumn-r.generatedColumn;if(n!==0){return n}n=strcmp(e.source,r.source);if(n!==0){return n}n=e.originalLine-r.originalLine;if(n!==0){return n}n=e.originalColumn-r.originalColumn;if(n!==0){return n}return strcmp(e.name,r.name)}r.compareByGeneratedPositionsInflated=compareByGeneratedPositionsInflated;function parseSourceMapInput(e){return JSON.parse(e.replace(/^\)]}'[^\n]*\n/,""))}r.parseSourceMapInput=parseSourceMapInput;function computeSourceURL(e,r,n){r=r||"";if(e){if(e[e.length-1]!=="/"&&r[0]!=="/"){e+="/"}r=e+r}if(n){var t=urlParse(n);if(!t){throw new Error("sourceMapURL could not be parsed")}if(t.path){var o=t.path.lastIndexOf("/");if(o>=0){t.path=t.path.substring(0,o+1)}}r=join(urlGenerate(t),r)}return normalize(r)}r.computeSourceURL=computeSourceURL},997:(e,r,n)=>{n(591).h;r.SourceMapConsumer=n(952).SourceMapConsumer;n(351)},284:(e,r,n)=>{e=n.nmd(e);var t=n(997).SourceMapConsumer;var o=n(17);var i;try{i=n(147);if(!i.existsSync||!i.readFileSync){i=null}}catch(e){}var a=n(650);function dynamicRequire(e,r){return e.require(r)}var u=false;var s=false;var l=false;var c="auto";var p={};var f={};var g=/^data:application\/json[^,]+base64,/;var h=[];var d=[];function isInBrowser(){if(c==="browser")return true;if(c==="node")return false;return typeof window!=="undefined"&&typeof XMLHttpRequest==="function"&&!(window.require&&window.module&&window.process&&window.process.type==="renderer")}function hasGlobalProcessEventEmitter(){return typeof process==="object"&&process!==null&&typeof process.on==="function"}function globalProcessVersion(){if(typeof process==="object"&&process!==null){return process.version}else{return""}}function globalProcessStderr(){if(typeof process==="object"&&process!==null){return process.stderr}}function globalProcessExit(e){if(typeof process==="object"&&process!==null&&typeof process.exit==="function"){return process.exit(e)}}function handlerExec(e){return function(r){for(var n=0;n"}var n=this.getLineNumber();if(n!=null){r+=":"+n;var t=this.getColumnNumber();if(t){r+=":"+t}}}var o="";var i=this.getFunctionName();var a=true;var u=this.isConstructor();var s=!(this.isToplevel()||u);if(s){var l=this.getTypeName();if(l==="[object Object]"){l="null"}var c=this.getMethodName();if(i){if(l&&i.indexOf(l)!=0){o+=l+"."}o+=i;if(c&&i.indexOf("."+c)!=i.length-c.length-1){o+=" [as "+c+"]"}}else{o+=l+"."+(c||"")}}else if(u){o+="new "+(i||"")}else if(i){o+=i}else{o+=r;a=false}if(a){o+=" ("+r+")"}return o}function cloneCallSite(e){var r={};Object.getOwnPropertyNames(Object.getPrototypeOf(e)).forEach((function(n){r[n]=/^(?:is|get)/.test(n)?function(){return e[n].call(e)}:e[n]}));r.toString=CallSiteToString;return r}function wrapCallSite(e,r){if(r===undefined){r={nextPosition:null,curPosition:null}}if(e.isNative()){r.curPosition=null;return e}var n=e.getFileName()||e.getScriptNameOrSourceURL();if(n){var t=e.getLineNumber();var o=e.getColumnNumber()-1;var i=/^v(10\.1[6-9]|10\.[2-9][0-9]|10\.[0-9]{3,}|1[2-9]\d*|[2-9]\d|\d{3,}|11\.11)/;var a=i.test(globalProcessVersion())?0:62;if(t===1&&o>a&&!isInBrowser()&&!e.isEval()){o-=a}var u=mapSourcePosition({source:n,line:t,column:o});r.curPosition=u;e=cloneCallSite(e);var s=e.getFunctionName;e.getFunctionName=function(){if(r.nextPosition==null){return s()}return r.nextPosition.name||s()};e.getFileName=function(){return u.source};e.getLineNumber=function(){return u.line};e.getColumnNumber=function(){return u.column+1};e.getScriptNameOrSourceURL=function(){return u.source};return e}var l=e.isEval()&&e.getEvalOrigin();if(l){l=mapEvalOrigin(l);e=cloneCallSite(e);e.getEvalOrigin=function(){return l};return e}return e}function prepareStackTrace(e,r){if(l){p={};f={}}var n=e.name||"Error";var t=e.message||"";var o=n+": "+t;var i={nextPosition:null,curPosition:null};var a=[];for(var u=r.length-1;u>=0;u--){a.push("\n at "+wrapCallSite(r[u],i));i.nextPosition=i.curPosition}i.curPosition=i.nextPosition=null;return o+a.reverse().join("")}function getErrorSource(e){var r=/\n at [^(]+ \((.*):(\d+):(\d+)\)/.exec(e.stack);if(r){var n=r[1];var t=+r[2];var o=+r[3];var a=p[n];if(!a&&i&&i.existsSync(n)){try{a=i.readFileSync(n,"utf8")}catch(e){a=""}}if(a){var u=a.split(/(?:\r\n|\r|\n)/)[t-1];if(u){return n+":"+t+"\n"+u+"\n"+new Array(o).join(" ")+"^"}}}return null}function printErrorAndExit(e){var r=getErrorSource(e);var n=globalProcessStderr();if(n&&n._handle&&n._handle.setBlocking){n._handle.setBlocking(true)}if(r){console.error();console.error(r)}console.error(e.stack);globalProcessExit(1)}function shimEmitUncaughtException(){var e=process.emit;process.emit=function(r){if(r==="uncaughtException"){var n=arguments[1]&&arguments[1].stack;var t=this.listeners(r).length>0;if(n&&!t){return printErrorAndExit(arguments[1])}}return e.apply(this,arguments)}}var S=h.slice(0);var _=d.slice(0);r.wrapCallSite=wrapCallSite;r.getErrorSource=getErrorSource;r.mapSourcePosition=mapSourcePosition;r.retrieveSourceMap=v;r.install=function(r){r=r||{};if(r.environment){c=r.environment;if(["node","browser","auto"].indexOf(c)===-1){throw new Error("environment "+c+" was unknown. Available options are {auto, browser, node}")}}if(r.retrieveFile){if(r.overrideRetrieveFile){h.length=0}h.unshift(r.retrieveFile)}if(r.retrieveSourceMap){if(r.overrideRetrieveSourceMap){d.length=0}d.unshift(r.retrieveSourceMap)}if(r.hookRequire&&!isInBrowser()){var n=dynamicRequire(e,"module");var t=n.prototype._compile;if(!t.__sourceMapSupport){n.prototype._compile=function(e,r){p[r]=e;f[r]=undefined;return t.call(this,e,r)};n.prototype._compile.__sourceMapSupport=true}}if(!l){l="emptyCacheBetweenOperations"in r?r.emptyCacheBetweenOperations:false}if(!u){u=true;Error.prepareStackTrace=prepareStackTrace}if(!s){var o="handleUncaughtExceptions"in r?r.handleUncaughtExceptions:true;try{var i=dynamicRequire(e,"worker_threads");if(i.isMainThread===false){o=false}}catch(e){}if(o&&hasGlobalProcessEventEmitter()){s=true;shimEmitUncaughtException()}}};r.resetRetrieveHandlers=function(){h.length=0;d.length=0;h=S.slice(0);d=_.slice(0);v=handlerExec(d);m=handlerExec(h)}},147:e=>{"use strict";e.exports=require("fs")},17:e=>{"use strict";e.exports=require("path")}};var r={};function __webpack_require__(n){var t=r[n];if(t!==undefined){return t.exports}var o=r[n]={id:n,loaded:false,exports:{}};var i=true;try{e[n](o,o.exports,__webpack_require__);i=false}finally{if(i)delete r[n]}o.loaded=true;return o.exports}(()=>{__webpack_require__.nmd=e=>{e.paths=[];if(!e.children)e.children=[];return e}})();if(typeof __webpack_require__!=="undefined")__webpack_require__.ab=__dirname+"/";var n={};(()=>{__webpack_require__(284).install()})();module.exports=n})(); --------------------------------------------------------------------------------