Compare commits
	
		
			75 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | e673438944 | ||
|   | f40e8894f1 | ||
|   | a1c666d855 | ||
|   | d5b70f51d8 | ||
|   | 2e941f2def | ||
|   | eef74457f7 | ||
|   | e168301d39 | ||
|   | 29f1eeb9e5 | ||
|   | faca7837b0 | ||
|   | dffa64995b | ||
|   | c0e291b502 | ||
|   | 2323559062 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | e80b8cc6d8 | ||
|   | 31e7cc5f84 | ||
|   | 9db0a23fb3 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 90e26af07a | ||
|   | 01ed3f7910 | ||
|   | 11ae4c31f6 | ||
|   | 983bf3e000 | ||
|   | 9a462131b5 | ||
|   | 1806a02fac | ||
|   | c1f17c078a | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 76bfd425d8 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 5a93241d03 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 2f13c4010e | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 1dd5af0c3a | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 55dd79473c | ||
|   | b1f1f719c7 | ||
|   | 68810d1ede | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | cd8b844a0a | ||
|   | 894f000c27 | ||
|   | f080c7125b | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 49b8353604 | ||
|   | 0d135e0c2f | ||
|   | 36d8e005ca | ||
|   | 012185ccbe | ||
|   | 881cacd606 | ||
|   | 076026291d | ||
|   | f4b1b8d38d | ||
|   | 316c3e4a7c | ||
|   | 5b1c96aee8 | ||
|   | 0f034385ce | ||
|   | 72750233ac | ||
|   | abdb186058 | ||
|   | 9b365965c1 | ||
|   | 583a3147f8 | ||
|   | 2913c18445 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 26e1d017b6 | ||
|   | 2a4b53665e | ||
|   | 03951fea2c | ||
|   | 04f80b2fda | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 240d54e928 | ||
|   | 070ea47eff | ||
|   | d3872b2920 | ||
|   | cb02c5f3d1 | ||
|   | f0d07f4abd | ||
|   | 31740423d9 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | f25fc8d621 | ||
|   | 8d9ae5d563 | ||
|   | 33d65376eb | ||
|   | 4ad06cec8a | ||
|   | bae85ae215 | ||
|   | 154c24e1f3 | ||
|   | 8f7787f9f5 | ||
|   | 87e1457170 | ||
|   | 467d3396dc | ||
|   | 370507b713 | ||
|   | 0ddb9e80d4 | ||
|   | daf8c4fb8d | ||
|   | db0ae322da | ||
|   | 5c0276ad2c | ||
|   | ca778fe8a3 | ||
|   | c3c3e01512 | ||
|   | a999bae018 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 4608f72b35 | 
							
								
								
									
										2
									
								
								.dockerignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.dockerignore
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| /coverage | ||||
| /node_modules | ||||
							
								
								
									
										33
									
								
								.github/CONTRIBUTING.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								.github/CONTRIBUTING.md
									
									
									
									
										vendored
									
									
								
							| @@ -2,35 +2,24 @@ | ||||
