diff --git a/packages/@aws-cdk/core/lib/bundling.ts b/packages/@aws-cdk/core/lib/bundling.ts index b472515026eaf..27045fd77c1e7 100644 --- a/packages/@aws-cdk/core/lib/bundling.ts +++ b/packages/@aws-cdk/core/lib/bundling.ts @@ -272,6 +272,7 @@ export class DockerImage extends BundlingDockerImage { 'build', '-t', tag, ...(options.file ? ['-f', join(path, options.file)] : []), ...(options.platform ? ['--platform', options.platform] : []), + ...(options.targetStage ? ['--target', options.targetStage] : []), ...flatten(Object.entries(buildArgs).map(([k, v]) => ['--build-arg', `${k}=${v}`])), path, ]; @@ -487,6 +488,15 @@ export interface DockerBuildOptions { * @default - no platform specified */ readonly platform?: string; + + /** + * Set build target for multi-stage container builds. Any stage defined afterwards will be ignored. + * + * Example value: `build-env` + * + * @default - Build all stages defined in the Dockerfile + */ + readonly targetStage?: string; } function flatten(x: string[][]) { diff --git a/packages/@aws-cdk/core/test/bundling.test.ts b/packages/@aws-cdk/core/test/bundling.test.ts index 5030603bb7c41..65b4f6247ba81 100644 --- a/packages/@aws-cdk/core/test/bundling.test.ts +++ b/packages/@aws-cdk/core/test/bundling.test.ts @@ -103,7 +103,7 @@ describe('bundling', () => { fingerprintStub.callsFake(() => imageHash); const platform = 'linux/someArch99'; - const image = DockerImage.fromBuild('docker-path', { platform }); + const image = DockerImage.fromBuild('docker-path', { platform: platform }); image.run(); const tagHash = crypto.createHash('sha256').update(JSON.stringify({ @@ -125,6 +125,44 @@ describe('bundling', () => { }); + test('bundling with image from asset with target stage', () => { + const spawnSyncStub = sinon.stub(child_process, 'spawnSync').returns({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + const imageHash = '123456abcdef'; + const fingerprintStub = sinon.stub(FileSystem, 'fingerprint'); + fingerprintStub.callsFake(() => imageHash); + const targetStage = 'i-love-testing'; + + const image = DockerImage.fromBuild('docker-path', { targetStage: targetStage }); + image.run(); + + const tagHash = crypto.createHash('sha256').update(JSON.stringify({ + path: 'docker-path', + targetStage, + })).digest('hex'); + const tag = `cdk-${tagHash}`; + + expect(spawnSyncStub.firstCall.calledWith('docker', [ + 'build', '-t', tag, + '--target', targetStage, + 'docker-path', + ])).toEqual(true); + + expect(spawnSyncStub.secondCall.calledWith('docker', [ + 'run', '--rm', + tag, + ])).toEqual(true); + + }); + + test('throws in case of spawnSync error', () => { sinon.stub(child_process, 'spawnSync').returns({ status: 0,