Merge pull request #601 from crazy-max/standalone-mode
Standalone mode support
This commit is contained in:
		
						commit
						c2085839e1
					
				
							
								
								
									
										59
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										59
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @ -814,3 +814,62 @@ jobs: | |||||||
|         name: Inspect |         name: Inspect | ||||||
|         run: | |         run: | | ||||||
|           docker buildx imagetools inspect localhost:5000/name/app:1.0.0 |           docker buildx imagetools inspect localhost:5000/name/app:1.0.0 | ||||||
|  | 
 | ||||||
|  |   standalone: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     steps: | ||||||
|  |       - | ||||||
|  |         name: Checkout | ||||||
|  |         uses: actions/checkout@v3 | ||||||
|  |       - | ||||||
|  |         name: Uninstall moby cli | ||||||
|  |         run: | | ||||||
|  |           sudo apt-get purge -y moby-cli moby-buildx | ||||||
|  |       - | ||||||
|  |         name: Set up Docker Buildx | ||||||
|  |         uses: docker/setup-buildx-action@v1 | ||||||
|  |       - | ||||||
|  |         name: Build | ||||||
|  |         uses: ./ | ||||||
|  |         with: | ||||||
|  |           context: ./test | ||||||
|  |           file: ./test/Dockerfile | ||||||
|  | 
 | ||||||
