diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5b1febccb..826a5b9ae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -499,6 +499,71 @@ jobs: if: always() uses: crazy-max/ghaction-dump-context@v1 + digest: + runs-on: ubuntu-latest + env: + DOCKER_IMAGE: localhost:5000/name/app + strategy: + fail-fast: false + matrix: + include: + - driver: docker + load: false + push: true + - driver: docker + load: true + push: false + - driver: docker-container + load: false + push: true + - driver: docker-container + load: true + push: false + services: + registry: + image: registry:2 + ports: + - 5000:5000 + steps: + - + name: Checkout + uses: actions/checkout@v2 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + with: + version: https://github.com/crazy-max/buildx.git#moby-imgdgst + driver: ${{ matrix.driver }} + driver-opts: | + network=host + image=moby/buildkit:master + - + name: Build + id: docker_build + uses: ./ + with: + context: ./test + load: ${{ matrix.load }} + push: ${{ matrix.push }} + tags: ${{ env.DOCKER_IMAGE }}:latest + platforms: ${{ matrix.platforms }} + - + name: Docker images + run: | + docker image ls --no-trunc + - + name: Check manifest + if: ${{ matrix.push }} + run: | + set -x + docker buildx imagetools inspect ${{ env.DOCKER_IMAGE }}@${{ steps.docker_build.outputs.digest }} --format '{{json .}}' + - + name: Inspect image + if: ${{ matrix.load }} + run: | + set -x + docker image inspect ${{ steps.docker_build.outputs.imageid }} + registry-cache: runs-on: ubuntu-latest services: diff --git a/README.md b/README.md index a05373609..8be7ccf86 100644 --- a/README.md +++ b/README.md @@ -241,7 +241,8 @@ Following outputs are available | Name | Type | Description | |-------------------|---------|---------------------------------------| -| `digest` | String | Image content-addressable identifier also called a digest | +| `imageid` | String | Image ID | +| `digest` | String | Image digest | | `metadata` | JSON | Build result metadata | ## Troubleshooting diff --git a/__tests__/buildx.test.ts b/__tests__/buildx.test.ts index 028b00140..d8855f609 100644 --- a/__tests__/buildx.test.ts +++ b/__tests__/buildx.test.ts @@ -7,7 +7,7 @@ import * as buildx from '../src/buildx'; 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 imageID = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9'; const metadata = `{ "containerimage.config.digest": "sha256:059b68a595b22564a1cbc167af369349fdc2ecc1f7bc092c2235cbf601a795fd", "containerimage.digest": "sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c" @@ -28,9 +28,9 @@ jest.spyOn(context, 'tmpNameSync').mockImplementation((): string => { describe('getImageID', () => { it('matches', async () => { const imageIDFile = await buildx.getImageIDFile(); - await fs.writeFileSync(imageIDFile, digest); - const imageID = await buildx.getImageID(); - expect(imageID).toEqual(digest); + await fs.writeFileSync(imageIDFile, imageID); + const expected = await buildx.getImageID(); + expect(expected).toEqual(imageID); }); }); @@ -43,6 +43,15 @@ describe('getMetadata', () => { }); }); +describe('getDigest', () => { + it('matches', async () => { + const metadataFile = await buildx.getMetadataFile(); + await fs.writeFileSync(metadataFile, metadata); + const expected = await buildx.getDigest(metadata); + expect(expected).toEqual('sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c'); + }); +}); + describe('isLocalOrTarExporter', () => { // prettier-ignore test.each([ diff --git a/action.yml b/action.yml index d6f58183e..a7c917753 100644 --- a/action.yml +++ b/action.yml @@ -89,8 +89,10 @@ inputs: required: false outputs: + imageid: + description: 'Image ID' digest: - description: 'Image content-addressable identifier also called a digest' + description: 'Image digest' metadata: description: 'Build result metadata' diff --git a/dist/index.js b/dist/index.js index 9340fde65..14484e46a 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.getMetadata = exports.getMetadataFile = 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.getDigest = 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)); @@ -81,6 +81,19 @@ function getMetadata() { }); } exports.getMetadata = getMetadata; +function getDigest(metadata) { + return __awaiter(this, void 0, void 0, function* () { + if (metadata === undefined) { + return undefined; + } + const metadataJSON = JSON.parse(metadata); + if (metadataJSON['containerimage.digest']) { + return metadataJSON['containerimage.digest']; + } + return undefined; + }); +} +exports.getDigest = getDigest; function getSecretString(kvp) { return __awaiter(this, void 0, void 0, function* () { return getSecret(kvp, false); @@ -517,15 +530,22 @@ function run() { } }); const imageID = yield buildx.getImageID(); + const metadata = yield buildx.getMetadata(); + const digest = yield buildx.getDigest(metadata); if (imageID) { - yield core.group(`Digest output`, () => __awaiter(this, void 0, void 0, function* () { + yield core.group(`ImageID`, () => __awaiter(this, void 0, void 0, function* () { core.info(imageID); - context.setOutput('digest', imageID); + context.setOutput('imageid', imageID); + })); + } + if (digest) { + yield core.group(`Digest`, () => __awaiter(this, void 0, void 0, function* () { + core.info(digest); + context.setOutput('digest', digest); })); } - const metadata = yield buildx.getMetadata(); if (metadata) { - yield core.group(`Metadata output`, () => __awaiter(this, void 0, void 0, function* () { + yield core.group(`Metadata`, () => __awaiter(this, void 0, void 0, function* () { core.info(metadata); context.setOutput('metadata', metadata); })); diff --git a/src/buildx.ts b/src/buildx.ts index 157f21c8b..6d065a7f5 100644 --- a/src/buildx.ts +++ b/src/buildx.ts @@ -34,6 +34,17 @@ export async function getMetadata(): Promise { return content; } +export async function getDigest(metadata: string | undefined): Promise { + if (metadata === undefined) { + return undefined; + } + const metadataJSON = JSON.parse(metadata); + if (metadataJSON['containerimage.digest']) { + return metadataJSON['containerimage.digest']; + } + return undefined; +} + export async function getSecretString(kvp: string): Promise { return getSecret(kvp, false); } diff --git a/src/main.ts b/src/main.ts index ceb4b3660..3c98e3df6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -34,16 +34,23 @@ async function run(): Promise { }); const imageID = await buildx.getImageID(); + const metadata = await buildx.getMetadata(); + const digest = await buildx.getDigest(metadata); + if (imageID) { - await core.group(`Digest output`, async () => { + await core.group(`ImageID`, async () => { core.info(imageID); - context.setOutput('digest', imageID); + context.setOutput('imageid', imageID); + }); + } + if (digest) { + await core.group(`Digest`, async () => { + core.info(digest); + context.setOutput('digest', digest); }); } - - const metadata = await buildx.getMetadata(); if (metadata) { - await core.group(`Metadata output`, async () => { + await core.group(`Metadata`, async () => { core.info(metadata); context.setOutput('metadata', metadata); });