diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildSettings.java b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildSettings.java index 49bb3c1e..fcf4dc16 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildSettings.java +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2021 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. @@ -16,7 +16,11 @@ package io.spring.initializr.generator.buildsystem.gradle; +import java.util.ArrayList; +import java.util.List; + import io.spring.initializr.generator.buildsystem.BuildSettings; +import io.spring.initializr.generator.buildsystem.Dependency; /** * Gradle-specific {@linkplain BuildSettings build settings}. @@ -27,9 +31,12 @@ public class GradleBuildSettings extends BuildSettings { private final String sourceCompatibility; + private final List pluginMappings; + protected GradleBuildSettings(Builder builder) { super(builder); this.sourceCompatibility = builder.sourceCompatibility; + this.pluginMappings = new ArrayList<>(builder.pluginMappings); } /** @@ -40,6 +47,14 @@ public class GradleBuildSettings extends BuildSettings { return this.sourceCompatibility; } + /** + * Return the {@link PluginMapping plugin mappings}, if any. + * @return the plugin mappings + */ + public List getPluginMappings() { + return this.pluginMappings; + } + /** * Builder for {@link GradleBuildSettings}. */ @@ -47,6 +62,8 @@ public class GradleBuildSettings extends BuildSettings { private String sourceCompatibility; + private final List pluginMappings = new ArrayList<>(); + /** * Set the java version compatibility to use when compiling Java source. * @param sourceCompatibility java version compatibility @@ -57,6 +74,21 @@ public class GradleBuildSettings extends BuildSettings { return self(); } + /** + * Map the plugin with the specified id to the specified {@link Dependency}. This + * is mandatory when a plugin does not have an appropriate plugin marker artifact. + * @param id the id of a plugin + * @param pluginDependency the dependency for that plugin + * @return this for method chaining + */ + public Builder mapPlugin(String id, Dependency pluginDependency) { + if (pluginDependency.getVersion() == null || pluginDependency.getVersion().isProperty()) { + throw new IllegalArgumentException("Mapping for plugin '" + id + "' must have a version"); + } + this.pluginMappings.add(new PluginMapping(id, pluginDependency)); + return this; + } + /** * Build a {@link GradleBuildSettings} with the current state of this builder. * @return a {@link GradleBuildSettings} @@ -67,4 +99,36 @@ public class GradleBuildSettings extends BuildSettings { } + /** + * Map a plugin identifier to a plugin implementation artifact. + */ + public static class PluginMapping { + + private final String id; + + private final Dependency dependency; + + PluginMapping(String id, Dependency dependency) { + this.id = id; + this.dependency = dependency; + } + + /** + * Return the id of the plugin. + * @return the plugin id + */ + public String getId() { + return this.id; + } + + /** + * Return the plugin implementation dependency. + * @return the plugin implementation + */ + public Dependency getDependency() { + return this.dependency; + } + + } + } diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleSettingsWriter.java b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleSettingsWriter.java index e832774e..f686a0c1 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleSettingsWriter.java +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleSettingsWriter.java @@ -16,7 +16,9 @@ package io.spring.initializr.generator.buildsystem.gradle; +import io.spring.initializr.generator.buildsystem.Dependency; import io.spring.initializr.generator.buildsystem.MavenRepository; +import io.spring.initializr.generator.buildsystem.gradle.GradleBuildSettings.PluginMapping; import io.spring.initializr.generator.io.IndentingWriter; /** @@ -41,15 +43,21 @@ public abstract class GradleSettingsWriter { } private void writePluginManagement(IndentingWriter writer, GradleBuild build) { - if (build.pluginRepositories().isEmpty()) { + if (build.pluginRepositories().isEmpty() && build.getSettings().getPluginMappings().isEmpty()) { return; } writer.println("pluginManagement {"); - writer.indented(() -> writeRepositories(writer, build)); + writer.indented(() -> { + writeRepositories(writer, build); + writeResolutionStrategy(writer, build); + }); writer.println("}"); } private void writeRepositories(IndentingWriter writer, GradleBuild build) { + if (build.pluginRepositories().isEmpty()) { + return; + } writer.println("repositories {"); writer.indented(() -> { build.pluginRepositories().items().map(this::repositoryAsString).forEach(writer::println); @@ -58,6 +66,29 @@ public abstract class GradleSettingsWriter { writer.println("}"); } + private void writeResolutionStrategy(IndentingWriter writer, GradleBuild build) { + if (build.getSettings().getPluginMappings().isEmpty()) { + return; + } + writer.println("resolutionStrategy {"); + writer.indented(() -> { + writer.println("eachPlugin {"); + writer.indented(() -> build.getSettings().getPluginMappings() + .forEach((pluginMapping) -> writePluginMapping(writer, pluginMapping))); + writer.println("}"); + }); + writer.println("}"); + } + + private void writePluginMapping(IndentingWriter writer, PluginMapping pluginMapping) { + writer.println("if (requested.id.id == " + wrapWithQuotes(pluginMapping.getId()) + ") {"); + Dependency dependency = pluginMapping.getDependency(); + String module = String.format("%s:%s:%s", dependency.getGroupId(), dependency.getArtifactId(), + dependency.getVersion().getValue()); + writer.indented(() -> writer.println("useModule(" + wrapWithQuotes(module) + ")")); + writer.println("}"); + } + private String repositoryAsString(MavenRepository repository) { if (MavenRepository.MAVEN_CENTRAL.equals(repository)) { return "mavenCentral()"; diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildSettingsTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildSettingsTests.java new file mode 100644 index 00000000..114f093f --- /dev/null +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildSettingsTests.java @@ -0,0 +1,64 @@ +/* + * Copyright 2012-2021 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 io.spring.initializr.generator.buildsystem.gradle; + +import io.spring.initializr.generator.buildsystem.Dependency; +import io.spring.initializr.generator.buildsystem.gradle.GradleBuildSettings.Builder; +import io.spring.initializr.generator.version.VersionReference; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +/** + * Tests for {@link GradleBuildSettings}. + * + * @author Stephane Nicoll + */ +class GradleBuildSettingsTests { + + @Test + void mapPluginWithoutVersionIsNotAllowed() { + Builder settingsBuilder = new Builder(); + assertThatIllegalArgumentException().isThrownBy( + () -> settingsBuilder.mapPlugin("test", Dependency.withCoordinates("com.example", "plugin").build())) + .withMessage("Mapping for plugin 'test' must have a version"); + } + + @Test + void mapPluginWithVersionReferenceIsNotAllowed() { + Builder settingsBuilder = new Builder(); + assertThatIllegalArgumentException() + .isThrownBy(() -> settingsBuilder.mapPlugin("test", + Dependency.withCoordinates("com.example", "plugin") + .version(VersionReference.ofProperty("test.version")).build())) + .withMessage("Mapping for plugin 'test' must have a version"); + } + + @Test + void settingsFromBuilderClonePluginMappings() { + Builder settingsBuilder = new Builder(); + settingsBuilder.mapPlugin("test", + Dependency.withCoordinates("com.example", "plugin").version(VersionReference.ofValue("1.0.0")).build()); + GradleBuildSettings firstSettings = settingsBuilder.build(); + settingsBuilder.mapPlugin("another", Dependency.withCoordinates("com.example", "another") + .version(VersionReference.ofValue("2.0.0")).build()); + assertThat(firstSettings.getPluginMappings()).singleElement() + .satisfies((pluginMapping) -> assertThat(pluginMapping.getId()).isEqualTo("test")); + } + +} diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GroovyDslGradleSettingsWriterTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GroovyDslGradleSettingsWriterTests.java index 2f60ffb3..76d9e448 100644 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GroovyDslGradleSettingsWriterTests.java +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GroovyDslGradleSettingsWriterTests.java @@ -20,8 +20,10 @@ import java.io.StringWriter; import java.util.Arrays; import java.util.List; +import io.spring.initializr.generator.buildsystem.Dependency; import io.spring.initializr.generator.buildsystem.MavenRepository; import io.spring.initializr.generator.io.IndentingWriter; +import io.spring.initializr.generator.version.VersionReference; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -73,6 +75,32 @@ class GroovyDslGradleSettingsWriterTests { "}"); } + @Test + void gradleBuildWithPluginMappings() { + GradleBuild build = new GradleBuild(); + build.settings() + .mapPlugin("com.example", + Dependency.withCoordinates("com.example", "gradle-plugin") + .version(VersionReference.ofValue("1.0.0")).build()) + .mapPlugin("org.acme", Dependency.withCoordinates("org.acme.plugin", "gradle") + .version(VersionReference.ofValue("2.0.0")).build()); + List lines = generateSettings(build); + assertThat(lines) + .containsSequence(// @formatter:off + "pluginManagement {", + " resolutionStrategy {", + " eachPlugin {", + " if (requested.id.id == 'com.example') {", + " useModule('com.example:gradle-plugin:1.0.0')", + " }", + " if (requested.id.id == 'org.acme') {", + " useModule('org.acme.plugin:gradle:2.0.0')", + " }", + " }", + " }", + "}"); // @formatter:on + } + @Test void artifactIdShouldBeUsedAsTheRootProjectName() { GradleBuild build = new GradleBuild(); diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/KotlinDslGradleSettingsWriterTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/KotlinDslGradleSettingsWriterTests.java index 70f89db5..5de6c5b0 100644 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/KotlinDslGradleSettingsWriterTests.java +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/KotlinDslGradleSettingsWriterTests.java @@ -20,8 +20,10 @@ import java.io.StringWriter; import java.util.Arrays; import java.util.List; +import io.spring.initializr.generator.buildsystem.Dependency; import io.spring.initializr.generator.buildsystem.MavenRepository; import io.spring.initializr.generator.io.IndentingWriter; +import io.spring.initializr.generator.version.VersionReference; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -72,6 +74,32 @@ class KotlinDslGradleSettingsWriterTests { " }", "}"); } + @Test + void gradleBuildWithPluginMappings() { + GradleBuild build = new GradleBuild(); + build.settings() + .mapPlugin("com.example", + Dependency.withCoordinates("com.example", "gradle-plugin") + .version(VersionReference.ofValue("1.0.0")).build()) + .mapPlugin("org.acme", Dependency.withCoordinates("org.acme.plugin", "gradle") + .version(VersionReference.ofValue("2.0.0")).build()); + List lines = generateSettings(build); + assertThat(lines) + .containsSequence(// @formatter:off + "pluginManagement {", + " resolutionStrategy {", + " eachPlugin {", + " if (requested.id.id == \"com.example\") {", + " useModule(\"com.example:gradle-plugin:1.0.0\")", + " }", + " if (requested.id.id == \"org.acme\") {", + " useModule(\"org.acme.plugin:gradle:2.0.0\")", + " }", + " }", + " }", + "}"); // @formatter:on + } + @Test void artifactIdShouldBeUsedAsTheRootProjectName() { GradleBuild build = new GradleBuild();