Add digest output
Fix platforms and allow inputs Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									44d05b9191
								
							
						
					
					
						commit
						38c1f188ca
					
				
							
								
								
									
										49
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										49
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @ -11,7 +11,54 @@ on: | ||||
|       - v2-working-branch # remove when merged to master | ||||
| 
 | ||||
| jobs: | ||||
|   main: | ||||
|   single: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - | ||||
|         name: Run local registry | ||||
|         run: | | ||||
|           docker run -d -p 5000:5000 registry:2 | ||||
|       - | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v2.3.1 | ||||
|       - | ||||
|         name: Set up QEMU | ||||
|         uses: ./setup-qemu/ # change to docker/setup-qemu-action@master | ||||
|         with: | ||||
|           platforms: all | ||||
|       - | ||||
|         name: Set up Docker Buildx | ||||
|         id: buildx | ||||
|         uses: ./setup-buildx/ # change to docker/setup-buildx-action@master | ||||
|         with: | ||||
|           driver-opt: network=host | ||||
|           buildkitd-flags: --allow-insecure-entitlement security.insecure | ||||
|       - | ||||
|         name: Build and push | ||||
|         id: docker_build | ||||
|         uses: ./ | ||||
|         with: | ||||
|           context: ./test | ||||
|           file: ./test/Dockerfile | ||||
|           builder: ${{ steps.buildx.outputs.name }} | ||||
|           allow: network.host,security.insecure | ||||
|           push: true | ||||
|           tags: | | ||||
|             localhost:5000/name/app:latest | ||||
|             localhost:5000/name/app:1.0.0 | ||||
|       - | ||||
|         name: Inspect | ||||
|         run: | | ||||
|           docker buildx imagetools inspect localhost:5000/name/app:1.0.0 | ||||
|       - | ||||
|         name: Image digest | ||||
|         run: echo ${{ steps.docker_build.outputs.digest }} | ||||
|       - | ||||
|         name: Dump context | ||||
|         if: always() | ||||
|         uses: crazy-max/ghaction-dump-context@v1 | ||||
| 
 | ||||
|   multi: | ||||
|     runs-on: ubuntu-latest | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|  | ||||
							
								
								
									
										52
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								README.md
									
									
									
									
									
								
							| @ -32,7 +32,56 @@ on: | ||||
|     tags: | ||||
| 
 | ||||
| jobs: | ||||
|   buildx: | ||||
|   main: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v2 | ||||
|       - | ||||
|         name: Set up QEMU | ||||
|         uses: docker/setup-qemu-action@v1 | ||||
|         with: | ||||
|           platforms: all | ||||
|       - | ||||
|         name: Set up Docker Buildx | ||||
|         id: buildx | ||||
|         uses: docker/setup-buildx-action@v1 | ||||
|       - | ||||
|         name: Login to DockerHub | ||||
|         uses: crazy-max/ghaction-docker-login@v1 # switch to docker/login-action@v1 when available  | ||||
|         with: | ||||
|           username: ${{ secrets.DOCKER_USERNAME }} | ||||
|           password: ${{ secrets.DOCKER_PASSWORD }} | ||||
|       - | ||||
|         name: Build and push | ||||
|         id: docker_build | ||||
|         uses: docker/build-push-action@v2 | ||||
|         with: | ||||
|           builder: ${{ steps.buildx.outputs.name }} | ||||
|           push: true | ||||
|           tags: | | ||||
|             user/app:latest | ||||
|             user/app:1.0.0 | ||||
|       - | ||||
|         name: Image digest | ||||
|         run: echo ${{ steps.docker_build.outputs.digest }} | ||||
| ``` | ||||
| 
 | ||||
| ### Multi-platform image | ||||
| 
 | ||||
| ```yaml | ||||
| name: ci | ||||
| 
 | ||||
| on: | ||||
|   pull_request: | ||||
|     branches: master | ||||
|   push: | ||||
|     branches: master | ||||
|     tags: | ||||
| 
 | ||||
