mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-15 01:07:30 +08:00
Merge branch '3.1.x' into 3.2.x
Closes gh-39133
This commit is contained in:
commit
c0fedc8f74
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* 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.
|
||||
@ -62,6 +62,7 @@ import org.springframework.boot.build.bom.Library.Group;
|
||||
import org.springframework.boot.build.bom.Library.LibraryVersion;
|
||||
import org.springframework.boot.build.bom.Library.Module;
|
||||
import org.springframework.boot.build.bom.Library.ProhibitedVersion;
|
||||
import org.springframework.boot.build.bom.Library.VersionAlignment;
|
||||
import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
|
||||
import org.springframework.boot.build.mavenplugin.MavenExec;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
@ -113,8 +114,12 @@ public class BomExtension {
|
||||
LibraryHandler libraryHandler = objects.newInstance(LibraryHandler.class, (version != null) ? version : "");
|
||||
action.execute(libraryHandler);
|
||||
LibraryVersion libraryVersion = new LibraryVersion(DependencyVersion.parse(libraryHandler.version));
|
||||
VersionAlignment versionAlignment = (libraryHandler.alignWithVersion != null)
|
||||
? new VersionAlignment(libraryHandler.alignWithVersion.from, libraryHandler.alignWithVersion.managedBy,
|
||||
this.project, this.libraries, libraryHandler.groups)
|
||||
: null;
|
||||
addLibrary(new Library(name, libraryHandler.calendarName, libraryVersion, libraryHandler.groups,
|
||||
libraryHandler.prohibitedVersions, libraryHandler.considerSnapshots));
|
||||
libraryHandler.prohibitedVersions, libraryHandler.considerSnapshots, versionAlignment));
|
||||
}
|
||||
|
||||
public void effectiveBomArtifact() {
|
||||
@ -220,6 +225,8 @@ public class BomExtension {
|
||||
|
||||
private String calendarName;
|
||||
|
||||
private AlignWithVersionHandler alignWithVersion;
|
||||
|
||||
@Inject
|
||||
public LibraryHandler(String version) {
|
||||
this.version = version;
|
||||
@ -251,6 +258,11 @@ public class BomExtension {
|
||||
handler.endsWith, handler.contains, handler.reason));
|
||||
}
|
||||
|
||||
public void alignWithVersion(Action<AlignWithVersionHandler> action) {
|
||||
this.alignWithVersion = new AlignWithVersionHandler();
|
||||
action.execute(this.alignWithVersion);
|
||||
}
|
||||
|
||||
public static class ProhibitedHandler {
|
||||
|
||||
private String reason;
|
||||
@ -368,6 +380,22 @@ public class BomExtension {
|
||||
|
||||
}
|
||||
|
||||
public static class AlignWithVersionHandler {
|
||||
|
||||
private String from;
|
||||
|
||||
private String managedBy;
|
||||
|
||||
public void from(String from) {
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
public void managedBy(String managedBy) {
|
||||
this.managedBy = managedBy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class UpgradeHandler {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* 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.
|
||||
@ -35,6 +35,7 @@ import org.gradle.api.tasks.TaskAction;
|
||||
import org.springframework.boot.build.bom.Library.Group;
|
||||
import org.springframework.boot.build.bom.Library.Module;
|
||||
import org.springframework.boot.build.bom.Library.ProhibitedVersion;
|
||||
import org.springframework.boot.build.bom.Library.VersionAlignment;
|
||||
import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
|
||||
|
||||
/**
|
||||
@ -69,6 +70,7 @@ public class CheckBom extends DefaultTask {
|
||||
List<String> libraryErrors = new ArrayList<>();
|
||||
checkExclusions(library, libraryErrors);
|
||||
checkProhibitedVersions(library, libraryErrors);
|
||||
checkVersionAlignment(library, libraryErrors);
|
||||
if (!libraryErrors.isEmpty()) {
|
||||
errors.add(library.getName());
|
||||
for (String libraryError : libraryErrors) {
|
||||
@ -148,4 +150,28 @@ public class CheckBom extends DefaultTask {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkVersionAlignment(Library library, List<String> errors) {
|
||||
VersionAlignment versionAlignment = library.getVersionAlignment();
|
||||
if (versionAlignment == null) {
|
||||
return;
|
||||
}
|
||||
Set<String> alignedVersions = versionAlignment.resolve();
|
||||
if (alignedVersions.size() == 1) {
|
||||
String alignedVersion = alignedVersions.iterator().next();
|
||||
if (!alignedVersion.equals(library.getVersion().getVersion().toString())) {
|
||||
errors.add("Version " + library.getVersion().getVersion() + " is misaligned. It should be "
|
||||
+ alignedVersion + ".");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (alignedVersions.isEmpty()) {
|
||||
errors.add("Version alignment requires a single version but none were found.");
|
||||
}
|
||||
else {
|
||||
errors.add("Version alignment requires a single version but " + alignedVersions.size() + " were found: "
|
||||
+ alignedVersions + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* 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.
|
||||
@ -16,12 +16,22 @@
|
||||
|
||||
package org.springframework.boot.build.bom;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
import org.gradle.api.artifacts.dsl.DependencyHandler;
|
||||
import org.gradle.api.artifacts.result.DependencyResult;
|
||||
|
||||
import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
|
||||
|
||||
@ -47,6 +57,8 @@ public class Library {
|
||||
|
||||
private final boolean considerSnapshots;
|
||||
|
||||
private final VersionAlignment versionAlignment;
|
||||
|
||||
/**
|
||||
* Create a new {@code Library} with the given {@code name}, {@code version}, and
|
||||
* {@code groups}.
|
||||
@ -57,9 +69,10 @@ public class Library {
|
||||
* @param groups groups in the library
|
||||
* @param prohibitedVersions version of the library that are prohibited
|
||||
* @param considerSnapshots whether to consider snapshots
|
||||
* @param versionAlignment version alignment, if any, for the library
|
||||
*/
|
||||
public Library(String name, String calendarName, LibraryVersion version, List<Group> groups,
|
||||
List<ProhibitedVersion> prohibitedVersions, boolean considerSnapshots) {
|
||||
List<ProhibitedVersion> prohibitedVersions, boolean considerSnapshots, VersionAlignment versionAlignment) {
|
||||
this.name = name;
|
||||
this.calendarName = (calendarName != null) ? calendarName : name;
|
||||
this.version = version;
|
||||
@ -68,6 +81,7 @@ public class Library {
|
||||
: name.toLowerCase(Locale.ENGLISH).replace(' ', '-') + ".version";
|
||||
this.prohibitedVersions = prohibitedVersions;
|
||||
this.considerSnapshots = considerSnapshots;
|
||||
this.versionAlignment = versionAlignment;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@ -98,6 +112,10 @@ public class Library {
|
||||
return this.considerSnapshots;
|
||||
}
|
||||
|
||||
public VersionAlignment getVersionAlignment() {
|
||||
return this.versionAlignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* A version or range of versions that are prohibited from being used in a bom.
|
||||
*/
|
||||
@ -280,4 +298,99 @@ public class Library {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Version alignment for a library.
|
||||
*/
|
||||
public static class VersionAlignment {
|
||||
|
||||
private final String from;
|
||||
|
||||
private final String managedBy;
|
||||
|
||||
private final Project project;
|
||||
|
||||
private final List<Library> libraries;
|
||||
|
||||
private final List<Group> groups;
|
||||
|
||||
private Set<String> alignedVersions;
|
||||
|
||||
VersionAlignment(String from, String managedBy, Project project, List<Library> libraries, List<Group> groups) {
|
||||
this.from = from;
|
||||
this.managedBy = managedBy;
|
||||
this.project = project;
|
||||
this.libraries = libraries;
|
||||
this.groups = groups;
|
||||
}
|
||||
|
||||
public Set<String> resolve() {
|
||||
if (this.managedBy == null) {
|
||||
throw new IllegalStateException("Version alignment without managedBy is not supported");
|
||||
}
|
||||
if (this.alignedVersions != null) {
|
||||
return this.alignedVersions;
|
||||
}
|
||||
Library managingLibrary = this.libraries.stream()
|
||||
.filter((candidate) -> this.managedBy.equals(candidate.getName()))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Managing library '" + this.managedBy + "' not found."));
|
||||
Map<String, String> versions = resolveAligningDependencies(managingLibrary);
|
||||
Set<String> versionsInLibrary = new HashSet<>();
|
||||
for (Group group : this.groups) {
|
||||
for (Module module : group.getModules()) {
|
||||
String version = versions.get(group.getId() + ":" + module.getName());
|
||||
if (version != null) {
|
||||
versionsInLibrary.add(version);
|
||||
}
|
||||
}
|
||||
for (String plugin : group.getPlugins()) {
|
||||
String version = versions.get(group.getId() + ":" + plugin);
|
||||
if (version != null) {
|
||||
versionsInLibrary.add(version);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.alignedVersions = versionsInLibrary;
|
||||
return this.alignedVersions;
|
||||
}
|
||||
|
||||
private Map<String, String> resolveAligningDependencies(Library manager) {
|
||||
DependencyHandler dependencyHandler = this.project.getDependencies();
|
||||
List<Dependency> boms = manager.getGroups()
|
||||
.stream()
|
||||
.flatMap((group) -> group.getBoms()
|
||||
.stream()
|
||||
.map((bom) -> dependencyHandler
|
||||
.platform(group.getId() + ":" + bom + ":" + manager.getVersion().getVersion())))
|
||||
.toList();
|
||||
List<Dependency> dependencies = new ArrayList<>();
|
||||
dependencies.addAll(boms);
|
||||
dependencies.add(dependencyHandler.create(this.from));
|
||||
Configuration alignmentConfiguration = this.project.getConfigurations()
|
||||
.detachedConfiguration(dependencies.toArray(new Dependency[0]));
|
||||
Map<String, String> versions = new HashMap<>();
|
||||
for (DependencyResult dependency : alignmentConfiguration.getIncoming()
|
||||
.getResolutionResult()
|
||||
.getAllDependencies()) {
|
||||
versions.put(dependency.getFrom().getModuleVersion().getModule().toString(),
|
||||
dependency.getFrom().getModuleVersion().getVersion());
|
||||
}
|
||||
return versions;
|
||||
}
|
||||
|
||||
String getFrom() {
|
||||
return this.from;
|
||||
}
|
||||
|
||||
String getManagedBy() {
|
||||
return this.managedBy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "version from dependencies of " + this.from + " that is managed by " + this.managedBy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* 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.
|
||||
@ -20,6 +20,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
@ -57,11 +58,16 @@ class MultithreadedLibraryUpdateResolver implements LibraryUpdateResolver {
|
||||
LOGGER.info("Looking for updates using {} threads", this.threads);
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(this.threads);
|
||||
try {
|
||||
return librariesToUpgrade.stream()
|
||||
.map((library) -> executorService.submit(
|
||||
() -> this.delegate.findLibraryUpdates(Collections.singletonList(library), librariesByName)))
|
||||
.flatMap(this::getResult)
|
||||
.toList();
|
||||
return librariesToUpgrade.stream().map((library) -> {
|
||||
if (library.getVersionAlignment() == null) {
|
||||
return executorService.submit(() -> this.delegate
|
||||
.findLibraryUpdates(Collections.singletonList(library), librariesByName));
|
||||
}
|
||||
else {
|
||||
return CompletableFuture.completedFuture(
|
||||
this.delegate.findLibraryUpdates(Collections.singletonList(library), librariesByName));
|
||||
}
|
||||
}).flatMap(this::getResult).toList();
|
||||
}
|
||||
finally {
|
||||
executorService.shutdownNow();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* 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.
|
||||
@ -22,6 +22,7 @@ import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
@ -31,6 +32,7 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.build.bom.Library;
|
||||
import org.springframework.boot.build.bom.Library.Group;
|
||||
import org.springframework.boot.build.bom.Library.Module;
|
||||
import org.springframework.boot.build.bom.Library.VersionAlignment;
|
||||
import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
|
||||
|
||||
/**
|
||||
@ -63,7 +65,7 @@ class StandardLibraryUpdateResolver implements LibraryUpdateResolver {
|
||||
}
|
||||
LOGGER.info("Looking for updates for {}", library.getName());
|
||||
long start = System.nanoTime();
|
||||
List<VersionOption> versionOptions = getVersionOptions(library, librariesByName);
|
||||
List<VersionOption> versionOptions = getVersionOptions(library);
|
||||
result.add(new LibraryWithVersionOptions(library, versionOptions));
|
||||
LOGGER.info("Found {} updates for {}, took {}", versionOptions.size(), library.getName(),
|
||||
Duration.ofNanos(System.nanoTime() - start));
|
||||
@ -75,8 +77,21 @@ class StandardLibraryUpdateResolver implements LibraryUpdateResolver {
|
||||
return library.getName().equals("Spring Boot");
|
||||
}
|
||||
|
||||
protected List<VersionOption> getVersionOptions(Library library, Map<String, Library> libraries) {
|
||||
return determineResolvedVersionOptions(library);
|
||||
protected List<VersionOption> getVersionOptions(Library library) {
|
||||
VersionOption option = determineAlignedVersionOption(library);
|
||||
return (option != null) ? List.of(option) : determineResolvedVersionOptions(library);
|
||||
}
|
||||
|
||||
private VersionOption determineAlignedVersionOption(Library library) {
|
||||
VersionAlignment versionAlignment = library.getVersionAlignment();
|
||||
if (versionAlignment != null) {
|
||||
Set<String> alignedVersions = versionAlignment.resolve();
|
||||
if (alignedVersions != null && alignedVersions.size() == 1) {
|
||||
return new VersionOption.AlignedVersionOption(
|
||||
DependencyVersion.parse(alignedVersions.iterator().next()), versionAlignment);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<VersionOption> determineResolvedVersionOptions(Library library) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* 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.
|
||||
@ -226,13 +226,13 @@ public abstract class UpgradeDependencies extends DefaultTask {
|
||||
|
||||
protected List<BiPredicate<Library, DependencyVersion>> determineUpdatePredicates(Milestone milestone) {
|
||||
List<BiPredicate<Library, DependencyVersion>> updatePredicates = new ArrayList<>();
|
||||
updatePredicates.add(this::compilesWithUpgradePolicy);
|
||||
updatePredicates.add(this::compliesWithUpgradePolicy);
|
||||
updatePredicates.add(this::isAnUpgrade);
|
||||
updatePredicates.add(this::isNotProhibited);
|
||||
return updatePredicates;
|
||||
}
|
||||
|
||||
private boolean compilesWithUpgradePolicy(Library library, DependencyVersion candidate) {
|
||||
private boolean compliesWithUpgradePolicy(Library library, DependencyVersion candidate) {
|
||||
return this.bom.getUpgrade().getPolicy().test(candidate, library.getVersion().getVersion());
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* 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.
|
||||
@ -18,7 +18,7 @@ package org.springframework.boot.build.bom.bomr;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.build.bom.Library;
|
||||
import org.springframework.boot.build.bom.Library.VersionAlignment;
|
||||
import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@ -46,17 +46,16 @@ class VersionOption {
|
||||
|
||||
static final class AlignedVersionOption extends VersionOption {
|
||||
|
||||
private final Library alignedWith;
|
||||
private final VersionAlignment alignedWith;
|
||||
|
||||
AlignedVersionOption(DependencyVersion version, Library alignedWith) {
|
||||
AlignedVersionOption(DependencyVersion version, VersionAlignment alignedWith) {
|
||||
super(version);
|
||||
this.alignedWith = alignedWith;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " (aligned with " + this.alignedWith.getName() + " "
|
||||
+ this.alignedWith.getVersion().getVersion() + ")";
|
||||
return super.toString() + " (aligned with " + this.alignedWith + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* 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.
|
||||
@ -53,7 +53,7 @@ class UpgradeApplicatorTests {
|
||||
FileCopyUtils.copy(new File("src/test/resources/gradle.properties"), gradleProperties);
|
||||
new UpgradeApplicator(bom.toPath(), gradleProperties.toPath())
|
||||
.apply(new Upgrade(new Library("ActiveMQ", null, new LibraryVersion(DependencyVersion.parse("5.15.11")),
|
||||
null, null, false), DependencyVersion.parse("5.16")));
|
||||
null, null, false, null), DependencyVersion.parse("5.16")));
|
||||
String bomContents = Files.readString(bom.toPath());
|
||||
assertThat(bomContents).hasSize(originalContents.length() - 3);
|
||||
}
|
||||
@ -64,9 +64,9 @@ class UpgradeApplicatorTests {
|
||||
FileCopyUtils.copy(new File("src/test/resources/bom.gradle"), bom);
|
||||
File gradleProperties = new File(this.temp, "gradle.properties");
|
||||
FileCopyUtils.copy(new File("src/test/resources/gradle.properties"), gradleProperties);
|
||||
new UpgradeApplicator(bom.toPath(), gradleProperties.toPath()).apply(new Upgrade(
|
||||
new Library("Kotlin", null, new LibraryVersion(DependencyVersion.parse("1.3.70")), null, null, false),
|
||||
DependencyVersion.parse("1.4")));
|
||||
new UpgradeApplicator(bom.toPath(), gradleProperties.toPath())
|
||||
.apply(new Upgrade(new Library("Kotlin", null, new LibraryVersion(DependencyVersion.parse("1.3.70")), null,
|
||||
null, false, null), DependencyVersion.parse("1.4")));
|
||||
Properties properties = new Properties();
|
||||
try (InputStream in = new FileInputStream(gradleProperties)) {
|
||||
properties.load(in);
|
||||
|
@ -1075,6 +1075,10 @@ bom {
|
||||
}
|
||||
}
|
||||
library("Neo4j Java Driver", "5.13.0") {
|
||||
alignWithVersion {
|
||||
from "org.springframework.data:spring-data-neo4j"
|
||||
managedBy "Spring Data Bom"
|
||||
}
|
||||
group("org.neo4j.driver") {
|
||||
modules = [
|
||||
"neo4j-java-driver"
|
||||
|
Loading…
Reference in New Issue
Block a user