Skip to content

Commit ea703d0

Browse files
MrArnoldPalmershivlaks
authored andcommitted
fix(cdk-assets): context path not honored by Docker asset build (#6957)
Prior v1.29.0, the context passed to the docker build command was always the current working directory. In v1.29.0, this was changed to be the directory the user passed when instantiating the asset. However, docker doesn't respect the context passed to the build command when the `--file` argument is also passed. This broke assets for users passing the `file` prop when constructing a `DockerImageAsset`. This is fixed by changing the current working directory of the `docker build` command and passing that context as `.`. Then docker uses the current working directory as the context and correctly finds the image definition file from the `file` prop. An existing integration test in the framework covers this case, but does not fail unless the stack is deployed fresh since the asset isn't rebuilt when the hash is not changed. Fix: #6954 #6814
1 parent 4f54ff7 commit ea703d0

File tree

3 files changed

+14
-8
lines changed

3 files changed

+14
-8
lines changed

packages/cdk-assets/lib/private/docker.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ export class Docker {
3737
'--tag', options.tag,
3838
...options.target ? ['--target', options.target] : [],
3939
...options.file ? ['--file', options.file] : [],
40-
options.directory,
40+
'.'
4141
];
42-
await this.execute(buildCommand);
42+
await this.execute(buildCommand, { cwd: options.directory });
4343
}
4444

4545
/**
@@ -100,4 +100,4 @@ async function obtainEcrCredentials(ecr: AWS.ECR, logger?: Logger) {
100100

101101
function flatten(x: string[][]) {
102102
return Array.prototype.concat([], ...x);
103-
}
103+
}

packages/cdk-assets/test/docker-images.test.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { mockAws, mockedApiFailure, mockedApiResult } from './mock-aws';
77
import { mockSpawn } from './mock-child_process';
88

99
let aws: ReturnType<typeof mockAws>;
10+
const absoluteDockerPath = '/simple/cdk.out/dockerdir';
1011
beforeEach(() => {
1112
mockfs({
1213
'/simple/cdk.out/assets.json': JSON.stringify({
@@ -33,7 +34,7 @@ beforeEach(() => {
3334
dockerImages: {
3435
theAsset: {
3536
source: {
36-
directory: '/simple/cdk.out/dockerdir'
37+
directory: absoluteDockerPath
3738
},
3839
destinations: {
3940
theDestination: {
@@ -112,7 +113,7 @@ describe('with a complete manifest', () => {
112113
mockSpawn(
113114
{ commandLine: ['docker', 'login', '--username', 'user', '--password-stdin', 'https://proxy.com/'] },
114115
{ commandLine: ['docker', 'inspect', 'cdkasset-theasset'], exitCode: 1 },
115-
{ commandLine: ['docker', 'build', '--tag', 'cdkasset-theasset', '/simple/cdk.out/dockerdir'] },
116+
{ commandLine: ['docker', 'build', '--tag', 'cdkasset-theasset', '.'], cwd: absoluteDockerPath },
116117
{ commandLine: ['docker', 'tag', 'cdkasset-theasset', '12345.amazonaws.com/repo:abcdef'] },
117118
{ commandLine: ['docker', 'push', '12345.amazonaws.com/repo:abcdef'] },
118119
);
@@ -135,7 +136,7 @@ test('correctly identify Docker directory if path is absolute', async () => {
135136
// Only care about the 'build' command line
136137
{ commandLine: ['docker', 'login'], prefix: true, },
137138
{ commandLine: ['docker', 'inspect'], exitCode: 1, prefix: true },
138-
{ commandLine: ['docker', 'build', '--tag', 'cdkasset-theasset', '/simple/cdk.out/dockerdir'] },
139+
{ commandLine: ['docker', 'build', '--tag', 'cdkasset-theasset', '.'], cwd: absoluteDockerPath },
139140
{ commandLine: ['docker', 'tag'], prefix: true },
140141
{ commandLine: ['docker', 'push'], prefix: true },
141142
);

packages/cdk-assets/test/mock-child_process.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ if (!(child_process as any).spawn.mockImplementationOnce) {
77

88
export interface Invocation {
99
commandLine: string[];
10+
cwd?: string;
1011
exitCode?: number;
1112
stdout?: string;
1213

@@ -20,7 +21,7 @@ export function mockSpawn(...invocations: Invocation[]) {
2021
let mock = (child_process.spawn as any);
2122
for (const _invocation of invocations) {
2223
const invocation = _invocation; // Mirror into variable for closure
23-
mock = mock.mockImplementationOnce((binary: string, args: string[], _options: any) => {
24+
mock = mock.mockImplementationOnce((binary: string, args: string[], options: child_process.SpawnOptions) => {
2425
if (invocation.prefix) {
2526
// Match command line prefix
2627
expect([binary, ...args].slice(0, invocation.commandLine.length)).toEqual(invocation.commandLine);
@@ -29,6 +30,10 @@ export function mockSpawn(...invocations: Invocation[]) {
2930
expect([binary, ...args]).toEqual(invocation.commandLine);
3031
}
3132

33+
if (invocation.cwd != null) {
34+
expect(options.cwd).toBe(invocation.cwd);
35+
}
36+
3237
const child: any = new events.EventEmitter();
3338
child.stdin = new events.EventEmitter();
3439
child.stdin.write = jest.fn();
@@ -57,4 +62,4 @@ function mockEmit(emitter: events.EventEmitter, event: string, data: any) {
5762
setImmediate(() => {
5863
emitter.emit(event, data);
5964
});
60-
}
65+
}

0 commit comments

Comments
 (0)