mirror of
				https://github.com/docker/setup-buildx-action.git
				synced 2025-10-31 01:20:09 +08:00 
			
		
		
		
	
						commit
						7117987c01
					
				
							
								
								
									
										140
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										140
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @ -30,21 +30,9 @@ jobs: | ||||
|         uses: actions/checkout@v3 | ||||
|       - | ||||
|         name: Set up Docker Buildx | ||||
|         id: buildx | ||||
|         uses: ./ | ||||
|         with: | ||||
|           version: ${{ matrix.buildx-version }} | ||||
|       - | ||||
|         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 | ||||
| 
 | ||||
|   multi: | ||||
|     runs-on: ubuntu-latest | ||||
| @ -54,28 +42,10 @@ jobs: | ||||
|         uses: actions/checkout@v3 | ||||
|       - | ||||
|         name: Set up Docker Buildx 1 | ||||
|         id: buildx1 | ||||
|         uses: ./ | ||||
|       - | ||||
|         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: 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 | ||||
| @ -328,18 +298,9 @@ jobs: | ||||
|           platforms: ${{ matrix.qemu-platforms }} | ||||
|       - | ||||
|         name: Set up Docker Buildx | ||||
|         id: buildx | ||||
|         uses: ./ | ||||
|         with: | ||||
|           version: ${{ matrix.buildx-version }} | ||||
|       - | ||||
|         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 | ||||
| @ -360,10 +321,6 @@ jobs: | ||||
|         uses: ./ | ||||
|         with: | ||||
|           version: https://github.com/docker/buildx.git#${{ matrix.ref }} | ||||
|       - | ||||
|         name: Check version | ||||
|         run: | | ||||
|           docker buildx version | ||||
|       - | ||||
|         name: Create Dockerfile | ||||
|         run: | | ||||
| @ -375,3 +332,100 @@ jobs: | ||||
|         uses: docker/build-push-action@master | ||||
|         with: | ||||
|           context: . | ||||
| 
 | ||||
|   standalone: | ||||
|     runs-on: ubuntu-latest | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|       matrix: | ||||
|         buildx-version: | ||||
|           - latest | ||||
|           - "" | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v3 | ||||
|       - | ||||
|         name: Uninstall docker cli | ||||
|         run: | | ||||
|           sudo apt-get purge -y moby-cli moby-buildx | ||||
|       - | ||||
|         name: Set up Docker Buildx | ||||
|         uses: ./ | ||||
|         with: | ||||
|           version: ${{ matrix.buildx-version }} | ||||
|       - | ||||
|         name: Check available in path | ||||
|         if: matrix.standalone | ||||
|         run: | | ||||
|           buildx version | ||||
| 
 | ||||
|   standalone-install-error: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v3 | ||||
|       - | ||||
|         name: Uninstall docker cli | ||||
|         run: | | ||||
|           sudo apt-get purge -y moby-cli moby-buildx | ||||
|       - | ||||
|         name: Set up Docker Buildx | ||||
|         id: buildx | ||||
|         continue-on-error: true | ||||
|         uses: ./ | ||||
|         with: | ||||
|           install: true | ||||
|       - | ||||
|         name: Check | ||||
|         run: | | ||||
|           echo "${{ toJson(steps.buildx) }}" | ||||
|           if [ "${{ steps.buildx.outcome }}" != "failure" ] || [ "${{ steps.buildx.conclusion }}" != "success" ]; then | ||||
|             echo "::error::Should have failed" | ||||
|             exit 1 | ||||
|           fi | ||||
| 
 | ||||
