Merge branch '3.3.x' into 3.4.x

Closes gh-44892
This commit is contained in:
Andy Wilkinson 2025-03-25 17:31:10 +00:00
commit 32234545af
3 changed files with 57 additions and 222 deletions

View File

@ -35,7 +35,9 @@ import org.antora.gradle.AntoraPlugin;
import org.antora.gradle.AntoraTask;
import org.gradle.StartParameter;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.file.Directory;
import org.gradle.api.file.FileCollection;
import org.gradle.api.logging.LogLevel;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.provider.Provider;
@ -46,7 +48,7 @@ import org.gradle.api.tasks.TaskProvider;
import org.springframework.boot.build.antora.AntoraAsciidocAttributes;
import org.springframework.boot.build.antora.GenerateAntoraPlaybook;
import org.springframework.boot.build.bom.BomExtension;
import org.springframework.boot.build.constraints.ExtractVersionConstraints;
import org.springframework.boot.build.bom.ResolvedBom;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@ -76,7 +78,10 @@ public class AntoraConventions {
}
private void apply(Project project, AntoraPlugin antoraPlugin) {
TaskProvider<ExtractVersionConstraints> dependencyVersionsTask = addDependencyVersionsTask(project);
Configuration resolvedBom = project.getConfigurations().create("resolveBom");
project.getDependencies()
.add(resolvedBom.getName(), project.getDependencies()
.project(Map.of("path", DEPENDENCIES_PATH, "configuration", "resolvedBom")));
project.getPlugins().apply(GenerateAntoraYmlPlugin.class);
TaskContainer tasks = project.getTasks();
TaskProvider<GenerateAntoraPlaybook> generateAntoraPlaybookTask = tasks.register(
@ -86,8 +91,8 @@ public class AntoraConventions {
(task) -> configureCopyAntoraPackageJsonTask(project, task));
TaskProvider<NpmInstallTask> npmInstallTask = tasks.register("antoraNpmInstall", NpmInstallTask.class,
(task) -> configureNpmInstallTask(project, task, copyAntoraPackageJsonTask));
tasks.withType(GenerateAntoraYmlTask.class, (generateAntoraYmlTask) -> configureGenerateAntoraYmlTask(project,
generateAntoraYmlTask, dependencyVersionsTask));
tasks.withType(GenerateAntoraYmlTask.class,
(generateAntoraYmlTask) -> configureGenerateAntoraYmlTask(project, generateAntoraYmlTask, resolvedBom));
tasks.withType(AntoraTask.class,
(antoraTask) -> configureAntoraTask(project, antoraTask, npmInstallTask, generateAntoraPlaybookTask));
project.getExtensions()
@ -118,21 +123,15 @@ public class AntoraConventions {
npmInstallTask.getNpmCommand().set(List.of("ci", "--silent", "--no-progress"));
}
private TaskProvider<ExtractVersionConstraints> addDependencyVersionsTask(Project project) {
return project.getTasks()
.register("dependencyVersions", ExtractVersionConstraints.class,
(task) -> task.enforcedPlatform(DEPENDENCIES_PATH));
}
private void configureGenerateAntoraYmlTask(Project project, GenerateAntoraYmlTask generateAntoraYmlTask,
TaskProvider<ExtractVersionConstraints> dependencyVersionsTask) {
Configuration resolvedBom) {
generateAntoraYmlTask.getOutputs().doNotCacheIf("getAsciidocAttributes() changes output", (task) -> true);
generateAntoraYmlTask.dependsOn(dependencyVersionsTask);
generateAntoraYmlTask.dependsOn(resolvedBom);
generateAntoraYmlTask.setProperty("componentName", "boot");
generateAntoraYmlTask.setProperty("outputFile",
project.getLayout().getBuildDirectory().file("generated/docs/antora-yml/antora.yml"));
generateAntoraYmlTask.setProperty("yml", getDefaultYml(project));
generateAntoraYmlTask.getAsciidocAttributes().putAll(getAsciidocAttributes(project, dependencyVersionsTask));
generateAntoraYmlTask.getAsciidocAttributes().putAll(getAsciidocAttributes(project, resolvedBom));
}
private Map<String, ?> getDefaultYml(Project project) {
@ -151,11 +150,11 @@ public class AntoraConventions {
return defaultYml;
}
private Provider<Map<String, String>> getAsciidocAttributes(Project project,
TaskProvider<ExtractVersionConstraints> dependencyVersionsTask) {
return dependencyVersionsTask.map((task) -> task.getVersionConstraints()).map((constraints) -> {
private Provider<Map<String, String>> getAsciidocAttributes(Project project, FileCollection resolvedBoms) {
return project.provider(() -> {
BomExtension bom = (BomExtension) project.project(DEPENDENCIES_PATH).getExtensions().getByName("bom");
return new AntoraAsciidocAttributes(project, bom, constraints).get();
ResolvedBom resolvedBom = ResolvedBom.readFrom(resolvedBoms.getSingleFile());
return new AntoraAsciidocAttributes(project, bom, resolvedBom).get();
});
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2012-2025 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.
@ -20,7 +20,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -32,6 +34,10 @@ import org.gradle.api.Project;
import org.springframework.boot.build.artifacts.ArtifactRelease;
import org.springframework.boot.build.bom.BomExtension;
import org.springframework.boot.build.bom.Library;
import org.springframework.boot.build.bom.ResolvedBom;
import org.springframework.boot.build.bom.ResolvedBom.Bom;
import org.springframework.boot.build.bom.ResolvedBom.Id;
import org.springframework.boot.build.bom.ResolvedBom.ResolvedLibrary;
import org.springframework.boot.build.properties.BuildProperties;
import org.springframework.boot.build.properties.BuildType;
import org.springframework.util.Assert;
@ -59,17 +65,48 @@ public class AntoraAsciidocAttributes {
private final Map<String, ?> projectProperties;
public AntoraAsciidocAttributes(Project project, BomExtension dependencyBom,
Map<String, String> dependencyVersions) {
public AntoraAsciidocAttributes(Project project, BomExtension dependencyBom, ResolvedBom resolvedBom) {
this.version = String.valueOf(project.getVersion());
this.latestVersion = Boolean.parseBoolean(String.valueOf(project.findProperty("latestVersion")));
this.buildType = BuildProperties.get(project).buildType();
this.artifactRelease = ArtifactRelease.forProject(project);
this.libraries = dependencyBom.getLibraries();
this.dependencyVersions = dependencyVersions;
this.dependencyVersions = dependencyVersionsOf(resolvedBom);
this.projectProperties = project.getProperties();
}
private static Map<String, String> dependencyVersionsOf(ResolvedBom resolvedBom) {
Map<String, String> dependencyVersions = new HashMap<>();
for (ResolvedLibrary library : resolvedBom.libraries()) {
dependencyVersions.putAll(dependencyVersionsOf(library.managedDependencies()));
for (Bom importedBom : library.importedBoms()) {
dependencyVersions.putAll(dependencyVersionsOf(importedBom));
}
}
return dependencyVersions;
}
private static Map<String, String> dependencyVersionsOf(Bom bom) {
Map<String, String> dependencyVersions = new HashMap<>();
if (bom != null) {
dependencyVersions.putAll(dependencyVersionsOf(bom.managedDependencies()));
dependencyVersions.putAll(dependencyVersionsOf(bom.parent()));
for (Bom importedBom : bom.importedBoms()) {
dependencyVersions.putAll(dependencyVersionsOf(importedBom));
}
}
return dependencyVersions;
}
private static Map<String, String> dependencyVersionsOf(Collection<Id> managedDependencies) {
Map<String, String> dependencyVersions = new HashMap<>();
for (Id managedDependency : managedDependencies) {
dependencyVersions.put(managedDependency.groupId() + ":" + managedDependency.artifactId(),
managedDependency.version());
}
return dependencyVersions;
}
AntoraAsciidocAttributes(String version, boolean latestVersion, BuildType buildType, List<Library> libraries,
Map<String, String> dependencyVersions, Map<String, ?> projectProperties) {
this.version = version;

View File

@ -1,201 +0,0 @@
/*
* Copyright 2012-2024 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.constraints;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.gradle.api.DefaultTask;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.ComponentMetadataDetails;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.DependencyConstraint;
import org.gradle.api.artifacts.DependencyConstraintMetadata;
import org.gradle.api.artifacts.DependencyConstraintSet;
import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.TaskAction;
import org.gradle.platform.base.Platform;
import org.springframework.boot.build.bom.BomExtension;
import org.springframework.boot.build.bom.BomPlugin;
import org.springframework.boot.build.bom.Library;
/**
* {@link Task} to extract constraints from a {@link Platform}. The platform's own
* constraints and those in any boms upon which it depends are extracted.
*
* @author Andy Wilkinson
*/
public abstract class ExtractVersionConstraints extends DefaultTask {
private final Configuration configuration;
private final Map<String, String> versionConstraints = new TreeMap<>();
private final Set<ConstrainedVersion> constrainedVersions = new TreeSet<>();
private final Set<VersionProperty> versionProperties = new TreeSet<>();
private final List<DependencyConstraintSet> dependencyConstraintSets = new ArrayList<>();
private final List<BomExtension> boms = new ArrayList<>();
private final DependencyHandler dependencies;
public ExtractVersionConstraints() {
this.dependencies = getProject().getDependencies();
this.configuration = getProject().getConfigurations().create(getName());
this.dependencies.getComponents().all(this::processMetadataDetails);
}
public void enforcedPlatform(String projectPath) {
this.configuration.getDependencies()
.add(this.dependencies
.enforcedPlatform(this.dependencies.project(Collections.singletonMap("path", projectPath))));
Project project = getProject().project(projectPath);
project.getPlugins().withType(BomPlugin.class).all((plugin) -> {
this.boms.add(project.getExtensions().getByType(BomExtension.class));
this.dependencyConstraintSets
.add(project.getConfigurations().getByName("apiElements").getAllDependencyConstraints());
});
}
@Internal
public Map<String, String> getVersionConstraints() {
return Collections.unmodifiableMap(this.versionConstraints);
}
@Internal
public Set<ConstrainedVersion> getConstrainedVersions() {
return this.constrainedVersions;
}
@Internal
public Set<VersionProperty> getVersionProperties() {
return this.versionProperties;
}
@TaskAction
void extractVersionConstraints() {
this.configuration.resolve();
this.boms.forEach(this::extractVersionProperties);
for (DependencyConstraintSet constraints : this.dependencyConstraintSets) {
for (DependencyConstraint constraint : constraints) {
this.versionConstraints.put(constraint.getGroup() + ":" + constraint.getName(),
constraint.getVersionConstraint().toString());
this.constrainedVersions.add(new ConstrainedVersion(constraint.getGroup(), constraint.getName(),
constraint.getVersionConstraint().toString()));
}
}
}
private void extractVersionProperties(BomExtension bomExtension) {
for (Library lib : bomExtension.getLibraries()) {
String versionProperty = lib.getVersionProperty();
if (versionProperty != null) {
this.versionProperties.add(new VersionProperty(lib.getName(), versionProperty));
}
}
}
private void processMetadataDetails(ComponentMetadataDetails details) {
details.allVariants((variantMetadata) -> variantMetadata.withDependencyConstraints((dependencyConstraints) -> {
for (DependencyConstraintMetadata constraint : dependencyConstraints) {
this.versionConstraints.put(constraint.getGroup() + ":" + constraint.getName(),
constraint.getVersionConstraint().toString());
this.constrainedVersions.add(new ConstrainedVersion(constraint.getGroup(), constraint.getName(),
constraint.getVersionConstraint().toString()));
}
}));
}
public static final class ConstrainedVersion implements Comparable<ConstrainedVersion>, Serializable {
private final String group;
private final String artifact;
private final String version;
private ConstrainedVersion(String group, String artifact, String version) {
this.group = group;
this.artifact = artifact;
this.version = version;
}
public String getGroup() {
return this.group;
}
public String getArtifact() {
return this.artifact;
}
public String getVersion() {
return this.version;
}
@Override
public int compareTo(ConstrainedVersion other) {
int groupComparison = this.group.compareTo(other.group);
if (groupComparison != 0) {
return groupComparison;
}
return this.artifact.compareTo(other.artifact);
}
}
public static final class VersionProperty implements Comparable<VersionProperty>, Serializable {
private final String libraryName;
private final String versionProperty;
public VersionProperty(String libraryName, String versionProperty) {
this.libraryName = libraryName;
this.versionProperty = versionProperty;
}
public String getLibraryName() {
return this.libraryName;
}
public String getVersionProperty() {
return this.versionProperty;
}
@Override
public int compareTo(VersionProperty other) {
int groupComparison = this.libraryName.compareToIgnoreCase(other.libraryName);
if (groupComparison != 0) {
return groupComparison;
}
return this.versionProperty.compareTo(other.versionProperty);
}
}
}