From dd9a998cfe3b760ccd0ccd330b85231a5ef825df Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Thu, 10 Oct 2024 08:33:55 +0200 Subject: [PATCH] Polish "Add property to specify Docker Compose flags" See gh-42571 --- .../core/DockerCliIntegrationTests.java | 11 +-- .../boot/docker/compose/core/1.yaml | 2 +- .../boot/docker/compose/core/3.yaml | 2 +- .../compose/core/DefaultDockerCompose.java | 3 +- .../boot/docker/compose/core/DockerCli.java | 40 +++++--- .../docker/compose/core/DockerCompose.java | 55 ++--------- .../compose/core/DockerComposeOptions.java | 94 ------------------- .../DockerComposeLifecycleManager.java | 3 +- .../lifecycle/DockerComposeProperties.java | 2 +- .../core/DefaultDockerComposeTests.java | 3 - 10 files changed, 48 insertions(+), 167 deletions(-) delete mode 100644 spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerComposeOptions.java diff --git a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/core/DockerCliIntegrationTests.java b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/core/DockerCliIntegrationTests.java index cbe2f8b4235..0ad06a64c6a 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/core/DockerCliIntegrationTests.java +++ b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/core/DockerCliIntegrationTests.java @@ -30,6 +30,7 @@ import java.util.UUID; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import org.springframework.boot.docker.compose.core.DockerCli.DockerComposeOptions; import org.springframework.boot.docker.compose.core.DockerCliCommand.ComposeConfig; import org.springframework.boot.docker.compose.core.DockerCliCommand.ComposeDown; import org.springframework.boot.docker.compose.core.DockerCliCommand.ComposePs; @@ -37,7 +38,6 @@ import org.springframework.boot.docker.compose.core.DockerCliCommand.ComposeStar import org.springframework.boot.docker.compose.core.DockerCliCommand.ComposeStop; import org.springframework.boot.docker.compose.core.DockerCliCommand.ComposeUp; import org.springframework.boot.docker.compose.core.DockerCliCommand.Inspect; -import org.springframework.boot.docker.compose.core.DockerCompose.Options; import org.springframework.boot.logging.LogLevel; import org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable; import org.springframework.boot.testsupport.container.TestImage; @@ -72,9 +72,8 @@ class DockerCliIntegrationTests { void runLifecycle() throws IOException { File composeFile = createComposeFile("redis-compose.yaml"); String projectName = UUID.randomUUID().toString(); - Options options = Options.get(DockerComposeFile.of(composeFile), Collections.emptySet(), - List.of("--project-name=" + projectName)); - DockerCli cli = new DockerCli(null, options); + DockerCli cli = new DockerCli(null, new DockerComposeOptions(DockerComposeFile.of(composeFile), + Collections.emptySet(), List.of("--project-name=" + projectName))); try { // Verify that no services are running (this is a fresh compose project) List ps = cli.run(new ComposePs()); @@ -113,8 +112,8 @@ class DockerCliIntegrationTests { @Test void shouldWorkWithMultipleComposeFiles() throws IOException { List composeFiles = createComposeFiles(); - Options options = Options.get(DockerComposeFile.of(composeFiles), Set.of("dev"), Collections.emptyList()); - DockerCli cli = new DockerCli(null, options); + DockerCli cli = new DockerCli(null, + new DockerComposeOptions(DockerComposeFile.of(composeFiles), Set.of("dev"), Collections.emptyList())); try { // List the config and verify that both redis are there DockerCliComposeConfigResponse config = cli.run(new ComposeConfig()); diff --git a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/1.yaml b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/1.yaml index d03a48e4aaf..24ec799a8d2 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/1.yaml +++ b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/1.yaml @@ -1,6 +1,6 @@ services: redis1: - profiles: [ dev ] + profiles: [ 'dev' ] image: '{imageName}' ports: - '6379' diff --git a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/3.yaml b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/3.yaml index d9ba4a51e55..32ef28fa5ec 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/3.yaml +++ b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/3.yaml @@ -1,6 +1,6 @@ services: redis3: - profiles: [ prod ] + profiles: [ 'prod' ] image: '{imageName}' ports: - '6379' diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DefaultDockerCompose.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DefaultDockerCompose.java index e457db2bd53..e50340605b1 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DefaultDockerCompose.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DefaultDockerCompose.java @@ -97,8 +97,7 @@ class DefaultDockerCompose implements DockerCompose { if (runningPsResponses.isEmpty()) { return Collections.emptyList(); } - DockerCompose.Options options = this.cli.getDockerComposeOptions(); - DockerComposeFile dockerComposeFile = options.getComposeFile(); + DockerComposeFile dockerComposeFile = this.cli.getDockerComposeFile(); List result = new ArrayList<>(); Map inspected = inspect(runningPsResponses); for (DockerCliComposePsResponse psResponse : runningPsResponses) { diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCli.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCli.java index 12c30145c69..3f92915ea5b 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCli.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCli.java @@ -18,6 +18,7 @@ package org.springframework.boot.docker.compose.core; import java.io.File; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -49,18 +50,18 @@ class DockerCli { private final DockerCommands dockerCommands; - private final DockerCompose.Options dockerComposeOptions; + private final DockerComposeOptions dockerComposeOptions; /** * Create a new {@link DockerCli} instance. * @param workingDirectory the working directory or {@code null} * @param dockerComposeOptions the Docker Compose options to use or {@code null}. */ - DockerCli(File workingDirectory, DockerCompose.Options dockerComposeOptions) { + DockerCli(File workingDirectory, DockerComposeOptions dockerComposeOptions) { this.processRunner = new ProcessRunner(workingDirectory); this.dockerCommands = dockerCommandsCache.computeIfAbsent(workingDirectory, (key) -> new DockerCommands(this.processRunner)); - this.dockerComposeOptions = (dockerComposeOptions != null) ? dockerComposeOptions : DockerCompose.Options.NONE; + this.dockerComposeOptions = (dockerComposeOptions != null) ? dockerComposeOptions : DockerComposeOptions.none(); } /** @@ -89,8 +90,7 @@ class DockerCli { case DOCKER -> new ArrayList<>(this.dockerCommands.get(type)); case DOCKER_COMPOSE -> { List result = new ArrayList<>(this.dockerCommands.get(type)); - DockerCompose.Options options = this.dockerComposeOptions; - DockerComposeFile composeFile = options.getComposeFile(); + DockerComposeFile composeFile = this.dockerComposeOptions.composeFile(); if (composeFile != null) { for (File file : composeFile.getFiles()) { result.add("--file"); @@ -99,14 +99,14 @@ class DockerCli { } result.add("--ansi"); result.add("never"); - Set activeProfiles = options.getActiveProfiles(); + Set activeProfiles = this.dockerComposeOptions.activeProfiles(); if (!CollectionUtils.isEmpty(activeProfiles)) { for (String profile : activeProfiles) { result.add("--profile"); result.add(profile); } } - List arguments = options.getArguments(); + List arguments = this.dockerComposeOptions.arguments(); if (!CollectionUtils.isEmpty(arguments)) { result.addAll(arguments); } @@ -116,11 +116,11 @@ class DockerCli { } /** - * Return the {@link DockerCompose.Options} being used by this CLI instance. - * @return the Docker Compose options + * Return the {@link DockerComposeFile} being used by this CLI instance. + * @return the Docker Compose file */ - DockerCompose.Options getDockerComposeOptions() { - return this.dockerComposeOptions; + DockerComposeFile getDockerComposeFile() { + return this.dockerComposeOptions.composeFile(); } /** @@ -190,4 +190,22 @@ class DockerCli { } + /** + * Options for Docker Compose. + * + * @param composeFile the Docker Compose file to use + * @param activeProfiles the profiles to activate + * @param arguments the arguments to pass to Docker Compose + */ + record DockerComposeOptions(DockerComposeFile composeFile, Set activeProfiles, List arguments) { + DockerComposeOptions { + activeProfiles = (activeProfiles != null) ? activeProfiles : Collections.emptySet(); + arguments = (arguments != null) ? arguments : Collections.emptyList(); + } + + static DockerComposeOptions none() { + return new DockerComposeOptions(null, null, null); + } + } + } diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCompose.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCompose.java index af1256baddb..129be08a073 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCompose.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCompose.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.List; import java.util.Set; +import org.springframework.boot.docker.compose.core.DockerCli.DockerComposeOptions; import org.springframework.boot.logging.LogLevel; /** @@ -126,61 +127,23 @@ public interface DockerCompose { * @return a {@link DockerCompose} instance */ static DockerCompose get(DockerComposeFile file, String hostname, Set activeProfiles) { - DockerCli cli = new DockerCli(null, Options.get(file, activeProfiles, Collections.emptyList())); - return new DefaultDockerCompose(cli, hostname); + return get(file, hostname, activeProfiles, Collections.emptyList()); } /** * Factory method used to create a {@link DockerCompose} instance. + * @param file the Docker Compose file * @param hostname the hostname used for services or {@code null} if the hostname - * @param options the Docker Compose options or {@code null} + * should be deduced + * @param activeProfiles a set of the profiles that should be activated + * @param arguments the arguments to pass to Docker Compose * @return a {@link DockerCompose} instance * @since 3.4.0 */ - static DockerCompose get(String hostname, Options options) { - DockerCli cli = new DockerCli(null, options); + static DockerCompose get(DockerComposeFile file, String hostname, Set activeProfiles, + List arguments) { + DockerCli cli = new DockerCli(null, new DockerComposeOptions(file, activeProfiles, arguments)); return new DefaultDockerCompose(cli, hostname); } - /** - * Docker Compose options that should be applied before any subcommand. - */ - interface Options { - - /** - * No options. - */ - Options NONE = get(null, Collections.emptySet(), Collections.emptyList()); - - /** - * Factory method used to create a {@link DockerCompose.Options} instance. - * @param file the Docker Compose file to use - * @param activeProfiles the Docker Compose profiles to activate - * @param arguments the additional Docker Compose arguments - * @return the Docker Compose options - */ - static Options get(DockerComposeFile file, Set activeProfiles, List arguments) { - return new DockerComposeOptions(file, activeProfiles, arguments); - } - - /** - * the Docker Compose a file to use. - * @return compose a file to use - */ - DockerComposeFile getComposeFile(); - - /** - * the Docker Compose profiles to activate. - * @return profiles to activate - */ - Set getActiveProfiles(); - - /** - * the additional Docker Compose arguments. - * @return additional arguments - */ - List getArguments(); - - } - } diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerComposeOptions.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerComposeOptions.java deleted file mode 100644 index fc3dd3a749c..00000000000 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerComposeOptions.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2012-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.docker.compose.core; - -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import org.springframework.core.style.ToStringCreator; - -/** - * Default {@link DockerCompose.Options} implementation. - * - * @author Dmytro Nosan - */ -final class DockerComposeOptions implements DockerCompose.Options { - - private final DockerComposeFile composeFile; - - private final Set activeProfiles; - - private final List arguments; - - /** - * Create a new {@link DockerComposeOptions} instance. - * @param composeFile the Docker Compose file to use - * @param activeProfiles the Docker Compose profiles to activate - * @param arguments the additional Docker Compose arguments (e.g. --project-name=...) - */ - DockerComposeOptions(DockerComposeFile composeFile, Set activeProfiles, List arguments) { - this.composeFile = composeFile; - this.activeProfiles = (activeProfiles != null) ? activeProfiles : Collections.emptySet(); - this.arguments = (arguments != null) ? arguments : Collections.emptyList(); - } - - @Override - public DockerComposeFile getComposeFile() { - return this.composeFile; - } - - @Override - public Set getActiveProfiles() { - return this.activeProfiles; - } - - @Override - public List getArguments() { - return this.arguments; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - DockerComposeOptions that = (DockerComposeOptions) obj; - return Objects.equals(this.composeFile, that.composeFile) - && Objects.equals(this.activeProfiles, that.activeProfiles) - && Objects.equals(this.arguments, that.arguments); - } - - @Override - public int hashCode() { - return Objects.hash(this.composeFile, this.activeProfiles, this.arguments); - } - - @Override - public String toString() { - ToStringCreator creator = new ToStringCreator(this); - creator.append("composeFile", this.composeFile); - creator.append("activeProfiles", this.activeProfiles); - creator.append("arguments", this.arguments); - return creator.toString(); - } - -} diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManager.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManager.java index 2bc2cd49bca..92259ad60db 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManager.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManager.java @@ -162,8 +162,7 @@ class DockerComposeLifecycleManager { protected DockerCompose getDockerCompose(DockerComposeFile composeFile, Set activeProfiles, List arguments) { - DockerCompose.Options options = DockerCompose.Options.get(composeFile, activeProfiles, arguments); - return DockerCompose.get(this.properties.getHost(), options); + return DockerCompose.get(composeFile, this.properties.getHost(), activeProfiles, arguments); } private boolean isIgnored(RunningService service) { diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeProperties.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeProperties.java index 4d840feadb6..d6e98ec0f0e 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeProperties.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeProperties.java @@ -47,7 +47,7 @@ public class DockerComposeProperties { private boolean enabled = true; /** - * Arguments to pass to the docker compose command. + * Arguments to pass to the Docker Compose command. */ private final List arguments = new ArrayList<>(); diff --git a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DefaultDockerComposeTests.java b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DefaultDockerComposeTests.java index 68dded1db97..a03ff984dc1 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DefaultDockerComposeTests.java +++ b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DefaultDockerComposeTests.java @@ -106,7 +106,6 @@ class DefaultDockerComposeTests { HostConfig hostConfig = null; DockerCliInspectResponse inspectResponse = new DockerCliInspectResponse(id, config, networkSettings, hostConfig); - willReturn(mock(DockerCompose.Options.class)).given(this.cli).getDockerComposeOptions(); willReturn(List.of(psResponse)).given(this.cli).run(new DockerCliCommand.ComposePs()); willReturn(List.of(inspectResponse)).given(this.cli).run(new DockerCliCommand.Inspect(List.of(id))); DefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST); @@ -133,7 +132,6 @@ class DefaultDockerComposeTests { hostConfig); willReturn(List.of(new DockerCliContextResponse("test", true, "https://192.168.1.1"))).given(this.cli) .run(new DockerCliCommand.Context()); - willReturn(mock(DockerCompose.Options.class)).given(this.cli).getDockerComposeOptions(); willReturn(List.of(psResponse)).given(this.cli).run(new DockerCliCommand.ComposePs()); willReturn(List.of(inspectResponse)).given(this.cli).run(new DockerCliCommand.Inspect(List.of(id))); DefaultDockerCompose compose = new DefaultDockerCompose(this.cli, null); @@ -150,7 +148,6 @@ class DefaultDockerComposeTests { DockerCliComposePsResponse psResponse = new DockerCliComposePsResponse(shortId, "name", "redis", "running"); Config config = new Config("redis", Collections.emptyMap(), Collections.emptyMap(), Collections.emptyList()); DockerCliInspectResponse inspectResponse = new DockerCliInspectResponse(longId, config, null, null); - willReturn(mock(DockerCompose.Options.class)).given(this.cli).getDockerComposeOptions(); willReturn(List.of(new DockerCliContextResponse("test", true, "https://192.168.1.1"))).given(this.cli) .run(new DockerCliCommand.Context()); willReturn(List.of(psResponse)).given(this.cli).run(new DockerCliCommand.ComposePs());