From fa81e8ca79df6188075f454f2f7ec16fcbb7d42b Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 20 Sep 2022 17:15:19 +0100 Subject: [PATCH] Skip processAot and processTestAot if there is no main or test code Closes gh-32424 --- .../gradle/plugin/SpringBootAotPlugin.java | 38 ++++++++++--------- .../boot/gradle/tasks/aot/AbstractAot.java | 32 +++++++++++++--- .../boot/gradle/tasks/aot/ProcessTestAot.java | 20 ++-------- .../SpringBootAotPluginIntegrationTests.java | 13 +++++++ ...IsSkippedWhenProjectHasNoMainSource.gradle | 13 +++++++ ...IsSkippedWhenProjectHasNoTestSource.gradle | 13 +++++++ 6 files changed, 88 insertions(+), 41 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processAotIsSkippedWhenProjectHasNoMainSource.gradle create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processTestAotIsSkippedWhenProjectHasNoTestSource.gradle diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootAotPlugin.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootAotPlugin.java index 371e6ef975..0e782c9379 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootAotPlugin.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootAotPlugin.java @@ -71,18 +71,21 @@ public class SpringBootAotPlugin implements Plugin { PluginContainer plugins = project.getPlugins(); plugins.withType(JavaPlugin.class).all((javaPlugin) -> { plugins.withType(SpringBootPlugin.class).all((bootPlugin) -> { - SourceSet aotSourceSet = configureSourceSet(project, "aot", SourceSet.MAIN_SOURCE_SET_NAME); - registerProcessAotTask(project, aotSourceSet); - SourceSet aotTestSourceSet = configureSourceSet(project, "aotTest", SourceSet.TEST_SOURCE_SET_NAME); - registerProcessTestAotTask(project, aotTestSourceSet); + JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class); + SourceSetContainer sourceSets = javaPluginExtension.getSourceSets(); + SourceSet mainSourceSet = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME); + SourceSet aotSourceSet = configureSourceSet(project, "aot", mainSourceSet); + registerProcessAotTask(project, aotSourceSet, mainSourceSet); + SourceSet testSourceSet = sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME); + SourceSet aotTestSourceSet = configureSourceSet(project, "aotTest", testSourceSet); + registerProcessTestAotTask(project, aotTestSourceSet, testSourceSet); }); }); } - private SourceSet configureSourceSet(Project project, String newSourceSetName, String existingSourceSetName) { + private SourceSet configureSourceSet(Project project, String newSourceSetName, SourceSet existingSourceSet) { JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class); SourceSetContainer sourceSets = javaPluginExtension.getSourceSets(); - SourceSet existingSourceSet = sourceSets.getByName(existingSourceSetName); return sourceSets.create(newSourceSetName, (sourceSet) -> { sourceSet.getJava().setSrcDirs(List.of("build/generated/" + newSourceSetName + "Sources")); sourceSet.getResources().setSrcDirs(List.of("build/generated/" + newSourceSetName + "Resources")); @@ -112,13 +115,13 @@ public class SpringBootAotPlugin implements Plugin { attributes.attribute(Usage.USAGE_ATTRIBUTE, javaRuntime); } - private void registerProcessAotTask(Project project, SourceSet aotSourceSet) { + private void registerProcessAotTask(Project project, SourceSet aotSourceSet, SourceSet mainSourceSet) { TaskProvider resolveMainClassName = project.getTasks() .named(SpringBootPlugin.RESOLVE_MAIN_CLASS_NAME_TASK_NAME, ResolveMainClassName.class); Provider aotClasses = project.getLayout().getBuildDirectory().dir("generated/aotClasses"); TaskProvider processAot = project.getTasks().register(PROCESS_AOT_TASK_NAME, ProcessAot.class, (task) -> { - configureAotTask(project, aotSourceSet, task, aotClasses); + configureAotTask(project, aotSourceSet, task, aotClasses, mainSourceSet); task.getApplicationClass() .set(resolveMainClassName.flatMap(ResolveMainClassName::readMainClassName)); }); @@ -128,13 +131,14 @@ public class SpringBootAotPlugin implements Plugin { } private void configureAotTask(Project project, SourceSet sourceSet, AbstractAot task, - Provider generatedClasses) { + Provider generatedClasses, SourceSet inputSourceSet) { task.setClasspath(sourceSet.getCompileClasspath()); - task.getSourcesDir().set(sourceSet.getJava().getSrcDirs().iterator().next()); - task.getResourcesDir().set(sourceSet.getResources().getSrcDirs().iterator().next()); - task.getClassesDir().set(generatedClasses); + task.getSourcesOutput().set(sourceSet.getJava().getSrcDirs().iterator().next()); + task.getResourcesOutput().set(sourceSet.getResources().getSrcDirs().iterator().next()); + task.getClassesOutput().set(generatedClasses); task.getGroupId().set(project.provider(() -> String.valueOf(project.getGroup()))); task.getArtifactId().set(project.provider(() -> project.getName())); + task.setInputClasses(inputSourceSet.getOutput().getClassesDirs()); } private void configureDependsOn(Project project, SourceSet aotSourceSet, @@ -145,15 +149,13 @@ public class SpringBootAotPlugin implements Plugin { .configure((processResources) -> processResources.dependsOn(processAot)); } - private void registerProcessTestAotTask(Project project, SourceSet aotTestSourceSet) { - JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class); - SourceSetContainer sourceSets = javaPluginExtension.getSourceSets(); - SourceSet testSourceSet = sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME); + private void registerProcessTestAotTask(Project project, SourceSet aotTestSourceSet, SourceSet testSourceSet) { Provider aotTestClasses = project.getLayout().getBuildDirectory().dir("generated/aotTestClasses"); TaskProvider processTestAot = project.getTasks().register(PROCESS_TEST_AOT_TASK_NAME, ProcessTestAot.class, (task) -> { - configureAotTask(project, aotTestSourceSet, task, aotTestClasses); - task.setTestSourceSet(testSourceSet); + configureAotTask(project, aotTestSourceSet, task, aotTestClasses, testSourceSet); + task.setTestRuntimeClasspath( + project.getConfigurations().getByName(testSourceSet.getImplementationConfigurationName())); }); project.getDependencies().add(aotTestSourceSet.getImplementationConfigurationName(), project.files(aotTestClasses)); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/AbstractAot.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/AbstractAot.java index d528293ce5..d2dda58575 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/AbstractAot.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/AbstractAot.java @@ -20,10 +20,16 @@ import java.util.ArrayList; import java.util.List; import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.FileCollection; import org.gradle.api.provider.Property; +import org.gradle.api.tasks.IgnoreEmptyDirectories; import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.JavaExec; import org.gradle.api.tasks.OutputDirectory; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.PathSensitivity; +import org.gradle.api.tasks.SkipWhenEmpty; import org.gradle.work.DisableCachingByDefault; /** @@ -46,6 +52,8 @@ public abstract class AbstractAot extends JavaExec { private final Property artifactId; + private FileCollection inputClasses; + protected AbstractAot() { this.sourcesDir = getProject().getObjects().directoryProperty(); this.resourcesDir = getProject().getObjects().directoryProperty(); @@ -65,25 +73,37 @@ public abstract class AbstractAot extends JavaExec { } @OutputDirectory - public final DirectoryProperty getSourcesDir() { + public final DirectoryProperty getSourcesOutput() { return this.sourcesDir; } @OutputDirectory - public final DirectoryProperty getResourcesDir() { + public final DirectoryProperty getResourcesOutput() { return this.resourcesDir; } @OutputDirectory - public final DirectoryProperty getClassesDir() { + public final DirectoryProperty getClassesOutput() { return this.classesDir; } + @InputFiles + @SkipWhenEmpty + @IgnoreEmptyDirectories + @PathSensitive(PathSensitivity.RELATIVE) + public final FileCollection getInputClasses() { + return this.inputClasses.getAsFileTree().matching((filter) -> filter.include((spec) -> !spec.isDirectory())); + } + + public void setInputClasses(FileCollection inputClasses) { + this.inputClasses = inputClasses; + } + List processorArgs() { List args = new ArrayList<>(); - args.add(getSourcesDir().getAsFile().get().getAbsolutePath()); - args.add(getResourcesDir().getAsFile().get().getAbsolutePath()); - args.add(getClassesDir().getAsFile().get().getAbsolutePath()); + args.add(getSourcesOutput().getAsFile().get().getAbsolutePath()); + args.add(getResourcesOutput().getAsFile().get().getAbsolutePath()); + args.add(getClassesOutput().getAsFile().get().getAbsolutePath()); args.add(getGroupId().get()); args.add(getArtifactId().get()); args.addAll(super.getArgs()); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/ProcessTestAot.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/ProcessTestAot.java index df0700c428..d4626e7288 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/ProcessTestAot.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/ProcessTestAot.java @@ -29,7 +29,6 @@ import org.gradle.api.file.FileCollection; import org.gradle.api.tasks.CacheableTask; import org.gradle.api.tasks.Classpath; import org.gradle.api.tasks.JavaExec; -import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.TaskAction; import org.springframework.boot.gradle.plugin.SpringBootPlugin; @@ -45,8 +44,6 @@ public class ProcessTestAot extends AbstractAot { private final Configuration junitPlatformLauncher; - private FileCollection testClassesDirs; - public ProcessTestAot() { getMainClass().set("org.springframework.test.context.aot.TestAotProcessor"); this.junitPlatformLauncher = createJUnitPlatformLauncher(); @@ -63,15 +60,6 @@ public class ProcessTestAot extends AbstractAot { return configuration; } - @Classpath - public FileCollection getTestClassesDirs() { - return this.testClassesDirs; - } - - public void setTestClassesDirs(FileCollection testClassesDirs) { - this.testClassesDirs = testClassesDirs; - } - @Classpath FileCollection getJUnitPlatformLauncher() { return this.junitPlatformLauncher; @@ -81,7 +69,7 @@ public class ProcessTestAot extends AbstractAot { @TaskAction public void exec() { List args = new ArrayList<>(); - args.add(this.testClassesDirs.getFiles().stream().filter(File::exists).map(File::getAbsolutePath) + args.add(this.getInputClasses().getFiles().stream().filter(File::exists).map(File::getAbsolutePath) .collect(Collectors.joining(File.pathSeparator))); args.addAll(processorArgs()); this.setArgs(args); @@ -89,10 +77,8 @@ public class ProcessTestAot extends AbstractAot { super.exec(); } - public void setTestSourceSet(SourceSet testSourceSet) { - setTestClassesDirs(testSourceSet.getOutput().getClassesDirs()); - this.junitPlatformLauncher.extendsFrom( - getProject().getConfigurations().getByName(testSourceSet.getImplementationConfigurationName())); + public void setTestRuntimeClasspath(Configuration configuration) { + this.junitPlatformLauncher.extendsFrom(configuration); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests.java index 17965073a9..1bf77abc19 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.nio.file.Files; import java.util.List; +import org.gradle.testkit.runner.TaskOutcome; import org.junit.jupiter.api.TestTemplate; import org.springframework.boot.gradle.junit.GradleCompatibility; @@ -94,4 +95,16 @@ class SpringBootAotPluginIntegrationTests { assertThat(output).contains("org.jboss.logging" + File.separatorChar + "jboss-logging"); } + @TestTemplate + void processAotIsSkippedWhenProjectHasNoMainSource() { + assertThat(this.gradleBuild.build("processAot").task(":processAot").getOutcome()) + .isEqualTo(TaskOutcome.NO_SOURCE); + } + + @TestTemplate + void processTestAotIsSkippedWhenProjectHasNoTestSource() { + assertThat(this.gradleBuild.build("processTestAot").task(":processTestAot").getOutcome()) + .isEqualTo(TaskOutcome.NO_SOURCE); + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processAotIsSkippedWhenProjectHasNoMainSource.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processAotIsSkippedWhenProjectHasNoMainSource.gradle new file mode 100644 index 0000000000..935a2856c6 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processAotIsSkippedWhenProjectHasNoMainSource.gradle @@ -0,0 +1,13 @@ +plugins { + id 'org.springframework.boot' + id 'org.springframework.boot.aot' + id 'java' +} + +repositories { + mavenCentral() +} + +springBoot { + mainClass = 'com.example.Application' +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processTestAotIsSkippedWhenProjectHasNoTestSource.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processTestAotIsSkippedWhenProjectHasNoTestSource.gradle new file mode 100644 index 0000000000..935a2856c6 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processTestAotIsSkippedWhenProjectHasNoTestSource.gradle @@ -0,0 +1,13 @@ +plugins { + id 'org.springframework.boot' + id 'org.springframework.boot.aot' + id 'java' +} + +repositories { + mavenCentral() +} + +springBoot { + mainClass = 'com.example.Application' +}