Skip to content

Commit

Permalink
display versions outside range with star
Browse files Browse the repository at this point in the history
  • Loading branch information
sultan authored and slawekjaranowski committed Nov 26, 2022
1 parent d4d0f26 commit d05e5cf
Show file tree
Hide file tree
Showing 10 changed files with 233 additions and 9 deletions.
Expand Up @@ -20,11 +20,19 @@
*/

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.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.Restriction;
import org.apache.maven.artifact.versioning.VersionRange;
import org.codehaus.mojo.versions.ordering.BoundArtifactVersion;
Expand All @@ -47,6 +55,10 @@ public abstract class AbstractVersionDetails
implements VersionDetails
{

private static final Pattern PREVIEW_PATTERN =
Pattern.compile( "(?i)(?:.*[-.](alpha|a|beta|b|milestone|m|preview|rc)"
+ "[-.]?(\\d{0,2}[a-z]?|\\d{6}\\.\\d{4})|\\d{8}(?:\\.?\\d{6})?)$" );

/**
* The current version. Guarded by {@link #currentVersionLock}.
*
Expand All @@ -61,6 +73,8 @@ public abstract class AbstractVersionDetails
*/
private boolean includeSnapshots = false;

protected boolean verboseDetail = true;

/**
* Not sure if we need to be thread safe, but there's no harm being careful, after all we could be invoked from an
* IDE.
Expand All @@ -77,6 +91,24 @@ protected AbstractVersionDetails()
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)
Expand Down Expand Up @@ -480,4 +512,87 @@ public boolean isVersionInRestriction( Restriction restriction, ArtifactVersion
}
return ( includeLower || lower != 0 ) && ( includeUpper || upper != 0 );
}

/**
* Returns the latest version newer than the specified current version, and within the specified update scope,
* or <code>null</code> if no such version exists.
* @param updateScope the scope of updates to include.
* @return the newest version after currentVersion within the specified update scope,
* or <code>null</code> if no version is available.
*/
public final ArtifactVersion getReportNewestUpdate( Optional<Segment> updateScope )
{
return getArtifactVersionStream( updateScope )
.min( Collections.reverseOrder( getVersionComparator() ) ).orElse( null );
}

/**
* Returns all versions newer than the specified current version, and within the specified update scope.
* @param updateScope the scope of updates to include.
* @return all versions after currentVersion within the specified update scope.
*/
public final ArtifactVersion[] getReportUpdates( Optional<Segment> updateScope )
{
TreeSet<ArtifactVersion> versions = getArtifactVersionStream( updateScope )
.collect( Collectors.toCollection( () -> new TreeSet<>( getVersionComparator() ) ) );
// filter out intermediate minor versions.
if ( !verboseDetail )
{
int major = 0;
int minor = 0;
boolean needOneMore = false;
for ( Iterator<ArtifactVersion> it = versions.descendingIterator(); it.hasNext(); )
{
ArtifactVersion version = it.next();
boolean isPreview = PREVIEW_PATTERN.matcher( version.toString() ).matches();

// encountered a version in same Major.Minor version, remove it.
if ( version.getMajorVersion() == major && version.getMinorVersion() == minor )
{
if ( needOneMore && !isPreview )
{
needOneMore = false;
continue;
}
it.remove();
continue;
}

// encountered a new Major.Minor version, keep it.
major = version.getMajorVersion();
minor = version.getMinorVersion();

// if version is a pre-release, also search for the last release.
needOneMore = isPreview;

}
}
return versions.toArray( new ArtifactVersion[0] );
}

/**
* Returns all versions newer than the specified current version, and within the specified update scope.
* @param updateScope the scope of updates to include.
* @return all versions after currentVersion within the specified update scope.
*/
private Stream<ArtifactVersion> getArtifactVersionStream( Optional<Segment> updateScope )
{
if ( isCurrentVersionDefined() )
{
try
{
Restriction restriction = restrictionFor( updateScope );

return Arrays.stream( getVersions() ).filter(
candidate -> ( isIncludeSnapshots() || !ArtifactUtils.isSnapshot( candidate.toString() ) )
&& isVersionInRestriction( restriction, candidate ) );
}
catch ( InvalidSegmentException ignored )
{
ignored.printStackTrace( System.err );
}
}
return Stream.empty();
}

}
@@ -0,0 +1,2 @@
invoker.goals.1=${project.groupId}:${project.artifactId}:${project.version}:property-updates-report
invoker.goals.2=${project.groupId}:${project.artifactId}:${project.version}:dependency-updates-report
@@ -0,0 +1,22 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>localhost</groupId>
<artifactId>it-823-ranges-update-report</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<name>ranges-update-report</name>
<url>http://localhost/</url>

