From 5e0321df72ee9578e1c01b545ee5eeaf58059808 Mon Sep 17 00:00:00 2001 From: Andrzej Jarmoniuk Date: Wed, 5 Oct 2022 08:35:23 +0200 Subject: [PATCH] #499: Add segment selection to update parent --- .../versions/AbstractVersionsUpdaterMojo.java | 24 +-- .../mojo/versions/UpdateParentMojo.java | 83 ++++++++-- .../versions/api/AbstractVersionDetails.java | 23 ++- .../mojo/versions/UpdateParentMojoTest.java | 148 ++++++++++++------ 4 files changed, 188 insertions(+), 90 deletions(-) diff --git a/src/main/java/org/codehaus/mojo/versions/AbstractVersionsUpdaterMojo.java b/src/main/java/org/codehaus/mojo/versions/AbstractVersionsUpdaterMojo.java index 15e7449670..d374a9cc1d 100644 --- a/src/main/java/org/codehaus/mojo/versions/AbstractVersionsUpdaterMojo.java +++ b/src/main/java/org/codehaus/mojo/versions/AbstractVersionsUpdaterMojo.java @@ -345,32 +345,10 @@ public void execute() protected ArtifactVersion findLatestVersion( Artifact artifact, VersionRange versionRange, Boolean allowingSnapshots, boolean usePluginRepositories ) throws ArtifactMetadataRetrievalException, MojoExecutionException - { - return findLatestVersion( artifact, versionRange, allowingSnapshots, usePluginRepositories, false ); - } - - /** - * Finds the latest version of the specified artifact that matches the version range. - * - * @param artifact The artifact. - * @param versionRange The version range. - * @param allowingSnapshots null for no override, otherwise the local override to apply. - * @param usePluginRepositories Use plugin repositories - * @param allowDowngrade whether downgrades should be allowed - * @return The latest version of the specified artifact that matches the specified version range or - * null if no matching version could be found. - * @throws ArtifactMetadataRetrievalException If the artifact metadata could not be found. - * @throws MojoExecutionException if something goes wrong. - * @since 1.0-alpha-1 - */ - protected ArtifactVersion findLatestVersion( Artifact artifact, VersionRange versionRange, - Boolean allowingSnapshots, boolean usePluginRepositories, - boolean allowDowngrade ) - throws ArtifactMetadataRetrievalException, MojoExecutionException { boolean includeSnapshots = allowingSnapshots != null ? allowingSnapshots : this.allowSnapshots; final ArtifactVersions artifactVersions = getHelper().lookupArtifactVersions( artifact, usePluginRepositories ); - return artifactVersions.getNewestVersion( versionRange, null, includeSnapshots, allowDowngrade ); + return artifactVersions.getNewestVersion( versionRange, null, includeSnapshots, false ); } /** diff --git a/src/main/java/org/codehaus/mojo/versions/UpdateParentMojo.java b/src/main/java/org/codehaus/mojo/versions/UpdateParentMojo.java index f7e62c01e6..e599fefd77 100644 --- a/src/main/java/org/codehaus/mojo/versions/UpdateParentMojo.java +++ b/src/main/java/org/codehaus/mojo/versions/UpdateParentMojo.java @@ -22,6 +22,11 @@ import javax.inject.Inject; import javax.xml.stream.XMLStreamException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Optional; +import java.util.stream.Collectors; + import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.manager.WagonManager; import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException; @@ -37,7 +42,10 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProjectBuilder; import org.apache.maven.repository.RepositorySystem; +import org.codehaus.mojo.versions.api.ArtifactVersions; import org.codehaus.mojo.versions.api.PomHelper; +import org.codehaus.mojo.versions.api.Segment; +import org.codehaus.mojo.versions.ordering.InvalidSegmentException; import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; import org.codehaus.mojo.versions.utils.DependencyBuilder; @@ -95,6 +103,30 @@ public class UpdateParentMojo extends AbstractVersionsUpdaterMojo defaultValue = "false" ) protected boolean allowDowngrade; + /** + * Whether to allow the major version number to be changed. + * + * @since 1.2 + */ + @Parameter( property = "allowMajorUpdates", defaultValue = "true" ) + protected boolean allowMajorUpdates = true; + + /** + * Whether to allow the minor version number to be changed. + * + * @since 1.2 + */ + @Parameter( property = "allowMinorUpdates", defaultValue = "true" ) + protected boolean allowMinorUpdates = true; + + /** + * Whether to allow the incremental version number to be changed. + * + * @since 1.2 + */ + @Parameter( property = "allowIncrementalUpdates", defaultValue = "true" ) + protected boolean allowIncrementalUpdates = true; + // -------------------------- OTHER METHODS -------------------------- @Inject @@ -135,10 +167,13 @@ protected void update( ModifiedPomXMLEventReader pom ) throw new MojoExecutionException( "skipResolution is only valid if parentVersion is set" ); } - String initialVersion = parentVersion == null ? getProject().getParent().getVersion() : parentVersion; + String initialVersion = parentVersion == null + ? getProject().getParent().getVersion() + : parentVersion; try { - ArtifactVersion artifactVersion = skipResolution ? new DefaultArtifactVersion( parentVersion ) + ArtifactVersion artifactVersion = skipResolution + ? new DefaultArtifactVersion( parentVersion ) : resolveTargetVersion( initialVersion ); if ( artifactVersion != null ) { @@ -166,10 +201,15 @@ protected void update( ModifiedPomXMLEventReader pom ) { throw new MojoExecutionException( e.getMessage(), e ); } + catch ( InvalidSegmentException e ) + { + throw new MojoExecutionException( "Invalid segment specification for version " + initialVersion, e ); + } } - private ArtifactVersion resolveTargetVersion( String initialVersion ) - throws MojoExecutionException, ArtifactMetadataRetrievalException, InvalidVersionSpecificationException + protected ArtifactVersion resolveTargetVersion( String initialVersion ) + throws MojoExecutionException, ArtifactMetadataRetrievalException, InvalidVersionSpecificationException, + InvalidSegmentException { Artifact artifact = getHelper().createDependencyArtifact( DependencyBuilder .newBuilder() @@ -186,14 +226,37 @@ private ArtifactVersion resolveTargetVersion( String initialVersion ) VersionRange.createFromVersionSpec( "[" + targetVersionRange.getRecommendedVersion() + ",)" ) ); } - ArtifactVersion artifactVersion = findLatestVersion( artifact, targetVersionRange, null, - false, allowDowngrade ); - if ( !shouldApplyUpdate( artifact, getProject().getParent().getVersion(), artifactVersion, forceUpdate ) ) + final ArtifactVersions versions = getHelper().lookupArtifactVersions( artifact, false ); + Optional unchangedSegment = determineUnchangedSegment( allowMajorUpdates, allowMinorUpdates, + allowIncrementalUpdates ); + + // currentVersion (set to parentVersion here) is not included in the version range for searching upgrades + // unless we set allowDowngrade to true + for ( ArtifactVersion candidate : reverse( versions.getNewerVersions( initialVersion, unchangedSegment, + allowSnapshots, !isBlank( parentVersion ) || allowDowngrade ) ) ) { - getLog().debug( "Update not applied. Exiting." ); - return null; + if ( allowDowngrade + || targetVersionRange == null + || ArtifactVersions.isVersionInRange( candidate, targetVersionRange ) ) + { + if ( shouldApplyUpdate( artifact, getProject().getParent().getVersion(), candidate, forceUpdate ) ) + { + return candidate; + } + else + { + getLog().debug( "Update not applied. Exiting." ); + return null; + } + } } - return artifactVersion; + + getLog().info( "No versions found" ); + return null; } + private static Iterable reverse( T[] array ) + { + return Arrays.stream( array ).sorted( Collections.reverseOrder() ).collect( Collectors.toList() ); + } } diff --git a/src/main/java/org/codehaus/mojo/versions/api/AbstractVersionDetails.java b/src/main/java/org/codehaus/mojo/versions/api/AbstractVersionDetails.java index 2eac6fe7db..747a448e47 100644 --- a/src/main/java/org/codehaus/mojo/versions/api/AbstractVersionDetails.java +++ b/src/main/java/org/codehaus/mojo/versions/api/AbstractVersionDetails.java @@ -177,20 +177,19 @@ public final ArtifactVersion getNewestVersion( VersionRange versionRange, Restri // so we only need to find the first candidate fulfilling the criteria for ( ArtifactVersion candidate : reverse( getVersions( includeSnapshots ) ) ) { - if ( !allowDowngrade && versionRange != null - && !ArtifactVersions.isVersionInRange( candidate, versionRange ) ) + if ( allowDowngrade || versionRange == null + || ArtifactVersions.isVersionInRange( candidate, versionRange ) ) { - continue; - } - if ( restriction != null && !isVersionInRestriction( restriction, candidate ) ) - { - continue; - } - if ( !includeSnapshots && ArtifactUtils.isSnapshot( candidate.toString() ) ) - { - continue; + if ( restriction != null && !isVersionInRestriction( restriction, candidate ) ) + { + continue; + } + if ( !includeSnapshots && ArtifactUtils.isSnapshot( candidate.toString() ) ) + { + continue; + } + return candidate; } - return candidate; } return null; } diff --git a/src/test/java/org/codehaus/mojo/versions/UpdateParentMojoTest.java b/src/test/java/org/codehaus/mojo/versions/UpdateParentMojoTest.java index bb39a26728..6d945334de 100644 --- a/src/test/java/org/codehaus/mojo/versions/UpdateParentMojoTest.java +++ b/src/test/java/org/codehaus/mojo/versions/UpdateParentMojoTest.java @@ -10,6 +10,7 @@ import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException; import org.apache.maven.artifact.metadata.ArtifactMetadataSource; import org.apache.maven.artifact.resolver.ArtifactResolver; +import org.apache.maven.artifact.versioning.ArtifactVersion; import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; import org.apache.maven.artifact.versioning.VersionRange; import org.apache.maven.model.Dependency; @@ -20,6 +21,7 @@ import org.apache.maven.repository.RepositorySystem; import org.codehaus.mojo.versions.api.PomHelper; import org.codehaus.mojo.versions.change.VersionChange; +import org.codehaus.mojo.versions.ordering.InvalidSegmentException; import org.codehaus.mojo.versions.utils.TestChangeRecorder; import org.junit.Before; import org.junit.BeforeClass; @@ -34,6 +36,7 @@ import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -60,6 +63,8 @@ public static void setUpStatic() {{ put( "parent-artifact", new String[] { "0.9.0", "1.0.0", "1.0.1-SNAPSHOT" } ); put( "issue-670-artifact", new String[] { "0.0.1-1", "0.0.1-1-impl-SNAPSHOT" } ); + put( "dummy-parent2", new String[] { "1.0", "2.0", "3.0", "3.0-alpha-1", "3.0-beta-1" } ); + put( "test-incremental", new String[] { "1.0.0", "1.1.0", "1.1.1", "2.0.0" } ); put( "unknown-artifact", new String[0] ); }} ); } @@ -174,69 +179,46 @@ public void testParentDowngradeForbidden() @Test public void testParentDowngradeAllowedWithRange() - throws MojoExecutionException, XMLStreamException, MojoFailureException + throws MojoExecutionException, ArtifactMetadataRetrievalException, + InvalidVersionSpecificationException, InvalidSegmentException { mojo.allowDowngrade = true; mojo.getProject().setParent( new MavenProject() {{ setGroupId( "default-group" ); setArtifactId( "parent-artifact" ); - setVersion( "[1.0.1-SNAPSHOT,)" ); }} ); - try ( MockedStatic pomHelper = mockStatic( PomHelper.class ) ) - { - pomHelper.when( () -> PomHelper.setProjectParentVersion( any(), any() ) ) - .thenReturn( true ); - mojo.update( null ); - } - assertThat( changeRecorder.getChanges(), - hasItem( new VersionChange( "default-group", "parent-artifact", "[1.0.1-SNAPSHOT,)", - "1.0.0" ) ) ); + ArtifactVersion newVersion = mojo.resolveTargetVersion( "[1.0.1-SNAPSHOT,)" ); + assertThat( newVersion, notNullValue() ); + assertThat( newVersion.toString(), is( "1.0.0" ) ); } @Test public void testParentDowngradeForbiddenWithRange() - throws MojoExecutionException, XMLStreamException, MojoFailureException + throws MojoExecutionException, ArtifactMetadataRetrievalException, + InvalidVersionSpecificationException, InvalidSegmentException { mojo.allowDowngrade = false; - mojo.getProject().setParent( new MavenProject() - {{ - setGroupId( "default-group" ); - setArtifactId( "parent-artifact" ); - setVersion( "[1.0.1-SNAPSHOT,)" ); - }} ); - - try ( MockedStatic pomHelper = mockStatic( PomHelper.class ) ) - { - pomHelper.when( () -> PomHelper.setProjectParentVersion( any(), any() ) ) - .thenReturn( true ); - mojo.update( null ); - } - assertThat( changeRecorder.getChanges(), is( empty() ) ); + ArtifactVersion newVersion = mojo.resolveTargetVersion( "[1.0.1-SNAPSHOT,)" ); + assertThat( newVersion, nullValue() ); } @Test public void testAllowSnapshots() - throws MojoExecutionException, XMLStreamException, MojoFailureException + throws MojoExecutionException, ArtifactMetadataRetrievalException, + InvalidVersionSpecificationException, InvalidSegmentException { mojo.allowSnapshots = true; mojo.getProject().setParent( new MavenProject() {{ setGroupId( "default-group" ); setArtifactId( "issue-670-artifact" ); - setVersion( "0.0.1-1" ); }} ); - try ( MockedStatic pomHelper = mockStatic( PomHelper.class ) ) - { - pomHelper.when( () -> PomHelper.setProjectParentVersion( any(), any() ) ) - .thenReturn( true ); - mojo.update( null ); - } - assertThat( changeRecorder.getChanges(), hasItem( new VersionChange( "default-group", - "issue-670-artifact", "0.0.1-1", - "0.0.1-1-impl-SNAPSHOT" ) ) ); + ArtifactVersion newVersion = mojo.resolveTargetVersion( "0.0.1-1" ); + assertThat( newVersion, notNullValue() ); + assertThat( newVersion.toString(), is( "0.0.1-1-impl-SNAPSHOT" ) ); } @Test @@ -265,21 +247,16 @@ public void testAllowSnapshotsWithParentVersion() @Test public void testIgnoredVersions() - throws MojoExecutionException, XMLStreamException, MojoFailureException, IllegalAccessException + throws MojoExecutionException, IllegalAccessException, + ArtifactMetadataRetrievalException, InvalidVersionSpecificationException, InvalidSegmentException { mojo.getProject().setParent( new MavenProject() {{ setGroupId( "default-group" ); setArtifactId( "parent-artifact" ); - setVersion( "0.9.0" ); }} ); setVariableValueToObject( mojo, "ignoredVersions", singleton( "1.0.0" ) ); - try ( MockedStatic pomHelper = mockStatic( PomHelper.class ) ) - { - pomHelper.when( () -> PomHelper.setProjectParentVersion( any(), any() ) ).thenReturn( true ); - mojo.update( null ); - } - assertThat( changeRecorder.getChanges(), is( empty() ) ); + assertThat( mojo.resolveTargetVersion( "0.9.0" ), nullValue() ); } @Test @@ -346,4 +323,85 @@ public void testShouldUpgradeToSnapshot() throws MojoExecutionException, XMLStre hasItem( new VersionChange( "default-group", "parent-artifact", "0.9.0", "1.0.1-SNAPSHOT" ) ) ); } + + @Test + public void testAllowMinorUpdates() + throws MojoExecutionException, ArtifactMetadataRetrievalException, + InvalidVersionSpecificationException, InvalidSegmentException + { + mojo.getProject().setParent( new MavenProject() + {{ + setGroupId( "default-group" ); + setArtifactId( "parent-artifact" ); + setVersion( "0.8.0" ); + }} ); + mojo.allowMajorUpdates = false; + mojo.allowMinorUpdates = true; + mojo.allowIncrementalUpdates = false; + + ArtifactVersion newVersion = mojo.resolveTargetVersion( "0.8.0" ); + + assertThat( newVersion, notNullValue() ); + assertThat( newVersion.toString(), is( "0.9.0" ) ); + } + + @Test + public void testAllowIncrementalUpdates() + throws MojoExecutionException, ArtifactMetadataRetrievalException, + InvalidVersionSpecificationException, InvalidSegmentException + { + mojo.getProject().setParent( new MavenProject() + {{ + setGroupId( "default-group" ); + setArtifactId( "test-incremental" ); + }} ); + mojo.allowMajorUpdates = false; + mojo.allowMinorUpdates = false; + mojo.allowIncrementalUpdates = true; + + ArtifactVersion newVersion = mojo.resolveTargetVersion( "1.1.0" ); + + assertThat( newVersion, notNullValue() ); + assertThat( newVersion.toString(), is( "1.1.1" ) ); + } + + @Test + public void testParentVersionRange() throws MojoExecutionException, XMLStreamException, MojoFailureException + { + mojo.getProject().setParent( new MavenProject() + {{ + setGroupId( "default-group" ); + setArtifactId( "dummy-parent2" ); + setVersion( "1.0" ); + }} ); + mojo.allowSnapshots = true; + mojo.parentVersion = "[,3.0-!)"; + try ( MockedStatic pomHelper = mockStatic( PomHelper.class ) ) + { + pomHelper.when( () -> PomHelper.setProjectParentVersion( any(), any() ) ).thenReturn( true ); + mojo.update( null ); + } + assertThat( changeRecorder.getChanges(), + hasItem( new VersionChange( "default-group", "dummy-parent2", "1.0", + "2.0" ) ) ); + } + + @Test + public void testParentVersionRange2() throws MojoExecutionException, XMLStreamException, MojoFailureException + { + mojo.getProject().setParent( new MavenProject() + {{ + setGroupId( "default-group" ); + setArtifactId( "test-parent2" ); + setVersion( "2.0" ); + }} ); + mojo.allowSnapshots = true; + mojo.parentVersion = "[,3.0-!)"; + try ( MockedStatic pomHelper = mockStatic( PomHelper.class ) ) + { + pomHelper.when( () -> PomHelper.setProjectParentVersion( any(), any() ) ).thenReturn( true ); + mojo.update( null ); + } + assertThat( changeRecorder.getChanges(), empty() ); + } }