|  |   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: Set up Docker Buildx | ||||||
|  |         uses: docker/setup-buildx-action@v1 | ||||||
|  |         with: | ||||||
|  |           driver: kubernetes | ||||||
|  |       - | ||||||
|  |         name: Build | ||||||
|  |         uses: ./ | ||||||
|  |         with: | ||||||
|  |           context: ./test | ||||||
|  |           file: ./test/Dockerfile | ||||||
|  | |||||||
| @ -78,6 +78,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', () => { | describe('getVersion', () => { | ||||||
|   it('valid', async () => { |   it('valid', async () => { | ||||||
|     const version = await buildx.getVersion(); |     const version = await buildx.getVersion(); | ||||||
|  | |||||||
| @ -151,7 +151,6 @@ describe('getArgs', () => { | |||||||
|         ['pull', 'false'], |         ['pull', 'false'], | ||||||
|       ]), |       ]), | ||||||
|       [ |       [ | ||||||
|         'buildx', |  | ||||||
|         'build', |         'build', | ||||||
|         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', |         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', | ||||||
|         '.' |         '.' | ||||||
| @ -168,7 +167,6 @@ describe('getArgs', () => { | |||||||
|         ['pull', 'false'], |         ['pull', 'false'], | ||||||
|       ]), |       ]), | ||||||
|       [ |       [ | ||||||
|         'buildx', |  | ||||||
|         'build', |         'build', | ||||||
|         '--build-arg', 'MY_ARG=val1,val2,val3', |         '--build-arg', 'MY_ARG=val1,val2,val3', | ||||||
|         '--build-arg', 'ARG=val', |         '--build-arg', 'ARG=val', | ||||||
| @ -187,7 +185,6 @@ describe('getArgs', () => { | |||||||
|         ['pull', 'false'], |         ['pull', 'false'], | ||||||
|       ]), |       ]), | ||||||
|       [ |       [ | ||||||
|         'buildx', |  | ||||||
|         'build', |         'build', | ||||||
|         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', |         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', | ||||||
|         '--tag', 'name/app:7.4', |         '--tag', 'name/app:7.4', | ||||||
| @ -208,7 +205,6 @@ describe('getArgs', () => { | |||||||
|         ['pull', 'false'], |         ['pull', 'false'], | ||||||
|       ]), |       ]), | ||||||
|       [ |       [ | ||||||
|         'buildx', |  | ||||||
|         'build', |         'build', | ||||||
|         '--label', 'org.opencontainers.image.title=buildkit', |         '--label', 'org.opencontainers.image.title=buildkit', | ||||||
|         '--label', 'org.opencontainers.image.description=concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit', |         '--label', 'org.opencontainers.image.description=concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit', | ||||||
| @ -228,7 +224,6 @@ describe('getArgs', () => { | |||||||
|         ['pull', 'false'], |         ['pull', 'false'], | ||||||
|       ]), |       ]), | ||||||
|       [ |       [ | ||||||
|         'buildx', |  | ||||||
|         'build', |         'build', | ||||||
|         '--platform', 'linux/amd64,linux/arm64', |         '--platform', 'linux/amd64,linux/arm64', | ||||||
|         '.' |         '.' | ||||||
| @ -245,7 +240,6 @@ describe('getArgs', () => { | |||||||
|         ['pull', 'false'], |         ['pull', 'false'], | ||||||
|       ]), |       ]), | ||||||
|       [ |       [ | ||||||
|         'buildx', |  | ||||||
|         'build', |         'build', | ||||||
|         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', |         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', | ||||||
|         '.' |         '.' | ||||||
| @ -263,7 +257,6 @@ describe('getArgs', () => { | |||||||
|         ['pull', 'false'], |         ['pull', 'false'], | ||||||
|       ]), |       ]), | ||||||
|       [ |       [ | ||||||
|         'buildx', |  | ||||||
|         'build', |         'build', | ||||||
|         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', |         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', | ||||||
|         '--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest', |         '--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest', | ||||||
| @ -282,7 +275,6 @@ describe('getArgs', () => { | |||||||
|         ['pull', 'false'], |         ['pull', 'false'], | ||||||
|       ]), |       ]), | ||||||
|       [ |       [ | ||||||
|         'buildx', |  | ||||||
|         'build', |         'build', | ||||||
|         '--output', '.', |         '--output', '.', | ||||||
|         '--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest', |         '--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest', | ||||||
| @ -305,7 +297,6 @@ describe('getArgs', () => { | |||||||
|         ['pull', 'false'], |         ['pull', 'false'], | ||||||
|       ]), |       ]), | ||||||
|       [ |       [ | ||||||
|         'buildx', |  | ||||||
|         'build', |         'build', | ||||||
|         '--file', './test/Dockerfile', |         '--file', './test/Dockerfile', | ||||||
|         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', |         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', | ||||||
| @ -340,7 +331,6 @@ ccc"`], | |||||||
|         ['pull', 'false'], |         ['pull', 'false'], | ||||||
|       ]), |       ]), | ||||||
|       [ |       [ | ||||||
|         'buildx', |  | ||||||
|         'build', |         'build', | ||||||
|         '--file', './test/Dockerfile', |         '--file', './test/Dockerfile', | ||||||
|         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', |         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', | ||||||
| @ -378,7 +368,6 @@ ccc`], | |||||||
|         ['pull', 'false'], |         ['pull', 'false'], | ||||||
|       ]), |       ]), | ||||||
|       [ |       [ | ||||||
|         'buildx', |  | ||||||
|         'build', |         'build', | ||||||
|         '--file', './test/Dockerfile', |         '--file', './test/Dockerfile', | ||||||
|         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', |         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', | ||||||
| @ -408,7 +397,6 @@ ccc`], | |||||||
|         ['pull', 'false'], |         ['pull', 'false'], | ||||||
|       ]), |       ]), | ||||||
|       [ |       [ | ||||||
|         'buildx', |  | ||||||
|         'build', |         'build', | ||||||
|         '--file', './test/Dockerfile', |         '--file', './test/Dockerfile', | ||||||
|         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', |         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', | ||||||
| @ -432,7 +420,6 @@ ccc`], | |||||||
|         ['pull', 'false'], |         ['pull', 'false'], | ||||||
|       ]), |       ]), | ||||||
|       [ |       [ | ||||||
|         'buildx', |  | ||||||
|         'build', |         'build', | ||||||
|         '--label', 'org.opencontainers.image.title=filter_results_top_n', |         '--label', 'org.opencontainers.image.title=filter_results_top_n', | ||||||
|         '--label', 'org.opencontainers.image.description=Reference implementation of operation "filter results (top-n)"', |         '--label', 'org.opencontainers.image.description=Reference implementation of operation "filter results (top-n)"', | ||||||
| @ -455,7 +442,6 @@ ccc`], | |||||||
|         ['pull', 'false'], |         ['pull', 'false'], | ||||||
|       ]), |       ]), | ||||||
|       [ |       [ | ||||||
|         'buildx', |  | ||||||
|         'build', |         'build', | ||||||
|         '--add-host', 'docker:10.180.0.1', |         '--add-host', 'docker:10.180.0.1', | ||||||
|         '--add-host', 'foo:10.0.0.1', |         '--add-host', 'foo:10.0.0.1', | ||||||
| @ -484,7 +470,6 @@ nproc=3`], | |||||||
|         ['pull', 'false'], |         ['pull', 'false'], | ||||||
|       ]), |       ]), | ||||||
|       [ |       [ | ||||||
|         'buildx', |  | ||||||
|         'build', |         'build', | ||||||
|         '--add-host', 'docker:10.180.0.1', |         '--add-host', 'docker:10.180.0.1', | ||||||
|         '--add-host', 'foo:10.0.0.1', |         '--add-host', 'foo:10.0.0.1', | ||||||
| @ -509,7 +494,6 @@ nproc=3`], | |||||||
|         ['pull', 'false'], |         ['pull', 'false'], | ||||||
|       ]), |       ]), | ||||||
|       [ |       [ | ||||||
|         'buildx', |  | ||||||
|         'build', |         'build', | ||||||
|         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', |         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', | ||||||
|         '--metadata-file', '/tmp/.docker-build-push-jest/metadata-file', |         '--metadata-file', '/tmp/.docker-build-push-jest/metadata-file', | ||||||
|  | |||||||
							
								
								
									
										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
											
										
									
								
							| @ -107,9 +107,10 @@ export function hasGitAuthToken(secrets: string[]): boolean { | |||||||
|   return false; |   return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function isAvailable(): Promise<boolean> { | export async function isAvailable(standalone?: boolean): Promise<boolean> { | ||||||
|  |   const cmd = getCommand([], standalone); | ||||||
|   return await exec |   return await exec | ||||||
|     .getExecOutput('docker', ['buildx'], { |     .getExecOutput(cmd.command, cmd.args, { | ||||||
|       ignoreReturnCode: true, |       ignoreReturnCode: true, | ||||||
|       silent: true |       silent: true | ||||||
|     }) |     }) | ||||||
| @ -118,12 +119,17 @@ export async function isAvailable(): Promise<boolean> { | |||||||
|         return false; |         return false; | ||||||
|       } |       } | ||||||
|       return res.exitCode == 0; |       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 |   return await exec | ||||||
|     .getExecOutput('docker', ['buildx', 'version'], { |     .getExecOutput(cmd.command, cmd.args, { | ||||||
|       ignoreReturnCode: true, |       ignoreReturnCode: true, | ||||||
|       silent: true |       silent: true | ||||||
|     }) |     }) | ||||||
| @ -146,3 +152,10 @@ export function parseVersion(stdout: string): string { | |||||||
| export function satisfies(version: string, range: string): boolean { | export function satisfies(version: string, range: string): boolean { | ||||||
|   return semver.satisfies(version, range) || /^[0-9a-f]{7}$/.exec(version) !== null; |   return semver.satisfies(version, range) || /^[0-9a-f]{7}$/.exec(version) !== null; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | export function getCommand(args: Array<string>, standalone?: boolean) { | ||||||
|  |   return { | ||||||
|  |     command: standalone ? 'buildx' : 'docker', | ||||||
|  |     args: standalone ? args : ['buildx', ...args] | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | |||||||
| @ -101,7 +101,6 @@ export async function getInputs(defaultContext: string): Promise<Inputs> { | |||||||
| export async function getArgs(inputs: Inputs, defaultContext: string, buildxVersion: string): Promise<Array<string>> { | export async function getArgs(inputs: Inputs, defaultContext: string, buildxVersion: string): Promise<Array<string>> { | ||||||
|   // prettier-ignore
 |   // prettier-ignore
 | ||||||
|   return [ |   return [ | ||||||
|     'buildx', |  | ||||||
|     ...await getBuildArgs(inputs, defaultContext, buildxVersion), |     ...await getBuildArgs(inputs, defaultContext, buildxVersion), | ||||||
|     ...await getCommonArgs(inputs, buildxVersion), |     ...await getCommonArgs(inputs, buildxVersion), | ||||||
|     handlebars.compile(inputs.context)({defaultContext}) |     handlebars.compile(inputs.context)({defaultContext}) | ||||||
|  | |||||||
							
								
								
									
										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; | ||||||
|  |     }); | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								src/main.ts
									
									
									
									
									
								
							| @ -1,30 +1,50 @@ | |||||||
| import * as fs from 'fs'; | import * as fs from 'fs'; | ||||||
| import * as buildx from './buildx'; | import * as buildx from './buildx'; | ||||||
| import * as context from './context'; | import * as context from './context'; | ||||||
|  | import * as docker from './docker'; | ||||||
| import * as stateHelper from './state-helper'; | import * as stateHelper from './state-helper'; | ||||||
| import * as core from '@actions/core'; | import * as core from '@actions/core'; | ||||||
| import * as exec from '@actions/exec'; | import * as exec from '@actions/exec'; | ||||||
| 
 | 
 | ||||||
| async function run(): Promise<void> { | async function run(): Promise<void> { | ||||||
|   try { |   try { | ||||||
|  |     const defContext = context.defaultContext(); | ||||||
|  |     const inputs: context.Inputs = await context.getInputs(defContext); | ||||||
|  | 
 | ||||||
|  |     // standalone if docker cli not available
 | ||||||
|  |     const standalone = !(await docker.isAvailable()); | ||||||
|  | 
 | ||||||
|     core.startGroup(`Docker info`); |     core.startGroup(`Docker info`); | ||||||
|     await exec.exec('docker', ['version']); |     if (standalone) { | ||||||
|     await exec.exec('docker', ['info']); |       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(); |     core.endGroup(); | ||||||
| 
 | 
 | ||||||
|     if (!(await buildx.isAvailable())) { |     if (!(await buildx.isAvailable(standalone))) { | ||||||
|       core.setFailed(`Docker buildx is required. See https://github.com/docker/setup-buildx-action to set up buildx.`); |       core.setFailed(`Docker buildx is required. See https://github.com/docker/setup-buildx-action to set up buildx.`); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     stateHelper.setTmpDir(context.tmpDir()); |     stateHelper.setTmpDir(context.tmpDir()); | ||||||
| 
 | 
 | ||||||
|     const buildxVersion = await buildx.getVersion(); |     const buildxVersion = await buildx.getVersion(standalone); | ||||||
|     const defContext = context.defaultContext(); |     await core.group(`Buildx version`, async () => { | ||||||
|     const inputs: context.Inputs = await context.getInputs(defContext); |       const versionCmd = buildx.getCommand(['version'], standalone); | ||||||
|  |       await exec.exec(versionCmd.command, versionCmd.args, { | ||||||
|  |         failOnStdErr: false | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
| 
 | 
 | ||||||
|     const args: string[] = await context.getArgs(inputs, defContext, buildxVersion); |     const args: string[] = await context.getArgs(inputs, defContext, buildxVersion); | ||||||
|  |     const buildCmd = buildx.getCommand(args, standalone); | ||||||
|     await exec |     await exec | ||||||
|       .getExecOutput('docker', args, { |       .getExecOutput(buildCmd.command, buildCmd.args, { | ||||||
|         ignoreReturnCode: true |         ignoreReturnCode: true | ||||||
|       }) |       }) | ||||||
|       .then(res => { |       .then(res => { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user