<properties>
<verion.dummy-api>[1.1.2,3.0]</verion.dummy-api>
</properties>
<dependencies>
<dependency>
<groupId>localhost</groupId>
<artifactId>dummy-api</artifactId>
<version>${verion.dummy-api}</version>
</dependency>
</dependencies>

</project>
@@ -0,0 +1,26 @@

propertyUpdatesReport = new File( basedir, "target/site/property-updates-report.html" ).text
.replaceAll( '<[^>]+>', ' ' )
.replaceAll( '&[^;]+;', ' ' )
.replaceAll( '\\s+', ' ' )

assert ! ( propertyUpdatesReport =~ /\b1\.1\.0-2\b/ )
assert ! ( propertyUpdatesReport =~ /\b1\.1\.1-2\b/ )
// Summary
assert propertyUpdatesReport =~ / \[1\.1\.2,3\.0\] 1\.1\.3 1\.3 3/
// Detail
assert propertyUpdatesReport =~ /Newer versions 1\.1\.3 Latest Incremental/
assert propertyUpdatesReport =~ /\b1\.2\.2 1\.3 Latest Minor 2\.0 2\.1 3\.0\b/

dependencyUpdatesReport = new File( basedir, "target/site/dependency-updates-report.html" ).text
.replaceAll( '<[^>]+>', ' ' )
.replaceAll( '&[^;]+;', ' ' )
.replaceAll( '\\s+', ' ' )

assert ! ( dependencyUpdatesReport =~ /\b1\.1\.0-2\b/ )
assert ! ( dependencyUpdatesReport =~ /\b1\.1\.1-2\b/ )
// Summary
assert propertyUpdatesReport =~ / \[1\.1\.2,3\.0\] 1\.1\.3 1\.3 3/
// Detail
assert propertyUpdatesReport =~ /Newer versions 1\.1\.3 Latest Incremental/
assert propertyUpdatesReport =~ /\b1\.2\.2 1\.3 Latest Minor 2\.0 2\.1 3\.0\b/
@@ -0,0 +1,2 @@
invoker.goals.1=${project.groupId}:${project.artifactId}:${project.version}:property-updates-report
invoker.goals.2=${project.groupId}:${project.artifactId}:${project.version}:dependency-updates-report
@@ -0,0 +1,22 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>localhost</groupId>
<artifactId>it-823-ranges-update-report</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<name>ranges-update-report</name>
<url>http://localhost/</url>

<properties>
<verion.dummy-api>[1.1.2,3.0)</verion.dummy-api>
</properties>
<dependencies>
<dependency>
<groupId>localhost</groupId>
<artifactId>dummy-api</artifactId>
<version>${verion.dummy-api}</version>
</dependency>
</dependencies>

</project>
@@ -0,0 +1,26 @@

propertyUpdatesReport = new File( basedir, "target/site/property-updates-report.html" ).text
.replaceAll( '<[^>]+>', ' ' )
.replaceAll( '&[^;]+;', ' ' )
.replaceAll( '\\s+', ' ' )

assert ! ( propertyUpdatesReport =~ /\b1\.1\.0-2\b/ )
assert ! ( propertyUpdatesReport =~ /\b1\.1\.1-2\b/ )
// Summary
assert propertyUpdatesReport =~ / \[1\.1\.2,3\.0\) 1\.1\.3 1\.3 3/
// Detail
assert propertyUpdatesReport =~ /Newer versions 1\.1\.3 Latest Incremental/
assert propertyUpdatesReport =~ /\b1\.2\.2 1\.3 Latest Minor 2\.0 2\.1 \* 3\.0\b/

dependencyUpdatesReport = new File( basedir, "target/site/dependency-updates-report.html" ).text
.replaceAll( '<[^>]+>', ' ' )
.replaceAll( '&[^;]+;', ' ' )
.replaceAll( '\\s+', ' ' )