|   standalone-kubernetes: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v3 | ||||
|       - | ||||
|         name: Uninstall moby | ||||
|         run: | | ||||
|           sudo apt-get purge -y moby-engine moby-cli moby-buildx | ||||
|       - | ||||
|         name: Setup k8s cluster | ||||
|         run: | | ||||
|           set -x | ||||
|           sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg | ||||
|           echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list | ||||
|           sudo apt-get update | ||||
|           sudo apt-get install -y kubelet kubeadm kubectl | ||||
|           sudo swapoff -a | ||||
|           sudo kubeadm init --cri-socket /run/containerd/containerd.sock | ||||
|           mkdir -p $HOME/.kube/ | ||||
|           sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config | ||||
|           sudo chown $USER $HOME/.kube/config | ||||
|           kubectl taint nodes --all node-role.kubernetes.io/master- | ||||
|           kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml | ||||
|           kubectl wait --for=condition=ready --timeout=30s node --all | ||||
|           kubectl get nodes -o wide | ||||
|       - | ||||
|         name: Create Dockerfile | ||||
|         run: | | ||||
|           cat > ./Dockerfile <<EOL | ||||
|           FROM alpine | ||||
|           RUN echo hello | ||||
|           EOL | ||||
|       - | ||||
|         name: Set up Docker Buildx | ||||
|         uses: ./ | ||||
|         with: | ||||
|           driver: kubernetes | ||||
|       - | ||||
|         name: Build | ||||
|         run: | | ||||
|           buildx build . | ||||
|  | ||||
							
								
								
									
										34
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								README.md
									
									
									
									
									
								
							| @ -24,6 +24,7 @@ ___ | ||||
