From b17556aa246de08d1f6ccb165ed336ec8ae79f56 Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Thu, 10 Dec 2020 21:08:16 +0100 Subject: [PATCH] chore(core): show Docker build output for BundlingDockerImage.fromAsset() Remove the `-q` option and use a known tag derived from the path to the Dockerfile and the build options. --- packages/@aws-cdk/core/lib/bundling.ts | 36 +++++++++--------- packages/@aws-cdk/core/test/bundling.test.ts | 39 +++++++++----------- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/packages/@aws-cdk/core/lib/bundling.ts b/packages/@aws-cdk/core/lib/bundling.ts index 234b3ce969b42..c9a9c07e77f34 100644 --- a/packages/@aws-cdk/core/lib/bundling.ts +++ b/packages/@aws-cdk/core/lib/bundling.ts @@ -1,4 +1,5 @@ import { spawnSync, SpawnSyncOptions } from 'child_process'; +import * as crypto from 'crypto'; import { FileSystem } from './fs'; /** @@ -108,20 +109,21 @@ export class BundlingDockerImage { public static fromAsset(path: string, options: DockerBuildOptions = {}) { const buildArgs = options.buildArgs || {}; + // Image tag derived from path and build options + const tagHash = crypto.createHash('sha256').update(JSON.stringify({ + path, + ...options, + })).digest('hex'); + const tag = `cdk-${tagHash}`; + const dockerArgs: string[] = [ - 'build', '-q', + 'build', '-t', tag, ...(options.file ? ['-f', options.file] : []), ...flatten(Object.entries(buildArgs).map(([k, v]) => ['--build-arg', `${k}=${v}`])), path, ]; - const docker = dockerExec(dockerArgs); - - const match = docker.stdout.toString().match(/sha256:[a-z0-9]+/); - - if (!match) { - throw new Error('Failed to extract image ID from Docker build output'); - } + dockerExec(dockerArgs); // Fingerprints the directory containing the Dockerfile we're building and // differentiates the fingerprint based on build arguments. We do this so @@ -129,7 +131,7 @@ export class BundlingDockerImage { // different every time the Docker layer cache is cleared, due primarily to // timestamps. const hash = FileSystem.fingerprint(path, { extraHash: JSON.stringify(options) }); - return new BundlingDockerImage(match[0], hash); + return new BundlingDockerImage(tag, hash); } /** @param image The Docker image */ @@ -166,13 +168,7 @@ export class BundlingDockerImage { ...command, ]; - dockerExec(dockerArgs, { - stdio: [ // show Docker output - 'ignore', // ignore stdio - process.stderr, // redirect stdout to stderr - 'inherit', // inherit stderr - ], - }); + dockerExec(dockerArgs); } /** @@ -303,7 +299,13 @@ function flatten(x: string[][]) { function dockerExec(args: string[], options?: SpawnSyncOptions) { const prog = process.env.CDK_DOCKER ?? 'docker'; - const proc = spawnSync(prog, args, options); + const proc = spawnSync(prog, args, options ?? { + stdio: [ // show Docker output + 'ignore', // ignore stdio + process.stderr, // redirect stdout to stderr + 'inherit', // inherit stderr + ], + }); if (proc.error) { throw proc.error; diff --git a/packages/@aws-cdk/core/test/bundling.test.ts b/packages/@aws-cdk/core/test/bundling.test.ts index 5bc4c0d55e1be..e2b0d6b43b98b 100644 --- a/packages/@aws-cdk/core/test/bundling.test.ts +++ b/packages/@aws-cdk/core/test/bundling.test.ts @@ -1,4 +1,5 @@ import * as child_process from 'child_process'; +import * as crypto from 'crypto'; import * as path from 'path'; import { nodeunitShim, Test } from 'nodeunit-shim'; import * as sinon from 'sinon'; @@ -46,11 +47,10 @@ nodeunitShim({ }, 'bundling with image from asset'(test: Test) { - const imageId = 'sha256:abcdef123456'; const spawnSyncStub = sinon.stub(child_process, 'spawnSync').returns({ status: 0, stderr: Buffer.from('stderr'), - stdout: Buffer.from(imageId), + stdout: Buffer.from('stdout'), pid: 123, output: ['stdout', 'stderr'], signal: null, @@ -67,33 +67,27 @@ nodeunitShim({ }); image.run(); + const tagHash = crypto.createHash('sha256').update(JSON.stringify({ + path: 'docker-path', + buildArgs: { + TEST_ARG: 'cdk-test', + }, + })).digest('hex'); + const tag = `cdk-${tagHash}`; + test.ok(spawnSyncStub.firstCall.calledWith('docker', [ - 'build', '-q', + 'build', '-t', tag, '--build-arg', 'TEST_ARG=cdk-test', 'docker-path', ])); test.ok(spawnSyncStub.secondCall.calledWith('docker', [ 'run', '--rm', - imageId, + tag, ])); test.done(); }, - 'throws if image id cannot be extracted from build output'(test: Test) { - sinon.stub(child_process, 'spawnSync').returns({ - status: 0, - stderr: Buffer.from('stderr'), - stdout: Buffer.from('stdout'), - pid: 123, - output: ['stdout', 'stderr'], - signal: null, - }); - - test.throws(() => BundlingDockerImage.fromAsset('docker-path'), /Failed to extract image ID from Docker build output/); - test.done(); - }, - 'throws in case of spawnSync error'(test: Test) { sinon.stub(child_process, 'spawnSync').returns({ status: 0, @@ -133,11 +127,10 @@ nodeunitShim({ }, 'BundlerDockerImage json is the bundler image if building an image'(test: Test) { - const imageId = 'sha256:abcdef123456'; sinon.stub(child_process, 'spawnSync').returns({ status: 0, stderr: Buffer.from('stderr'), - stdout: Buffer.from(imageId), + stdout: Buffer.from('stdout'), pid: 123, output: ['stdout', 'stderr'], signal: null, @@ -148,7 +141,11 @@ nodeunitShim({ const image = BundlingDockerImage.fromAsset('docker-path'); - test.equals(image.image, imageId); + const tagHash = crypto.createHash('sha256').update(JSON.stringify({ + path: 'docker-path', + })).digest('hex'); + + test.equals(image.image, `cdk-${tagHash}`); test.equals(image.toJSON(), imageHash); test.ok(fingerprintStub.calledWith('docker-path', sinon.match({ extraHash: JSON.stringify({}) }))); test.done();