|
|
@ -19,19 +19,25 @@ package org.springframework.boot.build.bom.bomr;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collection;
|
|
|
|
import java.util.Collection;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.Collections;
|
|
|
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
import java.util.Set;
|
|
|
|
import java.util.SortedSet;
|
|
|
|
import java.util.SortedSet;
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
|
|
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
|
|
|
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
|
|
|
|
|
|
|
import org.gradle.api.InvalidUserDataException;
|
|
|
|
import org.gradle.api.internal.tasks.userinput.UserInputHandler;
|
|
|
|
import org.gradle.api.internal.tasks.userinput.UserInputHandler;
|
|
|
|
|
|
|
|
|
|
|
|
import org.springframework.boot.build.bom.Library;
|
|
|
|
import org.springframework.boot.build.bom.Library;
|
|
|
|
|
|
|
|
import org.springframework.boot.build.bom.Library.DependencyVersions;
|
|
|
|
import org.springframework.boot.build.bom.Library.Group;
|
|
|
|
import org.springframework.boot.build.bom.Library.Group;
|
|
|
|
import org.springframework.boot.build.bom.Library.Module;
|
|
|
|
import org.springframework.boot.build.bom.Library.Module;
|
|
|
|
import org.springframework.boot.build.bom.Library.ProhibitedVersion;
|
|
|
|
import org.springframework.boot.build.bom.Library.ProhibitedVersion;
|
|
|
|
|
|
|
|
import org.springframework.boot.build.bom.Library.VersionAlignment;
|
|
|
|
import org.springframework.boot.build.bom.UpgradePolicy;
|
|
|
|
import org.springframework.boot.build.bom.UpgradePolicy;
|
|
|
|
import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
|
|
|
|
import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
|
|
|
|
import org.springframework.util.StringUtils;
|
|
|
|
import org.springframework.util.StringUtils;
|
|
|
@ -59,39 +65,91 @@ public final class InteractiveUpgradeResolver implements UpgradeResolver {
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public List<Upgrade> resolveUpgrades(Collection<Library> libraries) {
|
|
|
|
public List<Upgrade> resolveUpgrades(Collection<Library> libraries) {
|
|
|
|
return libraries.stream().map(this::resolveUpgrade).filter((upgrade) -> upgrade != null)
|
|
|
|
Map<String, Library> librariesByName = new HashMap<>();
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
for (Library library : libraries) {
|
|
|
|
|
|
|
|
librariesByName.put(library.getName(), library);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return libraries.stream().map((library) -> resolveUpgrade(library, librariesByName))
|
|
|
|
|
|
|
|
.filter((upgrade) -> upgrade != null).collect(Collectors.toList());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private Upgrade resolveUpgrade(Library library) {
|
|
|
|
private Upgrade resolveUpgrade(Library library, Map<String, Library> libraries) {
|
|
|
|
|
|
|
|
List<VersionOption> versionOptions = getVersionOptions(library, libraries);
|
|
|
|
|
|
|
|
if (versionOptions.isEmpty()) {
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
VersionOption current = new VersionOption(library.getVersion().getVersion());
|
|
|
|
|
|
|
|
VersionOption selected = this.userInputHandler
|
|
|
|
|
|
|
|
.selectOption(library.getName() + " " + library.getVersion().getVersion(), versionOptions, current);
|
|
|
|
|
|
|
|
return (selected.equals(current)) ? null : new Upgrade(library, selected.version);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private List<VersionOption> getVersionOptions(Library library, Map<String, Library> libraries) {
|
|
|
|
|
|
|
|
if (library.getVersion().getVersionAlignment() != null) {
|
|
|
|
|
|
|
|
VersionOption alignedVersionOption = alignedVersionOption(library, libraries);
|
|
|
|
|
|
|
|
if (!isPermitted(alignedVersionOption.version, library.getProhibitedVersions())) {
|
|
|
|
|
|
|
|
throw new InvalidUserDataException("Version alignment failed. Version " + alignedVersionOption.version
|
|
|
|
|
|
|
|
+ " from " + library.getName() + " is prohibited");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return Collections.singletonList(alignedVersionOption);
|
|
|
|
|
|
|
|
}
|
|
|
|
Map<String, SortedSet<DependencyVersion>> moduleVersions = new LinkedHashMap<>();
|
|
|
|
Map<String, SortedSet<DependencyVersion>> moduleVersions = new LinkedHashMap<>();
|
|
|
|
|
|
|
|
DependencyVersion libraryVersion = library.getVersion().getVersion();
|
|
|
|
for (Group group : library.getGroups()) {
|
|
|
|
for (Group group : library.getGroups()) {
|
|
|
|
for (Module module : group.getModules()) {
|
|
|
|
for (Module module : group.getModules()) {
|
|
|
|
moduleVersions.put(group.getId() + ":" + module.getName(),
|
|
|
|
moduleVersions.put(group.getId() + ":" + module.getName(),
|
|
|
|
getLaterVersionsForModule(group.getId(), module.getName(), library.getVersion()));
|
|
|
|
getLaterVersionsForModule(group.getId(), module.getName(), libraryVersion));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (String bom : group.getBoms()) {
|
|
|
|
for (String bom : group.getBoms()) {
|
|
|
|
moduleVersions.put(group.getId() + ":" + bom,
|
|
|
|
moduleVersions.put(group.getId() + ":" + bom,
|
|
|
|
getLaterVersionsForModule(group.getId(), bom, library.getVersion()));
|
|
|
|
getLaterVersionsForModule(group.getId(), bom, libraryVersion));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (String plugin : group.getPlugins()) {
|
|
|
|
for (String plugin : group.getPlugins()) {
|
|
|
|
moduleVersions.put(group.getId() + ":" + plugin,
|
|
|
|
moduleVersions.put(group.getId() + ":" + plugin,
|
|
|
|
getLaterVersionsForModule(group.getId(), plugin, library.getVersion()));
|
|
|
|
getLaterVersionsForModule(group.getId(), plugin, libraryVersion));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
List<DependencyVersion> allVersions = moduleVersions.values().stream().flatMap(SortedSet::stream).distinct()
|
|
|
|
List<DependencyVersion> allVersions = moduleVersions.values().stream().flatMap(SortedSet::stream).distinct()
|
|
|
|
.filter((dependencyVersion) -> isPermitted(dependencyVersion, library.getProhibitedVersions()))
|
|
|
|
.filter((dependencyVersion) -> isPermitted(dependencyVersion, library.getProhibitedVersions()))
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
if (allVersions.isEmpty()) {
|
|
|
|
if (allVersions.isEmpty()) {
|
|
|
|
return null;
|
|
|
|
return Collections.emptyList();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
List<VersionOption> versionOptions = allVersions.stream()
|
|
|
|
return allVersions.stream()
|
|
|
|
.map((version) -> new VersionOption(version, getMissingModules(moduleVersions, version)))
|
|
|
|
.map((version) -> new ResolvedVersionOption(version, getMissingModules(moduleVersions, version)))
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
VersionOption current = new VersionOption(library.getVersion(), Collections.emptyList());
|
|
|
|
}
|
|
|
|
VersionOption selected = this.userInputHandler.selectOption(library.getName() + " " + library.getVersion(),
|
|
|
|
|
|
|
|
versionOptions, current);
|
|
|
|
private VersionOption alignedVersionOption(Library library, Map<String, Library> libraries) {
|
|
|
|
return (selected.equals(current)) ? null : new Upgrade(library, selected.version);
|
|
|
|
VersionAlignment versionAlignment = library.getVersion().getVersionAlignment();
|
|
|
|
|
|
|
|
Library alignmentLibrary = libraries.get(versionAlignment.getLibraryName());
|
|
|
|
|
|
|
|
DependencyVersions dependencyVersions = alignmentLibrary.getDependencyVersions();
|
|
|
|
|
|
|
|
if (dependencyVersions == null) {
|
|
|
|
|
|
|
|
throw new InvalidUserDataException("Cannot align with library '" + versionAlignment.getLibraryName()
|
|
|
|
|
|
|
|
+ "' as it does not define any dependency versions");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!dependencyVersions.available()) {
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Set<String> versions = new HashSet<>();
|
|
|
|
|
|
|
|
for (Group group : library.getGroups()) {
|
|
|
|
|
|
|
|
for (Module module : group.getModules()) {
|
|
|
|
|
|
|
|
String version = dependencyVersions.getVersion(group.getId(), module.getName());
|
|
|
|
|
|
|
|
if (version != null) {
|
|
|
|
|
|
|
|
versions.add(version);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (versions.isEmpty()) {
|
|
|
|
|
|
|
|
throw new InvalidUserDataException("Cannot align with library '" + versionAlignment.getLibraryName()
|
|
|
|
|
|
|
|
+ "' as its dependency versions do not include any of this library's modules");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (versions.size() > 1) {
|
|
|
|
|
|
|
|
throw new InvalidUserDataException("Cannot align with library '" + versionAlignment.getLibraryName()
|
|
|
|
|
|
|
|
+ "' as it uses multiple different versions of this library's modules");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
String requiredVersion = versions.iterator().next();
|
|
|
|
|
|
|
|
return new AlignedVersionOption(DependencyVersion.parse(requiredVersion), alignmentLibrary);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private boolean isPermitted(DependencyVersion dependencyVersion, List<ProhibitedVersion> prohibitedVersions) {
|
|
|
|
private boolean isPermitted(DependencyVersion dependencyVersion, List<ProhibitedVersion> prohibitedVersions) {
|
|
|
@ -125,23 +183,53 @@ public final class InteractiveUpgradeResolver implements UpgradeResolver {
|
|
|
|
return versions;
|
|
|
|
return versions;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static final class VersionOption {
|
|
|
|
private static class VersionOption {
|
|
|
|
|
|
|
|
|
|
|
|
private final DependencyVersion version;
|
|
|
|
private final DependencyVersion version;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected VersionOption(DependencyVersion version) {
|
|
|
|
|
|
|
|
this.version = version;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public String toString() {
|
|
|
|
|
|
|
|
return this.version.toString();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final class AlignedVersionOption extends VersionOption {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final Library alignedWith;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private AlignedVersionOption(DependencyVersion version, Library alignedWith) {
|
|
|
|
|
|
|
|
super(version);
|
|
|
|
|
|
|
|
this.alignedWith = alignedWith;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public String toString() {
|
|
|
|
|
|
|
|
return super.toString() + " (aligned with " + this.alignedWith.getName() + " "
|
|
|
|
|
|
|
|
+ this.alignedWith.getVersion().getVersion() + ")";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final class ResolvedVersionOption extends VersionOption {
|
|
|
|
|
|
|
|
|
|
|
|
private final List<String> missingModules;
|
|
|
|
private final List<String> missingModules;
|
|
|
|
|
|
|
|
|
|
|
|
private VersionOption(DependencyVersion version, List<String> missingModules) {
|
|
|
|
private ResolvedVersionOption(DependencyVersion version, List<String> missingModules) {
|
|
|
|
this.version = version;
|
|
|
|
super(version);
|
|
|
|
this.missingModules = missingModules;
|
|
|
|
this.missingModules = missingModules;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
public String toString() {
|
|
|
|
if (this.missingModules.isEmpty()) {
|
|
|
|
if (this.missingModules.isEmpty()) {
|
|
|
|
return this.version.toString();
|
|
|
|
return super.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return this.version + " (some modules are missing: "
|
|
|
|
return super.toString() + " (some modules are missing: "
|
|
|
|
+ StringUtils.collectionToDelimitedString(this.missingModules, ", ") + ")";
|
|
|
|
+ StringUtils.collectionToDelimitedString(this.missingModules, ", ") + ")";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|