|   * [BuildKit daemon configuration](#buildkit-daemon-configuration) | ||||
|     * [Registry mirror](#registry-mirror) | ||||
|     * [Max parallelism](#max-parallelism) | ||||
|   * [Standalone mode](#standalone-mode) | ||||
| * [Customizing](#customizing) | ||||
|   * [inputs](#inputs) | ||||
|   * [outputs](#outputs) | ||||
| @ -180,6 +181,33 @@ jobs: | ||||
|           config: .github/buildkitd.toml | ||||
| ``` | ||||
| 
 | ||||
| ### Standalone mode | ||||
| 
 | ||||
| If you don't have the Docker CLI installed on the GitHub Runner, buildx binary | ||||
| is invoked directly, instead of calling it as a docker plugin. This can be | ||||
| useful if you want to use the `kubernetes` driver in your self-hosted runner: | ||||
| 
 | ||||
| ```yaml | ||||
| name: ci | ||||
| 
 | ||||
| on: | ||||
|   push: | ||||
| 
 | ||||
| jobs: | ||||
|   buildx: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - | ||||
|         name: Set up Docker Buildx | ||||
|         uses: docker/setup-buildx-action@v1 | ||||
|         with: | ||||
|           driver: kubernetes | ||||
|       - | ||||
|         name: Build | ||||
|         run: | | ||||
|           buildx build . | ||||
| ``` | ||||
| 
 | ||||
| ## Customizing | ||||
| 
 | ||||
| ### inputs | ||||
| @ -195,10 +223,10 @@ Following inputs can be used as `step.with` keys | ||||
| | `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/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) | | ||||
| | `config-inline`    | String  | Same as `config` but inline | | ||||
| | `config`¹          | String  | [BuildKit config file](https://github.com/docker/buildx/blob/master/docs/reference/buildx_create.md#config) | | ||||
| | `config-inline`¹   | String  | Same as `config` but inline | | ||||
| 
 | ||||
| > `config` and `config-inline` are mutually exclusive. | ||||
| > * ¹ `config` and `config-inline` are mutually exclusive | ||||
| 
 | ||||
| > `CSV` type must be a newline-delimited string | ||||
| > ```yaml | ||||
|  | ||||
| @ -32,6 +32,17 @@ describe('isAvailable', () => { | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| describe('isAvailable standalone', () => { | ||||
|   const execSpy = jest.spyOn(exec, 'getExecOutput'); | ||||
|   buildx.isAvailable(true); | ||||
| 
 | ||||
|   // eslint-disable-next-line jest/no-standalone-expect
 | ||||
|   expect(execSpy).toHaveBeenCalledWith(`buildx`, [], { | ||||
|     silent: true, | ||||
|     ignoreReturnCode: true | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| describe('getVersion', () => { | ||||
|   it('valid', async () => { | ||||
|     const version = await buildx.getVersion(); | ||||
| @ -75,29 +86,32 @@ describe('build', () => { | ||||
| 
 | ||||
|   // eslint-disable-next-line jest/no-disabled-tests
 | ||||
|   it.skip('builds refs/pull/648/head', async () => { | ||||
|     const buildxBin = await buildx.build('https://github.com/docker/buildx.git#refs/pull/648/head', tmpDir); | ||||
|     const buildxBin = await buildx.build('https://github.com/docker/buildx.git#refs/pull/648/head', tmpDir, false); | ||||
|     expect(fs.existsSync(buildxBin)).toBe(true); | ||||
|   }, 100000); | ||||
| 
 | ||||
|   // eslint-disable-next-line jest/no-disabled-tests
 | ||||
|   it.skip('builds 67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', async () => { | ||||
|     const buildxBin = await buildx.build('https://github.com/docker/buildx.git#67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', tmpDir); | ||||
|     const buildxBin = await buildx.build('https://github.com/docker/buildx.git#67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', tmpDir, false); | ||||
|     expect(fs.existsSync(buildxBin)).toBe(true); | ||||
|   }, 100000); | ||||
| }); | ||||
| 
 | ||||
| describe('install', () => { | ||||
|   const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-buildx-')); | ||||
| 
 | ||||
|   it('acquires v0.4.1 version of buildx', async () => { | ||||
|     const buildxBin = await buildx.install('v0.4.1', tmpDir); | ||||
|     expect(fs.existsSync(buildxBin)).toBe(true); | ||||
|   }, 100000); | ||||
| 
 | ||||
|   it('acquires latest version of buildx', async () => { | ||||
|     const buildxBin = await buildx.install('latest', tmpDir); | ||||
|     expect(fs.existsSync(buildxBin)).toBe(true); | ||||
|   }, 100000); | ||||
|   test.each([ | ||||
|     ['v0.4.1', false], | ||||
|     ['latest', false], | ||||
|     ['v0.4.1', true], | ||||
|     ['latest', true] | ||||
|   ])( | ||||
|     'acquires %p of buildx (standalone: %p)', | ||||
|     async (version, standalone) => { | ||||
|       const buildxBin = await buildx.install(version, tmpDir, standalone); | ||||
|       expect(fs.existsSync(buildxBin)).toBe(true); | ||||
|     }, | ||||
|     100000 | ||||
|   ); | ||||
| }); | ||||
| 
 | ||||
| describe('getConfig', () => { | ||||
|  | ||||
							
								
								
									
										16
									
								
								__tests__/docker.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								__tests__/docker.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| import {describe, expect, it, jest} from '@jest/globals'; | ||||
| import * as docker from '../src/docker'; | ||||
| import * as exec from '@actions/exec'; | ||||
| 
 | ||||
| describe('isAvailable', () => { | ||||
|   it('cli', () => { | ||||
|     const execSpy = jest.spyOn(exec, 'getExecOutput'); | ||||
|     docker.isAvailable(); | ||||
| 
 | ||||
|     // eslint-disable-next-line jest/no-standalone-expect
 | ||||
|     expect(execSpy).toHaveBeenCalledWith(`docker`, undefined, { | ||||
|       silent: true, | ||||
|       ignoreReturnCode: true | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										4
									
								
								dist/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								dist/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/index.js.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/index.js.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -41,9 +41,10 @@ export async function getConfig(s: string, file: boolean): Promise<string> { | ||||
|   return configFile; | ||||
| } | ||||
| 
 | ||||
| export async function isAvailable(): Promise<boolean> { | ||||
| export async function isAvailable(standalone?: boolean): Promise<boolean> { | ||||
|   const cmd = getCommand([], standalone); | ||||
|   return await exec | ||||
|     .getExecOutput('docker', ['buildx'], { | ||||
|     .getExecOutput(cmd.commandLine, cmd.args, { | ||||
|       ignoreReturnCode: true, | ||||
|       silent: true | ||||
|     }) | ||||
| @ -52,12 +53,17 @@ export async function isAvailable(): Promise<boolean> { | ||||
|         return false; | ||||
|       } | ||||
|       return res.exitCode == 0; | ||||
|     }) | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     .catch(error => { | ||||
|       return false; | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| export async function getVersion(): Promise<string> { | ||||
| export async function getVersion(standalone?: boolean): Promise<string> { | ||||
|   const cmd = getCommand(['version'], standalone); | ||||
|   return await exec | ||||
|     .getExecOutput('docker', ['buildx', 'version'], { | ||||
|     .getExecOutput(cmd.commandLine, cmd.args, { | ||||
|       ignoreReturnCode: true, | ||||
|       silent: true | ||||
|     }) | ||||
| @ -81,9 +87,10 @@ 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> { | ||||
| export async function inspect(name: string, standalone?: boolean): Promise<Builder> { | ||||
|   const cmd = getCommand(['inspect', name], standalone); | ||||
|   return await exec | ||||
|     .getExecOutput(`docker`, ['buildx', 'inspect', name], { | ||||
|     .getExecOutput(cmd.commandLine, cmd.args, { | ||||
|       ignoreReturnCode: true, | ||||
|       silent: true | ||||
|     }) | ||||
| @ -133,7 +140,7 @@ export async function inspect(name: string): Promise<Builder> { | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| export async function build(inputBuildRef: string, dockerConfigHome: string): Promise<string> { | ||||
| export async function build(inputBuildRef: string, dest: string, standalone: boolean): Promise<string> { | ||||
|   // eslint-disable-next-line prefer-const
 | ||||
|   let [repo, ref] = inputBuildRef.split('#'); | ||||
|   if (ref.length == 0) { | ||||
| @ -152,8 +159,27 @@ export async function build(inputBuildRef: string, dockerConfigHome: string): Pr | ||||
|   toolPath = tc.find('buildx', vspec); | ||||
|   if (!toolPath) { | ||||
|     const outFolder = path.join(context.tmpDir(), 'out').split(path.sep).join(path.posix.sep); | ||||
|     let buildWithStandalone = false; | ||||
|     const standaloneFound = await isAvailable(true); | ||||
|     const pluginFound = await isAvailable(false); | ||||
|     if (standalone && standaloneFound) { | ||||
|       core.debug(`Buildx standalone found, build with it`); | ||||
|       buildWithStandalone = true; | ||||
|     } else if (!standalone && pluginFound) { | ||||
|       core.debug(`Buildx plugin found, build with it`); | ||||
|       buildWithStandalone = false; | ||||
|     } else if (standaloneFound) { | ||||
|       core.debug(`Buildx plugin not found, but standalone found so trying to build with it`); | ||||
|       buildWithStandalone = true; | ||||
|     } else if (pluginFound) { | ||||
|       core.debug(`Buildx standalone not found, but plugin found so trying to build with it`); | ||||
|       buildWithStandalone = false; | ||||
|     } else { | ||||
|       throw new Error(`Neither buildx standalone or plugin have been found to build from ref`); | ||||
|     } | ||||
|     const buildCmd = getCommand(['build', '--target', 'binaries', '--build-arg', 'BUILDKIT_CONTEXT_KEEP_GIT_DIR=1', '--output', `type=local,dest=${outFolder}`, inputBuildRef], buildWithStandalone); | ||||
|     toolPath = await exec | ||||
|       .getExecOutput('docker', ['buildx', 'build', '--target', 'binaries', '--build-arg', 'BUILDKIT_CONTEXT_KEEP_GIT_DIR=1', '--output', `type=local,dest=${outFolder}`, inputBuildRef], { | ||||
|       .getExecOutput(buildCmd.commandLine, buildCmd.args, { | ||||
|         ignoreReturnCode: true | ||||
|       }) | ||||
|       .then(res => { | ||||
| @ -164,10 +190,13 @@ export async function build(inputBuildRef: string, dockerConfigHome: string): Pr | ||||
|       }); | ||||
|   } | ||||
| 
 | ||||
|   return setPlugin(toolPath, dockerConfigHome); | ||||
|   if (standalone) { | ||||
|     return setStandalone(toolPath, dest); | ||||
|   } | ||||
|   return setPlugin(toolPath, dest); | ||||
| } | ||||
| 
 | ||||
| export async function install(inputVersion: string, dockerConfigHome: string): Promise<string> { | ||||
| export async function install(inputVersion: string, dest: string, standalone: boolean): Promise<string> { | ||||
|   const release: github.GitHubRelease | null = await github.getRelease(inputVersion); | ||||
|   if (!release) { | ||||
|     throw new Error(`Cannot find buildx ${inputVersion} release`); | ||||
| @ -185,10 +214,40 @@ export async function install(inputVersion: string, dockerConfigHome: string): P | ||||
|     toolPath = await download(version); | ||||
|   } | ||||
| 
 | ||||
|   return setPlugin(toolPath, dockerConfigHome); | ||||
|   if (standalone) { | ||||
|     return setStandalone(toolPath, dest); | ||||
|   } | ||||
|   return setPlugin(toolPath, dest); | ||||
| } | ||||
| 
 | ||||
| async function setStandalone(toolPath: string, dest: string): Promise<string> { | ||||
|   core.info('Standalone mode'); | ||||
|   const toolBinPath = path.join(toolPath, context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx'); | ||||
| 
 | ||||
|   const binDir = path.join(dest, 'bin'); | ||||
|   core.debug(`Bin dir is ${binDir}`); | ||||
|   if (!fs.existsSync(binDir)) { | ||||
|     fs.mkdirSync(binDir, {recursive: true}); | ||||
|   } | ||||
| 
 | ||||
|   const filename: string = context.osPlat == 'win32' ? 'buildx.exe' : 'buildx'; | ||||
|   const buildxPath: string = path.join(binDir, filename); | ||||
|   core.debug(`Bin path is ${buildxPath}`); | ||||
|   fs.copyFileSync(toolBinPath, buildxPath); | ||||
| 
 | ||||
|   core.info('Fixing perms'); | ||||
|   fs.chmodSync(buildxPath, '0755'); | ||||
| 
 | ||||
|   core.addPath(binDir); | ||||
|   core.info('Added buildx to the path'); | ||||
| 
 | ||||
|   return buildxPath; | ||||
| } | ||||
| 
 | ||||
| async function setPlugin(toolPath: string, dockerConfigHome: string): Promise<string> { | ||||
|   core.info('Docker plugin mode'); | ||||
|   const toolBinPath = path.join(toolPath, context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx'); | ||||
| 
 | ||||
|   const pluginsDir: string = path.join(dockerConfigHome, 'cli-plugins'); | ||||
|   core.debug(`Plugins dir is ${pluginsDir}`); | ||||
|   if (!fs.existsSync(pluginsDir)) { | ||||
| @ -198,7 +257,7 @@ async function setPlugin(toolPath: string, dockerConfigHome: string): Promise<st | ||||
|   const filename: string = context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx'; | ||||
|   const pluginPath: string = path.join(pluginsDir, filename); | ||||
|   core.debug(`Plugin path is ${pluginPath}`); | ||||
|   fs.copyFileSync(path.join(toolPath, filename), pluginPath); | ||||
|   fs.copyFileSync(toolBinPath, pluginPath); | ||||
| 
 | ||||
|   core.info('Fixing perms'); | ||||
|   fs.chmodSync(pluginPath, '0755'); | ||||
| @ -269,3 +328,10 @@ export async function getBuildKitVersion(containerID: string): Promise<string> { | ||||
|       return bkitimage.stdout.trim(); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| export function getCommand(args: Array<string>, standalone?: boolean) { | ||||
|   return { | ||||
|     commandLine: standalone ? 'buildx' : 'docker', | ||||
|     args: standalone ? args : ['buildx', ...args] | ||||
|   }; | ||||
| } | ||||
|  | ||||
							
								
								
									
										19
									
								
								src/docker.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/docker.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| import * as exec from '@actions/exec'; | ||||
| 
 | ||||
| export async function isAvailable(): Promise<boolean> { | ||||
|   return await exec | ||||
|     .getExecOutput('docker', undefined, { | ||||
|       ignoreReturnCode: true, | ||||
|       silent: true | ||||
|     }) | ||||
|     .then(res => { | ||||
|       if (res.stderr.length > 0 && res.exitCode != 0) { | ||||
|         return false; | ||||
|       } | ||||
|       return res.exitCode == 0; | ||||
|     }) | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     .catch(error => { | ||||
|       return false; | ||||
|     }); | ||||
| } | ||||
							
								
								
									
										61
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								src/main.ts
									
									
									
									
									
								
							| @ -3,6 +3,7 @@ import * as path from 'path'; | ||||
| import * as uuid from 'uuid'; | ||||
| import * as buildx from './buildx'; | ||||
| import * as context from './context'; | ||||
| import * as docker from './docker'; | ||||
| import * as stateHelper from './state-helper'; | ||||
| import * as util from './util'; | ||||
| import * as core from '@actions/core'; | ||||
| @ -10,32 +11,54 @@ import * as exec from '@actions/exec'; | ||||
| 
 | ||||
| async function run(): Promise<void> { | ||||
|   try { | ||||
|     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'); | ||||
| 
 | ||||
|     // standalone if docker cli not available
 | ||||
|     const standalone = !(await docker.isAvailable()); | ||||
|     stateHelper.setStandalone(standalone); | ||||
| 
 | ||||
|     core.startGroup(`Docker info`); | ||||
|     if (standalone) { | ||||
|       core.info(`Docker info skipped in standalone mode`); | ||||
|     } else { | ||||
|       await exec.exec('docker', ['version'], { | ||||
|         failOnStdErr: false | ||||
|       }); | ||||
|       await exec.exec('docker', ['info'], { | ||||
|         failOnStdErr: false | ||||
|       }); | ||||
|     } | ||||
|     core.endGroup(); | ||||
| 
 | ||||
|     if (util.isValidUrl(inputs.version)) { | ||||
|       if (standalone) { | ||||
|         throw new Error(`Cannot build from source without the Docker CLI`); | ||||
|       } | ||||
|       core.startGroup(`Build and install buildx`); | ||||
|       await buildx.build(inputs.version, dockerConfigHome); | ||||
|       await buildx.build(inputs.version, dockerConfigHome, standalone); | ||||
|       core.endGroup(); | ||||
|     } else if (!(await buildx.isAvailable()) || inputs.version) { | ||||
|     } else if (!(await buildx.isAvailable(standalone)) || inputs.version) { | ||||
|       core.startGroup(`Download and install buildx`); | ||||
|       await buildx.install(inputs.version || 'latest', dockerConfigHome); | ||||
|       await buildx.install(inputs.version || 'latest', standalone ? context.tmpDir() : dockerConfigHome, standalone); | ||||
|       core.endGroup(); | ||||
|     } | ||||
| 
 | ||||
|     const buildxVersion = await buildx.getVersion(); | ||||
|     const buildxVersion = await buildx.getVersion(standalone); | ||||
|     await core.group(`Buildx version`, async () => { | ||||
|       const versionCmd = buildx.getCommand(['version'], standalone); | ||||
|       await exec.exec(versionCmd.commandLine, versionCmd.args, { | ||||
|         failOnStdErr: false | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     const builderName: string = inputs.driver == 'docker' ? 'default' : `builder-${uuid.v4()}`; | ||||
|     context.setOutput('name', builderName); | ||||
|     stateHelper.setBuilderName(builderName); | ||||
| 
 | ||||
|     if (inputs.driver !== 'docker') { | ||||
|       core.startGroup(`Creating a new builder instance`); | ||||
|       const createArgs: Array<string> = ['buildx', 'create', '--name', builderName, '--driver', inputs.driver]; | ||||
|       const createArgs: Array<string> = ['create', '--name', builderName, '--driver', inputs.driver]; | ||||
|       if (buildx.satisfies(buildxVersion, '>=0.3.0')) { | ||||
|         await context.asyncForEach(inputs.driverOpts, async driverOpt => { | ||||
|           createArgs.push('--driver-opt', driverOpt); | ||||
| @ -55,26 +78,31 @@ async function run(): Promise<void> { | ||||
|       } else if (inputs.configInline) { | ||||
|         createArgs.push('--config', await buildx.getConfigInline(inputs.configInline)); | ||||
|       } | ||||
|       await exec.exec('docker', createArgs); | ||||
|       const createCmd = buildx.getCommand(createArgs, standalone); | ||||
|       await exec.exec(createCmd.commandLine, createCmd.args); | ||||
|       core.endGroup(); | ||||
| 
 | ||||
|       core.startGroup(`Booting builder`); | ||||
|       const bootstrapArgs: Array<string> = ['buildx', 'inspect', '--bootstrap']; | ||||
|       const bootstrapArgs: Array<string> = ['inspect', '--bootstrap']; | ||||
|       if (buildx.satisfies(buildxVersion, '>=0.4.0')) { | ||||
|         bootstrapArgs.push('--builder', builderName); | ||||
|       } | ||||
|       await exec.exec('docker', bootstrapArgs); | ||||
|       const bootstrapCmd = buildx.getCommand(bootstrapArgs, standalone); | ||||
|       await exec.exec(bootstrapCmd.commandLine, bootstrapCmd.args); | ||||
|       core.endGroup(); | ||||
|     } | ||||
| 
 | ||||
|     if (inputs.install) { | ||||
|       if (standalone) { | ||||
|         throw new Error(`Cannot set buildx as default builder without the Docker CLI`); | ||||
|       } | ||||
|       core.startGroup(`Setting buildx as default builder`); | ||||
|       await exec.exec('docker', ['buildx', 'install']); | ||||
|       core.endGroup(); | ||||
|     } | ||||
| 
 | ||||
|     core.startGroup(`Inspect builder`); | ||||
|     const builder = await buildx.inspect(builderName); | ||||
|     const builder = await buildx.inspect(builderName, standalone); | ||||
|     core.info(JSON.stringify(builder, undefined, 2)); | ||||
|     context.setOutput('driver', builder.driver); | ||||
|     context.setOutput('endpoint', builder.node_endpoint); | ||||
| @ -83,7 +111,7 @@ async function run(): Promise<void> { | ||||
|     context.setOutput('platforms', builder.node_platforms); | ||||
|     core.endGroup(); | ||||
| 
 | ||||
|     if (inputs.driver == 'docker-container') { | ||||
|     if (!standalone && 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}`)); | ||||
| @ -114,8 +142,9 @@ async function cleanup(): Promise<void> { | ||||
| 
 | ||||
|   if (stateHelper.builderName.length > 0) { | ||||
|     core.startGroup(`Removing builder`); | ||||
|     const rmCmd = buildx.getCommand(['rm', stateHelper.builderName], /true/i.test(stateHelper.standalone)); | ||||
|     await exec | ||||
|       .getExecOutput('docker', ['buildx', 'rm', `${stateHelper.builderName}`], { | ||||
|       .getExecOutput(rmCmd.commandLine, rmCmd.args, { | ||||
|         ignoreReturnCode: true | ||||
|       }) | ||||
|       .then(res => { | ||||
|  | ||||
| @ -2,6 +2,7 @@ import * as core from '@actions/core'; | ||||
| 
 | ||||
| export const IsPost = !!process.env['STATE_isPost']; | ||||
| export const IsDebug = !!process.env['STATE_isDebug']; | ||||
| export const standalone = process.env['STATE_standalone'] || ''; | ||||
| export const builderName = process.env['STATE_builderName'] || ''; | ||||
| export const containerName = process.env['STATE_containerName'] || ''; | ||||
| 
 | ||||
| @ -9,6 +10,10 @@ export function setDebug(debug: string) { | ||||
|   core.saveState('isDebug', debug); | ||||
| } | ||||
| 
 | ||||
| export function setStandalone(standalone: boolean) { | ||||
|   core.saveState('standalone', standalone); | ||||
| } | ||||
| 
 | ||||
| export function setBuilderName(builderName: string) { | ||||
|   core.saveState('builderName', builderName); | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 CrazyMax
						CrazyMax