Merge pull request #1120 from crazy-max/build-summary
export build record and generate summary
This commit is contained in:
		
						commit
						c382f710d3
					
				
							
								
								
									
										23
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @ -1344,3 +1344,26 @@ jobs: | ||||
|         name: Check docker | ||||
|         run: | | ||||
|           docker image inspect localhost:5000/name/app:latest | ||||
| 
 | ||||
|   disable-summary: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v4 | ||||
|         with: | ||||
|           path: action | ||||
|       - | ||||
|         name: Set up Docker Buildx | ||||
|         uses: docker/setup-buildx-action@v3 | ||||
|         with: | ||||
|           version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} | ||||
|           driver-opts: | | ||||
|             image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} | ||||
|       - | ||||
|         name: Build | ||||
|         uses: ./action | ||||
|         with: | ||||
|           file: ./test/Dockerfile | ||||
|         env: | ||||
|           DOCKER_BUILD_NO_SUMMARY: true | ||||
|  | ||||
| @ -37,6 +37,7 @@ ___ | ||||
| * [Customizing](#customizing) | ||||
|   * [inputs](#inputs) | ||||
|   * [outputs](#outputs) | ||||
|   * [environment variables](#environment-variables) | ||||
| * [Troubleshooting](#troubleshooting) | ||||
| * [Contributing](#contributing) | ||||
| 
 | ||||
| @ -256,6 +257,12 @@ The following outputs are available: | ||||
| | `digest`   | String  | Image digest          | | ||||
| | `metadata` | JSON    | Build result metadata | | ||||
| 
 | ||||
| ### environment variables | ||||
| 
 | ||||
| | Name                      | Type | Description                                                                                                       | | ||||
| |---------------------------|------|-------------------------------------------------------------------------------------------------------------------| | ||||
| | `DOCKER_BUILD_NO_SUMMARY` | Bool | If `true`, [build summary](https://docs.docker.com/build/ci/github-actions/build-summary/) generation is disabled | | ||||
| 
 | ||||
| ## Troubleshooting | ||||
| 
 | ||||
| See [TROUBLESHOOTING.md](TROUBLESHOOTING.md) | ||||
|  | ||||
							
								
								
									
										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
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/licenses.txt
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/licenses.txt
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -2807,7 +2807,7 @@ minimatch | ||||
| ISC | ||||
| The ISC License | ||||
| 
 | ||||
| Copyright (c) Isaac Z. Schlueter and Contributors | ||||
| Copyright (c) 2011-2023 Isaac Z. Schlueter and Contributors | ||||
| 
 | ||||
| Permission to use, copy, modify, and/or distribute this software for any | ||||
| purpose with or without fee is hereby granted, provided that the above | ||||
|  | ||||
| @ -79,6 +79,25 @@ export async function getInputs(): Promise<Inputs> { | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| export function sanitizeInputs(inputs: Inputs) { | ||||
|   const res = {}; | ||||
|   for (const key of Object.keys(inputs)) { | ||||
|     if (key === 'github-token') { | ||||
|       continue; | ||||
|     } | ||||
|     const value: string | string[] | boolean = inputs[key]; | ||||
|     if (typeof value === 'boolean' && value === false) { | ||||
|       continue; | ||||
|     } else if (Array.isArray(value) && value.length === 0) { | ||||
|       continue; | ||||
|     } else if (!value) { | ||||
|       continue; | ||||
|     } | ||||
|     res[key] = value; | ||||
|   } | ||||
|   return res; | ||||
| } | ||||
| 
 | ||||
| export async function getArgs(inputs: Inputs, toolkit: Toolkit): Promise<Array<string>> { | ||||
|   const context = handlebars.compile(inputs.context)({ | ||||
|     defaultContext: Context.gitContext() | ||||
|  | ||||
							
								
								
									
										71
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										71
									
								
								src/main.ts
									
									
									
									
									
								
							| @ -4,11 +4,14 @@ import * as stateHelper from './state-helper'; | ||||
| import * as core from '@actions/core'; | ||||
| import * as actionsToolkit from '@docker/actions-toolkit'; | ||||
| 
 | ||||
| import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx'; | ||||
| import {History as BuildxHistory} from '@docker/actions-toolkit/lib/buildx/history'; | ||||
| import {Context} from '@docker/actions-toolkit/lib/context'; | ||||
| import {Docker} from '@docker/actions-toolkit/lib/docker/docker'; | ||||
| import {Exec} from '@docker/actions-toolkit/lib/exec'; | ||||
| import {GitHub} from '@docker/actions-toolkit/lib/github'; | ||||
| import {Toolkit} from '@docker/actions-toolkit/lib/toolkit'; | ||||
| import {Util} from '@docker/actions-toolkit/lib/util'; | ||||
| 
 | ||||
| import {ConfigFile} from '@docker/actions-toolkit/lib/types/docker/docker'; | ||||
| 
 | ||||
| @ -17,8 +20,10 @@ import * as context from './context'; | ||||
| actionsToolkit.run( | ||||
|   // main
 | ||||
|   async () => { | ||||
|     const startedTime = new Date(); | ||||
|     const inputs: context.Inputs = await context.getInputs(); | ||||
|     core.debug(`inputs: ${JSON.stringify(inputs)}`); | ||||
|     stateHelper.setInputs(inputs); | ||||
| 
 | ||||
|     const toolkit = new Toolkit(); | ||||
| 
 | ||||
| @ -78,6 +83,7 @@ actionsToolkit.run( | ||||
|     await core.group(`Builder info`, async () => { | ||||
|       const builder = await toolkit.builder.inspect(inputs.builder); | ||||
|       core.info(JSON.stringify(builder, null, 2)); | ||||
|       stateHelper.setBuilder(builder); | ||||
|     }); | ||||
| 
 | ||||
|     const args: string[] = await context.getArgs(inputs, toolkit); | ||||
| @ -87,11 +93,12 @@ actionsToolkit.run( | ||||
|     core.debug(`buildCmd.command: ${buildCmd.command}`); | ||||
|     core.debug(`buildCmd.args: ${JSON.stringify(buildCmd.args)}`); | ||||
| 
 | ||||
|     let err: Error | undefined; | ||||
|     await Exec.getExecOutput(buildCmd.command, buildCmd.args, { | ||||
|       ignoreReturnCode: true | ||||
|     }).then(res => { | ||||
|       if (res.stderr.length > 0 && res.exitCode != 0) { | ||||
|         throw new Error(`buildx failed with: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`); | ||||
|         err = Error(`buildx failed with: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
| @ -118,9 +125,52 @@ actionsToolkit.run( | ||||
|         core.setOutput('metadata', metadatadt); | ||||
|       }); | ||||
|     } | ||||
|     await core.group(`Reference`, async () => { | ||||
|       const ref = await buildRef(toolkit, startedTime, inputs.builder); | ||||
|       if (ref) { | ||||
|         core.info(ref); | ||||
|         stateHelper.setBuildRef(ref); | ||||
|       } else { | ||||
|         core.warning('No build ref found'); | ||||
|       } | ||||
|     }); | ||||
|     if (err) { | ||||
|       throw err; | ||||
|     } | ||||
|   }, | ||||
|   // post
 | ||||
|   async () => { | ||||
|     if (stateHelper.buildRef.length > 0) { | ||||
|       await core.group(`Generating build summary`, async () => { | ||||
|         if (process.env.DOCKER_BUILD_NO_SUMMARY && Util.parseBool(process.env.DOCKER_BUILD_NO_SUMMARY)) { | ||||
|           core.info('Summary disabled'); | ||||
|           return; | ||||
|         } | ||||
|         if (stateHelper.builder && stateHelper.builder.driver === 'cloud') { | ||||
|           core.info('Summary is not yet supported with Docker Build Cloud'); | ||||
|           return; | ||||
|         } | ||||
|         try { | ||||
|           const buildxHistory = new BuildxHistory(); | ||||
|           const exportRes = await buildxHistory.export({ | ||||
|             refs: [stateHelper.buildRef] | ||||
|           }); | ||||
|           core.info(`Build record exported to ${exportRes.dockerbuildFilename} (${Util.formatFileSize(exportRes.dockerbuildSize)})`); | ||||
|           const uploadRes = await GitHub.uploadArtifact({ | ||||
|             filename: exportRes.dockerbuildFilename, | ||||
|             mimeType: 'application/gzip', | ||||
|             retentionDays: 90 | ||||
|           }); | ||||
|           await GitHub.writeBuildSummary({ | ||||
|             exportRes: exportRes, | ||||
|             uploadRes: uploadRes, | ||||
|             inputs: stateHelper.inputs | ||||
|           }); | ||||
|         } catch (e) { | ||||
|           core.warning(e.message); | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
|     if (stateHelper.tmpDir.length > 0) { | ||||
|       await core.group(`Removing temp folder ${stateHelper.tmpDir}`, async () => { | ||||
|         fs.rmSync(stateHelper.tmpDir, {recursive: true}); | ||||
| @ -128,3 +178,22 @@ actionsToolkit.run( | ||||
|     } | ||||
|   } | ||||
| ); | ||||
| 
 | ||||
| async function buildRef(toolkit: Toolkit, since: Date, builder?: string): Promise<string> { | ||||
|   // get ref from metadata file
 | ||||
|   const ref = toolkit.buildxBuild.resolveRef(); | ||||
|   if (ref) { | ||||
|     return ref; | ||||
|   } | ||||
|   // otherwise, look for the very first build ref since the build has started
 | ||||
|   if (!builder) { | ||||
|     const currentBuilder = await toolkit.builder.inspect(); | ||||
|     builder = currentBuilder.name; | ||||
|   } | ||||
|   const refs = Buildx.refs({ | ||||
|     dir: Buildx.refsDir, | ||||
|     builderName: builder, | ||||
|     since: since | ||||
|   }); | ||||
|   return Object.keys(refs).length > 0 ? Object.keys(refs)[0] : ''; | ||||
| } | ||||
|  | ||||
| @ -1,7 +1,26 @@ | ||||
| import * as core from '@actions/core'; | ||||
| 
 | ||||
| import {BuilderInfo} from '@docker/actions-toolkit/lib/types/buildx/builder'; | ||||
| 
 | ||||
| import {Inputs, sanitizeInputs} from './context'; | ||||
| 
 | ||||
| export const tmpDir = process.env['STATE_tmpDir'] || ''; | ||||
| export const inputs = process.env['STATE_inputs'] ? JSON.parse(process.env['STATE_inputs']) : undefined; | ||||
| export const builder = process.env['STATE_builder'] ? <BuilderInfo>JSON.parse(process.env['STATE_builder']) : undefined; | ||||
| export const buildRef = process.env['STATE_buildRef'] || ''; | ||||
| 
 | ||||
| export function setTmpDir(tmpDir: string) { | ||||
|   core.saveState('tmpDir', tmpDir); | ||||
| } | ||||
| 
 | ||||
| export function setInputs(inputs: Inputs) { | ||||
|   core.saveState('inputs', JSON.stringify(sanitizeInputs(inputs))); | ||||
| } | ||||
| 
 | ||||
| export function setBuilder(builder: BuilderInfo) { | ||||
|   core.saveState('builder', JSON.stringify(builder)); | ||||
| } | ||||
| 
 | ||||
| export function setBuildRef(buildRef: string) { | ||||
|   core.saveState('buildRef', buildRef); | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 CrazyMax
						CrazyMax