Improve aggregation in the reference docs project
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details

Closes gh-46600
This commit is contained in:
Andy Wilkinson 2025-07-30 15:52:28 +01:00
parent add7d845d8
commit c9c80763b7
8 changed files with 164 additions and 33 deletions

View File

@ -84,6 +84,10 @@ configurations.all {
gradlePlugin {
plugins {
aggregatorPlugin {
id = "org.springframework.boot.aggregator"
implementationClass = "org.springframework.boot.build.aggregation.AggregatorPlugin"
}
annotationProcessorPlugin {
id = "org.springframework.boot.annotation-processor"
implementationClass = "org.springframework.boot.build.processors.AnnotationProcessorPlugin"

View File

@ -0,0 +1,50 @@
/*
* Copyright 2012-present 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 org.springframework.boot.build.aggregation;
import org.gradle.api.Named;
import org.gradle.api.attributes.Category;
import org.gradle.api.attributes.Usage;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.provider.Property;
/**
* An aggregate.
*
* @author Andy Wilkinson
*/
public interface Aggregate extends Named {
/**
* The {@link Category} used to select the variant that's included in the aggregate.
* @return the category
*/
Property<String> getCategory();
/**
* The {@link Usage} used to select the variant that's included in the aggregate.
* @return the usage
*/
Property<String> getUsage();
/**
* The aggregated files.
* @return the aggregated files
*/
ConfigurableFileCollection getFiles();
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 2012-present 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 org.springframework.boot.build.aggregation;
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.NamedDomainObjectProvider;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.DependencyScopeConfiguration;
import org.gradle.api.artifacts.ResolvableConfiguration;
import org.gradle.api.attributes.Category;
import org.gradle.api.attributes.Usage;
import org.gradle.api.model.ObjectFactory;
/**
* {@link Plugin} for aggregating the output of other projects.
*
* @author Andy Wilkinson
*/
public class AggregatorPlugin implements Plugin<Project> {
@Override
public void apply(Project target) {
NamedDomainObjectContainer<Aggregate> aggregates = target.getObjects().domainObjectContainer(Aggregate.class);
target.getExtensions().add("aggregates", aggregates);
aggregates.all((aggregate) -> {
NamedDomainObjectProvider<DependencyScopeConfiguration> dependencies = target.getConfigurations()
.dependencyScope(aggregate.getName() + "Dependencies",
(configuration) -> configureAttributes(configuration, aggregate, target.getObjects()));
NamedDomainObjectProvider<ResolvableConfiguration> aggregated = target.getConfigurations()
.resolvable(aggregate.getName(), (configuration) -> {
configuration.extendsFrom(dependencies.get());
configureAttributes(configuration, aggregate, target.getObjects());
});
target.getRootProject()
.allprojects((project) -> target.getDependencies().add(dependencies.getName(), project));
aggregate.getFiles()
.convention(aggregated.map((configuration) -> configuration.getIncoming()
.artifactView((view) -> view.setLenient(true))
.getFiles()));
});
}
private void configureAttributes(Configuration configuration, Aggregate aggregate, ObjectFactory objects) {
configuration.attributes((attributes) -> {
attributes.attributeProvider(Category.CATEGORY_ATTRIBUTE,
aggregate.getCategory().map((category) -> objects.named(Category.class, category)));
attributes.attributeProvider(Usage.USAGE_ATTRIBUTE,
aggregate.getUsage().map((usage) -> objects.named(Usage.class, usage)));
});
}
}

View File

@ -61,8 +61,6 @@ public abstract class AutoConfigurationMetadata extends DefaultTask {
private FileCollection classesDirectories;
public AutoConfigurationMetadata() {
getProject().getConfigurations()
.maybeCreate(AutoConfigurationPlugin.AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME);
this.moduleName = getProject().getName();
}

View File

@ -26,6 +26,8 @@ import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.attributes.Category;
import org.gradle.api.attributes.Usage;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension;
@ -53,11 +55,7 @@ import org.springframework.boot.build.optional.OptionalDependenciesPlugin;
*/
public class AutoConfigurationPlugin implements Plugin<Project> {
/**
* Name of the {@link Configuration} that holds the auto-configuration metadata
* artifact.
*/
public static final String AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME = "autoConfigurationMetadata";
private static final String AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME = "autoConfigurationMetadata";
@Override
public void apply(Project project) {
@ -83,6 +81,14 @@ public class AutoConfigurationPlugin implements Plugin<Project> {
addAnnotationProcessorsDependencies();
TaskContainer tasks = this.project.getTasks();
ConfigurationContainer configurations = this.project.getConfigurations();
configurations.consumable(AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME, (configuration) -> {
configuration.attributes((attributes) -> {
attributes.attribute(Category.CATEGORY_ATTRIBUTE,
this.project.getObjects().named(Category.class, Category.DOCUMENTATION));
attributes.attribute(Usage.USAGE_ATTRIBUTE,
this.project.getObjects().named(Usage.class, "auto-configuration-metadata"));
});
});
tasks.register("autoConfigurationMetadata", AutoConfigurationMetadata.class,
this::configureAutoConfigurationMetadata);
TaskProvider<CheckAutoConfigurationImports> checkAutoConfigurationImports = tasks.register(

View File

@ -36,6 +36,8 @@ import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileCollection;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.TaskAction;
import org.springframework.util.StringUtils;
@ -50,6 +52,7 @@ public abstract class DocumentAutoConfigurationClasses extends DefaultTask {
private FileCollection autoConfiguration;
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
public FileCollection getAutoConfiguration() {
return this.autoConfiguration;
}

View File

@ -23,6 +23,8 @@ import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.attributes.Category;
import org.gradle.api.attributes.Usage;
import org.gradle.api.file.RegularFile;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension;
@ -56,11 +58,7 @@ import org.springframework.util.StringUtils;
*/
public class ConfigurationPropertiesPlugin implements Plugin<Project> {
/**
* Name of the {@link Configuration} that holds the configuration property metadata
* artifact.
*/
public static final String CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME = "configurationPropertiesMetadata";
private static final String CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME = "configurationPropertiesMetadata";
/**
* Name of the {@link CheckAdditionalSpringConfigurationMetadata} task.
@ -108,7 +106,15 @@ public class ConfigurationPropertiesPlugin implements Plugin<Project> {
.getByType(JavaPluginExtension.class)
.getSourceSets()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
project.getConfigurations().maybeCreate(CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME);
project.getConfigurations()
.consumable(CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME, (configuration) -> {
configuration.attributes((attributes) -> {
attributes.attribute(Category.CATEGORY_ATTRIBUTE,
project.getObjects().named(Category.class, Category.DOCUMENTATION));
attributes.attribute(Usage.USAGE_ATTRIBUTE,
project.getObjects().named(Usage.class, "configuration-properties-metadata"));
});
});
project.afterEvaluate((evaluatedProject) -> evaluatedProject.getArtifacts()
.add(CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME,
mainSourceSet.getJava()

View File

@ -20,17 +20,16 @@ plugins {
id "dev.adamko.dokkatoo-html"
id "java"
id "org.antora"
id "org.jetbrains.kotlin.jvm"
id "org.springframework.boot.aggregator"
id "org.springframework.boot.antora-contributor"
id "org.springframework.boot.antora-dependencies"
id "org.springframework.boot.deployed"
id 'org.jetbrains.kotlin.jvm'
}
description = "Spring Boot Docs"
configurations {
autoConfiguration
configurationProperties
remoteSpringApplicationExample
resolvedBom
springApplicationExample
@ -69,20 +68,6 @@ plugins.withType(EclipsePlugin) {
}
dependencies {
autoConfiguration(project(path: ":spring-boot-project:spring-boot-actuator-autoconfigure", configuration: "autoConfigurationMetadata"))
autoConfiguration(project(path: ":spring-boot-project:spring-boot-autoconfigure", configuration: "autoConfigurationMetadata"))
autoConfiguration(project(path: ":spring-boot-project:spring-boot-devtools", configuration: "autoConfigurationMetadata"))
autoConfiguration(project(path: ":spring-boot-project:spring-boot-testcontainers", configuration: "autoConfigurationMetadata"))
configurationProperties(project(path: ":spring-boot-project:spring-boot", configuration: "configurationPropertiesMetadata"))
configurationProperties(project(path: ":spring-boot-project:spring-boot-actuator", configuration: "configurationPropertiesMetadata"))
configurationProperties(project(path: ":spring-boot-project:spring-boot-actuator-autoconfigure", configuration: "configurationPropertiesMetadata"))
configurationProperties(project(path: ":spring-boot-project:spring-boot-autoconfigure", configuration: "configurationPropertiesMetadata"))
configurationProperties(project(path: ":spring-boot-project:spring-boot-devtools", configuration: "configurationPropertiesMetadata"))
configurationProperties(project(path: ":spring-boot-project:spring-boot-docker-compose", configuration: "configurationPropertiesMetadata"))
configurationProperties(project(path: ":spring-boot-project:spring-boot-test-autoconfigure", configuration: "configurationPropertiesMetadata"))
configurationProperties(project(path: ":spring-boot-project:spring-boot-testcontainers", configuration: "configurationPropertiesMetadata"))
dokkatoo(project(path: ":spring-boot-project:spring-boot"))
dokkatoo(project(path: ":spring-boot-project:spring-boot-test"))
@ -257,8 +242,13 @@ tasks.register("documentStarters", org.springframework.boot.build.starters.Docum
outputDir = layout.buildDirectory.dir("generated/docs/using/starters/")
}
def autoConfigurationMetadataAggregate = aggregates.create("autoConfigurationMetadata") {
category = Category.DOCUMENTATION
usage = "auto-configuration-metadata"
}
tasks.register("documentAutoConfigurationClasses", org.springframework.boot.build.autoconfigure.DocumentAutoConfigurationClasses) {
autoConfiguration = configurations.autoConfiguration
autoConfiguration = autoConfigurationMetadataAggregate.files
outputDir = layout.buildDirectory.dir("generated/docs/auto-configuration-classes/documented-auto-configuration-classes/")
}
@ -272,8 +262,13 @@ tasks.register("documentDependencyVersionProperties", org.springframework.boot.b
resolvedBoms = configurations.resolvedBom
}
def configurationPropertiesMetadataAggregate = aggregates.create("configurationPropertiesMetadata") {
category = Category.DOCUMENTATION
usage = "configuration-properties-metadata"
}
tasks.register("documentConfigurationProperties", org.springframework.boot.build.context.properties.DocumentConfigurationProperties) {
configurationPropertyMetadata = configurations.configurationProperties
configurationPropertyMetadata = configurationPropertiesMetadataAggregate.files
outputDir = layout.buildDirectory.dir("generated/docs/application-properties")
}
@ -349,7 +344,7 @@ antoraContributions {
from("src/main") {
into "modules/ROOT/examples"
}
from(project.configurations.configurationProperties) {
from(configurationPropertiesMetadataAggregate.files) {
eachFile {
it.path = rootProject
.projectDir