Make sure that Maven plugin configuration can be amended

See gh-867
This commit is contained in:
Stephane Nicoll
2019-03-14 14:53:33 +01:00
parent ec6ac4b1d8
commit a5e2994f1d
6 changed files with 175 additions and 24 deletions

View File

@@ -41,9 +41,9 @@ public class KotlinJpaMavenBuildCustomizer implements BuildCustomizer<MavenBuild
if (this.buildMetadataResolver.hasFacet(build, "jpa")) { if (this.buildMetadataResolver.hasFacet(build, "jpa")) {
MavenPlugin kotlinNoArgPlugin = build.plugin("org.jetbrains.kotlin", MavenPlugin kotlinNoArgPlugin = build.plugin("org.jetbrains.kotlin",
"kotlin-maven-noarg", "${kotlin.version}"); "kotlin-maven-noarg", "${kotlin.version}");
kotlinNoArgPlugin kotlinNoArgPlugin.configuration((configuration) -> configuration.parameter(
.configuration((configuration) -> configuration.add("compilerPlugins", "compilerPlugins",
(compilerPlugins) -> compilerPlugins.add("plugin", "jpa"))); (compilerPlugins) -> compilerPlugins.parameter("plugin", "jpa")));
} }
} }

View File

@@ -45,10 +45,10 @@ class KotlinMavenBuildCustomizer implements BuildCustomizer<MavenBuild> {
MavenPlugin kotlinMavenPlugin = build.plugin("org.jetbrains.kotlin", MavenPlugin kotlinMavenPlugin = build.plugin("org.jetbrains.kotlin",
"kotlin-maven-plugin"); "kotlin-maven-plugin");
kotlinMavenPlugin.configuration((configuration) -> { kotlinMavenPlugin.configuration((configuration) -> {
configuration.add("args", (args) -> this.settings.getCompilerArgs() configuration.parameter("args", (args) -> this.settings.getCompilerArgs()
.forEach((arg) -> args.add("arg", arg))); .forEach((arg) -> args.parameter("arg", arg)));
configuration.add("compilerPlugins", configuration.parameter("compilerPlugins",
(compilerPlugins) -> compilerPlugins.add("plugin", "spring")); (compilerPlugins) -> compilerPlugins.parameter("plugin", "spring"));
}); });
kotlinMavenPlugin.dependency("org.jetbrains.kotlin", "kotlin-maven-allopen", kotlinMavenPlugin.dependency("org.jetbrains.kotlin", "kotlin-maven-allopen",
"${kotlin.version}"); "${kotlin.version}");

View File

@@ -42,11 +42,11 @@ class KotlinMavenFullBuildCustomizer implements BuildCustomizer<MavenBuild> {
MavenPlugin kotlinMavenPlugin = build.plugin("org.jetbrains.kotlin", MavenPlugin kotlinMavenPlugin = build.plugin("org.jetbrains.kotlin",
"kotlin-maven-plugin", "${kotlin.version}"); "kotlin-maven-plugin", "${kotlin.version}");
kotlinMavenPlugin.configuration((configuration) -> { kotlinMavenPlugin.configuration((configuration) -> {
configuration.add("args", (args) -> this.settings.getCompilerArgs() configuration.parameter("args", (args) -> this.settings.getCompilerArgs()
.forEach((arg) -> args.add("arg", arg))); .forEach((arg) -> args.parameter("arg", arg)));
configuration.add("compilerPlugins", configuration.parameter("compilerPlugins",
(compilerPlugins) -> compilerPlugins.add("plugin", "spring")); (compilerPlugins) -> compilerPlugins.parameter("plugin", "spring"));
configuration.add("jvmTarget", this.settings.getJvmTarget()); configuration.parameter("jvmTarget", this.settings.getJvmTarget());
}); });
kotlinMavenPlugin.execution("compile", kotlinMavenPlugin.execution("compile",
(compile) -> compile.phase("compile").goal("compile")); (compile) -> compile.phase("compile").goal("compile"));

View File

@@ -18,8 +18,11 @@ package io.spring.initializr.generator.buildsystem.maven;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors;
/** /**
* A plugin in a {@link MavenBuild}. * A plugin in a {@link MavenBuild}.
@@ -139,23 +142,58 @@ public class MavenPlugin {
*/ */
public static class ConfigurationCustomization { public static class ConfigurationCustomization {
private final List<Setting> settings = new ArrayList<>(); private final Map<String, Object> settings = new LinkedHashMap<>();
public ConfigurationCustomization add(String key, String value) { /**
this.settings.add(new Setting(key, value)); * Set the specified parameter with a single value.
* @param name the name of the parameter
* @param value the single value of the parameter
* @return this for method chaining
*/
public ConfigurationCustomization parameter(String name, String value) {
this.settings.put(name, value);
return this; return this;
} }
public ConfigurationCustomization add(String key, /**
* Configure the parameter with the specified {@code name}.
* @param parameter the name of the parameter
* @param consumer a consumer to further configure the parameter
* @return this for method chaining
* @throws IllegalArgumentException if a parameter with the same name is
* registered with a single value
*/
public ConfigurationCustomization parameter(String parameter,
Consumer<ConfigurationCustomization> consumer) { Consumer<ConfigurationCustomization> consumer) {
ConfigurationCustomization nestedConfiguration = new ConfigurationCustomization(); Object value = this.settings.computeIfAbsent(parameter,
(id) -> new ConfigurationCustomization());
if (!(value instanceof ConfigurationCustomization)) {
throw new IllegalArgumentException(String.format(
"Could not customize parameter '%s', a single value %s is already registered",
parameter, value));
}
ConfigurationCustomization nestedConfiguration = (ConfigurationCustomization) value;
consumer.accept(nestedConfiguration); consumer.accept(nestedConfiguration);
this.settings.add(new Setting(key, nestedConfiguration.settings));
return this; return this;
} }
Configuration build() { Configuration build() {
return new Configuration(this.settings); return new Configuration(this.settings.entrySet().stream()
.map((entry) -> resolve(entry.getKey(), entry.getValue()))
.collect(Collectors.toList()));
}
private Setting resolve(String key, Object value) {
if (value instanceof ConfigurationCustomization) {
List<Setting> values = ((ConfigurationCustomization) value).settings
.entrySet().stream()
.map((entry) -> resolve(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
return new Setting(key, values);
}
else {
return new Setting(key, value);
}
} }
} }

View File

@@ -336,9 +336,10 @@ class MavenBuildWriterTests {
build.setArtifact("demo"); build.setArtifact("demo");
MavenPlugin kotlin = build.plugin("org.jetbrains.kotlin", "kotlin-maven-plugin"); MavenPlugin kotlin = build.plugin("org.jetbrains.kotlin", "kotlin-maven-plugin");
kotlin.configuration((configuration) -> { kotlin.configuration((configuration) -> {
configuration.add("args", (args) -> args.add("arg", "-Xjsr305=strict")); configuration.parameter("args",
configuration.add("compilerPlugins", (args) -> args.parameter("arg", "-Xjsr305=strict"));
(compilerPlugins) -> compilerPlugins.add("plugin", "spring")); configuration.parameter("compilerPlugins",
(compilerPlugins) -> compilerPlugins.parameter("plugin", "spring"));
}); });
generatePom(build, (pom) -> { generatePom(build, (pom) -> {
NodeAssert plugin = pom.nodeAtPath("/project/build/plugins/plugin"); NodeAssert plugin = pom.nodeAtPath("/project/build/plugins/plugin");
@@ -363,8 +364,8 @@ class MavenBuildWriterTests {
execution.goal("process-asciidoc"); execution.goal("process-asciidoc");
execution.phase("generateProject-resources"); execution.phase("generateProject-resources");
execution.configuration((configuration) -> { execution.configuration((configuration) -> {
configuration.add("doctype", "book"); configuration.parameter("doctype", "book");
configuration.add("backend", "html"); configuration.parameter("backend", "html");
}); });
}); });
generatePom(build, (pom) -> { generatePom(build, (pom) -> {

View File

@@ -0,0 +1,112 @@
/*
* Copyright 2012-2019 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
*
* http://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.maven;
import java.util.List;
import io.spring.initializr.generator.buildsystem.maven.MavenPlugin.Setting;
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 MavenPlugin}.
*
* @author Stephane Nicoll
*/
class MavenPluginTests {
@Test
void configurationCanBeCustomized() {
MavenPlugin plugin = new MavenPlugin("com.example", "test-plugin");
plugin.configuration((customizer) -> customizer.parameter("enabled", "false")
.parameter("skip", "true"));
plugin.configuration((customizer) -> customizer.parameter("another", "test"));
assertThat(plugin.getConfiguration().getSettings().stream().map(Setting::getName))
.containsExactly("enabled", "skip", "another");
assertThat(
plugin.getConfiguration().getSettings().stream().map(Setting::getValue))
.containsExactly("false", "true", "test");
}
@Test
void configurationCanBeOverridden() {
MavenPlugin plugin = new MavenPlugin("com.example", "test-plugin");
plugin.configuration((customizer) -> customizer.parameter("enabled", "true"));
plugin.configuration((customizer) -> customizer.parameter("enabled", "false"));
assertThat(plugin.getConfiguration().getSettings().stream().map(Setting::getName))
.containsExactly("enabled");
assertThat(
plugin.getConfiguration().getSettings().stream().map(Setting::getValue))
.containsExactly("false");
}
@Test
@SuppressWarnings("unchecked")
void configurationWithNestedValuesCanBeCustomized() {
MavenPlugin plugin = new MavenPlugin("com.example", "test-plugin");
plugin.configuration((customizer) -> customizer.parameter("items",
(items) -> items.parameter("one", "true")));
plugin.configuration((customizer) -> customizer.parameter("items",
(items) -> items.parameter("two", "false")));
assertThat(plugin.getConfiguration().getSettings()).hasSize(1);
Setting setting = plugin.getConfiguration().getSettings().get(0);
assertThat(setting.getName()).isEqualTo("items");
assertThat(setting.getValue()).isInstanceOf(List.class);
List<Setting> values = (List<Setting>) setting.getValue();
assertThat(values.stream().map(Setting::getName)).containsExactly("one", "two");
assertThat(values.stream().map(Setting::getValue)).containsExactly("true",
"false");
}
@Test
@SuppressWarnings("unchecked")
void configurationWithSeveralLevelOfNestedValuesCanBeCustomized() {
MavenPlugin plugin = new MavenPlugin("com.example", "test-plugin");
plugin.configuration((customizer) -> customizer.parameter("items",
(items) -> items.parameter("subItems",
(subItems) -> subItems.parameter("one", "true"))));
plugin.configuration((customizer) -> customizer.parameter("items",
(items) -> items.parameter("subItems", (subItems) -> subItems
.parameter("one", "false").parameter("two", "true"))));
assertThat(plugin.getConfiguration().getSettings()).hasSize(1);
Setting setting = plugin.getConfiguration().getSettings().get(0);
assertThat(setting.getName()).isEqualTo("items");
assertThat(setting.getValue()).isInstanceOf(List.class);
List<Setting> items = (List<Setting>) setting.getValue();
assertThat(items).hasSize(1);
Setting item = items.get(0);
assertThat(item.getName()).isEqualTo("subItems");
assertThat(item.getValue()).isInstanceOf(List.class);
List<Setting> subItems = (List<Setting>) item.getValue();
assertThat(subItems.stream().map(Setting::getName)).containsExactly("one", "two");
assertThat(subItems.stream().map(Setting::getValue)).containsExactly("false",
"true");
}
@Test
void configurationCannotBeSwitchedToNestedValue() {
MavenPlugin plugin = new MavenPlugin("com.example", "test-plugin");
plugin.configuration((customizer) -> customizer.parameter("test", "value"));
assertThatIllegalArgumentException()
.isThrownBy(() -> plugin.configuration((customizer) -> customizer
.parameter("test", (test) -> test.parameter("one", "true"))))
.withMessageContaining("test").withMessageContaining("value");
}
}