From 0eeb85697ecbcb18862131de032907adb98900c9 Mon Sep 17 00:00:00 2001 From: jnizet Date: Fri, 12 Apr 2019 13:49:49 +0200 Subject: [PATCH 1/2] Add support for Gradle's tasksWithType This commit adds support for configuring several tasks at once using a type. It also migrates the Kotlin support so that, instead of configuring compileKotlin and compileTestKotlin, it configures all tasks of type KotlinCompile at once. See gh-890 --- .../kotlin/KotlinGradleBuildCustomizer.java | 5 +-- .../KotlinGradleBuildCustomizerTests.java | 10 +++--- .../gradle/kotlin-java11-build.gradle.gen | 11 ++----- .../project/kotlin/previous/build.gradle.gen | 11 ++----- .../project/kotlin/standard/build.gradle.gen | 11 ++----- .../kotlin/standard/war-build.gradle.gen | 11 ++----- .../buildsystem/gradle/GradleBuild.java | 24 ++++++++++++++ .../buildsystem/gradle/GradleBuildWriter.java | 24 ++++++++++++++ .../gradle/GradleBuildWriterTests.java | 32 +++++++++++++++++++ 9 files changed, 100 insertions(+), 39 deletions(-) diff --git a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinGradleBuildCustomizer.java b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinGradleBuildCustomizer.java index 9e8ef886..010759a3 100644 --- a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinGradleBuildCustomizer.java +++ b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinGradleBuildCustomizer.java @@ -26,6 +26,7 @@ import io.spring.initializr.generator.spring.build.BuildCustomizer; * {@link BuildCustomizer} for Kotlin projects build with Gradle. * * @author Andy Wilkinson + * @author Jean-Baptiste Nizet */ class KotlinGradleBuildCustomizer implements BuildCustomizer { @@ -39,8 +40,8 @@ class KotlinGradleBuildCustomizer implements BuildCustomizer { public void customize(GradleBuild build) { build.addPlugin("org.jetbrains.kotlin.jvm", this.settings.getVersion()); build.addPlugin("org.jetbrains.kotlin.plugin.spring", this.settings.getVersion()); - build.customizeTask("compileKotlin", this::customizeKotlinOptions); - build.customizeTask("compileTestKotlin", this::customizeKotlinOptions); + build.addImportedType("org.jetbrains.kotlin.gradle.tasks.KotlinCompile"); + build.customizeTasksWithType("KotlinCompile", this::customizeKotlinOptions); } private void customizeKotlinOptions(TaskCustomization compile) { diff --git a/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/code/kotlin/KotlinGradleBuildCustomizerTests.java b/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/code/kotlin/KotlinGradleBuildCustomizerTests.java index 4936526c..4f315bbb 100644 --- a/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/code/kotlin/KotlinGradleBuildCustomizerTests.java +++ b/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/code/kotlin/KotlinGradleBuildCustomizerTests.java @@ -48,11 +48,11 @@ class KotlinGradleBuildCustomizerTests { GradleBuild build = new GradleBuild(); new KotlinGradleBuildCustomizer(new SimpleKotlinProjectSettings("1.2.70")) .customize(build); - assertThat(build.getTaskCustomizations()).hasSize(2); - assertThat(build.getTaskCustomizations()).containsKeys("compileKotlin", - "compileTestKotlin"); - assertKotlinOptions(build.getTaskCustomizations().get("compileKotlin")); - assertKotlinOptions(build.getTaskCustomizations().get("compileTestKotlin")); + assertThat(build.getImportedTypes()) + .contains("org.jetbrains.kotlin.gradle.tasks.KotlinCompile"); + assertThat(build.getTasksWithTypeCustomizations()).hasSize(1); + assertThat(build.getTasksWithTypeCustomizations()).containsKeys("KotlinCompile"); + assertKotlinOptions(build.getTasksWithTypeCustomizations().get("KotlinCompile")); } private void assertKotlinOptions(TaskCustomization compileTask) { diff --git a/initializr-generator-spring/src/test/resources/project/gradle/kotlin-java11-build.gradle.gen b/initializr-generator-spring/src/test/resources/project/gradle/kotlin-java11-build.gradle.gen index b660e76a..2c4f0f49 100644 --- a/initializr-generator-spring/src/test/resources/project/gradle/kotlin-java11-build.gradle.gen +++ b/initializr-generator-spring/src/test/resources/project/gradle/kotlin-java11-build.gradle.gen @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + plugins { id 'org.springframework.boot' version '2.1.1.RELEASE' id 'org.jetbrains.kotlin.jvm' version '1.1.1' @@ -21,14 +23,7 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' } -compileKotlin { - kotlinOptions { - freeCompilerArgs = ['-Xjsr305=strict'] - jvmTarget = '1.8' - } -} - -compileTestKotlin { +tasks.withType(KotlinCompile) { kotlinOptions { freeCompilerArgs = ['-Xjsr305=strict'] jvmTarget = '1.8' diff --git a/initializr-generator-spring/src/test/resources/project/kotlin/previous/build.gradle.gen b/initializr-generator-spring/src/test/resources/project/kotlin/previous/build.gradle.gen index 7e1b750d..27e59faa 100644 --- a/initializr-generator-spring/src/test/resources/project/kotlin/previous/build.gradle.gen +++ b/initializr-generator-spring/src/test/resources/project/kotlin/previous/build.gradle.gen @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + buildscript { repositories { mavenCentral() @@ -29,14 +31,7 @@ dependencies { testCompile 'org.springframework.boot:spring-boot-starter-test' } -compileKotlin { - kotlinOptions { - freeCompilerArgs = ['-Xjsr305=strict'] - jvmTarget = '1.8' - } -} - -compileTestKotlin { +tasks.withType(KotlinCompile) { kotlinOptions { freeCompilerArgs = ['-Xjsr305=strict'] jvmTarget = '1.8' diff --git a/initializr-generator-spring/src/test/resources/project/kotlin/standard/build.gradle.gen b/initializr-generator-spring/src/test/resources/project/kotlin/standard/build.gradle.gen index bd22117d..2d88fb06 100644 --- a/initializr-generator-spring/src/test/resources/project/kotlin/standard/build.gradle.gen +++ b/initializr-generator-spring/src/test/resources/project/kotlin/standard/build.gradle.gen @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + plugins { id 'org.springframework.boot' version '2.1.1.RELEASE' id 'org.jetbrains.kotlin.jvm' version '1.1.1' @@ -21,14 +23,7 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' } -compileKotlin { - kotlinOptions { - freeCompilerArgs = ['-Xjsr305=strict'] - jvmTarget = '1.8' - } -} - -compileTestKotlin { +tasks.withType(KotlinCompile) { kotlinOptions { freeCompilerArgs = ['-Xjsr305=strict'] jvmTarget = '1.8' diff --git a/initializr-generator-spring/src/test/resources/project/kotlin/standard/war-build.gradle.gen b/initializr-generator-spring/src/test/resources/project/kotlin/standard/war-build.gradle.gen index e58db678..8ec33eb9 100644 --- a/initializr-generator-spring/src/test/resources/project/kotlin/standard/war-build.gradle.gen +++ b/initializr-generator-spring/src/test/resources/project/kotlin/standard/war-build.gradle.gen @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + plugins { id 'org.springframework.boot' version '2.1.1.RELEASE' id 'war' @@ -23,14 +25,7 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' } -compileKotlin { - kotlinOptions { - freeCompilerArgs = ['-Xjsr305=strict'] - jvmTarget = '1.8' - } -} - -compileTestKotlin { +tasks.withType(KotlinCompile) { kotlinOptions { freeCompilerArgs = ['-Xjsr305=strict'] jvmTarget = '1.8' diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuild.java b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuild.java index 6bce03d6..eb2c1bfd 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuild.java +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuild.java @@ -19,6 +19,7 @@ package io.spring.initializr.generator.buildsystem.gradle; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -34,6 +35,7 @@ import io.spring.initializr.generator.buildsystem.BuildItemResolver; * Gradle build configuration for a project. * * @author Andy Wilkinson + * @author Jean-Baptiste Nizet */ public class GradleBuild extends Build { @@ -49,6 +51,10 @@ public class GradleBuild extends Build { private final Map taskCustomizations = new LinkedHashMap<>(); + private final Set importedTypes = new HashSet<>(); + + private final Map tasksWithTypeCustomizations = new LinkedHashMap<>(); + private final Buildscript buildscript = new Buildscript(); public GradleBuild(BuildItemResolver buildItemResolver) { @@ -121,6 +127,24 @@ public class GradleBuild extends Build { return Collections.unmodifiableMap(this.configurationCustomizations); } + public void addImportedType(String type) { + this.importedTypes.add(type); + } + + public Set getImportedTypes() { + return Collections.unmodifiableSet(this.importedTypes); + } + + public void customizeTasksWithType(String typeName, + Consumer customizer) { + customizer.accept(this.tasksWithTypeCustomizations.computeIfAbsent(typeName, + (name) -> new TaskCustomization())); + } + + public Map getTasksWithTypeCustomizations() { + return Collections.unmodifiableMap(this.tasksWithTypeCustomizations); + } + public void customizeTask(String taskName, Consumer customizer) { customizer.accept(this.taskCustomizations.computeIfAbsent(taskName, (name) -> new TaskCustomization())); diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildWriter.java b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildWriter.java index bfed2c8c..23779f5e 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildWriter.java +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildWriter.java @@ -47,10 +47,12 @@ import io.spring.initializr.generator.version.VersionReference; * * @author Andy Wilkinson * @author Stephane Nicoll + * @author Jean-Baptiste Nizet */ public class GradleBuildWriter { public void writeTo(IndentingWriter writer, GradleBuild build) throws IOException { + writeImports(writer, build); boolean buildScriptWritten = writeBuildscript(writer, build); writePlugins(writer, build, buildScriptWritten); writeProperty(writer, "group", build.getGroup()); @@ -61,9 +63,18 @@ public class GradleBuildWriter { writeProperties(writer, build); writeDependencies(writer, build); writeBoms(writer, build); + writeTasksWithTypeCustomizations(writer, build); writeTaskCustomizations(writer, build); } + private void writeImports(IndentingWriter writer, GradleBuild build) { + build.getImportedTypes().stream().sorted().forEachOrdered( + (importedType) -> writer.println("import " + importedType)); + if (!build.getImportedTypes().isEmpty()) { + writer.println(); + } + } + private boolean writeBuildscript(IndentingWriter writer, GradleBuild build) { List dependencies = build.getBuildscript().getDependencies(); Map ext = build.getBuildscript().getExt(); @@ -276,6 +287,19 @@ public class GradleBuildWriter { return null; } + private void writeTasksWithTypeCustomizations(IndentingWriter writer, + GradleBuild build) { + Map tasksWithTypeCustomizations = build + .getTasksWithTypeCustomizations(); + + tasksWithTypeCustomizations.forEach((typeName, customization) -> { + writer.println(); + writer.println("tasks.withType(" + typeName + ") {"); + writer.indented(() -> writeTaskCustomization(writer, customization)); + writer.println("}"); + }); + } + private void writeTaskCustomizations(IndentingWriter writer, GradleBuild build) { Map taskCustomizations = build.getTaskCustomizations(); taskCustomizations.forEach((name, customization) -> { diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildWriterTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildWriterTests.java index 468af8bd..b4d02366 100644 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildWriterTests.java +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildWriterTests.java @@ -33,9 +33,25 @@ import static org.assertj.core.api.Assertions.assertThat; * Tests for {@link GradleBuildWriter} * * @author Andy Wilkinson + * @author Jean-Baptiste Nizet */ class GradleBuildWriterTests { + @Test + void gradleBuildWithImports() throws IOException { + GradleBuild build = new GradleBuild(); + build.addImportedType( + "org.springframework.boot.gradle.tasks.buildinfo.BuildInfo"); + build.addImportedType("org.jetbrains.kotlin.gradle.tasks.KotlinCompile"); + // same import added twice on purpose + build.addImportedType("org.jetbrains.kotlin.gradle.tasks.KotlinCompile"); + + List lines = generateBuild(build); + assertThat(lines.subList(0, 3)).containsExactly( + "import org.jetbrains.kotlin.gradle.tasks.KotlinCompile", + "import org.springframework.boot.gradle.tasks.buildinfo.BuildInfo", ""); + } + @Test void gradleBuildWithCoordinates() throws IOException { GradleBuild build = new GradleBuild(); @@ -139,6 +155,22 @@ class GradleBuildWriterTests { assertThat(lines).doesNotContain("repositories {"); } + @Test + void gradleBuildWithTaskWithTypesCustomizedWithNestedAssignments() + throws IOException { + GradleBuild build = new GradleBuild(); + build.customizeTasksWithType("KotlinCompile", (task) -> { + task.nested("kotlinOptions", (kotlinOptions) -> { + kotlinOptions.set("freeCompilerArgs", "['-Xjsr305=strict']"); + kotlinOptions.set("jvmTarget", "'1.8'"); + }); + }); + List lines = generateBuild(build); + assertThat(lines).containsSequence("tasks.withType(KotlinCompile) {", + " kotlinOptions {", " freeCompilerArgs = ['-Xjsr305=strict']", + " jvmTarget = '1.8'", " }", "}"); + } + @Test void gradleBuildWithTaskCustomizedWithInvocations() throws IOException { GradleBuild build = new GradleBuild(); From 0f645c71430198f0388708fbd12235448daf4bfe Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 30 Apr 2019 14:50:12 -0700 Subject: [PATCH 2/2] Polish "Add support for Gradle's tasksWithType" Closes gh-890 Co-authored-by: Stephane Nicoll --- .../kotlin/KotlinGradleBuildCustomizer.java | 4 +- .../buildsystem/gradle/GradleBuild.java | 20 ++++++-- .../buildsystem/gradle/GradleBuildWriter.java | 1 - .../gradle/GradleBuildWriterTests.java | 48 +++++++++---------- 4 files changed, 41 insertions(+), 32 deletions(-) diff --git a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinGradleBuildCustomizer.java b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinGradleBuildCustomizer.java index 010759a3..19b567c9 100644 --- a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinGradleBuildCustomizer.java +++ b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinGradleBuildCustomizer.java @@ -40,8 +40,8 @@ class KotlinGradleBuildCustomizer implements BuildCustomizer { public void customize(GradleBuild build) { build.addPlugin("org.jetbrains.kotlin.jvm", this.settings.getVersion()); build.addPlugin("org.jetbrains.kotlin.plugin.spring", this.settings.getVersion()); - build.addImportedType("org.jetbrains.kotlin.gradle.tasks.KotlinCompile"); - build.customizeTasksWithType("KotlinCompile", this::customizeKotlinOptions); + build.customizeTasksWithType("org.jetbrains.kotlin.gradle.tasks.KotlinCompile", + this::customizeKotlinOptions); } private void customizeKotlinOptions(TaskCustomization compile) { diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuild.java b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuild.java index eb2c1bfd..6fad200f 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuild.java +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuild.java @@ -31,6 +31,9 @@ import java.util.function.Consumer; import io.spring.initializr.generator.buildsystem.Build; import io.spring.initializr.generator.buildsystem.BuildItemResolver; +import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; + /** * Gradle build configuration for a project. * @@ -127,17 +130,24 @@ public class GradleBuild extends Build { return Collections.unmodifiableMap(this.configurationCustomizations); } - public void addImportedType(String type) { - this.importedTypes.add(type); - } - public Set getImportedTypes() { return Collections.unmodifiableSet(this.importedTypes); } + /** + * Customize tasks matching a given type. + * @param typeName the name of type. Can use the short form for well-known types such + * as {@code JavaCompile}, use a fully qualified name if an import is required + * @param customizer a callback to customize tasks matching that type + */ public void customizeTasksWithType(String typeName, Consumer customizer) { - customizer.accept(this.tasksWithTypeCustomizations.computeIfAbsent(typeName, + String packageName = ClassUtils.getPackageName(typeName); + if (!StringUtils.isEmpty(packageName)) { + this.importedTypes.add(typeName); + } + String shortName = ClassUtils.getShortName(typeName); + customizer.accept(this.tasksWithTypeCustomizations.computeIfAbsent(shortName, (name) -> new TaskCustomization())); } diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildWriter.java b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildWriter.java index 23779f5e..647c46d4 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildWriter.java +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildWriter.java @@ -291,7 +291,6 @@ public class GradleBuildWriter { GradleBuild build) { Map tasksWithTypeCustomizations = build .getTasksWithTypeCustomizations(); - tasksWithTypeCustomizations.forEach((typeName, customization) -> { writer.println(); writer.println("tasks.withType(" + typeName + ") {"); diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildWriterTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildWriterTests.java index b4d02366..7ce940d0 100644 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildWriterTests.java +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuildWriterTests.java @@ -34,24 +34,10 @@ import static org.assertj.core.api.Assertions.assertThat; * * @author Andy Wilkinson * @author Jean-Baptiste Nizet + * @author Stephane Nicoll */ class GradleBuildWriterTests { - @Test - void gradleBuildWithImports() throws IOException { - GradleBuild build = new GradleBuild(); - build.addImportedType( - "org.springframework.boot.gradle.tasks.buildinfo.BuildInfo"); - build.addImportedType("org.jetbrains.kotlin.gradle.tasks.KotlinCompile"); - // same import added twice on purpose - build.addImportedType("org.jetbrains.kotlin.gradle.tasks.KotlinCompile"); - - List lines = generateBuild(build); - assertThat(lines.subList(0, 3)).containsExactly( - "import org.jetbrains.kotlin.gradle.tasks.KotlinCompile", - "import org.springframework.boot.gradle.tasks.buildinfo.BuildInfo", ""); - } - @Test void gradleBuildWithCoordinates() throws IOException { GradleBuild build = new GradleBuild(); @@ -159,16 +145,30 @@ class GradleBuildWriterTests { void gradleBuildWithTaskWithTypesCustomizedWithNestedAssignments() throws IOException { GradleBuild build = new GradleBuild(); - build.customizeTasksWithType("KotlinCompile", (task) -> { - task.nested("kotlinOptions", (kotlinOptions) -> { - kotlinOptions.set("freeCompilerArgs", "['-Xjsr305=strict']"); - kotlinOptions.set("jvmTarget", "'1.8'"); - }); - }); + build.customizeTasksWithType("org.jetbrains.kotlin.gradle.tasks.KotlinCompile", + (task) -> task.nested("kotlinOptions", (kotlinOptions) -> kotlinOptions + .set("freeCompilerArgs", "['-Xjsr305=strict']"))); + build.customizeTasksWithType("org.jetbrains.kotlin.gradle.tasks.KotlinCompile", + (task) -> task.nested("kotlinOptions", + (kotlinOptions) -> kotlinOptions.set("jvmTarget", "'1.8'"))); List lines = generateBuild(build); - assertThat(lines).containsSequence("tasks.withType(KotlinCompile) {", - " kotlinOptions {", " freeCompilerArgs = ['-Xjsr305=strict']", - " jvmTarget = '1.8'", " }", "}"); + assertThat(lines) + .containsOnlyOnce( + "import org.jetbrains.kotlin.gradle.tasks.KotlinCompile") + .containsSequence("tasks.withType(KotlinCompile) {", + " kotlinOptions {", + " freeCompilerArgs = ['-Xjsr305=strict']", + " jvmTarget = '1.8'", " }", "}"); + } + + @Test + void gradleBuildWithTaskWithTypesAndShortTypes() throws IOException { + GradleBuild build = new GradleBuild(); + build.customizeTasksWithType("JavaCompile", + (javaCompile) -> javaCompile.set("options.fork", "true")); + assertThat(generateBuild(build)).doesNotContain("import JavaCompile") + .containsSequence("tasks.withType(JavaCompile) {", + " options.fork = true", "}"); } @Test