Skip to content

Commit 9ba8a33

Browse files
committed
Allow configuration of files that are copied for docker compose (#8847)
This commit adds support for a `withFileCopyInclusions` method on `ComposeContainer` and `DockerComposeContainer`. It allows to specify what files or directories should be copied, instead of just copying all files. If not used, the current behaviour is preserved.
1 parent 18a7c27 commit 9ba8a33

File tree

4 files changed

+54
-11
lines changed

4 files changed

+54
-11
lines changed

core/src/main/java/org/testcontainers/containers/ComposeContainer.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ public class ComposeContainer extends FailureDetectingExternalResource implement
6767

6868
private String project;
6969

70+
private List<String> fileCopyInclusions = new ArrayList<>();
71+
7072
public ComposeContainer(File... composeFiles) {
7173
this(Arrays.asList(composeFiles));
7274
}
@@ -134,7 +136,8 @@ public void start() {
134136
this.options,
135137
this.services,
136138
this.scalingPreferences,
137-
this.env
139+
this.env,
140+
this.fileCopyInclusions
138141
);
139142
this.composeDelegate.startAmbassadorContainer();
140143
this.composeDelegate.waitUntilServiceStarted(this.tailChildContainers);
@@ -165,7 +168,7 @@ public void stop() {
165168
if (removeImages != null) {
166169
cmd += " --rmi " + removeImages.dockerRemoveImagesType();
167170
}
168-
this.composeDelegate.runWithCompose(this.localCompose, cmd, this.env);
171+
this.composeDelegate.runWithCompose(this.localCompose, cmd, this.env, this.fileCopyInclusions);
169172
} finally {
170173
this.project = this.composeDelegate.randomProjectId();
171174
}
@@ -352,6 +355,11 @@ public ComposeContainer withStartupTimeout(Duration startupTimeout) {
352355
return this;
353356
}
354357

358+
public ComposeContainer withFileCopyInclusions(String... fileCopyInclusions) {
359+
this.fileCopyInclusions = Arrays.asList(fileCopyInclusions);
360+
return this;
361+
}
362+
355363
public Optional<ContainerState> getContainerByServiceName(String serviceName) {
356364
return this.composeDelegate.getContainerByServiceName(serviceName);
357365
}

core/src/main/java/org/testcontainers/containers/ComposeDelegate.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ void createServices(
126126
final Set<String> options,
127127
final List<String> services,
128128
final Map<String, Integer> scalingPreferences,
129-
Map<String, String> env
129+
Map<String, String> env,
130+
List<String> fileCopyInclusions
130131
) {
131132
// services that have been explicitly requested to be started. If empty, all services should be started.
132133
final String serviceNameArgs = Stream
@@ -160,7 +161,7 @@ void createServices(
160161
}
161162

162163
// Run the docker compose container, which starts up the services
163-
runWithCompose(localCompose, command, env);
164+
runWithCompose(localCompose, command, env, fileCopyInclusions);
164165
}
165166

166167
private String getUpCommand(String options) {
@@ -237,18 +238,24 @@ private String getServiceNameFromContainer(com.github.dockerjava.api.model.Conta
237238
}
238239

239240
public void runWithCompose(boolean localCompose, String cmd) {
240-
runWithCompose(localCompose, cmd, Collections.emptyMap());
241+
runWithCompose(localCompose, cmd, Collections.emptyMap(), Collections.emptyList());
241242
}
242243

243-
public void runWithCompose(boolean localCompose, String cmd, Map<String, String> env) {
244+
public void runWithCompose(
245+
boolean localCompose,
246+
String cmd,
247+
Map<String, String> env,
248+
List<String> fileCopyInclusions
249+
) {
244250
Preconditions.checkNotNull(composeFiles);
245251
Preconditions.checkArgument(!composeFiles.isEmpty(), "No docker compose file have been provided");
246252

247253
final DockerCompose dockerCompose;
248254
if (localCompose) {
249255
dockerCompose = new LocalDockerCompose(this.executable, composeFiles, project);
250256
} else {
251-
dockerCompose = new ContainerisedDockerCompose(this.defaultImageName, composeFiles, project);
257+
dockerCompose =
258+
new ContainerisedDockerCompose(this.defaultImageName, composeFiles, project, fileCopyInclusions);
252259
}
253260

254261
dockerCompose.withCommand(cmd).withEnv(env).invoke();

core/src/main/java/org/testcontainers/containers/ContainerisedDockerCompose.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ class ContainerisedDockerCompose extends GenericContainer<ContainerisedDockerCom
2424

2525
public static final char UNIX_PATH_SEPARATOR = ':';
2626

27-
public ContainerisedDockerCompose(DockerImageName dockerImageName, List<File> composeFiles, String identifier) {
27+
public ContainerisedDockerCompose(
28+
DockerImageName dockerImageName,
29+
List<File> composeFiles,
30+
String identifier,
31+
List<String> fileCopyInclusions
32+
) {
2833
super(dockerImageName);
2934
addEnv(ENV_PROJECT_NAME, identifier);
3035

@@ -43,7 +48,22 @@ public ContainerisedDockerCompose(DockerImageName dockerImageName, List<File> co
4348
final String composeFileEnvVariableValue = Joiner.on(UNIX_PATH_SEPARATOR).join(absoluteDockerComposeFiles); // we always need the UNIX path separator
4449
logger().debug("Set env COMPOSE_FILE={}", composeFileEnvVariableValue);
4550
addEnv(ENV_COMPOSE_FILE, composeFileEnvVariableValue);
46-
withCopyFileToContainer(MountableFile.forHostPath(pwd), containerPwd);
51+
if (fileCopyInclusions.isEmpty()) {
52+
logger().info("Copying all files in {} into the container", pwd);
53+
withCopyFileToContainer(MountableFile.forHostPath(pwd), containerPwd);
54+
} else {
55+
// Always copy the compose file itself
56+
logger().info("Copying docker compose file: {}", dockerComposeBaseFile.getAbsolutePath());
57+
withCopyFileToContainer(
58+
MountableFile.forHostPath(dockerComposeBaseFile.getAbsolutePath()),
59+
convertToUnixFilesystemPath(dockerComposeBaseFile.getAbsolutePath())
60+
);
61+
for (String pathToCopy : fileCopyInclusions) {
62+
String hostPath = pwd + "/" + pathToCopy;
63+
logger().info("Copying inclusion file: {}", hostPath);
64+
withCopyFileToContainer(MountableFile.forHostPath(hostPath), convertToUnixFilesystemPath(hostPath));
65+
}
66+
}
4767

4868
// Ensure that compose can access docker. Since the container is assumed to be running on the same machine
4969
// as the docker daemon, just mapping the docker control socket is OK.

core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ public class DockerComposeContainer<SELF extends DockerComposeContainer<SELF>>
6868

6969
private String project;
7070

71+
private List<String> fileCopyInclusions = new ArrayList<>();
72+
7173
@Deprecated
7274
public DockerComposeContainer(File composeFile, String identifier) {
7375
this(identifier, composeFile);
@@ -140,7 +142,8 @@ public void start() {
140142
this.options,
141143
this.services,
142144
this.scalingPreferences,
143-
this.env
145+
this.env,
146+
this.fileCopyInclusions
144147
);
145148
this.composeDelegate.startAmbassadorContainer();
146149
this.composeDelegate.waitUntilServiceStarted(this.tailChildContainers);
@@ -172,7 +175,7 @@ public void stop() {
172175
if (removeImages != null) {
173176
cmd += " --rmi " + removeImages.dockerRemoveImagesType();
174177
}
175-
this.composeDelegate.runWithCompose(this.localCompose, cmd, this.env);
178+
this.composeDelegate.runWithCompose(this.localCompose, cmd, this.env, this.fileCopyInclusions);
176179
} finally {
177180
this.project = this.composeDelegate.randomProjectId();
178181
}
@@ -355,6 +358,11 @@ public SELF withStartupTimeout(Duration startupTimeout) {
355358
return self();
356359
}
357360

361+
public SELF withFileCopyInclusions(String... fileCopyInclusions) {
362+
this.fileCopyInclusions = Arrays.asList(fileCopyInclusions);
363+
return self();
364+
}
365+
358366
public Optional<ContainerState> getContainerByServiceName(String serviceName) {
359367
return this.composeDelegate.getContainerByServiceName(serviceName);
360368
}

0 commit comments

Comments
 (0)