Skip to content

Commit c51596e

Browse files
jogoldrix0rrr
authored andcommitted
feat(toolkit): allow to pass build args to docker build (#2604)
1 parent 96c2842 commit c51596e

File tree

7 files changed

+108
-5
lines changed

7 files changed

+108
-5
lines changed

packages/@aws-cdk/assets-docker/README.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,20 @@ This will instruct the toolkit to build a Docker image from `my-image`, push it
2020
to an AWS ECR repository and wire the name of the repository as CloudFormation
2121
parameters to your stack.
2222

23-
Use `asset.imageUri` can be used to reference the image (it includes both the
24-
ECR image URL and tag.
23+
Use `asset.imageUri` to reference the image (it includes both the ECR image URL
24+
and tag.
25+
26+
You can optionally pass build args to the `docker build` command by specifying
27+
the `buildArgs` property:
28+
29+
```typescript
30+
const asset = new DockerImageAsset(this, 'MyBuildImage', {
31+
directory: path.join(__dirname, 'my-image'),
32+
buildArgs: {
33+
HTTP_PROXY: 'http://10.20.30.2:1234'
34+
}
35+
});
36+
```
2537

2638
### Pull Permissions
2739

packages/@aws-cdk/assets-docker/lib/image-asset.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ export interface DockerImageAssetProps {
2222
* @default automatically derived from the asset's ID.
2323
*/
2424
readonly repositoryName?: string;
25+
26+
/**
27+
* Build args to pass to the `docker build` command
28+
*
29+
* @default no build args are passed
30+
*/
31+
readonly buildArgs?: { [key: string]: string };
2532
}
2633

2734
/**
@@ -75,6 +82,7 @@ export class DockerImageAsset extends cdk.Construct {
7582
id: this.node.uniqueId,
7683
imageNameParameter: imageNameParameter.logicalId,
7784
repositoryName: props.repositoryName,
85+
buildArgs: props.buildArgs
7886
};
7987

8088
this.node.addMetadata(cxapi.ASSET_METADATA, asset);

packages/@aws-cdk/assets-docker/test/test.image-asset.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,24 @@ export = {
3131
test.done();
3232
},
3333

34+
'with build args'(test: Test) {
35+
// GIVEN
36+
const stack = new cdk.Stack();
37+
38+
// WHEN
39+
const asset = new DockerImageAsset(stack, 'Image', {
40+
directory: path.join(__dirname, 'demo-image'),
41+
buildArgs: {
42+
a: 'b'
43+
}
44+
});
45+
46+
// THEN
47+
const assetMetadata = asset.node.metadata.find(({ type }) => type === 'aws:cdk:asset');
48+
test.deepEqual(assetMetadata && assetMetadata.data.buildArgs, { a: 'b' });
49+
test.done();
50+
},
51+
3452
'asset.repository.grantPull can be used to grant a principal permissions to use the image'(test: Test) {
3553
// GIVEN
3654
const stack = new cdk.Stack();

packages/@aws-cdk/aws-ecs/lib/images/asset-image.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ export interface AssetImageProps {
99
* The directory where the Dockerfile is stored
1010
*/
1111
readonly directory: string;
12+
13+
/**
14+
* Build args to pass to the `docker build` command
15+
*
16+
* @default no build args are passed
17+
*/
18+
readonly buildArgs?: { [key: string]: string };
1219
}
1320

1421
/**
@@ -19,7 +26,10 @@ export class AssetImage extends ContainerImage {
1926

2027
constructor(scope: cdk.Construct, id: string, props: AssetImageProps) {
2128
super();
22-
this.asset = new DockerImageAsset(scope, id, { directory: props.directory });
29+
this.asset = new DockerImageAsset(scope, id, {
30+
directory: props.directory,
31+
buildArgs: props.buildArgs,
32+
});
2333
}
2434

2535
public bind(containerDefinition: ContainerDefinition): void {

packages/@aws-cdk/cx-api/lib/metadata/assets.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,16 @@ export interface ContainerImageAssetMetadataEntry {
8181
* Note, this is only the repository name, without the registry and
8282
* the tag parts.
8383
*
84-
* * @default automatically derived from the asset's ID.
84+
* @default automatically derived from the asset's ID.
8585
*/
8686
readonly repositoryName?: string;
87+
88+
/**
89+
* Build args to pass to the `docker build` command
90+
*
91+
* @default no build args are passed
92+
*/
93+
readonly buildArgs?: { [key: string]: string };
8794
}
8895

8996
export type AssetMetadataEntry = FileAssetMetadataEntry | ContainerImageAssetMetadataEntry;

packages/aws-cdk/lib/docker.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ export async function prepareContainerAsset(asset: ContainerImageAssetMetadataEn
6464

6565
const baseCommand = ['docker',
6666
'build',
67+
...Object.entries(asset.buildArgs || {}).map(([k, v]) => `--build-arg ${k}=${v}`), // Pass build args if any
6768
'--quiet',
6869
asset.path];
70+
6971
const command = ci
7072
? [...baseCommand, '--cache-from', latest] // This does not fail if latest is not available
7173
: baseCommand;

packages/aws-cdk/test/test.docker.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import cxapi = require('@aws-cdk/cx-api');
22
import { Test } from 'nodeunit';
3+
import sinon = require('sinon');
34
import { ToolkitInfo } from '../lib';
45
import { prepareContainerAsset } from '../lib/docker';
6+
import os = require('../lib/os');
57
import { MockSDK } from './util/mock-sdk';
68

79
export = {
@@ -51,4 +53,48 @@ export = {
5153

5254
test.done();
5355
},
54-
};
56+
57+
async 'passes the correct args to docker build'(test: Test) {
58+
// GIVEN
59+
const toolkit = new ToolkitInfo({
60+
sdk: new MockSDK(),
61+
bucketName: 'BUCKET_NAME',
62+
bucketEndpoint: 'BUCKET_ENDPOINT',
63+
environment: { name: 'env', account: '1234', region: 'abc' }
64+
});
65+
66+
const prepareEcrRepositoryStub = sinon.stub(toolkit, 'prepareEcrRepository').resolves({
67+
repositoryUri: 'uri',
68+
repositoryName: 'name'
69+
});
70+
71+
const shellStub = sinon.stub(os, 'shell').rejects('STOPTEST');
72+
73+
// WHEN
74+
const asset: cxapi.ContainerImageAssetMetadataEntry = {
75+
id: 'assetId',
76+
imageNameParameter: 'MyParameter',
77+
packaging: 'container-image',
78+
path: '/foo',
79+
repositoryName: 'some-name',
80+
buildArgs: {
81+
a: 'b',
82+
c: 'd'
83+
}
84+
};
85+
86+
try {
87+
await prepareContainerAsset(asset, toolkit, false);
88+
} catch (e) {
89+
if (!/STOPTEST/.test(e.toString())) { throw e; }
90+
}
91+
92+
// THEN
93+
const command = ['docker', 'build', '--build-arg a=b', '--build-arg c=d', '--quiet', '/foo'];
94+
test.ok(shellStub.calledWith(command));
95+
96+
prepareEcrRepositoryStub.restore();
97+
shellStub.restore();
98+
test.done();
99+
}
100+
};

0 commit comments

Comments
 (0)