|  | ||||
| Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. | ||||
|  | ||||
| Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE). | ||||
| Contributions to this project are [released](https://docs.github.com/en/github/site-policy/github-terms-of-service#6-contributions-under-repository-license) | ||||
| to the public under the [project's open source license](LICENSE). | ||||
|  | ||||
| ## Submitting a pull request | ||||
|  | ||||
| 1. [Fork](https://github.com/docker/setup-buildx-action/fork) and clone the repository | ||||
| 2. Configure and install the dependencies: `yarn install` | ||||
| 3. Create a new branch: `git checkout -b my-branch-name` | ||||
| 4. Make your change, add tests, and make sure the tests still pass | ||||
| 5. Run pre-checkin: `yarn run pre-checkin` | ||||
| 6. Push to your fork and [submit a pull request](https://github.com/docker/setup-buildx-action/compare) | ||||
| 7. Pat yourself on the back and wait for your pull request to be reviewed and merged. | ||||
|  | ||||
| ## Container based developer flow | ||||
|  | ||||
| If you don't want to maintain a Node developer environment that fits this project you can use containerized commands instead of invoking yarn directly. | ||||
|  | ||||
| ``` | ||||
| # format code and build javascript artifacts | ||||
| docker buildx bake pre-checkin | ||||
|  | ||||
| # validate all code has correctly formatted and built | ||||
| docker buildx bake validate | ||||
|  | ||||
| # run tests | ||||
| docker buildx bake test | ||||
| ``` | ||||
| 4. Make your changes | ||||
| 5. Make sure the tests pass: `docker buildx bake test` | ||||
| 6. Format code and build javascript artifacts: `docker buildx bake pre-checkin` | ||||
| 7. Validate all code has correctly formatted and built: `docker buildx bake validate` | ||||
| 8. Push to your fork and [submit a pull request](https://github.com/docker/setup-buildx-action/compare) | ||||
| 9. Pat your self on the back and wait for your pull request to be reviewed and merged. | ||||
|  | ||||
| Here are a few things you can do that will increase the likelihood of your pull request being accepted: | ||||
|  | ||||
| - Write tests. | ||||
| - Make sure the `README.md` and any other relevant **documentation are kept up-to-date**. | ||||
| - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. | ||||
| - Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as **separate pull requests**. | ||||
| @@ -39,5 +28,5 @@ Here are a few things you can do that will increase the likelihood of your pull | ||||
| ## Resources | ||||
|  | ||||
| - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) | ||||
| - [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) | ||||
| - [GitHub Help](https://help.github.com) | ||||
| - [Using Pull Requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) | ||||
| - [GitHub Help](https://docs.github.com/en) | ||||
|   | ||||
							
								
								
									
										3
									
								
								.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
								
							| @@ -30,4 +30,5 @@ about: Create a report to help us improve | ||||
|  | ||||
| ### Logs | ||||
|  | ||||
| > Download the [log file of your build](https://help.github.com/en/actions/configuring-and-managing-workflows/managing-a-workflow-run#downloading-logs) and [attach it](https://help.github.com/en/github/managing-your-work-on-github/file-attachments-on-issues-and-pull-requests) to this issue. | ||||
| > 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. | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								.github/buildkit-container-logs.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.github/buildkit-container-logs.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 13 KiB | 
							
								
								
									
										77
									
								
								.github/labels.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										77
									
								
								.github/labels.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,77 +0,0 @@ | ||||
| ## more info https://github.com/crazy-max/ghaction-github-labeler | ||||
| - # automerge | ||||
|   name: ":bell: automerge" | ||||
|   color: "8f4fbc" | ||||
|   description: "" | ||||
| - # bot | ||||
|   name: ":robot: bot" | ||||
|   color: "69cde9" | ||||
|   description: "" | ||||
| - # bug | ||||
|   name: ":bug: bug" | ||||
|   color: "b60205" | ||||
|   description: "" | ||||
| - # dependencies | ||||
|   name: ":game_die: dependencies" | ||||
|   color: "0366d6" | ||||
|   description: "" | ||||
| - # documentation | ||||
|   name: ":memo: documentation" | ||||
|   color: "c5def5" | ||||
|   description: "" | ||||
| - # duplicate | ||||
|   name: ":busts_in_silhouette: duplicate" | ||||
|   color: "cccccc" | ||||
|   description: "" | ||||
| - # enhancement | ||||
|   name: ":sparkles: enhancement" | ||||
|   color: "0054ca" | ||||
|   description: "" | ||||
| - # feature request | ||||
|   name: ":bulb: feature request" | ||||
|   color: "0e8a16" | ||||
|   description: "" | ||||
| - # feedback | ||||
|   name: ":mega: feedback" | ||||
|   color: "03a9f4" | ||||
|   description: "" | ||||
| - # future maybe | ||||
|   name: ":rocket: future maybe" | ||||
|   color: "fef2c0" | ||||
|   description: "" | ||||
| - # good first issue | ||||
|   name: ":hatching_chick: good first issue" | ||||
|   color: "7057ff" | ||||
|   description: "" | ||||
| - # help wanted | ||||
|   name: ":pray: help wanted" | ||||
|   color: "4caf50" | ||||
|   description: "" | ||||
| - # hold | ||||
|   name: ":hand: hold" | ||||
|   color: "24292f" | ||||
|   description: "" | ||||
| - # invalid | ||||
|   name: ":no_entry_sign: invalid" | ||||
|   color: "e6e6e6" | ||||
|   description: "" | ||||
| - # maybe bug | ||||
|   name: ":interrobang: maybe bug" | ||||
|   color: "ff5722" | ||||
|   description: "" | ||||
| - # needs more info | ||||
|   name: ":thinking: needs more info" | ||||
|   color: "795548" | ||||
|   description: "" | ||||
| - # question | ||||
|   name: ":question: question" | ||||
|   color: "3f51b5" | ||||
|   description: "" | ||||
| - # upstream | ||||
|   name: ":eyes: upstream" | ||||
|   color: "fbca04" | ||||
|   description: "" | ||||
| - # wontfix | ||||
|   name: ":coffin: wontfix" | ||||
|   color: "ffffff" | ||||
|   description: "" | ||||
							
								
								
									
										
											BIN
										
									
								
								.github/setup-buildx-action.png
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.github/setup-buildx-action.png
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 11 KiB | 
							
								
								
									
										184
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										184
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,18 +1,18 @@ | ||||
| name: ci | ||||
|  | ||||
| on: | ||||
|   schedule: | ||||
|     - cron: '0 10 * * *' # everyday at 10am | ||||
|   push: | ||||
|     branches: | ||||
|       - master | ||||
|       - releases/v* | ||||
|     paths-ignore: | ||||
|       - "**.md" | ||||
|       - 'master' | ||||
|       - 'releases/v*' | ||||
|     tags: | ||||
|       - 'v*' | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - master | ||||
|       - releases/v* | ||||
|     paths-ignore: | ||||
|       - "**.md" | ||||
|       - 'master' | ||||
|       - 'releases/v*' | ||||
|  | ||||
| jobs: | ||||
|   main: | ||||
| @@ -22,7 +22,7 @@ jobs: | ||||
|       matrix: | ||||
|         buildx-version: | ||||
|           - latest | ||||
|           - v0.2.2 | ||||
|           - v0.4.1 | ||||
|           - "" | ||||
|     steps: | ||||
|       - | ||||
| @@ -35,11 +35,13 @@ jobs: | ||||
|         with: | ||||
|           version: ${{ matrix.buildx-version }} | ||||
|       - | ||||
|         name: Builder instance name | ||||
|         run: echo ${{ steps.buildx.outputs.name }} | ||||
|       - | ||||
|         name: Available platforms | ||||
|         run: echo ${{ steps.buildx.outputs.platforms }} | ||||
|         name: Inspect builder | ||||
|         run: | | ||||
|           echo "Name:      ${{ steps.buildx.outputs.name }}" | ||||
|           echo "Endpoint:  ${{ steps.buildx.outputs.endpoint }}" | ||||
|           echo "Status:    ${{ steps.buildx.outputs.status }}" | ||||
|           echo "Flags:     ${{ steps.buildx.outputs.flags }}" | ||||
|           echo "Platforms: ${{ steps.buildx.outputs.platforms }}" | ||||
|       - | ||||
|         name: Dump context | ||||
|         uses: crazy-max/ghaction-dump-context@v1 | ||||
| @@ -55,15 +57,81 @@ jobs: | ||||
|         id: buildx1 | ||||
|         uses: ./ | ||||
|       - | ||||
|         name: Builder 1 instance name | ||||
|         run: echo ${{ steps.buildx1.outputs.name }} | ||||
|         name: Inspect builder 1 | ||||
|         run: | | ||||
|           echo "Name:      ${{ steps.buildx1.outputs.name }}" | ||||
|           echo "Endpoint:  ${{ steps.buildx1.outputs.endpoint }}" | ||||
|           echo "Status:    ${{ steps.buildx1.outputs.status }}" | ||||
|           echo "Flags:     ${{ steps.buildx1.outputs.flags }}" | ||||
|           echo "Platforms: ${{ steps.buildx1.outputs.platforms }}" | ||||
|       - | ||||
|         name: Set up Docker Buildx 2 | ||||
|         id: buildx2 | ||||
|         uses: ./ | ||||
|       - | ||||
|         name: Builder 2 instance name | ||||
|         run: echo ${{ steps.buildx2.outputs.name }} | ||||
|         name: Inspect builder 2 | ||||
|         run: | | ||||
|           echo "Name:      ${{ steps.buildx2.outputs.name }}" | ||||
|           echo "Endpoint:  ${{ steps.buildx2.outputs.endpoint }}" | ||||
|           echo "Status:    ${{ steps.buildx2.outputs.status }}" | ||||
|           echo "Flags:     ${{ steps.buildx2.outputs.flags }}" | ||||
|           echo "Platforms: ${{ steps.buildx2.outputs.platforms }}" | ||||
|  | ||||
|   error: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v2 | ||||
|       - | ||||
|         name: Stop docker | ||||
|         run: | | ||||
|           sudo systemctl stop docker | ||||
|       - | ||||
|         name: Set up Docker Buildx | ||||
|         id: buildx | ||||
|         continue-on-error: true | ||||
|         uses: ./ | ||||
|       - | ||||
|         name: Check | ||||
|         run: | | ||||
|           echo "${{ toJson(steps.buildx) }}" | ||||
|           if [ "${{ steps.buildx.outcome }}" != "failure" ] || [ "${{ steps.buildx.conclusion }}" != "success" ]; then | ||||
|             echo "::error::Should have failed" | ||||
|             exit 1 | ||||
|           fi | ||||
|       - | ||||
|         name: Dump context | ||||
|         if: always() | ||||
|         uses: crazy-max/ghaction-dump-context@v1 | ||||
|  | ||||
|   debug: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v2 | ||||
|       - | ||||
|         name: Create Dockerfile | ||||
|         run: | | ||||
|           cat > ./Dockerfile <<EOL | ||||
|           FROM alpine | ||||
|           RUN uname -a | ||||
|           EOL | ||||
|       - | ||||
|         name: Set up QEMU | ||||
|         uses: docker/setup-qemu-action@v1 | ||||
|       - | ||||
|         name: Set up Docker Buildx | ||||
|         uses: ./ | ||||
|         with: | ||||
|           buildkitd-flags: --debug | ||||
|       - | ||||
|         name: Build | ||||
|         uses: docker/build-push-action@v2 | ||||
|         with: | ||||
|           context: . | ||||
|           platforms: linux/amd64,linux/arm64,linux/ppc64le | ||||
|  | ||||
|   install: | ||||
|     runs-on: ubuntu-latest | ||||
| @@ -175,6 +243,40 @@ jobs: | ||||
|         uses: ./ | ||||
|         with: | ||||
|           endpoint: mycontext | ||||
|         env: | ||||
|           DOCKER_CONTEXT: mycontext | ||||
|  | ||||
|   config: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v2 | ||||
|       - | ||||
|         name: Create buildkitd conf | ||||
|         run: | | ||||
|           cat > /tmp/buildkitd.toml <<EOL | ||||
|           debug = true | ||||
|           [registry."docker.io"] | ||||
|             mirrors = ["mirror.gcr.io"] | ||||
|           EOL | ||||
|       - | ||||
|         name: Create Dockerfile | ||||
|         run: | | ||||
|           cat > ./Dockerfile <<EOL | ||||
|           FROM alpine | ||||
|           EOL | ||||
|       - | ||||
|         name: Set up Docker Buildx | ||||
|         uses: ./ | ||||
|         with: | ||||
|           buildkitd-flags: --debug | ||||
|           config: /tmp/buildkitd.toml | ||||
|       - | ||||
|         name: Build | ||||
|         uses: docker/build-push-action@v2 | ||||
|         with: | ||||
|           context: . | ||||
|  | ||||
|   with-qemu: | ||||
|     runs-on: ubuntu-latest | ||||
| @@ -183,7 +285,7 @@ jobs: | ||||
|       matrix: | ||||
|         buildx-version: | ||||
|           - latest | ||||
|           - v0.2.2 | ||||
|           - v0.4.1 | ||||
|           - "" | ||||
|         qemu-platforms: | ||||
|           - all | ||||
| @@ -204,8 +306,44 @@ jobs: | ||||
|         with: | ||||
|           version: ${{ matrix.buildx-version }} | ||||
|       - | ||||
|         name: Available platforms | ||||
|         run: echo ${{ steps.buildx.outputs.platforms }} | ||||
|         name: Inspect builder | ||||
|         run: | | ||||
|           echo "Name:      ${{ steps.buildx.outputs.name }}" | ||||
|           echo "Endpoint:  ${{ steps.buildx.outputs.endpoint }}" | ||||
|           echo "Status:    ${{ steps.buildx.outputs.status }}" | ||||
|           echo "Flags:     ${{ steps.buildx.outputs.flags }}" | ||||
|           echo "Platforms: ${{ steps.buildx.outputs.platforms }}" | ||||
|  | ||||
|   build-ref: | ||||
|     runs-on: ubuntu-latest | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|       matrix: | ||||
|         ref: | ||||
|           - master | ||||
|           - refs/tags/v0.5.1 | ||||
|           - refs/pull/648/head | ||||
|     steps: | ||||
|       - | ||||
|         name: Builder instance name | ||||
|         run: echo ${{ steps.buildx.outputs.name }} | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v2 | ||||
|       - | ||||
|         name: Set up Docker Buildx | ||||
|         uses: ./ | ||||
|         with: | ||||
|           version: https://github.com/docker/buildx.git#${{ matrix.ref }} | ||||
|       - | ||||
|         name: Check version | ||||
|         run: | | ||||
|           docker buildx version | ||||
|       - | ||||
|         name: Create Dockerfile | ||||
|         run: | | ||||
|           cat > ./Dockerfile <<EOL | ||||
|           FROM alpine | ||||
|           EOL | ||||
|       - | ||||
|         name: Build | ||||
|         uses: docker/build-push-action@master | ||||
|         with: | ||||
|           context: . | ||||
|   | ||||
							
								
								
									
										20
									
								
								.github/workflows/labels.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								.github/workflows/labels.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,20 +0,0 @@ | ||||
| name: labels | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - 'master' | ||||
|     paths: | ||||
|       - '.github/labels.yml' | ||||
|       - '.github/workflows/labels.yml' | ||||
|  | ||||
| jobs: | ||||
|   labeler: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v2 | ||||
|       - | ||||
|         name: Run Labeler | ||||
|         uses: crazy-max/ghaction-github-labeler@v3 | ||||
							
								
								
									
										39
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							| @@ -3,28 +3,14 @@ name: test | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - master | ||||
|       - releases/v* | ||||
|     paths-ignore: | ||||
|       - "**.md" | ||||
|       - 'master' | ||||
|       - 'releases/v*' | ||||
|   pull_request: | ||||
|     paths-ignore: | ||||
|       - "**.md" | ||||
|     branches: | ||||
|       - 'master' | ||||
|       - 'releases/v*' | ||||
|  | ||||
| jobs: | ||||
|   test-containerized: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v2 | ||||
|       - | ||||
|         name: Validate | ||||
|         run: docker buildx bake validate | ||||
|       - | ||||
|         name: Test | ||||
|         run: docker buildx bake test | ||||
|  | ||||
|   test: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
| @@ -32,15 +18,20 @@ jobs: | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v2 | ||||
|       - | ||||
|         name: Install | ||||
|         run: yarn install | ||||
|         name: Validate | ||||
|         uses: docker/bake-action@v1 | ||||
|         with: | ||||
|           targets: validate | ||||
|       - | ||||
|         name: Set up Docker Buildx | ||||
|         uses: ./ | ||||
|       - | ||||
|         name: Test | ||||
|         run: yarn run test | ||||
|         uses: docker/bake-action@v1 | ||||
|         with: | ||||
|           targets: test | ||||
|       - | ||||
|         name: Upload coverage | ||||
|         uses: codecov/codecov-action@v1 | ||||
|         if: success() | ||||
|         with: | ||||
|           token: ${{ secrets.CODECOV_TOKEN }} | ||||
|           file: ./coverage/clover.xml | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| { | ||||
|   "printWidth": 120, | ||||
|   "printWidth": 240, | ||||
|   "tabWidth": 2, | ||||
|   "useTabs": false, | ||||
|   "semi": true, | ||||
|   | ||||
							
								
								
									
										52
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -1,52 +0,0 @@ | ||||
| #syntax=docker/dockerfile:1.1-experimental | ||||
|  | ||||
| FROM node:14 AS deps | ||||
| WORKDIR /src | ||||
| COPY package.json yarn.lock ./ | ||||
| RUN --mount=type=cache,target=/usr/local/share/.cache/yarn \ | ||||
|   yarn install | ||||
|  | ||||
| FROM scratch AS update-yarn | ||||
| COPY --from=deps /src/yarn.lock / | ||||
|  | ||||
| FROM deps AS validate-yarn | ||||
| COPY .git .git | ||||
| RUN status=$(git status --porcelain -- yarn.lock); if [ -n "$status" ]; then echo $status; exit 1; fi | ||||
|  | ||||
| FROM deps AS base | ||||
| COPY . . | ||||
|  | ||||
| FROM base AS build | ||||
| RUN yarn build | ||||
|  | ||||
| FROM deps AS test | ||||
| COPY --from=docker /usr/local/bin/docker /usr/bin/ | ||||
| ARG TARGETOS | ||||
| ARG TARGETARCH | ||||
| ARG BUILDX_VERSION=v0.4.2 | ||||
| ENV RUNNER_TEMP=/tmp/github_runner | ||||
| ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache | ||||
| RUN mkdir -p /usr/local/lib/docker/cli-plugins && \ | ||||
|   curl -fsSL https://github.com/docker/buildx/releases/download/$BUILDX_VERSION/buildx-$BUILDX_VERSION.$TARGETOS-$TARGETARCH > /usr/local/lib/docker/cli-plugins/docker-buildx && \ | ||||
|   chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx && \ | ||||
|   docker buildx version | ||||
| COPY . . | ||||
| RUN yarn run test | ||||
|  | ||||
| FROM base AS run-format | ||||
| RUN yarn run format | ||||
|  | ||||
| FROM scratch AS format | ||||
| COPY --from=run-format /src/src/*.ts /src/ | ||||
|  | ||||
| FROM base AS validate-format | ||||
| RUN yarn run format-check | ||||
|  | ||||
| FROM scratch AS dist | ||||
| COPY --from=build /src/dist/ /dist/ | ||||
|  | ||||
| FROM build AS validate-build | ||||
| RUN status=$(git status --porcelain -- dist); if [ -n "$status" ]; then echo $status; exit 1; fi | ||||
|  | ||||
| FROM base AS dev | ||||
| ENTRYPOINT ["bash"] | ||||
							
								
								
									
										63
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								README.md
									
									
									
									
									
								
							| @@ -8,10 +8,10 @@ | ||||
|  | ||||
| GitHub Action to set up Docker [Buildx](https://github.com/docker/buildx). | ||||
|  | ||||
| > :bulb: See also: | ||||
| > * [login](https://github.com/docker/login-action) action | ||||
| > * [setup-qemu](https://github.com/docker/setup-qemu-action) action | ||||
| > * [build-push](https://github.com/docker/build-push-action) action | ||||
| This action will create and boot a builder that can be used in the following steps of your workflow if you're using | ||||
| [buildx](https://github.com/docker/buildx). By default, the `docker-container` [builder driver](https://github.com/docker/buildx/blob/master/docs/reference/buildx_create.md#driver) | ||||
| will be used to be able to build multi-platform images and export cache thanks to the [BuildKit](https://github.com/moby/buildkit) | ||||
| container. | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -25,8 +25,9 @@ ___ | ||||
|   * [inputs](#inputs) | ||||
|   * [outputs](#outputs) | ||||
|   * [environment variables](#environment-variables) | ||||
| * [Notes](#notes) | ||||
|   * [BuildKit container logs](#buildkit-container-logs) | ||||
| * [Keep up-to-date with GitHub Dependabot](#keep-up-to-date-with-github-dependabot) | ||||
| * [Limitation](#limitation) | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| @@ -50,11 +51,13 @@ jobs: | ||||
|         id: buildx | ||||
|         uses: docker/setup-buildx-action@v1 | ||||
|       - | ||||
|         name: Builder instance name | ||||
|         run: echo ${{ steps.buildx.outputs.name }} | ||||
|       - | ||||
|         name: Available platforms | ||||
|         run: echo ${{ steps.buildx.outputs.platforms }} | ||||
|         name: Inspect builder | ||||
|         run: | | ||||
|           echo "Name:      ${{ steps.buildx.outputs.name }}" | ||||
|           echo "Endpoint:  ${{ steps.buildx.outputs.endpoint }}" | ||||
|           echo "Status:    ${{ steps.buildx.outputs.status }}" | ||||
|           echo "Flags:     ${{ steps.buildx.outputs.flags }}" | ||||
|           echo "Platforms: ${{ steps.buildx.outputs.platforms }}" | ||||
| ``` | ||||
|  | ||||
| ### With QEMU | ||||
| @@ -122,13 +125,14 @@ Following inputs can be used as `step.with` keys | ||||
|  | ||||
| | Name               | Type    | Description                       | | ||||
| |--------------------|---------|-----------------------------------| | ||||
| | `version`          | String  | [Buildx](https://github.com/docker/buildx) version. (eg. `v0.3.0`, `latest`) | | ||||
| | `driver`           | String  | Sets the [builder driver](https://github.com/docker/buildx#--driver-driver) to be used (default `docker-container`) | | ||||
| | `driver-opts`      | CSV     | List of additional [driver-specific options](https://github.com/docker/buildx#--driver-opt-options) (eg. `image=moby/buildkit:master`) | | ||||
| | `version`          | String  | [buildx](https://github.com/docker/buildx) version. (eg. `v0.3.0`, `latest`, `https://github.com/docker/buildx.git#master`) | | ||||
| | `driver`           | String  | Sets the [builder driver](https://github.com/docker/buildx/blob/master/docs/reference/buildx_create.md#driver) to be used (default `docker-container`) | | ||||
| | `driver-opts`      | CSV     | List of additional [driver-specific options](https://github.com/docker/buildx/blob/master/docs/reference/buildx_create.md#driver-opt) (eg. `image=moby/buildkit:master`) | | ||||
| | `buildkitd-flags`  | String  | [Flags for buildkitd](https://github.com/moby/buildkit/blob/master/docs/buildkitd.toml.md) daemon (since [buildx v0.3.0](https://github.com/docker/buildx/releases/tag/v0.3.0)) | | ||||
| | `install`          | Bool    | Sets up `docker build` command as an alias to `docker buildx` (default `false`) | | ||||
| | `use`              | Bool    | Switch to this builder instance (default `true`) | | ||||
| | `endpoint`         | String  | [Optional address for docker socket](https://github.com/docker/buildx#buildx-create-options-contextendpoint) or context from `docker context ls` | | ||||
| | `endpoint`         | String  | [Optional address for docker socket](https://github.com/docker/buildx/blob/master/docs/reference/buildx_create.md#description) or context from `docker context ls` | | ||||
| | `config`           | String  | [BuildKit config file](https://github.com/docker/buildx/blob/master/docs/reference/buildx_create.md#config) | | ||||
|  | ||||
| > `CSV` type must be a newline-delimited string | ||||
| > ```yaml | ||||
| @@ -146,8 +150,12 @@ Following outputs are available | ||||
|  | ||||
| | Name          | Type    | Description                           | | ||||
| |---------------|---------|---------------------------------------| | ||||
| | `name`        | String  | Builder instance name | | ||||
| | `platforms`   | String  | Available platforms (comma separated) | | ||||
| | `name`        | String  | Builder name | | ||||
| | `driver`      | String  | Builder driver | | ||||
| | `endpoint`    | String  | Builder node endpoint | | ||||
| | `status`      | String  | Builder node status | | ||||
| | `flags`       | String  | Builder node flags (if applicable) | | ||||
| | `platforms`   | String  | Builder node platforms available (comma separated) | | ||||
|  | ||||
| ### environment variables | ||||
|  | ||||
| @@ -157,6 +165,25 @@ The following [official docker environment variables](https://docs.docker.com/en | ||||
| |-----------------|---------|-------------|-------------------------------------------------| | ||||
| | `DOCKER_CONFIG` | String  | `~/.docker` | The location of your client configuration files | | ||||
|  | ||||
| ## Notes | ||||
|  | ||||
| ### BuildKit container logs | ||||
|  | ||||
| To display BuildKit container logs (when `docker-container` driver is used) you have to [enable step debug logging](https://docs.github.com/en/actions/managing-workflow-runs/enabling-debug-logging#enabling-step-debug-logging) | ||||
| or you can also enable debugging in the [setup-buildx action step](https://github.com/docker/setup-buildx-action): | ||||
|  | ||||
| ```yaml | ||||
|   - | ||||
|     name: Set up Docker Buildx | ||||
|     uses: docker/setup-buildx-action@v1 | ||||
|     with: | ||||
|       buildkitd-flags: --debug | ||||
| ``` | ||||
|  | ||||
| Logs will be available at the end of a job: | ||||
|  | ||||
|  | ||||
|  | ||||
| ## Keep up-to-date with GitHub Dependabot | ||||
|  | ||||
| Since [Dependabot](https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-github-dependabot) | ||||
| @@ -172,7 +199,3 @@ updates: | ||||
|     schedule: | ||||
|       interval: "daily" | ||||
| ``` | ||||
|  | ||||
| ## Limitation | ||||
|  | ||||
| This action is only available for Linux [virtual environments](https://docs.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners#supported-virtual-environments-and-hardware-resources). | ||||
|   | ||||
| @@ -1,58 +1,110 @@ | ||||
| import fs = require('fs'); | ||||
| import * as docker from '../src/docker'; | ||||
| import * as buildx from '../src/buildx'; | ||||
| import * as path from 'path'; | ||||
| import * as fs from 'fs'; | ||||
| import * as os from 'os'; | ||||
| import * as path from 'path'; | ||||
| import * as buildx from '../src/buildx'; | ||||
| import * as context from '../src/context'; | ||||
| import * as semver from 'semver'; | ||||
| import * as exec from '@actions/exec'; | ||||
|  | ||||
| jest.spyOn(context, 'tmpDir').mockImplementation((): string => { | ||||
|   const tmpDir = path.join('/tmp/.docker-setup-buildx-jest').split(path.sep).join(path.posix.sep); | ||||
|   if (!fs.existsSync(tmpDir)) { | ||||
|     fs.mkdirSync(tmpDir, {recursive: true}); | ||||
|   } | ||||
|   return tmpDir; | ||||
| }); | ||||
|  | ||||
| describe('isAvailable', () => { | ||||
|   const execSpy: jest.SpyInstance = jest.spyOn(exec, 'getExecOutput'); | ||||
|   buildx.isAvailable(); | ||||
|  | ||||
|   expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx'], { | ||||
|     silent: true, | ||||
|     ignoreReturnCode: true | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| describe('getVersion', () => { | ||||
|   it('valid', async () => { | ||||
|     await exec.exec('docker', ['buildx', 'version']); | ||||
|   async function isDaemonRunning() { | ||||
|     return await exec | ||||
|       .getExecOutput(`docker`, ['version', '--format', '{{.Server.Os}}'], { | ||||
|         ignoreReturnCode: true, | ||||
|         silent: true | ||||
|       }) | ||||
|       .then(res => { | ||||
|         return !res.stdout.trim().includes(' ') && res.exitCode == 0; | ||||
|       }); | ||||
|   } | ||||
|   (isDaemonRunning() ? it : it.skip)( | ||||
|     'valid', | ||||
|     async () => { | ||||
|       const version = await buildx.getVersion(); | ||||
|       console.log(`version: ${version}`); | ||||
|       expect(semver.valid(version)).not.toBeNull(); | ||||
|   }, 100000); | ||||
|     }, | ||||
|     100000 | ||||
|   ); | ||||
| }); | ||||
|  | ||||
| describe('parseVersion', () => { | ||||
|   test.each([ | ||||
|     ['github.com/docker/buildx 0.4.1+azure bda4882a65349ca359216b135896bddc1d92461c', '0.4.1'], | ||||
|     ['github.com/docker/buildx v0.4.1 bda4882a65349ca359216b135896bddc1d92461c', '0.4.1'], | ||||
|     ['github.com/docker/buildx v0.4.2 fb7b670b764764dc4716df3eba07ffdae4cc47b2', '0.4.2'] | ||||
|     ['github.com/docker/buildx v0.4.2 fb7b670b764764dc4716df3eba07ffdae4cc47b2', '0.4.2'], | ||||
|     ['github.com/docker/buildx f117971 f11797113e5a9b86bd976329c5dbb8a8bfdfadfa', 'f117971'] | ||||
|   ])('given %p', async (stdout, expected) => { | ||||
|     expect(await buildx.parseVersion(stdout)).toEqual(expected); | ||||
|     expect(buildx.parseVersion(stdout)).toEqual(expected); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| describe('platforms', () => { | ||||
| describe('satisfies', () => { | ||||
|   test.each([ | ||||
|     ['0.4.1', '>=0.3.2', true], | ||||
|     ['bda4882a65349ca359216b135896bddc1d92461c', '>0.1.0', false], | ||||
|     ['f117971', '>0.6.0', true] | ||||
|   ])('given %p', async (version, range, expected) => { | ||||
|     expect(buildx.satisfies(version, range)).toBe(expected); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| describe('inspect', () => { | ||||
|   async function isDaemonRunning() { | ||||
|     return await docker.isDaemonRunning(); | ||||
|     return await exec | ||||
|       .getExecOutput(`docker`, ['version', '--format', '{{.Server.Os}}'], { | ||||
|         ignoreReturnCode: true, | ||||
|         silent: true | ||||
|       }) | ||||
|       .then(res => { | ||||
|         return !res.stdout.trim().includes(' ') && res.exitCode == 0; | ||||
|       }); | ||||
|   } | ||||
|   (isDaemonRunning() ? it : it.skip)( | ||||
|     'valid', | ||||
|     async () => { | ||||
|       const platforms = buildx.platforms(); | ||||
|       console.log(`platforms: ${platforms}`); | ||||
|       expect(platforms).not.toBeUndefined(); | ||||
|       expect(platforms).not.toEqual(''); | ||||
|       const builder = await buildx.inspect(''); | ||||
|       console.log('builder', builder); | ||||
|       expect(builder).not.toBeUndefined(); | ||||
|       expect(builder.name).not.toEqual(''); | ||||
|       expect(builder.driver).not.toEqual(''); | ||||
|       expect(builder.node_platforms).not.toEqual(''); | ||||
|     }, | ||||
|     100000 | ||||
|   ); | ||||
| }); | ||||
|  | ||||
| describe('countBuilders', () => { | ||||
|   it('valid', async () => { | ||||
|     const countBuilders = await buildx.countBuilders(); | ||||
|     console.log(`countBuilders: ${countBuilders}`); | ||||
|     expect(countBuilders).toBeGreaterThan(0); | ||||
| describe('build', () => { | ||||
|   it.skip('valid', async () => { | ||||
|     const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-buildx-')); | ||||
|     const buildxBin = await buildx.build('https://github.com/docker/buildx.git#refs/pull/648/head', tmpDir); | ||||
|     console.log(buildxBin); | ||||
|     expect(fs.existsSync(buildxBin)).toBe(true); | ||||
|   }, 100000); | ||||
| }); | ||||
|  | ||||
| describe('install', () => { | ||||
|   const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-buildx-')); | ||||
|   it('acquires v0.2.2 version of buildx', async () => { | ||||
|     const buildxBin = await buildx.install('v0.2.2', tmpDir); | ||||
|   it('acquires v0.4.1 version of buildx', async () => { | ||||
|     const buildxBin = await buildx.install('v0.4.1', tmpDir); | ||||
|     console.log(buildxBin); | ||||
|     expect(fs.existsSync(buildxBin)).toBe(true); | ||||
|   }, 100000); | ||||
|   | ||||
| @@ -1,5 +1,16 @@ | ||||
| import * as fs from 'fs'; | ||||
| import * as os from 'os'; | ||||
| import * as path from 'path'; | ||||
| import * as context from '../src/context'; | ||||
|  | ||||
| jest.spyOn(context, 'tmpDir').mockImplementation((): string => { | ||||
|   const tmpDir = path.join('/tmp/.docker-setup-buildx-jest').split(path.sep).join(path.posix.sep); | ||||
|   if (!fs.existsSync(tmpDir)) { | ||||
|     fs.mkdirSync(tmpDir, {recursive: true}); | ||||
|   } | ||||
|   return tmpDir; | ||||
| }); | ||||
|  | ||||
| describe('getInputList', () => { | ||||
|   it('handles single line correctly', async () => { | ||||
|     await setInput('foo', 'bar'); | ||||
| @@ -78,6 +89,27 @@ describe('asyncForEach', () => { | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| describe('setOutput', () => { | ||||
|   beforeEach(() => { | ||||
|     process.stdout.write = jest.fn(); | ||||
|   }); | ||||
|  | ||||
|   it('setOutput produces the correct command', () => { | ||||
|     context.setOutput('some output', 'some value'); | ||||
|     assertWriteCalls([`::set-output name=some output::some value${os.EOL}`]); | ||||
|   }); | ||||
|  | ||||
|   it('setOutput handles bools', () => { | ||||
|     context.setOutput('some output', false); | ||||
|     assertWriteCalls([`::set-output name=some output::false${os.EOL}`]); | ||||
|   }); | ||||
|  | ||||
|   it('setOutput handles numbers', () => { | ||||
|     context.setOutput('some output', 1.01); | ||||
|     assertWriteCalls([`::set-output name=some output::1.01${os.EOL}`]); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| // See: https://github.com/actions/toolkit/blob/master/packages/core/src/core.ts#L67 | ||||
| function getInputName(name: string): string { | ||||
|   return `INPUT_${name.replace(/ /g, '_').toUpperCase()}`; | ||||
| @@ -86,3 +118,11 @@ function getInputName(name: string): string { | ||||
| function setInput(name: string, value: string): void { | ||||
|   process.env[getInputName(name)] = value; | ||||
| } | ||||
|  | ||||
| // Assert that process.stdout.write calls called only with the given arguments. | ||||
| function assertWriteCalls(calls: string[]): void { | ||||
|   expect(process.stdout.write).toHaveBeenCalledTimes(calls.length); | ||||
|   for (let i = 0; i < calls.length; i++) { | ||||
|     expect(process.stdout.write).toHaveBeenNthCalledWith(i + 1, calls[i]); | ||||
|   } | ||||
| } | ||||
|   | ||||
							
								
								
									
										9
									
								
								__tests__/git.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								__tests__/git.test.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| import * as git from '../src/git'; | ||||
|  | ||||
| describe('git', () => { | ||||
|   it('returns git remote ref', async () => { | ||||
|     const ref: string = await git.getRemoteSha('https://github.com/docker/buildx.git', 'refs/pull/648/head'); | ||||
|     console.log(`ref: ${ref}`); | ||||
|     expect(ref).toEqual('f11797113e5a9b86bd976329c5dbb8a8bfdfadfa'); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										11
									
								
								__tests__/util.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								__tests__/util.test.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| import * as util from '../src/util'; | ||||
|  | ||||
| describe('isValidUrl', () => { | ||||
|   test.each([ | ||||
|     ['https://github.com/docker/buildx.git', true], | ||||
|     ['https://github.com/docker/buildx.git#refs/pull/648/head', true], | ||||
|     ['v0.4.1', false] | ||||
|   ])('given %p', async (url, expected) => { | ||||
|     expect(util.isValidUrl(url)).toEqual(expected); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										15
									
								
								action.yml
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								action.yml
									
									
									
									
									
								
							| @@ -32,12 +32,23 @@ inputs: | ||||
|   endpoint: | ||||
|     description: 'Optional address for docker socket or context from `docker context ls`' | ||||
|     required: false | ||||
|   config: | ||||
|     description: 'BuildKit config file' | ||||
|     required: false | ||||
|  | ||||
| outputs: | ||||
|   name: | ||||
|     description: 'Builder instance name' | ||||
|     description: 'Builder name' | ||||
|   driver: | ||||
|     description: 'Builder driver' | ||||
|   endpoint: | ||||
|     description: 'Builder node endpoint' | ||||
|   status: | ||||
|     description: 'Builder node status' | ||||
|   flags: | ||||
|     description: 'Builder node flags (if applicable)' | ||||
|   platforms: | ||||
|     description: 'Available platforms (comma separated)' | ||||
|     description: 'Builder node platforms available (comma separated)' | ||||
|  | ||||
| runs: | ||||
|   using: 'node12' | ||||
|   | ||||
							
								
								
									
										3
									
								
								codecov.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								codecov.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| comment: false | ||||
| github_checks: | ||||
|   annotations: false | ||||
							
								
								
									
										10469
									
								
								dist/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10469
									
								
								dist/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,42 +1,67 @@ | ||||
| variable "NODE_VERSION" { | ||||
|   default = "12" | ||||
| } | ||||
|  | ||||
| target "node-version" { | ||||
|   args = { | ||||
|     NODE_VERSION = NODE_VERSION | ||||
|   } | ||||
| } | ||||
|  | ||||
| group "default" { | ||||
|   targets = ["build"] | ||||
| } | ||||
|  | ||||
| group "pre-checkin" { | ||||
|   targets = ["update-yarn", "format", "build"] | ||||
|   targets = ["vendor-update", "format", "build"] | ||||
| } | ||||
|  | ||||
| group "validate" { | ||||
| 	targets = ["validate-format", "validate-build", "validate-yarn"] | ||||
| } | ||||
|  | ||||
| target "update-yarn" { | ||||
|   target = "update-yarn" | ||||
|   output = ["."] | ||||
|   targets = ["format-validate", "build-validate", "vendor-validate"] | ||||
| } | ||||
|  | ||||
| target "build" { | ||||
|   target = "dist" | ||||
|   inherits = ["node-version"] | ||||
|   dockerfile = "./hack/build.Dockerfile" | ||||
|   target = "build-update" | ||||
|   output = ["."] | ||||
| } | ||||
|  | ||||
| target "test" { | ||||
|   target = "test" | ||||
| target "build-validate" { | ||||
|   inherits = ["node-version"] | ||||
|   dockerfile = "./hack/build.Dockerfile" | ||||
|   target = "build-validate" | ||||
| } | ||||
|  | ||||
| target "format" { | ||||
|   target = "format" | ||||
|   inherits = ["node-version"] | ||||
|   dockerfile = "./hack/build.Dockerfile" | ||||
|   target = "format-update" | ||||
|   output = ["."] | ||||
| } | ||||
|  | ||||
| target "validate-format" { | ||||
|   target = "validate-format" | ||||
| target "format-validate" { | ||||
|   inherits = ["node-version"] | ||||
|   dockerfile = "./hack/build.Dockerfile" | ||||
|   target = "format-validate" | ||||
| } | ||||
|  | ||||
| target "validate-build" { | ||||
|   target = "validate-build" | ||||
| target "vendor-update" { | ||||
|   inherits = ["node-version"] | ||||
|   dockerfile = "./hack/vendor.Dockerfile" | ||||
|   target = "update" | ||||
|   output = ["."] | ||||
| } | ||||
|  | ||||
| target "validate-yarn" { | ||||
| 	target = "validate-yarn" | ||||
| target "vendor-validate" { | ||||
|   inherits = ["node-version"] | ||||
|   dockerfile = "./hack/vendor.Dockerfile" | ||||
|   target = "validate" | ||||
| } | ||||
|  | ||||
| target "test" { | ||||
|   inherits = ["node-version"] | ||||
|   dockerfile = "./hack/test.Dockerfile" | ||||
|   target = "test-coverage" | ||||
|   output = ["./coverage"] | ||||
| } | ||||
							
								
								
									
										42
									
								
								hack/build.Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								hack/build.Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| # syntax=docker/dockerfile:1.2 | ||||
| ARG NODE_VERSION | ||||
|  | ||||
| FROM node:${NODE_VERSION}-alpine AS base | ||||
| RUN apk add --no-cache cpio findutils git | ||||
| WORKDIR /src | ||||
|  | ||||
| FROM base AS deps | ||||
| RUN --mount=type=bind,target=.,rw \ | ||||
|   --mount=type=cache,target=/src/node_modules \ | ||||
|   yarn install | ||||
|  | ||||
| FROM deps AS build | ||||
| RUN --mount=type=bind,target=.,rw \ | ||||
|   --mount=type=cache,target=/src/node_modules \ | ||||
|   yarn run build && mkdir /out && cp -Rf dist /out/ | ||||
|  | ||||
| FROM scratch AS build-update | ||||
| COPY --from=build /out / | ||||
|  | ||||
| FROM build AS build-validate | ||||
| RUN --mount=type=bind,target=.,rw \ | ||||
|   git add -A && cp -rf /out/* .; \ | ||||
|   if [ -n "$(git status --porcelain -- dist)" ]; then \ | ||||
|     echo >&2 'ERROR: Build result differs. Please build first with "docker buildx bake build"'; \ | ||||
|     git status --porcelain -- dist; \ | ||||
|     exit 1; \ | ||||
|   fi | ||||
|  | ||||
| FROM deps AS format | ||||
| RUN --mount=type=bind,target=.,rw \ | ||||
|   --mount=type=cache,target=/src/node_modules \ | ||||
|   yarn run format \ | ||||
|   && mkdir /out && find . -name '*.ts' -not -path './node_modules/*' | cpio -pdm /out | ||||
|  | ||||
| FROM scratch AS format-update | ||||
| COPY --from=format /out / | ||||
|  | ||||
| FROM deps AS format-validate | ||||
| RUN --mount=type=bind,target=.,rw \ | ||||
|   --mount=type=cache,target=/src/node_modules \ | ||||
|   yarn run format-check \ | ||||
| @@ -1,6 +0,0 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| iidfile=$(mktemp -t docker-iidfile.XXXXXXXXXX) | ||||
| DOCKER_BUILDKIT=1 docker build --iidfile $iidfile --progress=plain . | ||||
| docker run -it --rm $(cat $iidfile) | ||||
| docker rmi $(cat $iidfile) | ||||
							
								
								
									
										23
									
								
								hack/test.Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								hack/test.Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| # syntax=docker/dockerfile:1.2 | ||||
| ARG NODE_VERSION | ||||
|  | ||||
| FROM node:${NODE_VERSION}-alpine AS base | ||||
| RUN apk add --no-cache git | ||||
| WORKDIR /src | ||||
|  | ||||
| FROM base AS deps | ||||
| RUN --mount=type=bind,target=.,rw \ | ||||
|   --mount=type=cache,target=/src/node_modules \ | ||||
|   yarn install | ||||
|  | ||||
| FROM deps AS test | ||||
| ENV RUNNER_TEMP=/tmp/github_runner | ||||
| ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache | ||||
| RUN --mount=type=bind,target=.,rw \ | ||||
|   --mount=type=cache,target=/src/node_modules \ | ||||
|   --mount=type=bind,from=crazymax/docker,source=/usr/libexec/docker/cli-plugins/docker-buildx,target=/usr/libexec/docker/cli-plugins/docker-buildx \ | ||||
|   --mount=type=bind,from=crazymax/docker,source=/usr/local/bin/docker,target=/usr/bin/docker \ | ||||
|   yarn run test --coverageDirectory=/tmp/coverage | ||||
|  | ||||
| FROM scratch AS test-coverage | ||||
| COPY --from=test /tmp/coverage / | ||||
							
								
								
									
										23
									
								
								hack/vendor.Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								hack/vendor.Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| # syntax=docker/dockerfile:1.2 | ||||
| ARG NODE_VERSION | ||||
|  | ||||
| FROM node:${NODE_VERSION}-alpine AS base | ||||
| RUN apk add --no-cache git | ||||
| WORKDIR /src | ||||
|  | ||||
| FROM base AS vendored | ||||
| RUN --mount=type=bind,target=.,rw \ | ||||
|   --mount=type=cache,target=/src/node_modules \ | ||||
|   yarn install && mkdir /out && cp yarn.lock /out | ||||
|  | ||||
| FROM scratch AS update | ||||
| COPY --from=vendored /out / | ||||
|  | ||||
| FROM vendored AS validate | ||||
| RUN --mount=type=bind,target=.,rw \ | ||||
|   git add -A && cp -rf /out/* .; \ | ||||
|   if [ -n "$(git status --porcelain -- yarn.lock)" ]; then \ | ||||
|     echo >&2 'ERROR: Vendor result differs. Please vendor your package with "docker buildx bake vendor-update"'; \ | ||||
|     git status --porcelain -- yarn.lock; \ | ||||
|     exit 1; \ | ||||
|   fi | ||||
							
								
								
									
										31
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								package.json
									
									
									
									
									
								
							| @@ -27,23 +27,24 @@ | ||||
|   ], | ||||
|   "license": "Apache-2.0", | ||||
|   "dependencies": { | ||||
|     "@actions/core": "^1.2.6", | ||||
|     "@actions/exec": "^1.0.4", | ||||
|     "@actions/http-client": "^1.0.9", | ||||
|     "@actions/tool-cache": "^1.6.1", | ||||
|     "semver": "^7.3.2" | ||||
|     "@actions/core": "^1.4.0", | ||||
|     "@actions/exec": "^1.1.0", | ||||
|     "@actions/http-client": "^1.0.11", | ||||
|     "@actions/tool-cache": "^1.7.1", | ||||
|     "semver": "^7.3.5", | ||||
|     "uuid": "^8.3.2" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@types/jest": "^26.0.3", | ||||
|     "@types/node": "^14.0.14", | ||||
|     "@vercel/ncc": "^0.23.0", | ||||
|     "dotenv": "^8.2.0", | ||||
|     "jest": "^26.1.0", | ||||
|     "jest-circus": "^26.1.0", | ||||
|     "jest-runtime": "^26.1.0", | ||||
|     "prettier": "^2.0.5", | ||||
|     "ts-jest": "^26.1.1", | ||||
|     "typescript": "^3.9.5", | ||||
|     "@types/jest": "^26.0.23", | ||||
|     "@types/node": "^14.17.4", | ||||
|     "@vercel/ncc": "^0.28.6", | ||||
|     "dotenv": "^8.6.0", | ||||
|     "jest": "^26.6.3", | ||||
|     "jest-circus": "^26.6.3", | ||||
|     "jest-runtime": "^26.6.3", | ||||
|     "prettier": "^2.3.1", | ||||
|     "ts-jest": "^26.5.6", | ||||
|     "typescript": "^4.3.4", | ||||
|     "typescript-formatter": "^7.2.2" | ||||
|   } | ||||
| } | ||||
|   | ||||
							
								
								
									
										191
									
								
								src/buildx.ts
									
									
									
									
									
								
							
							
						
						
									
										191
									
								
								src/buildx.ts
									
									
									
									
									
								
							| @@ -3,65 +3,148 @@ import * as path from 'path'; | ||||
| import * as semver from 'semver'; | ||||
| import * as util from 'util'; | ||||
| import * as context from './context'; | ||||
| import * as exec from './exec'; | ||||
| import * as git from './git'; | ||||
| import * as github from './github'; | ||||
| import * as core from '@actions/core'; | ||||
| import * as exec from '@actions/exec'; | ||||
| import * as tc from '@actions/tool-cache'; | ||||
|  | ||||
| export async function getVersion(): Promise<string> { | ||||
|   return await exec.exec(`docker`, ['buildx', 'version'], true).then(res => { | ||||
|     if (res.stderr != '' && !res.success) { | ||||
|       throw new Error(res.stderr); | ||||
|     } | ||||
|     return parseVersion(res.stdout); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| export async function parseVersion(stdout: string): Promise<string> { | ||||
|   const matches = /\sv?([0-9.]+)/.exec(stdout); | ||||
|   if (!matches) { | ||||
|     throw new Error(`Cannot parse Buildx version`); | ||||
|   } | ||||
|   return semver.clean(matches[1]); | ||||
| } | ||||
| export type Builder = { | ||||
|   name?: string; | ||||
|   driver?: string; | ||||
|   node_name?: string; | ||||
|   node_endpoint?: string; | ||||
|   node_status?: string; | ||||
|   node_flags?: string; | ||||
|   node_platforms?: string; | ||||
| }; | ||||
|  | ||||
| export async function isAvailable(): Promise<Boolean> { | ||||
|   return await exec.exec(`docker`, ['buildx'], true).then(res => { | ||||
|     if (res.stderr != '' && !res.success) { | ||||
|   return await exec | ||||
|     .getExecOutput('docker', ['buildx'], { | ||||
|       ignoreReturnCode: true, | ||||
|       silent: true | ||||
|     }) | ||||
|     .then(res => { | ||||
|       if (res.stderr.length > 0 && res.exitCode != 0) { | ||||
|         return false; | ||||
|       } | ||||
|     return res.success; | ||||
|       return res.exitCode == 0; | ||||
|     }); | ||||
| } | ||||
|  | ||||
| export async function countBuilders(): Promise<number> { | ||||
|   return await exec.exec(`docker`, ['buildx', 'ls'], true).then(res => { | ||||
|     if (res.stderr != '' && !res.success) { | ||||
|       throw new Error(`Cannot list builders: ${res.stderr}`); | ||||
| export async function getVersion(): Promise<string> { | ||||
|   return await exec | ||||
|     .getExecOutput('docker', ['buildx', 'version'], { | ||||
|       ignoreReturnCode: true, | ||||
|       silent: true | ||||
|     }) | ||||
|     .then(res => { | ||||
|       if (res.stderr.length > 0 && res.exitCode != 0) { | ||||
|         throw new Error(res.stderr.trim()); | ||||
|       } | ||||
|     return (res.stdout.trim().split(`\n`).length - 1) / 2; | ||||
|       return parseVersion(res.stdout.trim()); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| export async function platforms(): Promise<String | undefined> { | ||||
|   return await exec.exec(`docker`, ['buildx', 'inspect'], true).then(res => { | ||||
|     if (res.stderr != '' && !res.success) { | ||||
|       throw new Error(res.stderr); | ||||
| export function parseVersion(stdout: string): string { | ||||
|   const matches = /\sv?([0-9a-f]{7}|[0-9.]+)/.exec(stdout); | ||||
|   if (!matches) { | ||||
|     throw new Error(`Cannot parse buildx version`); | ||||
|   } | ||||
|     for (const line of res.stdout.trim().split(`\n`)) { | ||||
|       if (line.startsWith('Platforms')) { | ||||
|         return line.replace('Platforms: ', '').replace(/\s/g, '').trim(); | ||||
|   return matches[1]; | ||||
| } | ||||
|  | ||||
| export function satisfies(version: string, range: string): boolean { | ||||
|   return semver.satisfies(version, range) || /^[0-9a-f]{7}$/.exec(version) !== null; | ||||
| } | ||||
|  | ||||
| export async function inspect(name: string): Promise<Builder> { | ||||
|   return await exec | ||||
|     .getExecOutput(`docker`, ['buildx', 'inspect', name], { | ||||
|       ignoreReturnCode: true, | ||||
|       silent: true | ||||
|     }) | ||||
|     .then(res => { | ||||
|       if (res.stderr.length > 0 && res.exitCode != 0) { | ||||
|         throw new Error(res.stderr.trim()); | ||||
|       } | ||||
|       const builder: Builder = {}; | ||||
|       itlines: for (const line of res.stdout.trim().split(`\n`)) { | ||||
|         const [key, ...rest] = line.split(':'); | ||||
|         const value = rest.map(v => v.trim()).join(':'); | ||||
|         if (key.length == 0 || value.length == 0) { | ||||
|           continue; | ||||
|         } | ||||
|         switch (key) { | ||||
|           case 'Name': { | ||||
|             if (builder.name == undefined) { | ||||
|               builder.name = value; | ||||
|             } else { | ||||
|               builder.node_name = value; | ||||
|             } | ||||
|             break; | ||||
|           } | ||||
|           case 'Driver': { | ||||
|             builder.driver = value; | ||||
|             break; | ||||
|           } | ||||
|           case 'Endpoint': { | ||||
|             builder.node_endpoint = value; | ||||
|             break; | ||||
|           } | ||||
|           case 'Status': { | ||||
|             builder.node_status = value; | ||||
|             break; | ||||
|           } | ||||
|           case 'Flags': { | ||||
|             builder.node_flags = value; | ||||
|             break; | ||||
|           } | ||||
|           case 'Platforms': { | ||||
|             builder.node_platforms = value.replace(/\s/g, ''); | ||||
|             break itlines; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|       return builder; | ||||
|     }); | ||||
| } | ||||
|  | ||||
| export async function build(inputBuildRef: string, dockerConfigHome: string): Promise<string> { | ||||
|   let [repo, ref] = inputBuildRef.split('#'); | ||||
|   if (ref.length == 0) { | ||||
|     ref = 'master'; | ||||
|   } | ||||
|  | ||||
|   const sha = await git.getRemoteSha(repo, ref); | ||||
|   core.debug(`Remote ref ${sha} found`); | ||||
|  | ||||
|   let toolPath: string; | ||||
|   toolPath = tc.find('buildx', sha); | ||||
|   if (!toolPath) { | ||||
|     const outFolder = path.join(context.tmpDir(), 'out').split(path.sep).join(path.posix.sep); | ||||
|     toolPath = await exec | ||||
|       .getExecOutput('docker', ['buildx', 'build', '--target', 'binaries', '--build-arg', 'BUILDKIT_CONTEXT_KEEP_GIT_DIR=1', '--output', `type=local,dest=${outFolder}`, inputBuildRef], { | ||||
|         ignoreReturnCode: true | ||||
|       }) | ||||
|       .then(res => { | ||||
|         if (res.stderr.length > 0 && res.exitCode != 0) { | ||||
|           core.warning(res.stderr.trim()); | ||||
|         } | ||||
|         return tc.cacheFile(`${outFolder}/buildx`, context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx', 'buildx', sha); | ||||
|       }); | ||||
|   } | ||||
|  | ||||
|   return setPlugin(toolPath, dockerConfigHome); | ||||
| } | ||||
|  | ||||
| export async function install(inputVersion: string, dockerConfigHome: string): Promise<string> { | ||||
|   const release: github.GitHubRelease | null = await github.getRelease(inputVersion); | ||||
|   if (!release) { | ||||
|     throw new Error(`Cannot find buildx ${inputVersion} release`); | ||||
|   } | ||||
|   core.debug(`Release found: ${release.tag_name}`); | ||||
|   core.debug(`Release ${release.tag_name} found`); | ||||
|   const version = release.tag_name.replace(/^v+|v+$/g, ''); | ||||
|  | ||||
|   let toolPath: string; | ||||
| @@ -74,6 +157,10 @@ export async function install(inputVersion: string, dockerConfigHome: string): P | ||||
|     toolPath = await download(version); | ||||
|   } | ||||
|  | ||||
|   return setPlugin(toolPath, dockerConfigHome); | ||||
| } | ||||
|  | ||||
| async function setPlugin(toolPath: string, dockerConfigHome: string): Promise<string> { | ||||
|   const pluginsDir: string = path.join(dockerConfigHome, 'cli-plugins'); | ||||
|   core.debug(`Plugins dir is ${pluginsDir}`); | ||||
|   if (!fs.existsSync(pluginsDir)) { | ||||
| @@ -85,7 +172,7 @@ export async function install(inputVersion: string, dockerConfigHome: string): P | ||||
|   core.debug(`Plugin path is ${pluginPath}`); | ||||
|   fs.copyFileSync(path.join(toolPath, filename), pluginPath); | ||||
|  | ||||
|   core.info('🔨 Fixing perms...'); | ||||
|   core.info('Fixing perms'); | ||||
|   fs.chmodSync(pluginPath, '0755'); | ||||
|  | ||||
|   return pluginPath; | ||||
| @@ -93,15 +180,11 @@ export async function install(inputVersion: string, dockerConfigHome: string): P | ||||
|  | ||||
| async function download(version: string): Promise<string> { | ||||
|   const targetFile: string = context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx'; | ||||
|   const downloadUrl = util.format( | ||||
|     'https://github.com/docker/buildx/releases/download/v%s/%s', | ||||
|     version, | ||||
|     await filename(version) | ||||
|   ); | ||||
|   const downloadUrl = util.format('https://github.com/docker/buildx/releases/download/v%s/%s', version, await filename(version)); | ||||
|   let downloadPath: string; | ||||
|  | ||||
|   try { | ||||
|     core.info(`⬇️ Downloading ${downloadUrl}...`); | ||||
|     core.info(`Downloading ${downloadUrl}`); | ||||
|     downloadPath = await tc.downloadTool(downloadUrl); | ||||
|     core.debug(`Downloaded to ${downloadPath}`); | ||||
|   } catch (error) { | ||||
| @@ -136,3 +219,31 @@ async function filename(version: string): Promise<string> { | ||||
|   const ext: string = context.osPlat == 'win32' ? '.exe' : ''; | ||||
|   return util.format('buildx-v%s.%s-%s%s', version, platform, arch, ext); | ||||
| } | ||||
|  | ||||
| export async function getBuildKitVersion(containerID: string): Promise<string> { | ||||
|   return exec | ||||
|     .getExecOutput(`docker`, ['inspect', '--format', '{{.Config.Image}}', containerID], { | ||||
|       ignoreReturnCode: true, | ||||
|       silent: true | ||||
|     }) | ||||
|     .then(bkitimage => { | ||||
|       if (bkitimage.exitCode == 0 && bkitimage.stdout.length > 0) { | ||||
|         return exec | ||||
|           .getExecOutput(`docker`, ['run', '--rm', bkitimage.stdout.trim(), '--version'], { | ||||
|             ignoreReturnCode: true, | ||||
|             silent: true | ||||
|           }) | ||||
|           .then(bkitversion => { | ||||
|             if (bkitversion.exitCode == 0 && bkitversion.stdout.length > 0) { | ||||
|               return `${bkitimage.stdout.trim()} => ${bkitversion.stdout.trim()}`; | ||||
|             } else if (bkitversion.stderr.length > 0) { | ||||
|               core.warning(bkitversion.stderr.trim()); | ||||
|             } | ||||
|             return bkitversion.stdout.trim(); | ||||
|           }); | ||||
|       } else if (bkitimage.stderr.length > 0) { | ||||
|         core.warning(bkitimage.stderr.trim()); | ||||
|       } | ||||
|       return bkitimage.stdout.trim(); | ||||
|     }); | ||||
| } | ||||
|   | ||||
| @@ -1,9 +1,20 @@ | ||||
| import fs from 'fs'; | ||||
| import * as os from 'os'; | ||||
| import path from 'path'; | ||||
| import * as core from '@actions/core'; | ||||
| import {issueCommand} from '@actions/core/lib/command'; | ||||
|  | ||||
| let _tmpDir: string; | ||||
| export const osPlat: string = os.platform(); | ||||
| export const osArch: string = os.arch(); | ||||
|  | ||||
| export function tmpDir(): string { | ||||
|   if (!_tmpDir) { | ||||
|     _tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-setup-buildx-')).split(path.sep).join(path.posix.sep); | ||||
|   } | ||||
|   return _tmpDir; | ||||
| } | ||||
|  | ||||
| export interface Inputs { | ||||
|   version: string; | ||||
|   driver: string; | ||||
| @@ -12,6 +23,7 @@ export interface Inputs { | ||||
|   install: boolean; | ||||
|   use: boolean; | ||||
|   endpoint: string; | ||||
|   config: string; | ||||
| } | ||||
|  | ||||
| export async function getInputs(): Promise<Inputs> { | ||||
| @@ -19,12 +31,11 @@ export async function getInputs(): Promise<Inputs> { | ||||
|     version: core.getInput('version'), | ||||
|     driver: core.getInput('driver') || 'docker-container', | ||||
|     driverOpts: await getInputList('driver-opts', true), | ||||
|     buildkitdFlags: | ||||
|       core.getInput('buildkitd-flags') || | ||||
|       '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host', | ||||
|     install: /true/i.test(core.getInput('install')), | ||||
|     use: /true/i.test(core.getInput('use')), | ||||
|     endpoint: core.getInput('endpoint') | ||||
|     buildkitdFlags: core.getInput('buildkitd-flags') || '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host', | ||||
|     install: core.getBooleanInput('install'), | ||||
|     use: core.getBooleanInput('use'), | ||||
|     endpoint: core.getInput('endpoint'), | ||||
|     config: core.getInput('config') | ||||
|   }; | ||||
| } | ||||
|  | ||||
| @@ -36,10 +47,7 @@ export async function getInputList(name: string, ignoreComma?: boolean): Promise | ||||
|   return items | ||||
|     .split(/\r?\n/) | ||||
|     .filter(x => x) | ||||
|     .reduce<string[]>( | ||||
|       (acc, line) => acc.concat(!ignoreComma ? line.split(',').filter(x => x) : line).map(pat => pat.trim()), | ||||
|       [] | ||||
|     ); | ||||
|     .reduce<string[]>((acc, line) => acc.concat(!ignoreComma ? line.split(',').filter(x => x) : line).map(pat => pat.trim()), []); | ||||
| } | ||||
|  | ||||
| export const asyncForEach = async (array, callback) => { | ||||
| @@ -47,3 +55,8 @@ export const asyncForEach = async (array, callback) => { | ||||
|     await callback(array[index], index, array); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| // FIXME: Temp fix https://github.com/actions/toolkit/issues/777 | ||||
| export function setOutput(name: string, value: any): void { | ||||
|   issueCommand('set-output', {name}, value); | ||||
| } | ||||
|   | ||||
| @@ -1,7 +0,0 @@ | ||||
| import * as exec from './exec'; | ||||
|  | ||||
| export async function isDaemonRunning(): Promise<boolean> { | ||||
|   return await exec.exec(`docker`, ['version', '--format', '{{.Server.Os}}'], true).then(res => { | ||||
|     return !res.stdout.includes(' ') && res.success; | ||||
|   }); | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/exec.ts
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								src/exec.ts
									
									
									
									
									
								
							| @@ -1,34 +0,0 @@ | ||||
| import * as aexec from '@actions/exec'; | ||||
| import {ExecOptions} from '@actions/exec'; | ||||
|  | ||||
| export interface ExecResult { | ||||
|   success: boolean; | ||||
|   stdout: string; | ||||
|   stderr: string; | ||||
| } | ||||
|  | ||||
| export const exec = async (command: string, args: string[] = [], silent: boolean): Promise<ExecResult> => { | ||||
|   let stdout: string = ''; | ||||
|   let stderr: string = ''; | ||||
|  | ||||
|   const options: ExecOptions = { | ||||
|     silent: silent, | ||||
|     ignoreReturnCode: true | ||||
|   }; | ||||
|   options.listeners = { | ||||
|     stdout: (data: Buffer) => { | ||||
|       stdout += data.toString(); | ||||
|     }, | ||||
|     stderr: (data: Buffer) => { | ||||
|       stderr += data.toString(); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   const returnCode: number = await aexec.exec(command, args, options); | ||||
|  | ||||
|   return { | ||||
|     success: returnCode === 0, | ||||
|     stdout: stdout.trim(), | ||||
|     stderr: stderr.trim() | ||||
|   }; | ||||
| }; | ||||
							
								
								
									
										19
									
								
								src/git.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/git.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| import * as exec from '@actions/exec'; | ||||
|  | ||||
| export async function getRemoteSha(repo: string, ref: string): Promise<string> { | ||||
|   return await exec | ||||
|     .getExecOutput(`git`, ['ls-remote', repo, ref], { | ||||
|       ignoreReturnCode: true, | ||||
|       silent: true | ||||
|     }) | ||||
|     .then(res => { | ||||
|       if (res.stderr.length > 0 && res.exitCode != 0) { | ||||
|         throw new Error(res.stderr); | ||||
|       } | ||||
|       const [rsha, rref] = res.stdout.trim().split(/[\s\t]/); | ||||
|       if (rsha.length == 0) { | ||||
|         throw new Error(`Cannot find remote ref for ${repo}#${ref}`); | ||||
|       } | ||||
|       return rsha; | ||||
|     }); | ||||
| } | ||||
							
								
								
									
										108
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								src/main.ts
									
									
									
									
									
								
							| @@ -1,52 +1,44 @@ | ||||
| import * as core from '@actions/core'; | ||||
| import * as exec from '@actions/exec'; | ||||
| import * as os from 'os'; | ||||
| import * as path from 'path'; | ||||
| import * as semver from 'semver'; | ||||
| import * as buildx from './buildx'; | ||||
| import * as context from './context'; | ||||
| import * as mexec from './exec'; | ||||
| import * as stateHelper from './state-helper'; | ||||
| import * as util from './util'; | ||||
| import * as core from '@actions/core'; | ||||
| import * as exec from '@actions/exec'; | ||||
|  | ||||
| async function run(): Promise<void> { | ||||
|   try { | ||||
|     if (os.platform() !== 'linux') { | ||||
|       core.setFailed('Only supported on linux platform'); | ||||
|       return; | ||||
|     } | ||||
|     core.startGroup(`Docker info`); | ||||
|     await exec.exec('docker', ['version']); | ||||
|     await exec.exec('docker', ['info']); | ||||
|     core.endGroup(); | ||||
|  | ||||
|     const inputs: context.Inputs = await context.getInputs(); | ||||
|     const dockerConfigHome: string = process.env.DOCKER_CONFIG || path.join(os.homedir(), '.docker'); | ||||
|  | ||||
|     if (!(await buildx.isAvailable()) || inputs.version) { | ||||
|       core.startGroup(`👉 Installing Buildx`); | ||||
|     if (util.isValidUrl(inputs.version)) { | ||||
|       core.startGroup(`Build and install buildx`); | ||||
|       await buildx.build(inputs.version, dockerConfigHome); | ||||
|       core.endGroup(); | ||||
|     } else if (!(await buildx.isAvailable()) || inputs.version) { | ||||
|       core.startGroup(`Download and install buildx`); | ||||
|       await buildx.install(inputs.version || 'latest', dockerConfigHome); | ||||
|       core.endGroup(); | ||||
|     } | ||||
|  | ||||
|     const buildxVersion = await buildx.getVersion(); | ||||
|     core.info(`📣 Buildx version: ${buildxVersion}`); | ||||
|  | ||||
|     const builderName: string = | ||||
|       inputs.driver == 'docker' ? 'default' : `builder-${process.env.GITHUB_JOB}-${(await buildx.countBuilders()) + 1}`; | ||||
|     core.setOutput('name', builderName); | ||||
|     const builderName: string = inputs.driver == 'docker' ? 'default' : `builder-${require('uuid').v4()}`; | ||||
|     context.setOutput('name', builderName); | ||||
|     stateHelper.setBuilderName(builderName); | ||||
|  | ||||
|     if (inputs.driver !== 'docker') { | ||||
|       core.startGroup(`🔨 Creating a new builder instance`); | ||||
|       core.startGroup(`Creating a new builder instance`); | ||||
|       let createArgs: Array<string> = ['buildx', 'create', '--name', builderName, '--driver', inputs.driver]; | ||||
|       if (semver.satisfies(buildxVersion, '>=0.3.0')) { | ||||
|         let hasImageDriverOpt: boolean = false; | ||||
|       if (buildx.satisfies(buildxVersion, '>=0.3.0')) { | ||||
|         await context.asyncForEach(inputs.driverOpts, async driverOpt => { | ||||
|           if (driverOpt.startsWith('image=')) { | ||||
|             hasImageDriverOpt = true; | ||||
|           } | ||||
|           createArgs.push('--driver-opt', driverOpt); | ||||
|         }); | ||||
|         if (!hasImageDriverOpt) { | ||||
|           //FIXME: Temporary fix (docker/build-push-action#154, docker/build-push-action#162) | ||||
|           createArgs.push('--driver-opt', 'image=moby/buildkit:v0.8-beta'); | ||||
|         } | ||||
|         if (inputs.buildkitdFlags) { | ||||
|           createArgs.push('--buildkitd-flags', inputs.buildkitdFlags); | ||||
|         } | ||||
| @@ -57,39 +49,79 @@ async function run(): Promise<void> { | ||||
|       if (inputs.endpoint) { | ||||
|         createArgs.push(inputs.endpoint); | ||||
|       } | ||||
|       if (inputs.config) { | ||||
|         createArgs.push('--config', inputs.config); | ||||
|       } | ||||
|       await exec.exec('docker', createArgs); | ||||
|       core.endGroup(); | ||||
|  | ||||
|       core.startGroup(`🏃 Booting builder`); | ||||
|       await exec.exec('docker', ['buildx', 'inspect', '--bootstrap']); | ||||
|       core.startGroup(`Booting builder`); | ||||
|       let bootstrapArgs: Array<string> = ['buildx', 'inspect', '--bootstrap']; | ||||
|       if (buildx.satisfies(buildxVersion, '>=0.4.0')) { | ||||
|         bootstrapArgs.push('--builder', builderName); | ||||
|       } | ||||
|       await exec.exec('docker', bootstrapArgs); | ||||
|       core.endGroup(); | ||||
|     } | ||||
|  | ||||
|     if (inputs.install) { | ||||
|       core.startGroup(`🤝 Setting buildx as default builder`); | ||||
|       core.startGroup(`Setting buildx as default builder`); | ||||
|       await exec.exec('docker', ['buildx', 'install']); | ||||
|       core.endGroup(); | ||||
|     } | ||||
|  | ||||
|     core.startGroup(`🛒 Extracting available platforms`); | ||||
|     const platforms = await buildx.platforms(); | ||||
|     core.info(`${platforms}`); | ||||
|     core.setOutput('platforms', platforms); | ||||
|     core.startGroup(`Inspect builder`); | ||||
|     const builder = await buildx.inspect(builderName); | ||||
|     core.info(JSON.stringify(builder, undefined, 2)); | ||||
|     context.setOutput('driver', builder.driver); | ||||
|     context.setOutput('endpoint', builder.node_endpoint); | ||||
|     context.setOutput('status', builder.node_status); | ||||
|     context.setOutput('flags', builder.node_flags); | ||||
|     context.setOutput('platforms', builder.node_platforms); | ||||
|     core.endGroup(); | ||||
|  | ||||
|     if (inputs.driver == 'docker-container') { | ||||
|       stateHelper.setContainerName(`buildx_buildkit_${builder.node_name}`); | ||||
|       core.startGroup(`BuildKit version`); | ||||
|       core.info(await buildx.getBuildKitVersion(`buildx_buildkit_${builder.node_name}`)); | ||||
|       core.endGroup(); | ||||
|     } | ||||
|     if (core.isDebug() || builder.node_flags?.includes('--debug')) { | ||||
|       stateHelper.setDebug('true'); | ||||
|     } | ||||
|   } catch (error) { | ||||
|     core.setFailed(error.message); | ||||
|   } | ||||
| } | ||||
|  | ||||
| async function cleanup(): Promise<void> { | ||||
|   if (stateHelper.builderName.length == 0) { | ||||
|     return; | ||||
|   } | ||||
|   await mexec.exec('docker', ['buildx', 'rm', `${stateHelper.builderName}`], false).then(res => { | ||||
|     if (res.stderr != '' && !res.success) { | ||||
|       core.warning(res.stderr); | ||||
|   if (stateHelper.IsDebug && stateHelper.containerName.length > 0) { | ||||
|     core.startGroup(`BuildKit container logs`); | ||||
|     await exec | ||||
|       .getExecOutput('docker', ['logs', `${stateHelper.containerName}`], { | ||||
|         ignoreReturnCode: true | ||||
|       }) | ||||
|       .then(res => { | ||||
|         if (res.stderr.length > 0 && res.exitCode != 0) { | ||||
|           core.warning(res.stderr.trim()); | ||||
|         } | ||||
|       }); | ||||
|     core.endGroup(); | ||||
|   } | ||||
|  | ||||
|   if (stateHelper.builderName.length > 0) { | ||||
|     core.startGroup(`Removing builder`); | ||||
|     await exec | ||||
|       .getExecOutput('docker', ['buildx', 'rm', `${stateHelper.builderName}`], { | ||||
|         ignoreReturnCode: true | ||||
|       }) | ||||
|       .then(res => { | ||||
|         if (res.stderr.length > 0 && res.exitCode != 0) { | ||||
|           core.warning(res.stderr.trim()); | ||||
|         } | ||||
|       }); | ||||
|     core.endGroup(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| if (!stateHelper.IsPost) { | ||||
|   | ||||
| @@ -1,12 +1,22 @@ | ||||
| import * as core from '@actions/core'; | ||||
|  | ||||
| export const IsPost = !!process.env['STATE_isPost']; | ||||
| export const IsDebug = !!process.env['STATE_isDebug']; | ||||
| export const builderName = process.env['STATE_builderName'] || ''; | ||||
| export const containerName = process.env['STATE_containerName'] || ''; | ||||
|  | ||||
| export function setDebug(debug: string) { | ||||
|   core.saveState('isDebug', debug); | ||||
| } | ||||
|  | ||||
| export function setBuilderName(builderName: string) { | ||||
|   core.saveState('builderName', builderName); | ||||
| } | ||||
|  | ||||
| export function setContainerName(containerName: string) { | ||||
|   core.saveState('containerName', containerName); | ||||
| } | ||||
|  | ||||
| if (!IsPost) { | ||||
|   core.saveState('isPost', 'true'); | ||||
| } | ||||
|   | ||||
							
								
								
									
										8
									
								
								src/util.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/util.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| export function isValidUrl(url: string): boolean { | ||||
|   try { | ||||
|     new URL(url); | ||||
|   } catch (e) { | ||||
|     return false; | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user