From c0b121fe44084a47a0893d4bad2947650b8ad82d Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Mon, 16 Aug 2021 23:44:13 +0200 Subject: [PATCH] Add `metadata` output Signed-off-by: CrazyMax --- .github/workflows/ci.yml | 24 ----------------------- README.md | 10 ++++------ __tests__/buildx.test.ts | 15 +++++++++++++++ __tests__/context.test.ts | 25 +++++++++++++++++++++++- action.yml | 2 ++ dist/index.js | 40 +++++++++++++++++++++++++++++++-------- src/buildx.ts | 12 ++++++++++++ src/context.ts | 4 +++- src/main.ts | 19 ++++++++++++------- 9 files changed, 104 insertions(+), 47 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bd30bed..3ba5de2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,9 +70,6 @@ jobs: 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: Check digest run: | @@ -133,9 +130,6 @@ jobs: 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: Check digest run: | @@ -191,9 +185,6 @@ jobs: 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: Check digest run: | @@ -392,9 +383,6 @@ jobs: 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: Check digest run: | @@ -447,9 +435,6 @@ jobs: name: Inspect (1) run: | docker buildx imagetools inspect localhost:5000/name/app:latest - - - name: Image digest (1) - run: echo ${{ steps.docker_build.outputs.digest }} - name: Check digest (1) run: | @@ -480,9 +465,6 @@ jobs: name: Inspect (2) run: | docker buildx imagetools inspect localhost:5000/name/app:latest - - - name: Image digest (2) - run: echo ${{ steps.docker_build2.outputs.digest }} - name: Check digest (2) run: | @@ -557,9 +539,6 @@ jobs: 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: Check digest run: | @@ -622,9 +601,6 @@ jobs: 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: Check digest run: | diff --git a/README.md b/README.md index 5bdb96e..f72ad4a 100644 --- a/README.md +++ b/README.md @@ -100,9 +100,6 @@ jobs: with: push: true tags: user/app:latest - - - name: Image digest - run: echo ${{ steps.docker_build.outputs.digest }} ``` Building from the current repository automatically uses the [GitHub Token](https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token) @@ -223,9 +220,10 @@ Following inputs can be used as `step.with` keys Following outputs are available -| Name | Type | Description | -|---------------|---------|---------------------------------------| -| `digest` | String | Image content-addressable identifier also called a digest | +| Name | Type | Description | +|-------------------|---------|---------------------------------------| +| `digest` | String | Image content-addressable identifier also called a digest | +| `metadata` | JSON | Build result metadata | ## Troubleshooting diff --git a/__tests__/buildx.test.ts b/__tests__/buildx.test.ts index 8e65651..e64ac90 100644 --- a/__tests__/buildx.test.ts +++ b/__tests__/buildx.test.ts @@ -8,6 +8,10 @@ import * as context from '../src/context'; const tmpNameSync = path.join('/tmp/.docker-build-push-jest', '.tmpname-jest').split(path.sep).join(path.posix.sep); const digest = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9'; +const metadata = `{ + "containerimage.config.digest": "sha256:059b68a595b22564a1cbc167af369349fdc2ecc1f7bc092c2235cbf601a795fd", + "containerimage.digest": "sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c" +}`; jest.spyOn(context, 'tmpDir').mockImplementation((): string => { const tmpDir = path.join('/tmp/.docker-build-push-jest').split(path.sep).join(path.posix.sep); @@ -32,6 +36,17 @@ describe('getImageID', () => { }); }); +describe('getMetadata', () => { + it('matches', async () => { + const metadataFile = await buildx.getMetadataFile(); + console.log(`metadataFile: ${metadataFile}`); + await fs.writeFileSync(metadataFile, metadata); + const expected = await buildx.getMetadata(); + console.log(`metadata: ${expected}`); + expect(expected).toEqual(metadata); + }); +}); + describe('isLocalOrTarExporter', () => { // prettier-ignore test.each([ diff --git a/__tests__/context.test.ts b/__tests__/context.test.ts index 3fc2cfe..3435701 100644 --- a/__tests__/context.test.ts +++ b/__tests__/context.test.ts @@ -425,7 +425,30 @@ ccc`], '--output', 'type=local,dest=./release-out', '.' ] - ] + ], + [ + '0.6.0', + new Map([ + ['context', '.'], + ['tag', 'localhost:5000/name/app:latest'], + ['file', './test/Dockerfile'], + ['network', 'host'], + ['load', 'false'], + ['no-cache', 'false'], + ['push', 'true'], + ['pull', 'false'] + ]), + [ + 'buildx', + 'build', + '--iidfile', '/tmp/.docker-build-push-jest/iidfile', + '--metadata-file', '/tmp/.docker-build-push-jest/metadata-file', + '--file', './test/Dockerfile', + '--network', 'host', + '--push', + '.' + ] + ], ])( 'given %p with %p as inputs, returns %p', async (buildxVersion: string, inputs: Map, expected: Array) => { diff --git a/action.yml b/action.yml index 49f08fb..abcfe2f 100644 --- a/action.yml +++ b/action.yml @@ -79,6 +79,8 @@ inputs: outputs: digest: description: 'Image content-addressable identifier also called a digest' + metadata: + description: 'Build result metadata' runs: using: 'node12' diff --git a/dist/index.js b/dist/index.js index ead03d6..8a233d7 100644 --- a/dist/index.js +++ b/dist/index.js @@ -38,7 +38,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.satisfies = exports.parseVersion = exports.getVersion = exports.isAvailable = exports.hasGitAuthToken = exports.isLocalOrTarExporter = exports.getSecret = exports.getSecretFile = exports.getSecretString = exports.getImageID = exports.getImageIDFile = void 0; +exports.satisfies = exports.parseVersion = exports.getVersion = exports.isAvailable = exports.hasGitAuthToken = exports.isLocalOrTarExporter = exports.getSecret = exports.getSecretFile = exports.getSecretString = exports.getMetadata = exports.getMetadataFile = exports.getImageID = exports.getImageIDFile = void 0; const sync_1 = __importDefault(__nccwpck_require__(8750)); const fs_1 = __importDefault(__nccwpck_require__(5747)); const path_1 = __importDefault(__nccwpck_require__(5622)); @@ -61,6 +61,22 @@ function getImageID() { }); } exports.getImageID = getImageID; +function getMetadataFile() { + return __awaiter(this, void 0, void 0, function* () { + return path_1.default.join(context.tmpDir(), 'metadata-file').split(path_1.default.sep).join(path_1.default.posix.sep); + }); +} +exports.getMetadataFile = getMetadataFile; +function getMetadata() { + return __awaiter(this, void 0, void 0, function* () { + const metadataFile = yield getMetadataFile(); + if (!fs_1.default.existsSync(metadataFile)) { + return undefined; + } + return fs_1.default.readFileSync(metadataFile, { encoding: 'utf-8' }); + }); +} +exports.getMetadata = getMetadata; function getSecretString(kvp) { return __awaiter(this, void 0, void 0, function* () { return getSecret(kvp, false); @@ -311,6 +327,9 @@ function getBuildArgs(inputs, defaultContext, buildxVersion) { if (!buildx.isLocalOrTarExporter(inputs.outputs) && (inputs.platforms.length == 0 || buildx.satisfies(buildxVersion, '>=0.4.2'))) { args.push('--iidfile', yield buildx.getImageIDFile()); } + if (buildx.satisfies(buildxVersion, '>=0.6.0')) { + args.push('--metadata-file', yield buildx.getMetadataFile()); + } yield exports.asyncForEach(inputs.cacheFrom, (cacheFrom) => __awaiter(this, void 0, void 0, function* () { args.push('--cache-from', cacheFrom); })); @@ -476,13 +495,18 @@ function run() { throw new Error(`buildx failed with: ${res.stderr.match(/(.*)\s*$/)[0].trim()}`); } }); - const imageID = yield buildx.getImageID(); - if (imageID) { - core.startGroup(`Extracting digest`); - core.info(`${imageID}`); - context.setOutput('digest', imageID); - core.endGroup(); - } + yield core.group(`Setting outputs`, () => __awaiter(this, void 0, void 0, function* () { + const imageID = yield buildx.getImageID(); + const metadata = yield buildx.getMetadata(); + if (imageID) { + core.info(`digest=${imageID}`); + context.setOutput('digest', imageID); + } + if (metadata) { + core.info(`metadata=${metadata}`); + context.setOutput('metadata', metadata); + } + })); } catch (error) { core.setFailed(error.message); diff --git a/src/buildx.ts b/src/buildx.ts index 116fd2a..77b450b 100644 --- a/src/buildx.ts +++ b/src/buildx.ts @@ -18,6 +18,18 @@ export async function getImageID(): Promise { return fs.readFileSync(iidFile, {encoding: 'utf-8'}); } +export async function getMetadataFile(): Promise { + return path.join(context.tmpDir(), 'metadata-file').split(path.sep).join(path.posix.sep); +} + +export async function getMetadata(): Promise { + const metadataFile = await getMetadataFile(); + if (!fs.existsSync(metadataFile)) { + return undefined; + } + return fs.readFileSync(metadataFile, {encoding: 'utf-8'}); +} + export async function getSecretString(kvp: string): Promise { return getSecret(kvp, false); } diff --git a/src/context.ts b/src/context.ts index 552b0fe..b951a9b 100644 --- a/src/context.ts +++ b/src/context.ts @@ -2,7 +2,6 @@ import csvparse from 'csv-parse/lib/sync'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -import * as semver from 'semver'; import * as tmp from 'tmp'; import * as core from '@actions/core'; @@ -122,6 +121,9 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, buildxVersio if (!buildx.isLocalOrTarExporter(inputs.outputs) && (inputs.platforms.length == 0 || buildx.satisfies(buildxVersion, '>=0.4.2'))) { args.push('--iidfile', await buildx.getImageIDFile()); } + if (buildx.satisfies(buildxVersion, '>=0.6.0')) { + args.push('--metadata-file', await buildx.getMetadataFile()); + } await asyncForEach(inputs.cacheFrom, async cacheFrom => { args.push('--cache-from', cacheFrom); }); diff --git a/src/main.ts b/src/main.ts index 4b6af66..d1ce06d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -33,13 +33,18 @@ async function run(): Promise { } }); - const imageID = await buildx.getImageID(); - if (imageID) { - core.startGroup(`Extracting digest`); - core.info(`${imageID}`); - context.setOutput('digest', imageID); - core.endGroup(); - } + await core.group(`Setting outputs`, async () => { + const imageID = await buildx.getImageID(); + const metadata = await buildx.getMetadata(); + if (imageID) { + core.info(`digest=${imageID}`); + context.setOutput('digest', imageID); + } + if (metadata) { + core.info(`metadata=${metadata}`); + context.setOutput('metadata', metadata); + } + }); } catch (error) { core.setFailed(error.message); }