| jobs: | ||||
|   multi: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - | ||||
| @ -58,7 +107,6 @@ jobs: | ||||
|         uses: docker/build-push-action@v2 | ||||
|         with: | ||||
|           builder: ${{ steps.buildx.outputs.name }} | ||||
|           platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le,linux/s390x | ||||
|           push: true | ||||
|           tags: | | ||||
|             user/app:latest | ||||
|  | ||||
							
								
								
									
										15
									
								
								__tests__/buildx.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								__tests__/buildx.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| import fs from 'fs'; | ||||
| import * as buildx from '../src/buildx'; | ||||
| 
 | ||||
| const digest = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9'; | ||||
| 
 | ||||
| describe('getImageID', () => { | ||||
|   it('matches', async () => { | ||||
|     const imageIDFile = await buildx.getImageIDFile(); | ||||
|     console.log(`imageIDFile: ${imageIDFile}`); | ||||
|     await fs.writeFileSync(imageIDFile, digest); | ||||
|     const imageID = await buildx.getImageID(); | ||||
|     console.log(`imageID: ${imageID}`); | ||||
|     expect(imageID).toEqual(digest); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										16
									
								
								action.yml
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								action.yml
									
									
									
									
									
								
							| @ -19,13 +19,13 @@ inputs: | ||||
|     required: false | ||||
|     default: './Dockerfile' | ||||
|   build-args: | ||||
|     description: "Newline-delimited list of build-time variables" | ||||
|     description: "List of build-time variables" | ||||
|     required: false | ||||
|   labels: | ||||
|     description: "Newline-delimited list of metadata for an image" | ||||
|     description: "List of metadata for an image" | ||||
|     required: false | ||||
|   tags: | ||||
|     description: "Newline-delimited list of tags" | ||||
|     description: "List of tags" | ||||
|     required: false | ||||
|   pull: | ||||
|     description: "Always attempt to pull a newer version of the image" | ||||
| @ -35,14 +35,14 @@ inputs: | ||||
|     description: "Sets the target stage to build" | ||||
|     required: false | ||||
|   allow: | ||||
|     description: "Allow extra privileged entitlement (eg. network.host,security.insecure)" | ||||
|     description: "List of extra privileged entitlement (eg. network.host,security.insecure)" | ||||
|     required: false | ||||
|   no-cache: | ||||
|     description: "Do not use cache when building the image" | ||||
|     required: false | ||||
|     default: 'false' | ||||
|   platforms: | ||||
|     description: "Comma-delimited list of target platforms for build" | ||||
|     description: "List of target platforms for build" | ||||
|     required: false | ||||
|   load: | ||||
|     description: "Load is a shorthand for --output=type=docker" | ||||
| @ -53,13 +53,13 @@ inputs: | ||||
|     required: false | ||||
|     default: 'false' | ||||
|   outputs: | ||||
|     description: "Newline-delimited list of output destinations (format: type=local,dest=path)" | ||||
|     description: "List of output destinations (format: type=local,dest=path)" | ||||
|     required: false | ||||
|   cache-from: | ||||
|     description: "Newline-delimited list of external cache sources for buildx (eg. user/app:cache, type=local,src=path/to/dir)" | ||||
|     description: "List of external cache sources for buildx (eg. user/app:cache, type=local,src=path/to/dir)" | ||||
|     required: false | ||||
|   cache-to: | ||||
|     description: "Newline-delimited list of cache export destinations for buildx (eg. user/app:cache, type=local,dest=path/to/dir)" | ||||
|     description: "List of cache export destinations for buildx (eg. user/app:cache, type=local,dest=path/to/dir)" | ||||
|     required: false | ||||
| 
 | ||||
| outputs: | ||||
|  | ||||
							
								
								
									
										80
									
								
								dist/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										80
									
								
								dist/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1025,6 +1025,12 @@ function run() { | ||||
|             core.info(`🏃 Starting build...`); | ||||
|             const args = yield context_1.getArgs(inputs); | ||||
|             yield exec.exec('docker', args); | ||||
|             const imageID = yield buildx.getImageID(); | ||||
|             if (imageID) { | ||||
|                 core.info('🛒 Extracting digest...'); | ||||
|                 core.info(`${imageID}`); | ||||
|                 core.setOutput('digest', imageID); | ||||
|             } | ||||
|         } | ||||
|         catch (error) { | ||||
|             core.setFailed(error.message); | ||||
| @ -1405,8 +1411,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge | ||||
|     }); | ||||
| }; | ||||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||||
| exports.asyncForEach = exports.getInputList = exports.getArgs = exports.getInputs = void 0; | ||||
| exports.asyncForEach = exports.getInputList = exports.getArgs = exports.getInputs = exports.tmpDir = void 0; | ||||
| const fs = __importStar(__webpack_require__(747)); | ||||
| const os = __importStar(__webpack_require__(87)); | ||||
| const path = __importStar(__webpack_require__(622)); | ||||
| const buildx = __importStar(__webpack_require__(982)); | ||||
| const core = __importStar(__webpack_require__(470)); | ||||
| exports.tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-build-push-')); | ||||
| function getInputs() { | ||||
|     return __awaiter(this, void 0, void 0, function* () { | ||||
|         return { | ||||
| @ -1440,24 +1451,6 @@ function getArgs(inputs) { | ||||
|     }); | ||||
| } | ||||
| exports.getArgs = getArgs; | ||||
| function getCommonArgs(inputs) { | ||||
|     return __awaiter(this, void 0, void 0, function* () { | ||||
|         let args = []; | ||||
|         if (inputs.noCache) { | ||||
|             args.push('--no-cache'); | ||||
|         } | ||||
|         if (inputs.pull) { | ||||
|             args.push('--pull'); | ||||
|         } | ||||
|         if (inputs.load) { | ||||
|             args.push('--load'); | ||||
|         } | ||||
|         if (inputs.push) { | ||||
|             args.push('--push'); | ||||
|         } | ||||
|         return args; | ||||
|     }); | ||||
| } | ||||
| function getBuildArgs(inputs) { | ||||
|     return __awaiter(this, void 0, void 0, function* () { | ||||
|         let args = ['build']; | ||||
| @ -1473,12 +1466,15 @@ function getBuildArgs(inputs) { | ||||
|         if (inputs.target) { | ||||
|             args.push('--target', inputs.target); | ||||
|         } | ||||
|         if (inputs.allow) { | ||||
|         if (inputs.allow.length > 0) { | ||||
|             args.push('--allow', inputs.allow.join(',')); | ||||
|         } | ||||
|         if (inputs.platforms) { | ||||
|         if (inputs.platforms.length > 0) { | ||||
|             args.push('--platform', inputs.platforms.join(',')); | ||||
|         } | ||||
|         else { | ||||
|             args.push('--iidfile', yield buildx.getImageIDFile()); | ||||
|         } | ||||
|         yield exports.asyncForEach(inputs.outputs, (output) => __awaiter(this, void 0, void 0, function* () { | ||||
|             args.push('--output', output); | ||||
|         })); | ||||
| @ -1494,6 +1490,24 @@ function getBuildArgs(inputs) { | ||||
|         return args; | ||||
|     }); | ||||
| } | ||||
| function getCommonArgs(inputs) { | ||||
|     return __awaiter(this, void 0, void 0, function* () { | ||||
|         let args = []; | ||||
|         if (inputs.noCache) { | ||||
|             args.push('--no-cache'); | ||||
|         } | ||||
|         if (inputs.pull) { | ||||
|             args.push('--pull'); | ||||
|         } | ||||
|         if (inputs.load) { | ||||
|             args.push('--load'); | ||||
|         } | ||||
|         if (inputs.push) { | ||||
|             args.push('--push'); | ||||
|         } | ||||
|         return args; | ||||
|     }); | ||||
| } | ||||
| function getInputList(name) { | ||||
|     return __awaiter(this, void 0, void 0, function* () { | ||||
|         const items = core.getInput(name); | ||||
| @ -1838,9 +1852,31 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge | ||||
|         step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||||
|     }); | ||||
| }; | ||||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||||
|     return (mod && mod.__esModule) ? mod : { "default": mod }; | ||||
| }; | ||||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||||
| exports.use = exports.isAvailable = void 0; | ||||
| exports.use = exports.isAvailable = exports.getImageID = exports.getImageIDFile = void 0; | ||||
| const fs_1 = __importDefault(__webpack_require__(747)); | ||||
| const path_1 = __importDefault(__webpack_require__(622)); | ||||
| const context = __importStar(__webpack_require__(482)); | ||||
| const exec = __importStar(__webpack_require__(807)); | ||||
| function getImageIDFile() { | ||||
|     return __awaiter(this, void 0, void 0, function* () { | ||||
|         return path_1.default.join(context.tmpDir, 'iidfile'); | ||||
|     }); | ||||
| } | ||||
| exports.getImageIDFile = getImageIDFile; | ||||
| function getImageID() { | ||||
|     return __awaiter(this, void 0, void 0, function* () { | ||||
|         const iidFile = yield getImageIDFile(); | ||||
|         if (!fs_1.default.existsSync(iidFile)) { | ||||
|             return undefined; | ||||
|         } | ||||
|         return fs_1.default.readFileSync(iidFile, { encoding: 'utf-8' }); | ||||
|     }); | ||||
| } | ||||
| exports.getImageID = getImageID; | ||||
| function isAvailable() { | ||||
|     return __awaiter(this, void 0, void 0, function* () { | ||||
|         return yield exec.exec(`docker`, ['buildx'], true).then(res => { | ||||
|  | ||||
| @ -1,5 +1,20 @@ | ||||
| import fs from 'fs'; | ||||
| import path from 'path'; | ||||
| import * as context from './context'; | ||||
| import * as exec from './exec'; | ||||
| 
 | ||||
| export async function getImageIDFile(): Promise<string> { | ||||
|   return path.join(context.tmpDir, 'iidfile'); | ||||
| } | ||||
| 
 | ||||
| export async function getImageID(): Promise<string | undefined> { | ||||
|   const iidFile = await getImageIDFile(); | ||||
|   if (!fs.existsSync(iidFile)) { | ||||
|     return undefined; | ||||
|   } | ||||
|   return fs.readFileSync(iidFile, {encoding: 'utf-8'}); | ||||
| } | ||||
| 
 | ||||
| export async function isAvailable(): Promise<Boolean> { | ||||
|   return await exec.exec(`docker`, ['buildx'], true).then(res => { | ||||
|     if (res.stderr != '' && !res.success) { | ||||
|  | ||||
| @ -1,5 +1,11 @@ | ||||
| import * as fs from 'fs'; | ||||
| import * as os from 'os'; | ||||
| import * as path from 'path'; | ||||
| import * as buildx from './buildx'; | ||||
| import * as core from '@actions/core'; | ||||
| 
 | ||||
| export const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-build-push-')); | ||||
| 
 | ||||
| export interface Inputs { | ||||
|   context: string; | ||||
|   file: string; | ||||
| @ -48,6 +54,43 @@ export async function getArgs(inputs: Inputs): Promise<Array<string>> { | ||||
|   return args; | ||||
| } | ||||
| 
 | ||||
| async function getBuildArgs(inputs: Inputs): Promise<Array<string>> { | ||||
|   let args: Array<string> = ['build']; | ||||
|   await asyncForEach(inputs.buildArgs, async buildArg => { | ||||
|     args.push('--build-arg', buildArg); | ||||
|   }); | ||||
|   await asyncForEach(inputs.labels, async label => { | ||||
|     args.push('--label', label); | ||||
|   }); | ||||
|   await asyncForEach(inputs.tags, async tag => { | ||||
|     args.push('--tag', tag); | ||||
|   }); | ||||
|   if (inputs.target) { | ||||
|     args.push('--target', inputs.target); | ||||
|   } | ||||
|   if (inputs.allow.length > 0) { | ||||
|     args.push('--allow', inputs.allow.join(',')); | ||||
|   } | ||||
|   if (inputs.platforms.length > 0) { | ||||
|     args.push('--platform', inputs.platforms.join(',')); | ||||
|   } else { | ||||
|     args.push('--iidfile', await buildx.getImageIDFile()); | ||||
|   } | ||||
|   await asyncForEach(inputs.outputs, async output => { | ||||
|     args.push('--output', output); | ||||
|   }); | ||||
|   await asyncForEach(inputs.cacheFrom, async cacheFrom => { | ||||
|     args.push('--cache-from', cacheFrom); | ||||
|   }); | ||||
|   await asyncForEach(inputs.cacheTo, async cacheTo => { | ||||
|     args.push('--cache-to', cacheTo); | ||||
|   }); | ||||
|   if (inputs.file) { | ||||
|     args.push('--file', inputs.file); | ||||
|   } | ||||
|   return args; | ||||
| } | ||||
| 
 | ||||
| async function getCommonArgs(inputs: Inputs): Promise<Array<string>> { | ||||
|   let args: Array<string> = []; | ||||
|   if (inputs.noCache) { | ||||
| @ -65,41 +108,6 @@ async function getCommonArgs(inputs: Inputs): Promise<Array<string>> { | ||||
|   return args; | ||||
| } | ||||
| 
 | ||||
| async function getBuildArgs(inputs: Inputs): Promise<Array<string>> { | ||||
|   let args: Array<string> = ['build']; | ||||
|   await asyncForEach(inputs.buildArgs, async buildArg => { | ||||
|     args.push('--build-arg', buildArg); | ||||
|   }); | ||||
|   await asyncForEach(inputs.labels, async label => { | ||||
|     args.push('--label', label); | ||||
|   }); | ||||
|   await asyncForEach(inputs.tags, async tag => { | ||||
|     args.push('--tag', tag); | ||||
|   }); | ||||
|   if (inputs.target) { | ||||
|     args.push('--target', inputs.target); | ||||
|   } | ||||
|   if (inputs.allow) { | ||||
|     args.push('--allow', inputs.allow.join(',')); | ||||
|   } | ||||
|   if (inputs.platforms) { | ||||
|     args.push('--platform', inputs.platforms.join(',')); | ||||
|   } | ||||
|   await asyncForEach(inputs.outputs, async output => { | ||||
|     args.push('--output', output); | ||||
|   }); | ||||
|   await asyncForEach(inputs.cacheFrom, async cacheFrom => { | ||||
|     args.push('--cache-from', cacheFrom); | ||||
|   }); | ||||
|   await asyncForEach(inputs.cacheTo, async cacheTo => { | ||||
|     args.push('--cache-to', cacheTo); | ||||
|   }); | ||||
|   if (inputs.file) { | ||||
|     args.push('--file', inputs.file); | ||||
|   } | ||||
|   return args; | ||||
| } | ||||
| 
 | ||||
| export async function getInputList(name: string): Promise<string[]> { | ||||
|   const items = core.getInput(name); | ||||
|   if (items == '') { | ||||
|  | ||||
| @ -25,6 +25,13 @@ async function run(): Promise<void> { | ||||
|     core.info(`🏃 Starting build...`); | ||||
|     const args: string[] = await getArgs(inputs); | ||||
|     await exec.exec('docker', args); | ||||
| 
 | ||||
|     const imageID = await buildx.getImageID(); | ||||
|     if (imageID) { | ||||
|       core.info('🛒 Extracting digest...'); | ||||
|       core.info(`${imageID}`); | ||||
|       core.setOutput('digest', imageID); | ||||
|     } | ||||
|   } catch (error) { | ||||
|     core.setFailed(error.message); | ||||
|   } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 CrazyMax
						CrazyMax