Skip to content

Commit

Permalink
Merge pull request #208 from crazy-max/build-summary
Browse files Browse the repository at this point in the history
export build record and generate summary
  • Loading branch information
crazy-max committed Jun 17, 2024
2 parents bc96707 + bc3c21b commit 6460b33
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 4 deletions.
24 changes: 24 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -522,3 +522,27 @@ 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
-
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 }}
network=host
-
name: Build
uses: ./
with:
files: |
./test/config.hcl
targets: app
env:
DOCKER_BUILD_NO_SUMMARY: true
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ ___
* [Customizing](#customizing)
* [inputs](#inputs)
* [outputs](#outputs)
* [environment variables](#environment-variables)
* [Subactions](#subactions)
* [`list-targets`](#list-targets)
* [Contributing](#contributing)
Expand Down Expand Up @@ -255,6 +256,12 @@ The following outputs are available
|------------|----------|----------------------------|
| `targets` | List/CSV | List of extracted targest |
### 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 |
## Contributing
Want to contribute? Awesome! You can find information about contributing to
Expand Down
4 changes: 2 additions & 2 deletions dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,28 @@ 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;
}
if (key === 'workdir' && value === '.') {
continue;
}
res[key] = value;
}
return res;
}

export async function getArgs(inputs: Inputs, definition: BakeDefinition, toolkit: Toolkit): Promise<Array<string>> {
// prettier-ignore
return [
Expand Down
84 changes: 83 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ import * as path from 'path';
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 {BakeDefinition} from '@docker/actions-toolkit/lib/types/buildx/bake';
import {ConfigFile} from '@docker/actions-toolkit/lib/types/docker/docker';
Expand All @@ -18,7 +21,12 @@ import * as stateHelper from './state-helper';
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();
const gitAuthToken = process.env.BUILDX_BAKE_GIT_AUTH_TOKEN ?? inputs['github-token'];

Expand Down Expand Up @@ -78,6 +86,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);
});

let definition: BakeDefinition | undefined;
Expand All @@ -103,6 +112,7 @@ actionsToolkit.run(
if (!definition) {
throw new Error('Bake definition not set');
}
stateHelper.setBakeDefinition(definition);

const args: string[] = await context.getArgs(inputs, definition, toolkit);
const buildCmd = await toolkit.buildx.getCommand(args);
Expand All @@ -119,13 +129,14 @@ actionsToolkit.run(
});
});

let err: Error | undefined;
await Exec.getExecOutput(buildCmd.command, buildCmd.args, {
cwd: inputs.workdir,
env: buildEnv,
ignoreReturnCode: true
}).then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(`buildx bake failed with: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
err = Error(`buildx bake failed with: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
}
});

Expand All @@ -137,13 +148,84 @@ actionsToolkit.run(
core.setOutput('metadata', metadatadt);
});
}
await core.group(`Build references`, async () => {
const refs = await buildRefs(toolkit, startedTime, inputs.builder);
if (refs) {
for (const ref of refs) {
core.info(ref);
}
stateHelper.setBuildRefs(refs);
} else {
core.warning('No build refs found');
}
});
if (err) {
throw err;
}
},
// post
async () => {
if (stateHelper.buildRefs.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.buildRefs
});
core.info(`Build records 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,
bakeDefinition: stateHelper.bakeDefinition
});
} 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});
});
}
}
);

async function buildRefs(toolkit: Toolkit, since: Date, builder?: string): Promise<Array<string>> {
// get refs from metadata file
const metaRefs = toolkit.buildxBake.resolveRefs();
if (metaRefs) {
return metaRefs;
}
// 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 res = Buildx.refs({
dir: Buildx.refsDir,
builderName: builder,
since: since
});
const refs: Array<string> = [];
for (const ref in res) {
if (Object.prototype.hasOwnProperty.call(res, ref)) {
refs.push(ref);
}
}
return refs;
}
25 changes: 25 additions & 0 deletions src/state-helper.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,32 @@
import * as core from '@actions/core';

import {BakeDefinition} from '@docker/actions-toolkit/lib/types/buildx/bake';
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 bakeDefinition = process.env['STATE_bakeDefinition'] ? <BakeDefinition>JSON.parse(process.env['STATE_bakeDefinition']) : undefined;
export const buildRefs = process.env['STATE_buildRefs'] ? process.env['STATE_buildRefs'].split(',') : [];

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 setBakeDefinition(bakeDefinition: BakeDefinition) {
core.saveState('bakeDefinition', JSON.stringify(bakeDefinition));
}

export function setBuildRefs(buildRefs: Array<string>) {
core.saveState('buildRefs', buildRefs.join(','));
}

0 comments on commit 6460b33

Please sign in to comment.