Improve issues and commit messages for moving to non-patch snapshots

Closes gh-43045
This commit is contained in:
Andy Wilkinson 2025-02-03 11:35:40 +00:00
parent e207e7ca83
commit c8afa398f1
8 changed files with 94 additions and 57 deletions

View File

@ -71,7 +71,7 @@ public final class InteractiveUpgradeResolver implements UpgradeResolver {
} }
VersionOption defaultOption = new VersionOption(library.getVersion().getVersion()); VersionOption defaultOption = new VersionOption(library.getVersion().getVersion());
VersionOption selected = selectOption(defaultOption, library, versionOptions); VersionOption selected = selectOption(defaultOption, library, versionOptions);
return (selected.equals(defaultOption)) ? null : new Upgrade(library, selected.getVersion()); return (selected.equals(defaultOption)) ? null : selected.upgrade(library);
} }
private VersionOption selectOption(VersionOption defaultOption, Library library, private VersionOption selectOption(VersionOption defaultOption, Library library,

View File

@ -19,7 +19,7 @@ package org.springframework.boot.build.bom.bomr;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.BiPredicate; import java.util.function.BiFunction;
import javax.inject.Inject; import javax.inject.Inject;
@ -77,27 +77,35 @@ public abstract class MoveToSnapshots extends UpgradeDependencies {
} }
@Override @Override
protected List<BiPredicate<Library, DependencyVersion>> determineUpdatePredicates(Milestone milestone) { protected BiFunction<Library, DependencyVersion, VersionOption> createVersionOptionResolver(Milestone milestone) {
return switch (this.buildType) { return switch (this.buildType) {
case OPEN_SOURCE -> determineOpenSourceUpdatePredicates(milestone); case OPEN_SOURCE -> createOpenSourceVersionOptionResolver(milestone);
case COMMERCIAL -> super.determineUpdatePredicates(milestone); case COMMERCIAL -> super.createVersionOptionResolver(milestone);
}; };
} }
private List<BiPredicate<Library, DependencyVersion>> determineOpenSourceUpdatePredicates(Milestone milestone) { private BiFunction<Library, DependencyVersion, VersionOption> createOpenSourceVersionOptionResolver(
Milestone milestone) {
Map<String, List<Release>> scheduledReleases = getScheduledOpenSourceReleases(milestone); Map<String, List<Release>> scheduledReleases = getScheduledOpenSourceReleases(milestone);
List<BiPredicate<Library, DependencyVersion>> predicates = super.determineUpdatePredicates(milestone); BiFunction<Library, DependencyVersion, VersionOption> resolver = super.createVersionOptionResolver(milestone);
predicates.add((library, candidate) -> { return (library, dependencyVersion) -> {
VersionOption versionOption = resolver.apply(library, dependencyVersion);
if (versionOption != null) {
List<Release> releases = scheduledReleases.get(library.getCalendarName()); List<Release> releases = scheduledReleases.get(library.getCalendarName());
boolean match = (releases != null) List<Release> matches = releases.stream()
&& releases.stream().anyMatch((release) -> candidate.isSnapshotFor(release.getVersion())); .filter((release) -> dependencyVersion.isSnapshotFor(release.getVersion()))
if (logger.isInfoEnabled() && !match) { .toList();
logger.info("Ignoring {}. No release of {} scheduled before {}", candidate, library.getName(), if (matches.isEmpty()) {
milestone.getDueOn()); if (logger.isInfoEnabled()) {
logger.info("Ignoring {}. No release of {} scheduled before {}", dependencyVersion,
library.getName(), milestone.getDueOn());
} }
return match; return null;
}); }
return predicates; return new VersionOption.SnapshotVersionOption(versionOption.getVersion(), matches.get(0).getVersion());
}
return versionOption;
};
} }
private Map<String, List<Release>> getScheduledOpenSourceReleases(Milestone milestone) { private Map<String, List<Release>> getScheduledOpenSourceReleases(Milestone milestone) {

View File

@ -24,7 +24,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.function.BiPredicate; import java.util.function.BiFunction;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -46,13 +46,12 @@ class StandardLibraryUpdateResolver implements LibraryUpdateResolver {
private final VersionResolver versionResolver; private final VersionResolver versionResolver;
private final BiPredicate<Library, DependencyVersion> predicate; private final BiFunction<Library, DependencyVersion, VersionOption> versionOptionResolver;
StandardLibraryUpdateResolver(VersionResolver versionResolver, StandardLibraryUpdateResolver(VersionResolver versionResolver,
List<BiPredicate<Library, DependencyVersion>> predicates) { BiFunction<Library, DependencyVersion, VersionOption> versionOptionResolver) {
this.versionResolver = versionResolver; this.versionResolver = versionResolver;
this.predicate = (library, dependencyVersion) -> predicates.stream() this.versionOptionResolver = versionOptionResolver;
.allMatch((predicate) -> predicate.test(library, dependencyVersion));
} }
@Override @Override
@ -111,14 +110,18 @@ class StandardLibraryUpdateResolver implements LibraryUpdateResolver {
getLaterVersionsForModule(group.getId(), plugin, library)); getLaterVersionsForModule(group.getId(), plugin, library));
} }
} }
return moduleVersions.values() List<VersionOption> versionOptions = new ArrayList<>();
.stream() moduleVersions.values().stream().flatMap(SortedSet::stream).distinct().forEach((dependencyVersion) -> {
.flatMap(SortedSet::stream) VersionOption versionOption = this.versionOptionResolver.apply(library, dependencyVersion);
.distinct() if (versionOption != null) {
.filter((dependencyVersion) -> this.predicate.test(library, dependencyVersion)) List<String> missingModules = getMissingModules(moduleVersions, dependencyVersion);
.map((version) -> (VersionOption) new VersionOption.ResolvedVersionOption(version, if (!missingModules.isEmpty()) {
getMissingModules(moduleVersions, version))) versionOption = new VersionOption.ResolvedVersionOption(versionOption.getVersion(), missingModules);
.toList(); }
versionOptions.add(versionOption);
}
});
return versionOptions;
} }
private List<String> getMissingModules(Map<String, SortedSet<DependencyVersion>> moduleVersions, private List<String> getMissingModules(Map<String, SortedSet<DependencyVersion>> moduleVersions,

View File

@ -17,8 +17,6 @@
package org.springframework.boot.build.bom.bomr; package org.springframework.boot.build.bom.bomr;
import org.springframework.boot.build.bom.Library; import org.springframework.boot.build.bom.Library;
import org.springframework.boot.build.bom.Library.LibraryVersion;
import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
/** /**
* An upgrade to change a {@link Library} to use a new version. * An upgrade to change a {@link Library} to use a new version.
@ -31,19 +29,8 @@ import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
*/ */
record Upgrade(Library from, Library to, Library toRelease) { record Upgrade(Library from, Library to, Library toRelease) {
Upgrade(Library from, DependencyVersion to) {
this(from, from.withVersion(new LibraryVersion(to)));
}
Upgrade(Library from, Library to) { Upgrade(Library from, Library to) {
this(from, to, withReleaseVersion(to)); this(from, to, to);
}
private static Library withReleaseVersion(Library to) {
String version = to.getVersion().toString();
version = version.replace(".BUILD-SNAPSHOT", "");
version = version.replace("-SNAPSHOT", "");
return to.withVersion(new LibraryVersion(DependencyVersion.parse(version)));
} }
} }

View File

@ -24,9 +24,11 @@ import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.BiPredicate; import java.util.function.BiPredicate;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -231,7 +233,7 @@ public abstract class UpgradeDependencies extends DefaultTask {
private LibraryUpdateResolver getLibraryUpdateResolver(Milestone milestone) { private LibraryUpdateResolver getLibraryUpdateResolver(Milestone milestone) {
VersionResolver versionResolver = new MavenMetadataVersionResolver(getRepositories()); VersionResolver versionResolver = new MavenMetadataVersionResolver(getRepositories());
LibraryUpdateResolver libraryResolver = new StandardLibraryUpdateResolver(versionResolver, LibraryUpdateResolver libraryResolver = new StandardLibraryUpdateResolver(versionResolver,
determineUpdatePredicates(milestone)); createVersionOptionResolver(milestone));
return new MultithreadedLibraryUpdateResolver(getThreads().get(), libraryResolver); return new MultithreadedLibraryUpdateResolver(getThreads().get(), libraryResolver);
} }
@ -246,12 +248,19 @@ public abstract class UpgradeDependencies extends DefaultTask {
.toList(); .toList();
} }
protected List<BiPredicate<Library, DependencyVersion>> determineUpdatePredicates(Milestone milestone) { protected BiFunction<Library, DependencyVersion, VersionOption> createVersionOptionResolver(Milestone milestone) {
List<BiPredicate<Library, DependencyVersion>> updatePredicates = new ArrayList<>(); List<BiPredicate<Library, DependencyVersion>> updatePredicates = new ArrayList<>();
updatePredicates.add(this::compliesWithUpgradePolicy); updatePredicates.add(this::compliesWithUpgradePolicy);
updatePredicates.add(this::isAnUpgrade); updatePredicates.add(this::isAnUpgrade);
updatePredicates.add(this::isNotProhibited); updatePredicates.add(this::isNotProhibited);
return updatePredicates; return (library, dependencyVersion) -> {
if (this.compliesWithUpgradePolicy(library, dependencyVersion)
&& this.isAnUpgrade(library, dependencyVersion)
&& this.isNotProhibited(library, dependencyVersion)) {
return new VersionOption.ResolvedVersionOption(dependencyVersion, Collections.emptyList());
}
return null;
};
} }
private boolean compliesWithUpgradePolicy(Library library, DependencyVersion candidate) { private boolean compliesWithUpgradePolicy(Library library, DependencyVersion candidate) {

View File

@ -18,6 +18,8 @@ package org.springframework.boot.build.bom.bomr;
import java.util.List; import java.util.List;
import org.springframework.boot.build.bom.Library;
import org.springframework.boot.build.bom.Library.LibraryVersion;
import org.springframework.boot.build.bom.Library.VersionAlignment; import org.springframework.boot.build.bom.Library.VersionAlignment;
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;
@ -44,6 +46,10 @@ class VersionOption {
return this.version.toString(); return this.version.toString();
} }
Upgrade upgrade(Library library) {
return new Upgrade(library, library.withVersion(new LibraryVersion(this.version)));
}
static final class AlignedVersionOption extends VersionOption { static final class AlignedVersionOption extends VersionOption {
private final VersionAlignment alignedWith; private final VersionAlignment alignedWith;
@ -80,4 +86,26 @@ class VersionOption {
} }
static final class SnapshotVersionOption extends VersionOption {
private final DependencyVersion releaseVersion;
SnapshotVersionOption(DependencyVersion version, DependencyVersion releaseVersion) {
super(version);
this.releaseVersion = releaseVersion;
}
@Override
public String toString() {
return super.toString() + " (for " + this.releaseVersion + ")";
}
@Override
Upgrade upgrade(Library library) {
return new Upgrade(library, library.withVersion(new LibraryVersion(super.version)),
library.withVersion(new LibraryVersion(this.releaseVersion)));
}
}
} }

View File

@ -52,11 +52,10 @@ class UpgradeApplicatorTests {
String originalContents = Files.readString(bom.toPath()); String originalContents = Files.readString(bom.toPath());
File gradleProperties = new File(this.temp, "gradle.properties"); File gradleProperties = new File(this.temp, "gradle.properties");
FileCopyUtils.copy(new File("src/test/resources/gradle.properties"), gradleProperties); FileCopyUtils.copy(new File("src/test/resources/gradle.properties"), gradleProperties);
new UpgradeApplicator(bom.toPath(), gradleProperties.toPath()).apply( Library activeMq = new Library("ActiveMQ", null, new LibraryVersion(DependencyVersion.parse("5.15.11")), null,
new Upgrade( null, false, null, null, null, Collections.emptyMap());
new Library("ActiveMQ", null, new LibraryVersion(DependencyVersion.parse("5.15.11")), null, new UpgradeApplicator(bom.toPath(), gradleProperties.toPath())
null, false, null, null, null, Collections.emptyMap()), .apply(new Upgrade(activeMq, activeMq.withVersion(new LibraryVersion(DependencyVersion.parse("5.16")))));
DependencyVersion.parse("5.16")));
String bomContents = Files.readString(bom.toPath()); String bomContents = Files.readString(bom.toPath());
assertThat(bomContents).hasSize(originalContents.length() - 3); assertThat(bomContents).hasSize(originalContents.length() - 3);
} }
@ -67,9 +66,10 @@ class UpgradeApplicatorTests {
FileCopyUtils.copy(new File("src/test/resources/bom.gradle"), bom); FileCopyUtils.copy(new File("src/test/resources/bom.gradle"), bom);
File gradleProperties = new File(this.temp, "gradle.properties"); File gradleProperties = new File(this.temp, "gradle.properties");
FileCopyUtils.copy(new File("src/test/resources/gradle.properties"), gradleProperties); FileCopyUtils.copy(new File("src/test/resources/gradle.properties"), gradleProperties);
Library kotlin = new Library("Kotlin", null, new LibraryVersion(DependencyVersion.parse("1.3.70")), null, null,
false, null, null, null, Collections.emptyMap());
new UpgradeApplicator(bom.toPath(), gradleProperties.toPath()) new UpgradeApplicator(bom.toPath(), gradleProperties.toPath())
.apply(new Upgrade(new Library("Kotlin", null, new LibraryVersion(DependencyVersion.parse("1.3.70")), null, .apply(new Upgrade(kotlin, kotlin.withVersion(new LibraryVersion(DependencyVersion.parse("1.4")))));
null, false, null, null, null, Collections.emptyMap()), DependencyVersion.parse("1.4")));
Properties properties = new Properties(); Properties properties = new Properties();
try (InputStream in = new FileInputStream(gradleProperties)) { try (InputStream in = new FileInputStream(gradleProperties)) {
properties.load(in); properties.load(in);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2024-2024 the original author or authors. * Copyright 2024-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -35,7 +35,7 @@ class UpgradeTests {
void createToRelease() { void createToRelease() {
Library from = new Library("Test", null, new LibraryVersion(DependencyVersion.parse("1.0.0")), null, null, Library from = new Library("Test", null, new LibraryVersion(DependencyVersion.parse("1.0.0")), null, null,
false, null, null, null, null); false, null, null, null, null);
Upgrade upgrade = new Upgrade(from, DependencyVersion.parse("1.0.1")); Upgrade upgrade = new Upgrade(from, from.withVersion(new LibraryVersion(DependencyVersion.parse("1.0.1"))));
assertThat(upgrade.from().getNameAndVersion()).isEqualTo("Test 1.0.0"); assertThat(upgrade.from().getNameAndVersion()).isEqualTo("Test 1.0.0");
assertThat(upgrade.to().getNameAndVersion()).isEqualTo("Test 1.0.1"); assertThat(upgrade.to().getNameAndVersion()).isEqualTo("Test 1.0.1");
assertThat(upgrade.toRelease().getNameAndVersion()).isEqualTo("Test 1.0.1"); assertThat(upgrade.toRelease().getNameAndVersion()).isEqualTo("Test 1.0.1");
@ -45,7 +45,9 @@ class UpgradeTests {
void createToSnapshot() { void createToSnapshot() {
Library from = new Library("Test", null, new LibraryVersion(DependencyVersion.parse("1.0.0")), null, null, Library from = new Library("Test", null, new LibraryVersion(DependencyVersion.parse("1.0.0")), null, null,
false, null, null, null, null); false, null, null, null, null);
Upgrade upgrade = new Upgrade(from, DependencyVersion.parse("1.0.1-SNAPSHOT")); Upgrade upgrade = new Upgrade(from,
from.withVersion(new LibraryVersion(DependencyVersion.parse("1.0.1-SNAPSHOT"))),
from.withVersion(new LibraryVersion(DependencyVersion.parse("1.0.1"))));
assertThat(upgrade.from().getNameAndVersion()).isEqualTo("Test 1.0.0"); assertThat(upgrade.from().getNameAndVersion()).isEqualTo("Test 1.0.0");
assertThat(upgrade.to().getNameAndVersion()).isEqualTo("Test 1.0.1-SNAPSHOT"); assertThat(upgrade.to().getNameAndVersion()).isEqualTo("Test 1.0.1-SNAPSHOT");
assertThat(upgrade.toRelease().getNameAndVersion()).isEqualTo("Test 1.0.1"); assertThat(upgrade.toRelease().getNameAndVersion()).isEqualTo("Test 1.0.1");