assert ! ( dependencyUpdatesReport =~ /\b1\.1\.0-2\b/ )
assert ! ( dependencyUpdatesReport =~ /\b1\.1\.1-2\b/ )
// Summary
assert propertyUpdatesReport =~ / \[1\.1\.2,3\.0\) 1\.1\.3 1\.3 3/
// Detail
assert propertyUpdatesReport =~ /Newer versions 1\.1\.3 Latest Incremental/
assert propertyUpdatesReport =~ /\b1\.2\.2 1\.3 Latest Minor 2\.0 2\.1 \* 3\.0\b/
Expand Up @@ -62,11 +62,11 @@ public abstract class AbstractVersionsReportRenderer<T> extends VersionsReportRe
*/
protected T model;

protected ArtifactVersionsCache newestUpdateCache
= new ArtifactVersionsCache( AbstractVersionDetails::getNewestUpdate );
protected final ArtifactVersionsCache newestUpdateCache
= new ArtifactVersionsCache( AbstractVersionDetails::getReportNewestUpdate );

protected ArtifactVersionsCache allUpdatesCache
= new ArtifactVersionsCache( AbstractVersionDetails::getAllUpdates );
protected final ArtifactVersionsCache allUpdatesCache
= new ArtifactVersionsCache( AbstractVersionDetails::getReportUpdates );

protected final SinkEventAttributes headerAttributes
= new SinkEventAttributeSet( SinkEventAttributes.WIDTH, "30%" );
Expand Down Expand Up @@ -231,6 +231,7 @@ protected void renderSummaryTableHeader( boolean hasScope, boolean hasType )

protected void renderSummaryTableRow( Dependency artifact, ArtifactVersions details, boolean includeScope )
{
details.setCurrentVersion( artifact.getVersion() );
ArtifactVersion[] allUpdates = allUpdatesCache.get( details, empty() );
boolean upToDate = allUpdates == null || allUpdates.length == 0;

Expand Down Expand Up @@ -263,7 +264,6 @@ protected void renderNewestVersions( AbstractVersionDetails details )
renderBoldCell( newestUpdateCache.get( details, of( MAJOR ) ) );
}

@SuppressWarnings( "checkstyle:MethodLength" )
protected void renderDependencyDetailTable( Dependency artifact, ArtifactVersions details, boolean includeScope )
{
ArtifactVersion[] allUpdates = allUpdatesCache.get( details, empty() );
Expand Down Expand Up @@ -363,6 +363,12 @@ else if ( newestUpdateCache.get( details, of( MAJOR ) ) != null )
}
}

/**
* Builds the list of restrictions for the given artifact or property, based on its version range.
* used to determine if a candidate version is outside the range, and if it should be displayed with a star.
* @param details the artifact or property for which to render the versions.
* @return the list of restrictions for the spec versions range.
*/
private List<Restriction> getArtifactVersionRange( AbstractVersionDetails details )
{
try
Expand All @@ -381,7 +387,7 @@ private List<Restriction> getArtifactVersionRange( AbstractVersionDetails detail
/**
* Renders the list of versions that are available for the given artifact or property.
* @param allUpdates the list of all updates available.
* @param details TODO.
* @param details the versions details for the given artifact or property.
*/
protected void renderVersions( ArtifactVersion[] allUpdates, AbstractVersionDetails details )
{
Expand Down
Expand Up @@ -145,18 +145,22 @@ protected void renderSummaryTableRow( Dependency artifact, PluginUpdatesDetails
boolean upToDate = !details.isUpdateAvailable();

sink.tableRow();
sink.tableCell();

sink.tableCell();
renderIcon( upToDate );
sink.tableCell_();

renderCells( artifact.getGroupId(), artifact.getArtifactId() );
renderBoldCell( upToDate, artifact.getVersion() );
renderNewestVersions( details );

sink.tableCell();
renderIcon( !details.isDependencyUpdateAvailable() );
sink.tableCell_();

sink.tableRow_();
}

@SuppressWarnings( "checkstyle:MethodLength" )
private void renderPluginDetail( Dependency artifact, PluginUpdatesDetails details )
{
sink.section2();
Expand Down
Expand Up @@ -119,7 +119,6 @@ private void renderPropertySummaryTableRow( Property property, PropertyVersions
sink.tableRow_();
}

@SuppressWarnings( "checkstyle:MethodLength" )
protected void renderPropertyDetailTable( Property property, PropertyVersions details )
{
ArtifactVersion[] allUpdates = allUpdatesCache.get( details, empty() );
Expand Down

0 comments on commit d05e5cf

Please sign in to comment.