mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-05 00:56:58 +08:00
Merge branch '3.0.x' into 3.1.x
Closes gh-36255
This commit is contained in:
commit
64eaca4db3
@ -22,7 +22,6 @@ import java.nio.file.Files;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.tngtech.archunit.base.DescribedPredicate;
|
||||
import com.tngtech.archunit.core.domain.JavaClass;
|
||||
@ -45,9 +44,12 @@ import org.gradle.api.Task;
|
||||
import org.gradle.api.file.DirectoryProperty;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.file.FileTree;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.tasks.IgnoreEmptyDirectories;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputFiles;
|
||||
import org.gradle.api.tasks.Internal;
|
||||
import org.gradle.api.tasks.Optional;
|
||||
import org.gradle.api.tasks.OutputDirectory;
|
||||
import org.gradle.api.tasks.PathSensitive;
|
||||
import org.gradle.api.tasks.PathSensitivity;
|
||||
@ -65,17 +67,20 @@ public abstract class ArchitectureCheck extends DefaultTask {
|
||||
|
||||
public ArchitectureCheck() {
|
||||
getOutputDirectory().convention(getProject().getLayout().getBuildDirectory().dir(getName()));
|
||||
getRules().addAll(allPackagesShouldBeFreeOfTangles(),
|
||||
allBeanPostProcessorBeanMethodsShouldBeStaticAndHaveParametersThatWillNotCausePrematureInitialization(),
|
||||
allBeanFactoryPostProcessorBeanMethodsShouldBeStaticAndHaveNoParameters(),
|
||||
noClassesShouldCallStepVerifierStepVerifyComplete(),
|
||||
noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList());
|
||||
getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList()));
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void checkArchitecture() throws IOException {
|
||||
JavaClasses javaClasses = new ClassFileImporter()
|
||||
.importPaths(this.classes.getFiles().stream().map(File::toPath).toList());
|
||||
List<EvaluationResult> violations = Stream.of(allPackagesShouldBeFreeOfTangles(),
|
||||
allBeanPostProcessorBeanMethodsShouldBeStaticAndHaveParametersThatWillNotCausePrematureInitialization(),
|
||||
allBeanFactoryPostProcessorBeanMethodsShouldBeStaticAndHaveNoParameters(),
|
||||
noClassesShouldCallStepVerifierStepVerifyComplete(),
|
||||
noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList())
|
||||
List<EvaluationResult> violations = getRules().get()
|
||||
.stream()
|
||||
.map((rule) -> rule.evaluate(javaClasses))
|
||||
.filter(EvaluationResult::hasViolation)
|
||||
.toList();
|
||||
@ -202,7 +207,20 @@ public abstract class ArchitectureCheck extends DefaultTask {
|
||||
return this.classes.getAsFileTree();
|
||||
}
|
||||
|
||||
@Optional
|
||||
@InputFiles
|
||||
@PathSensitive(PathSensitivity.RELATIVE)
|
||||
public abstract DirectoryProperty getResourcesDirectory();
|
||||
|
||||
@OutputDirectory
|
||||
public abstract DirectoryProperty getOutputDirectory();
|
||||
|
||||
@Internal
|
||||
public abstract ListProperty<ArchRule> getRules();
|
||||
|
||||
@Input
|
||||
// The rules themselves can't be an input as they aren't serializable so we use their
|
||||
// descriptions instead
|
||||
abstract ListProperty<String> getRuleDescriptions();
|
||||
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ public class ArchitecturePlugin implements Plugin<Project> {
|
||||
.register("checkArchitecture" + StringUtils.capitalize(sourceSet.getName()), ArchitectureCheck.class,
|
||||
(task) -> {
|
||||
task.setClasses(sourceSet.getOutput().getClassesDirs());
|
||||
task.getResourcesDirectory().set(sourceSet.getOutput().getResourcesDir());
|
||||
task.setDescription("Checks the architecture of the classes of the " + sourceSet.getName()
|
||||
+ " source set.");
|
||||
task.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);
|
||||
|
@ -17,27 +17,48 @@
|
||||
package org.springframework.boot.build.autoconfigure;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import com.tngtech.archunit.core.domain.JavaClass;
|
||||
import com.tngtech.archunit.lang.ArchCondition;
|
||||
import com.tngtech.archunit.lang.ArchRule;
|
||||
import com.tngtech.archunit.lang.ConditionEvents;
|
||||
import com.tngtech.archunit.lang.SimpleConditionEvent;
|
||||
import com.tngtech.archunit.lang.syntax.ArchRuleDefinition;
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.plugins.JavaPlugin;
|
||||
import org.gradle.api.plugins.JavaPluginExtension;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.tasks.PathSensitivity;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
|
||||
import org.springframework.boot.build.DeployedPlugin;
|
||||
import org.springframework.boot.build.architecture.ArchitectureCheck;
|
||||
import org.springframework.boot.build.architecture.ArchitecturePlugin;
|
||||
|
||||
/**
|
||||
* {@link Plugin} for projects that define auto-configuration. When applied, the plugin
|
||||
* applies the {@link DeployedPlugin}. Additionally, it reacts to the presence of the
|
||||
* {@link JavaPlugin} by:
|
||||
* applies the {@link DeployedPlugin}. Additionally, when the {@link JavaPlugin} is
|
||||
* applied it:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Adding a dependency on the auto-configuration annotation processor.
|
||||
* <li>Defining a task that produces metadata describing the auto-configuration. The
|
||||
* metadata is made available as an artifact in the
|
||||
* <li>Adds a dependency on the auto-configuration annotation processor.
|
||||
* <li>Defines a task that produces metadata describing the auto-configuration. The
|
||||
* metadata is made available as an artifact in the {@code autoConfigurationMetadata}
|
||||
* configuration.
|
||||
* <li>Reacts to the {@link ArchitecturePlugin} being applied and:
|
||||
* <ul>
|
||||
* <li>Adds a rule to the {@code checkArchitectureMain} task to verify that all
|
||||
* {@code AutoConfiguration} classes are listed in the {@code AutoConfiguration.imports}
|
||||
* file.
|
||||
* </ul>
|
||||
* </ul>
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
@ -50,6 +71,8 @@ public class AutoConfigurationPlugin implements Plugin<Project> {
|
||||
*/
|
||||
public static final String AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME = "autoConfigurationMetadata";
|
||||
|
||||
private static final String AUTO_CONFIGURATION_IMPORTS_PATH = "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports";
|
||||
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
project.getPlugins().apply(DeployedPlugin.class);
|
||||
@ -77,7 +100,62 @@ public class AutoConfigurationPlugin implements Plugin<Project> {
|
||||
project.provider((Callable<File>) task::getOutputFile),
|
||||
(artifact) -> artifact.builtBy(task));
|
||||
});
|
||||
project.getPlugins().withType(ArchitecturePlugin.class, (architecturePlugin) -> {
|
||||
project.getTasks().named("checkArchitectureMain", ArchitectureCheck.class).configure((task) -> {
|
||||
SourceSet main = project.getExtensions()
|
||||
.getByType(JavaPluginExtension.class)
|
||||
.getSourceSets()
|
||||
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
|
||||
File resourcesDirectory = main.getOutput().getResourcesDir();
|
||||
task.dependsOn(main.getProcessResourcesTaskName());
|
||||
task.getInputs().files(resourcesDirectory).optional().withPathSensitivity(PathSensitivity.RELATIVE);
|
||||
task.getRules()
|
||||
.add(allClassesAnnotatedWithAutoConfigurationShouldBeListedInAutoConfigurationImports(
|
||||
autoConfigurationImports(project, resourcesDirectory)));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private ArchRule allClassesAnnotatedWithAutoConfigurationShouldBeListedInAutoConfigurationImports(
|
||||
Provider<AutoConfigurationImports> imports) {
|
||||
return ArchRuleDefinition.classes()
|
||||
.that()
|
||||
.areAnnotatedWith("org.springframework.boot.autoconfigure.AutoConfiguration")
|
||||
.should(beListedInAutoConfigurationImports(imports))
|
||||
.allowEmptyShould(true);
|
||||
}
|
||||
|
||||
private ArchCondition<JavaClass> beListedInAutoConfigurationImports(Provider<AutoConfigurationImports> imports) {
|
||||
return new ArchCondition<>("be listed in " + AUTO_CONFIGURATION_IMPORTS_PATH) {
|
||||
|
||||
@Override
|
||||
public void check(JavaClass item, ConditionEvents events) {
|
||||
AutoConfigurationImports autoConfigurationImports = imports.get();
|
||||
if (!autoConfigurationImports.imports.contains(item.getName())) {
|
||||
events.add(SimpleConditionEvent.violated(item,
|
||||
item.getName() + " was not listed in " + autoConfigurationImports.importsFile));
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private Provider<AutoConfigurationImports> autoConfigurationImports(Project project, File resourcesDirectory) {
|
||||
Path importsFile = new File(resourcesDirectory, AUTO_CONFIGURATION_IMPORTS_PATH).toPath();
|
||||
return project.provider(() -> {
|
||||
try {
|
||||
return new AutoConfigurationImports(project.getProjectDir().toPath().relativize(importsFile),
|
||||
Files.readAllLines(importsFile));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new RuntimeException("Failed to read AutoConfiguration.imports", ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static record AutoConfigurationImports(Path importsFile, List<String> imports) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user