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..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 @@ -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 label : labels.entrySet()) { + writer.println("- \"%s=%s\"".formatted(label.getKey(), label.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 588b81e149..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 @@ -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 labels; + 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.labels = Collections.unmodifiableMap(new TreeMap<>(builder.labels)); } public String getName() { @@ -84,6 +88,10 @@ public String getCommand() { return this.command; } + public Map getLabels() { + return this.labels; + } + /** * Builder for {@link ComposeService}. */ @@ -103,6 +111,8 @@ public static class Builder { private String command; + private final Map labels = 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.labels.put(key, value); + return this; + } + + public Builder label(Map label) { + this.labels.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/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 8a5bdad477..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 @@ -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.getLabels()).containsOnly(entry("foo", "bar")); }); } @@ -184,4 +187,24 @@ 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.getLabels()).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.getLabels()).containsExactly(entry("a", "aaa"), entry("b", "bb"), + entry("z", "zz"))); + } + }