From 9359be990c5dc86e4b1739f752f6839a2b14f2b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Wed, 28 Feb 2024 15:17:45 -0600 Subject: [PATCH 1/3] Add support for labels in ComposeService `label` is required for custom images in docker compose using `org.springframework.boot.service-connection`. --- .../docker/compose/ComposeService.java | 22 ++++++++++++++++- .../compose/ComposeServiceContainerTests.java | 24 ++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/container/docker/compose/ComposeService.java b/initializr-generator/src/main/java/io/spring/initializr/generator/container/docker/compose/ComposeService.java index 588b81e149..4b00604f7e 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/container/docker/compose/ComposeService.java +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/container/docker/compose/ComposeService.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * 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. @@ -29,6 +29,7 @@ * * @author Moritz Halbritter * @author Stephane Nicoll + * @author Eddú Meléndez */ public final class ComposeService { @@ -46,6 +47,8 @@ public final class ComposeService { private final String command; + private final Map label; + private ComposeService(Builder builder) { this.name = builder.name; this.image = builder.image; @@ -54,6 +57,7 @@ private ComposeService(Builder builder) { this.environment = Collections.unmodifiableMap(new TreeMap<>(builder.environment)); this.ports = Collections.unmodifiableSet(new TreeSet<>(builder.ports)); this.command = builder.command; + this.label = Collections.unmodifiableMap(new TreeMap<>(builder.label)); } public String getName() { @@ -84,6 +88,10 @@ public String getCommand() { return this.command; } + public Map getLabel() { + return this.label; + } + /** * Builder for {@link ComposeService}. */ @@ -103,6 +111,8 @@ public static class Builder { private String command; + private final Map label = new TreeMap<>(); + protected Builder(String name) { this.name = name; } @@ -152,6 +162,16 @@ public Builder command(String command) { return this; } + public Builder label(String key, String value) { + this.label.put(key, value); + return this; + } + + public Builder label(Map label) { + this.label.putAll(label); + return this; + } + /** * Builds the {@link ComposeService} instance. * @return the built instance diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/container/docker/compose/ComposeServiceContainerTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/container/docker/compose/ComposeServiceContainerTests.java index 8a5bdad477..2169b611e9 100644 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/container/docker/compose/ComposeServiceContainerTests.java +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/container/docker/compose/ComposeServiceContainerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * 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. @@ -27,6 +27,7 @@ * Tests for {@link ComposeServiceContainer}. * * @author Stephane Nicoll + * @author Eddú Meléndez */ class ComposeServiceContainerTests { @@ -126,6 +127,7 @@ void customizeService() { service.environment("param", "value"); service.ports(8080); service.command("run"); + service.label("foo", "bar"); }); assertThat(container.values()).singleElement().satisfies((service) -> { assertThat(service.getName()).isEqualTo("test"); @@ -135,6 +137,7 @@ void customizeService() { assertThat(service.getEnvironment()).containsOnly(entry("param", "value")); assertThat(service.getPorts()).containsOnly(8080); assertThat(service.getCommand()).isEqualTo("run"); + assertThat(service.getLabel()).containsOnly(entry("foo", "bar")); }); } @@ -184,4 +187,23 @@ void removeWithNonMatchingName() { assertThat(container.isEmpty()).isFalse(); } + @Test + void labelKeysAreSorted() { + ComposeServiceContainer container = new ComposeServiceContainer(); + container.add("test", (service) -> service.imageAndTag("my-image").label("z", "zz")); + container.add("test", (service) -> service.label("a", "aa")); + assertThat(container.values()).singleElement() + .satisfies((service) -> assertThat(service.getLabel()).containsExactly(entry("a", "aa"), entry("z", "zz"))); + } + + @Test + void labelIsMerged() { + ComposeServiceContainer container = new ComposeServiceContainer(); + container.add("test", (service) -> service.imageAndTag("my-image").label(Map.of("a", "aa", "z", "zz"))); + container.add("test", (service) -> service.label(Map.of("a", "aaa", "b", "bb"))); + assertThat(container.values()).singleElement() + .satisfies((service) -> assertThat(service.getLabel()).containsExactly(entry("a", "aaa"), entry("b", "bb"), + entry("z", "zz"))); + } + } From c93cdd988df6f5bf2f122ba5c9d48a007b9092ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Wed, 28 Feb 2024 15:30:30 -0600 Subject: [PATCH 2/3] Rename to labels and write labels section in compose file --- .../docker/compose/ComposeFileWriter.java | 16 +++++++++++++++- .../container/docker/compose/ComposeService.java | 14 +++++++------- .../docker/compose/ComposeFileWriterTests.java | 8 ++++++-- .../compose/ComposeServiceContainerTests.java | 7 ++++--- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/container/docker/compose/ComposeFileWriter.java b/initializr-generator/src/main/java/io/spring/initializr/generator/container/docker/compose/ComposeFileWriter.java index e1767c8f88..3466e91c8b 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/container/docker/compose/ComposeFileWriter.java +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/container/docker/compose/ComposeFileWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * 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. @@ -29,6 +29,7 @@ * * @author Stephane Nicoll * @author Moritz Halbritter + * @author Eddú Meléndez */ public class ComposeFileWriter { @@ -52,6 +53,7 @@ private void writeService(IndentingWriter writer, ComposeService service) { writer.indented(() -> { writer.println("image: '%s:%s'".formatted(service.getImage(), service.getImageTag())); writerServiceEnvironment(writer, service.getEnvironment()); + writerServiceLabels(writer, service.getLabels()); writerServicePorts(writer, service.getPorts()); writeServiceCommand(writer, service.getCommand()); }); @@ -89,4 +91,16 @@ private void writeServiceCommand(IndentingWriter writer, String command) { writer.println("command: '%s'".formatted(command)); } + private void writerServiceLabels(IndentingWriter writer, Map labels) { + if (labels.isEmpty()) { + return; + } + writer.println("labels:"); + writer.indented(() -> { + for (Map.Entry env : labels.entrySet()) { + writer.println("- \"%s=%s\"".formatted(env.getKey(), env.getValue())); + } + }); + } + } diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/container/docker/compose/ComposeService.java b/initializr-generator/src/main/java/io/spring/initializr/generator/container/docker/compose/ComposeService.java index 4b00604f7e..6616bbb5c0 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/container/docker/compose/ComposeService.java +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/container/docker/compose/ComposeService.java @@ -47,7 +47,7 @@ public final class ComposeService { private final String command; - private final Map label; + private final Map labels; private ComposeService(Builder builder) { this.name = builder.name; @@ -57,7 +57,7 @@ private ComposeService(Builder builder) { this.environment = Collections.unmodifiableMap(new TreeMap<>(builder.environment)); this.ports = Collections.unmodifiableSet(new TreeSet<>(builder.ports)); this.command = builder.command; - this.label = Collections.unmodifiableMap(new TreeMap<>(builder.label)); + this.labels = Collections.unmodifiableMap(new TreeMap<>(builder.labels)); } public String getName() { @@ -88,8 +88,8 @@ public String getCommand() { return this.command; } - public Map getLabel() { - return this.label; + public Map getLabels() { + return this.labels; } /** @@ -111,7 +111,7 @@ public static class Builder { private String command; - private final Map label = new TreeMap<>(); + private final Map labels = new TreeMap<>(); protected Builder(String name) { this.name = name; @@ -163,12 +163,12 @@ public Builder command(String command) { } public Builder label(String key, String value) { - this.label.put(key, value); + this.labels.put(key, value); return this; } public Builder label(Map label) { - this.label.putAll(label); + this.labels.putAll(label); return this; } diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/container/docker/compose/ComposeFileWriterTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/container/docker/compose/ComposeFileWriterTests.java index 3f3ea81b46..28d2f97d9c 100644 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/container/docker/compose/ComposeFileWriterTests.java +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/container/docker/compose/ComposeFileWriterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * 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. @@ -30,6 +30,7 @@ * * @author Moritz Halbritter * @author Stephane Nicoll + * @author Eddú Meléndez */ class ComposeFileWriterTests { @@ -58,7 +59,8 @@ void writeDetailedService() { .environment("ELASTIC_PASSWORD", "secret") .environment("discovery.type", "single-node") .ports(9200, 9300) - .command("bin/run thing")); + .command("bin/run thing") + .label("foo", "bar")); assertThat(write(file)).isEqualToIgnoringNewLines(""" services: elasticsearch: @@ -66,6 +68,8 @@ void writeDetailedService() { environment: - 'ELASTIC_PASSWORD=secret' - 'discovery.type=single-node' + labels: + - "foo=bar" ports: - '9200' - '9300' diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/container/docker/compose/ComposeServiceContainerTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/container/docker/compose/ComposeServiceContainerTests.java index 2169b611e9..15e9424316 100644 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/container/docker/compose/ComposeServiceContainerTests.java +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/container/docker/compose/ComposeServiceContainerTests.java @@ -137,7 +137,7 @@ void customizeService() { assertThat(service.getEnvironment()).containsOnly(entry("param", "value")); assertThat(service.getPorts()).containsOnly(8080); assertThat(service.getCommand()).isEqualTo("run"); - assertThat(service.getLabel()).containsOnly(entry("foo", "bar")); + assertThat(service.getLabels()).containsOnly(entry("foo", "bar")); }); } @@ -193,7 +193,8 @@ void labelKeysAreSorted() { container.add("test", (service) -> service.imageAndTag("my-image").label("z", "zz")); container.add("test", (service) -> service.label("a", "aa")); assertThat(container.values()).singleElement() - .satisfies((service) -> assertThat(service.getLabel()).containsExactly(entry("a", "aa"), entry("z", "zz"))); + .satisfies( + (service) -> assertThat(service.getLabels()).containsExactly(entry("a", "aa"), entry("z", "zz"))); } @Test @@ -202,7 +203,7 @@ void labelIsMerged() { container.add("test", (service) -> service.imageAndTag("my-image").label(Map.of("a", "aa", "z", "zz"))); container.add("test", (service) -> service.label(Map.of("a", "aaa", "b", "bb"))); assertThat(container.values()).singleElement() - .satisfies((service) -> assertThat(service.getLabel()).containsExactly(entry("a", "aaa"), entry("b", "bb"), + .satisfies((service) -> assertThat(service.getLabels()).containsExactly(entry("a", "aaa"), entry("b", "bb"), entry("z", "zz"))); } From 9038e15e6bc1c67635d52348a433bfda43761563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 29 Feb 2024 00:28:56 -0500 Subject: [PATCH 3/3] Update ComposeFileWriter.java --- .../generator/container/docker/compose/ComposeFileWriter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/container/docker/compose/ComposeFileWriter.java b/initializr-generator/src/main/java/io/spring/initializr/generator/container/docker/compose/ComposeFileWriter.java index 3466e91c8b..d4a679f549 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/container/docker/compose/ComposeFileWriter.java +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/container/docker/compose/ComposeFileWriter.java @@ -97,8 +97,8 @@ private void writerServiceLabels(IndentingWriter writer, Map lab } writer.println("labels:"); writer.indented(() -> { - for (Map.Entry env : labels.entrySet()) { - writer.println("- \"%s=%s\"".formatted(env.getKey(), env.getValue())); + for (Map.Entry label : labels.entrySet()) { + writer.println("- \"%s=%s\"".formatted(label.getKey(), label.getValue())); } }); }