Skip to content

Commit

Permalink
mojohaus#960: displayDependencyUpdates should display updates from le…
Browse files Browse the repository at this point in the history
…sser segments

mojohaus#299: allowAnyUpdates should be ignored with a warning message if any of: allowMajorUpdates, allowMinorUpdates, allowIncrementalUpdates is set to false
  • Loading branch information
jarmoniuk committed May 23, 2023
1 parent 0fe821e commit 40f06e2
Show file tree
Hide file tree
Showing 26 changed files with 708 additions and 311 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,7 @@
* under the License.
*/

import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.Objects;
import java.util.Optional;
import java.util.TreeSet;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand Down Expand Up @@ -64,45 +59,64 @@ public abstract class AbstractVersionDetails implements VersionDetails {
*/
private ArtifactVersion currentVersion = null;

private VersionRange currentVersionRange = null;
protected boolean verboseDetail = true;

protected AbstractVersionDetails() {}

@Override
public Restriction restrictionFor(Optional<Segment> scope) throws InvalidSegmentException {
// one range spec can have multiple restrictions, and multiple 'lower bound', we want the highest one.
// [1.0,2.0),[3.0,4.0) -> 3.0
ArtifactVersion highestLowerBound = currentVersion;
if (currentVersion != null) {
try {
highestLowerBound =
VersionRange.createFromVersionSpec(currentVersion.toString()).getRestrictions().stream()
.map(Restriction::getLowerBound)
.filter(Objects::nonNull)
.max(getVersionComparator())
.orElse(currentVersion);
} catch (InvalidVersionSpecificationException ignored) {
ignored.printStackTrace(System.err);
}
}

final ArtifactVersion currentVersion = highestLowerBound;
ArtifactVersion nextVersion = scope.filter(s -> s.isMajorTo(SUBINCREMENTAL))
.map(s -> (ArtifactVersion) new BoundArtifactVersion(currentVersion, Segment.of(s.value() + 1)))
/**
* <p>One range spec can have multiple restrictions, and multiple 'lower bound', we want the highest one.</p>
* <p>[1.0,2.0),[3.0,4.0) -> 3.0</p>
* @param versionSpec version specification, possibly containing multiple ranges
* @return highest lower bound of the given version specification
*/
private ArtifactVersion getHighestLowerBound() {
return currentVersionRange.getRestrictions().stream()
.map(Restriction::getLowerBound)
.filter(Objects::nonNull)
.max(getVersionComparator())
.orElse(currentVersion);
}

@Override
public Restriction restrictionForSelectedSegment(Optional<Segment> selectedSegment) throws InvalidSegmentException {
ArtifactVersion highestLowerBound = getHighestLowerBound();
ArtifactVersion nextVersion = selectedSegment
.filter(s -> s.isMajorTo(SUBINCREMENTAL))
.map(Segment::minorTo)
.map(s -> (ArtifactVersion) new BoundArtifactVersion(highestLowerBound, s))
.orElse(highestLowerBound);
return new Restriction(
nextVersion,
false,
scope.filter(MAJOR::isMajorTo)
.map(s -> (ArtifactVersion) new BoundArtifactVersion(currentVersion, s))
selectedSegment
.filter(MAJOR::isMajorTo)
.map(s -> (ArtifactVersion) new BoundArtifactVersion(highestLowerBound, s))
.orElse(null),
false);
}

@Override
public Restriction restrictionForUnchangedSegment(Optional<Segment> unchangedSegment, boolean allowDowngrade)
throws InvalidSegmentException {
ArtifactVersion highestLowerBound = getHighestLowerBound();
ArtifactVersion lowerBound = allowDowngrade
? getLowerBound(highestLowerBound, unchangedSegment)
.map(DefaultArtifactVersionCache::of)
.orElse(null)
: highestLowerBound;
ArtifactVersion upperBound = unchangedSegment
.map(s -> (ArtifactVersion) new BoundArtifactVersion(
highestLowerBound, s.isMajorTo(SUBINCREMENTAL) ? Segment.minorTo(s) : s))
.orElse(null);
return new Restriction(lowerBound, allowDowngrade, upperBound, allowDowngrade);
}

@Override
public Restriction restrictionForIgnoreScope(Optional<Segment> ignored) {
ArtifactVersion nextVersion = ignored.map(s -> (ArtifactVersion) new BoundArtifactVersion(currentVersion, s))
.orElse(currentVersion);
ArtifactVersion highestLowerBound = getHighestLowerBound();
ArtifactVersion nextVersion = ignored.map(s -> (ArtifactVersion) new BoundArtifactVersion(highestLowerBound, s))
.orElse(highestLowerBound);
return new Restriction(nextVersion, false, null, false);
}

Expand All @@ -119,6 +133,11 @@ public final ArtifactVersion getCurrentVersion() {
@Override
public final void setCurrentVersion(ArtifactVersion currentVersion) {
this.currentVersion = currentVersion;
try {
currentVersionRange = VersionRange.createFromVersionSpec(currentVersion.toString());
} catch (InvalidVersionSpecificationException e) {
e.printStackTrace();
}
}

@Override
Expand Down Expand Up @@ -216,8 +235,8 @@ public final ArtifactVersion[] getNewerVersions(
.orElse(null)
: currentVersion;
ArtifactVersion upperBound = unchangedSegment
.map(s -> (ArtifactVersion) new BoundArtifactVersion(
currentVersion, s.isMajorTo(SUBINCREMENTAL) ? Segment.of(s.value() + 1) : s))
.map(s -> (ArtifactVersion)
new BoundArtifactVersion(currentVersion, s.isMajorTo(SUBINCREMENTAL) ? Segment.minorTo(s) : s))
.orElse(null);

Restriction restriction = new Restriction(lowerBound, allowDowngrade, upperBound, allowDowngrade);
Expand All @@ -226,26 +245,22 @@ public final ArtifactVersion[] getNewerVersions(

@Override
public Optional<ArtifactVersion> getNewestVersion(
String versionString, Optional<Segment> upperBoundSegment, boolean includeSnapshots, boolean allowDowngrade)
Optional<Segment> unchangedSegment, boolean includeSnapshots, boolean allowDowngrade)
throws InvalidSegmentException {
ArtifactVersion currentVersion = DefaultArtifactVersionCache.of(versionString);
ArtifactVersion lowerBound = allowDowngrade
? getLowerBound(currentVersion, upperBoundSegment)
.map(DefaultArtifactVersionCache::of)
.orElse(null)
: currentVersion;
ArtifactVersion upperBound = upperBoundSegment
.map(s -> (ArtifactVersion) new BoundArtifactVersion(
currentVersion, s.isMajorTo(SUBINCREMENTAL) ? Segment.of(s.value() + 1) : s))
.orElse(null);

Restriction restriction = new Restriction(lowerBound, allowDowngrade, upperBound, allowDowngrade);
Restriction restriction = restrictionForUnchangedSegment(unchangedSegment, allowDowngrade);
return Arrays.stream(getVersions(includeSnapshots))
.filter(candidate -> isVersionInRestriction(restriction, candidate))
.filter(candidate -> includeSnapshots || !ArtifactUtils.isSnapshot(candidate.toString()))
.max(getVersionComparator());
}

@Override
public Optional<ArtifactVersion> getNewestVersion(
String ignored, Optional<Segment> unchangedSegment, boolean includeSnapshots, boolean allowDowngrade)
throws InvalidSegmentException {
return getNewestVersion(unchangedSegment, includeSnapshots, allowDowngrade);
}

@Override
public final ArtifactVersion[] getVersions(Restriction restriction, boolean includeSnapshots) {
return getVersions(null, restriction, includeSnapshots);
Expand All @@ -264,10 +279,10 @@ public final ArtifactVersion[] getVersions(
}

@Override
public final ArtifactVersion getNewestUpdate(
public final ArtifactVersion getNewestUpdateWithinSegment(
ArtifactVersion currentVersion, Optional<Segment> updateScope, boolean includeSnapshots) {
try {
return getNewestVersion(restrictionFor(updateScope), includeSnapshots);
return getNewestVersion(restrictionForSelectedSegment(updateScope), includeSnapshots);
} catch (InvalidSegmentException e) {
return null;
}
Expand All @@ -277,16 +292,16 @@ public final ArtifactVersion getNewestUpdate(
public final ArtifactVersion[] getAllUpdates(
ArtifactVersion currentVersion, Optional<Segment> updateScope, boolean includeSnapshots) {
try {
return getVersions(restrictionFor(updateScope), includeSnapshots);
return getVersions(restrictionForSelectedSegment(updateScope), includeSnapshots);
} catch (InvalidSegmentException e) {
return null;
}
}

@Override
public final ArtifactVersion getNewestUpdate(Optional<Segment> updateScope, boolean includeSnapshots) {
public final ArtifactVersion getNewestUpdateWithinSegment(Optional<Segment> updateScope, boolean includeSnapshots) {
if (isCurrentVersionDefined()) {
return getNewestUpdate(getCurrentVersion(), updateScope, includeSnapshots);
return getNewestUpdateWithinSegment(getCurrentVersion(), updateScope, includeSnapshots);
}
return null;
}
Expand Down Expand Up @@ -435,7 +450,7 @@ public final ArtifactVersion[] getReportUpdates(Optional<Segment> updateScope, b
private Stream<ArtifactVersion> getArtifactVersionStream(Optional<Segment> updateScope, boolean includeSnapshots) {
if (isCurrentVersionDefined()) {
try {
Restriction restriction = restrictionFor(updateScope);
Restriction restriction = restrictionForSelectedSegment(updateScope);

return Arrays.stream(getVersions(includeSnapshots))
.filter(candidate -> isVersionInRestriction(restriction, candidate));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import org.apache.commons.lang3.tuple.Triple;

/**
* Utility providing a cached {@link ArtifactVersions#getNewestUpdate(Optional, boolean)} API
* Utility providing a cached {@link ArtifactVersions#getNewestUpdateWithinSegment(Optional, boolean)} API
*/
public class ArtifactVersionsCache {
private TriFunction<AbstractVersionDetails, Optional<Segment>, Boolean, ?> cachedFunction;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ public ArtifactVersion getNewestVersion(
? null
: upperBoundSegment
.map(s -> (ArtifactVersion) new BoundArtifactVersion(
currentVersion, s.isMajorTo(SUBINCREMENTAL) ? Segment.of(s.value() + 1) : s))
currentVersion, s.isMajorTo(SUBINCREMENTAL) ? Segment.minorTo(s) : s))
.orElse(null);
if (helper.getLog().isDebugEnabled()) {
helper.getLog().debug("Property ${" + property.getName() + "}: upperBound is: " + upperBound);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
* under the License.
*/

import java.util.Optional;

/**
* Indicates the segment along with its 0-based index
*
Expand Down Expand Up @@ -46,6 +48,26 @@ public static Segment of(int index) {
return values()[index];
}

/**
* Creates a segment that has a greater scope than the given segment or {@code null}
* if the segment is already {@link #MAJOR}
* @param other segment that the new segment is to be based on
* @return that has a greater scope than the given segment or {@code null}
* if the segment is already {@link #MAJOR}
*/
public static Segment majorTo(Segment other) {
return Optional.ofNullable(other).map(s -> of(s.value() - 1)).orElse(null);
}

/**
* Creates a segment that has a lesser scope than the given segment
* @param other segment that the new segment is to be based on
* @return that has a lesser scope than the given segment
*/
public static Segment minorTo(Segment other) {
return Optional.ofNullable(other).map(s -> of(s.value() + 1)).orElse(MAJOR);
}

/**
* Returns true if the given segment is more major than the other
* @param other other segment to compare
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ ArtifactVersion getNewestVersion(
* should be included.
*
* @param versionString current version
* @param upperBoundSegment the upper bound segment; empty() means no upper bound
* @param unchangedSegment segment that may not be changed; empty() means no upper bound
* @param includeSnapshots whether snapshot versions should be included
* @param allowDowngrade whether to allow downgrading if the current version is a snapshots and snapshots
* are disallowed
Expand All @@ -208,7 +208,26 @@ ArtifactVersion getNewestVersion(
* the segment count)
*/
Optional<ArtifactVersion> getNewestVersion(
String versionString, Optional<Segment> upperBoundSegment, boolean includeSnapshots, boolean allowDowngrade)
Optional<Segment> unchangedSegment, boolean includeSnapshots, boolean allowDowngrade)
throws InvalidSegmentException;

/**
* Returns the latest version, newer than the given version, given the upper bound segment and whether snapshots
* should be included.
*
* @param versionString current version
* @param unchangedSegment segment that may not be changed; empty() means no upper bound
* @param includeSnapshots whether snapshot versions should be included
* @param allowDowngrade whether to allow downgrading if the current version is a snapshots and snapshots
* are disallowed
* @return newer version or {@link Optional#empty()} if none can be found
* @throws InvalidSegmentException if the requested segment is outside the bounds (less than 1 or greater than
* the segment count)
* @deprecated please use {@link #getNewestVersion(Optional, boolean, boolean)}
*/
@Deprecated
Optional<ArtifactVersion> getNewestVersion(
String versionString, Optional<Segment> unchangedSegment, boolean includeSnapshots, boolean allowDowngrade)
throws InvalidSegmentException;

/**
Expand All @@ -223,7 +242,7 @@ Optional<ArtifactVersion> getNewestVersion(
* @throws InvalidSegmentException thrown if the updateScope is greater than the number of segments
* @since 1.0-beta-1
*/
ArtifactVersion getNewestUpdate(
ArtifactVersion getNewestUpdateWithinSegment(
ArtifactVersion currentVersion, Optional<Segment> updateScope, boolean includeSnapshots)
throws InvalidSegmentException;

Expand Down Expand Up @@ -285,8 +304,9 @@ ArtifactVersion[] getAllUpdates(
throws InvalidSegmentException;

/**
* Returns the newest version newer than the specified current version, but within the specified update scope or
* <code>null</code> if no such version exists.
* <p>Returns the newest version newer than the specified current version, <u>only within the segment specified
* by {@code updateScope}</u> or {@code null} if no such version exists.</p>
* <p>If {@code updateScope} is {@link Optional#empty()}, will return all updates.</p>
*
* @param updateScope the update scope to include.
* @param includeSnapshots <code>true</code> if snapshots are to be included.
Expand All @@ -295,7 +315,7 @@ ArtifactVersion[] getAllUpdates(
* @throws InvalidSegmentException thrown if the updateScope is greater than the number of segments
* @since 1.0-beta-1
*/
ArtifactVersion getNewestUpdate(Optional<Segment> updateScope, boolean includeSnapshots)
ArtifactVersion getNewestUpdateWithinSegment(Optional<Segment> updateScope, boolean includeSnapshots)
throws InvalidSegmentException;

/**
Expand Down Expand Up @@ -331,21 +351,29 @@ ArtifactVersion[] getAllUpdates(Optional<Segment> updateScope, boolean includeSn

/**
* <p>Returns a {@linkplain Restriction} object for computing version <em>upgrades</em>
* with the given segment allowing updates, with all more major segments locked in place.</p>
* <p>The resulting restriction could be thought of as one
* retaining the versions on positions up to the held position,
* the position right after the position held in place will be incremented by one,
* and on all positions which are more minor than that, the range would contain -&infin;
* for the bottom bound and +&infin; for the above bound.</p>
* <p>This will allow matching the required versions while not matching versions which are considered
* inferior than the zeroth version, i.e. versions with a qualifier.</p>
* <u>within the given segment</u> allowing updates, with all more major segments locked in place,
* but also <u>ignoring all version updates from lesser scopes</u>.</p>
*
* @param selectedSegment segment, for which the restriction is to be built or {@link Optional#empty()} for no restriction
* @return {@linkplain Restriction} object based on the arguments
* @throws InvalidSegmentException if the requested segment is outside the bounds (less than 1 or greater than
* the segment count)
*/
Restriction restrictionForSelectedSegment(Optional<Segment> selectedSegment) throws InvalidSegmentException;

/**
* <p>Returns a {@linkplain Restriction} object for computing version <em>upgrades</em>
* <u>within the all segments minor/lesser to the provided {@code unchangedSegment}.</p>
* <p>If the provided segment is {@link Optional#empty()}, all possible updates are returned.</p>
*
* @param scope most major segment where updates are allowed Optional.empty() for no restriction
* @param unchangedSegment segment, which should not be changed or {@link Optional#empty()} for no restriction
* @param allowDowngrade whether downgrades are allowed
* @return {@linkplain Restriction} object based on the arguments
* @throws InvalidSegmentException if the requested segment is outside the bounds (less than 1 or greater than
* the segment count)
*/
Restriction restrictionFor(Optional<Segment> scope) throws InvalidSegmentException;
Restriction restrictionForUnchangedSegment(Optional<Segment> unchangedSegment, boolean allowDowngrade)
throws InvalidSegmentException;

/**
* Returns the {@link Restriction} objects for a segemnt scope which is to be <b>ignored</b>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@

import static java.util.Optional.empty;
import static java.util.Optional.of;
import static org.codehaus.mojo.versions.api.Segment.INCREMENTAL;
import static org.codehaus.mojo.versions.api.Segment.MAJOR;
import static org.codehaus.mojo.versions.api.Segment.MINOR;
import static org.codehaus.mojo.versions.api.Segment.*;

/**
* Utility class for manipulating with {@link Segment} objects
Expand Down Expand Up @@ -79,7 +77,8 @@ public static Optional<Segment> determineUnchangedSegment(
: allowIncrementalUpdates ? of(MINOR) : of(INCREMENTAL);
if (log != null && log.isDebugEnabled()) {
log.debug(unchangedSegment
.map(s -> Segment.of(s.value() + 1).toString())
.map(Segment::minorTo)
.map(Segment::toString)
.orElse("ALL") + " version changes allowed");
}
return unchangedSegment;
Expand Down
Loading

0 comments on commit 40f06e2

Please sign in to comment.