Skip to content

Commit 28b046a

Browse files
committed
Merge pull request #42571 from nosan
* pr/42571: Polish "Add property to specify Docker Compose flags" Add property to specify Docker Compose flags Closes gh-42571
2 parents 31fada6 + dd9a998 commit 28b046a

File tree

9 files changed

+103
-23
lines changed

9 files changed

+103
-23
lines changed

spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/core/DockerCliIntegrationTests.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,13 @@
2424
import java.time.Duration;
2525
import java.util.Collections;
2626
import java.util.List;
27+
import java.util.Set;
28+
import java.util.UUID;
2729

2830
import org.junit.jupiter.api.Test;
2931
import org.junit.jupiter.api.io.TempDir;
3032

33+
import org.springframework.boot.docker.compose.core.DockerCli.DockerComposeOptions;
3134
import org.springframework.boot.docker.compose.core.DockerCliCommand.ComposeConfig;
3235
import org.springframework.boot.docker.compose.core.DockerCliCommand.ComposeDown;
3336
import org.springframework.boot.docker.compose.core.DockerCliCommand.ComposePs;
@@ -60,22 +63,25 @@ class DockerCliIntegrationTests {
6063

6164
@Test
6265
void runBasicCommand() {
63-
DockerCli cli = new DockerCli(null, null, Collections.emptySet());
66+
DockerCli cli = new DockerCli(null, null);
6467
List<DockerCliContextResponse> context = cli.run(new DockerCliCommand.Context());
6568
assertThat(context).isNotEmpty();
6669
}
6770

6871
@Test
6972
void runLifecycle() throws IOException {
7073
File composeFile = createComposeFile("redis-compose.yaml");
71-
DockerCli cli = new DockerCli(null, DockerComposeFile.of(composeFile), Collections.emptySet());
74+
String projectName = UUID.randomUUID().toString();
75+
DockerCli cli = new DockerCli(null, new DockerComposeOptions(DockerComposeFile.of(composeFile),
76+
Collections.emptySet(), List.of("--project-name=" + projectName)));
7277
try {
7378
// Verify that no services are running (this is a fresh compose project)
7479
List<DockerCliComposePsResponse> ps = cli.run(new ComposePs());
7580
assertThat(ps).isEmpty();
7681
// List the config and verify that redis is there
7782
DockerCliComposeConfigResponse config = cli.run(new ComposeConfig());
7883
assertThat(config.services()).containsOnlyKeys("redis");
84+
assertThat(config.name()).isEqualTo(projectName);
7985
// Run up
8086
cli.run(new ComposeUp(LogLevel.INFO, Collections.emptyList()));
8187
// Run ps and use id to run inspect on the id
@@ -106,7 +112,8 @@ void runLifecycle() throws IOException {
106112
@Test
107113
void shouldWorkWithMultipleComposeFiles() throws IOException {
108114
List<File> composeFiles = createComposeFiles();
109-
DockerCli cli = new DockerCli(null, DockerComposeFile.of(composeFiles), Collections.emptySet());
115+
DockerCli cli = new DockerCli(null,
116+
new DockerComposeOptions(DockerComposeFile.of(composeFiles), Set.of("dev"), Collections.emptyList()));
110117
try {
111118
// List the config and verify that both redis are there
112119
DockerCliComposeConfigResponse config = cli.run(new ComposeConfig());
@@ -146,7 +153,8 @@ private static File createComposeFile(String resource) throws IOException {
146153
private static List<File> createComposeFiles() throws IOException {
147154
File file1 = createComposeFile("1.yaml");
148155
File file2 = createComposeFile("2.yaml");
149-
return List.of(file1, file2);
156+
File file3 = createComposeFile("3.yaml");
157+
return List.of(file1, file2, file3);
150158
}
151159

152160
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
services:
22
redis1:
3+
profiles: [ 'dev' ]
34
image: '{imageName}'
45
ports:
56
- '6379'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
services:
2+
redis3:
3+
profiles: [ 'prod' ]
4+
image: '{imageName}'
5+
ports:
6+
- '6379'

spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCli.java

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.springframework.boot.docker.compose.core.DockerCliCommand.Type;
3232
import org.springframework.boot.logging.LogLevel;
3333
import org.springframework.core.log.LogMessage;
34+
import org.springframework.util.CollectionUtils;
3435

3536
/**
3637
* Wrapper around {@code docker} and {@code docker-compose} command line tools.
@@ -49,22 +50,18 @@ class DockerCli {
4950

5051
private final DockerCommands dockerCommands;
5152

52-
private final DockerComposeFile composeFile;
53-
54-
private final Set<String> activeProfiles;
53+
private final DockerComposeOptions dockerComposeOptions;
5554

5655
/**
5756
* Create a new {@link DockerCli} instance.
5857
* @param workingDirectory the working directory or {@code null}
59-
* @param composeFile the Docker Compose file to use
60-
* @param activeProfiles the Docker Compose profiles to activate
58+
* @param dockerComposeOptions the Docker Compose options to use or {@code null}.
6159
*/
62-
DockerCli(File workingDirectory, DockerComposeFile composeFile, Set<String> activeProfiles) {
60+
DockerCli(File workingDirectory, DockerComposeOptions dockerComposeOptions) {
6361
this.processRunner = new ProcessRunner(workingDirectory);
6462
this.dockerCommands = dockerCommandsCache.computeIfAbsent(workingDirectory,
6563
(key) -> new DockerCommands(this.processRunner));
66-
this.composeFile = composeFile;
67-
this.activeProfiles = (activeProfiles != null) ? activeProfiles : Collections.emptySet();
64+
this.dockerComposeOptions = (dockerComposeOptions != null) ? dockerComposeOptions : DockerComposeOptions.none();
6865
}
6966

7067
/**
@@ -93,17 +90,25 @@ private List<String> createCommand(Type type) {
9390
case DOCKER -> new ArrayList<>(this.dockerCommands.get(type));
9491
case DOCKER_COMPOSE -> {
9592
List<String> result = new ArrayList<>(this.dockerCommands.get(type));
96-
if (this.composeFile != null) {
97-
for (File file : this.composeFile.getFiles()) {
93+
DockerComposeFile composeFile = this.dockerComposeOptions.composeFile();
94+
if (composeFile != null) {
95+
for (File file : composeFile.getFiles()) {
9896
result.add("--file");
9997
result.add(file.getPath());
10098
}
10199
}
102100
result.add("--ansi");
103101
result.add("never");
104-
for (String profile : this.activeProfiles) {
105-
result.add("--profile");
106-
result.add(profile);
102+
Set<String> activeProfiles = this.dockerComposeOptions.activeProfiles();
103+
if (!CollectionUtils.isEmpty(activeProfiles)) {
104+
for (String profile : activeProfiles) {
105+
result.add("--profile");
106+
result.add(profile);
107+
}
108+
}
109+
List<String> arguments = this.dockerComposeOptions.arguments();
110+
if (!CollectionUtils.isEmpty(arguments)) {
111+
result.addAll(arguments);
107112
}
108113
yield result;
109114
}
@@ -115,7 +120,7 @@ private List<String> createCommand(Type type) {
115120
* @return the Docker Compose file
116121
*/
117122
DockerComposeFile getDockerComposeFile() {
118-
return this.composeFile;
123+
return this.dockerComposeOptions.composeFile();
119124
}
120125

121126
/**
@@ -185,4 +190,22 @@ List<String> get(Type type) {
185190

186191
}
187192

193+
/**
194+
* Options for Docker Compose.
195+
*
196+
* @param composeFile the Docker Compose file to use
197+
* @param activeProfiles the profiles to activate
198+
* @param arguments the arguments to pass to Docker Compose
199+
*/
200+
record DockerComposeOptions(DockerComposeFile composeFile, Set<String> activeProfiles, List<String> arguments) {
201+
DockerComposeOptions {
202+
activeProfiles = (activeProfiles != null) ? activeProfiles : Collections.emptySet();
203+
arguments = (arguments != null) ? arguments : Collections.emptyList();
204+
}
205+
206+
static DockerComposeOptions none() {
207+
return new DockerComposeOptions(null, null, null);
208+
}
209+
}
210+
188211
}

spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCompose.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
package org.springframework.boot.docker.compose.core;
1818

1919
import java.time.Duration;
20+
import java.util.Collections;
2021
import java.util.List;
2122
import java.util.Set;
2223

24+
import org.springframework.boot.docker.compose.core.DockerCli.DockerComposeOptions;
2325
import org.springframework.boot.logging.LogLevel;
2426

2527
/**
@@ -125,7 +127,22 @@ public interface DockerCompose {
125127
* @return a {@link DockerCompose} instance
126128
*/
127129
static DockerCompose get(DockerComposeFile file, String hostname, Set<String> activeProfiles) {
128-
DockerCli cli = new DockerCli(null, file, activeProfiles);
130+
return get(file, hostname, activeProfiles, Collections.emptyList());
131+
}
132+
133+
/**
134+
* Factory method used to create a {@link DockerCompose} instance.
135+
* @param file the Docker Compose file
136+
* @param hostname the hostname used for services or {@code null} if the hostname
137+
* should be deduced
138+
* @param activeProfiles a set of the profiles that should be activated
139+
* @param arguments the arguments to pass to Docker Compose
140+
* @return a {@link DockerCompose} instance
141+
* @since 3.4.0
142+
*/
143+
static DockerCompose get(DockerComposeFile file, String hostname, Set<String> activeProfiles,
144+
List<String> arguments) {
145+
DockerCli cli = new DockerCli(null, new DockerComposeOptions(file, activeProfiles, arguments));
129146
return new DefaultDockerCompose(cli, hostname);
130147
}
131148

spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManager.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ void start() {
109109
}
110110
DockerComposeFile composeFile = getComposeFile();
111111
Set<String> activeProfiles = this.properties.getProfiles().getActive();
112-
DockerCompose dockerCompose = getDockerCompose(composeFile, activeProfiles);
112+
List<String> arguments = this.properties.getArguments();
113+
DockerCompose dockerCompose = getDockerCompose(composeFile, activeProfiles, arguments);
113114
if (!dockerCompose.hasDefinedServices()) {
114115
logger.warn(LogMessage.format("No services defined in Docker Compose file %s with active profiles %s",
115116
composeFile, activeProfiles));
@@ -159,8 +160,9 @@ protected DockerComposeFile getComposeFile() {
159160
return composeFile;
160161
}
161162

162-
protected DockerCompose getDockerCompose(DockerComposeFile composeFile, Set<String> activeProfiles) {
163-
return DockerCompose.get(composeFile, this.properties.getHost(), activeProfiles);
163+
protected DockerCompose getDockerCompose(DockerComposeFile composeFile, Set<String> activeProfiles,
164+
List<String> arguments) {
165+
return DockerCompose.get(composeFile, this.properties.getHost(), activeProfiles, arguments);
164166
}
165167

166168
private boolean isIgnored(RunningService service) {

spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeProperties.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ public class DockerComposeProperties {
4646
*/
4747
private boolean enabled = true;
4848

49+
/**
50+
* Arguments to pass to the Docker Compose command.
51+
*/
52+
private final List<String> arguments = new ArrayList<>();
53+
4954
/**
5055
* Paths to the Docker Compose configuration files.
5156
*/
@@ -88,6 +93,10 @@ public void setEnabled(boolean enabled) {
8893
this.enabled = enabled;
8994
}
9095

96+
public List<String> getArguments() {
97+
return this.arguments;
98+
}
99+
91100
public List<File> getFile() {
92101
return this.file;
93102
}

spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManagerTests.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ class DockerComposeLifecycleManagerTests {
7575

7676
private Set<String> activeProfiles;
7777

78+
private List<String> arguments;
79+
7880
private GenericApplicationContext applicationContext;
7981

8082
private TestSpringApplicationShutdownHandlers shutdownHandlers;
@@ -358,6 +360,14 @@ void startGetsDockerComposeWithActiveProfiles() {
358360
assertThat(this.activeProfiles).containsExactly("my-profile");
359361
}
360362

363+
@Test
364+
void startGetsDockerComposeWithArguments() {
365+
this.properties.getArguments().add("--project-name=test");
366+
setUpRunningServices();
367+
this.lifecycleManager.start();
368+
assertThat(this.arguments).containsExactly("--project-name=test");
369+
}
370+
361371
@Test
362372
void startPublishesEvent() {
363373
EventCapturingListener listener = new EventCapturingListener();
@@ -519,8 +529,10 @@ protected DockerComposeFile getComposeFile() {
519529
}
520530

521531
@Override
522-
protected DockerCompose getDockerCompose(DockerComposeFile composeFile, Set<String> activeProfiles) {
532+
protected DockerCompose getDockerCompose(DockerComposeFile composeFile, Set<String> activeProfiles,
533+
List<String> arguments) {
523534
DockerComposeLifecycleManagerTests.this.activeProfiles = activeProfiles;
535+
DockerComposeLifecycleManagerTests.this.arguments = arguments;
524536
return DockerComposeLifecycleManagerTests.this.dockerCompose;
525537
}
526538

spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/DockerComposePropertiesTests.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ void getWhenNoPropertiesReturnsNew() {
6363
@Test
6464
void getWhenPropertiesReturnsBound() {
6565
Map<String, String> source = new LinkedHashMap<>();
66+
source.put("spring.docker.compose.arguments", "--project-name=test,--progress=auto");
6667
source.put("spring.docker.compose.file", "my-compose.yml");
6768
source.put("spring.docker.compose.lifecycle-management", "start-only");
6869
source.put("spring.docker.compose.host", "myhost");
@@ -76,6 +77,7 @@ void getWhenPropertiesReturnsBound() {
7677
source.put("spring.docker.compose.readiness.tcp.read-timeout", "500ms");
7778
Binder binder = new Binder(new MapConfigurationPropertySource(source));
7879
DockerComposeProperties properties = DockerComposeProperties.get(binder);
80+
assertThat(properties.getArguments()).containsExactly("--project-name=test", "--progress=auto");
7981
assertThat(properties.getFile()).containsExactly(new File("my-compose.yml"));
8082
assertThat(properties.getLifecycleManagement()).isEqualTo(LifecycleManagement.START_ONLY);
8183
assertThat(properties.getHost()).isEqualTo("myhost");

0 commit comments

Comments
 (0)