From 2e86ee7c67c5f45a3935b74242fe4ff79e91bb77 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 --- .../it-update-parent-002/invoker.properties | 1 - src/it/it-update-parent-002/pom.xml | 50 ------ src/it/it-update-parent-002/verify.bsh | 33 ---- .../it-update-parent-003/invoker.properties | 1 - src/it/it-update-parent-003/pom.xml | 50 ------ src/it/it-update-parent-003/verify.bsh | 32 ---- .../versions/AbstractVersionsUpdaterMojo.java | 24 +-- .../mojo/versions/UpdateParentMojo.java | 83 ++++++++-- .../versions/api/AbstractVersionDetails.java | 23 ++- .../mojo/versions/UpdateParentMojoTest.java | 148 ++++++++++++------ 10 files changed, 188 insertions(+), 257 deletions(-) delete mode 100644 src/it/it-update-parent-002/invoker.properties delete mode 100644 src/it/it-update-parent-002/pom.xml delete mode 100644 src/it/it-update-parent-002/verify.bsh delete mode 100644 src/it/it-update-parent-003/invoker.properties delete mode 100644 src/it/it-update-parent-003/pom.xml delete mode 100644 src/it/it-update-parent-003/verify.bsh diff --git a/src/it/it-update-parent-002/invoker.properties b/src/it/it-update-parent-002/invoker.properties deleted file mode 100644 index be7a896ce6..0000000000 --- a/src/it/it-update-parent-002/invoker.properties +++ /dev/null @@ -1 +0,0 @@ -invoker.goals=${project.groupId}:${project.artifactId}:${project.version}:update-parent diff --git a/src/it/it-update-parent-002/pom.xml b/src/it/it-update-parent-002/pom.xml deleted file mode 100644 index c82d7a938c..0000000000 --- a/src/it/it-update-parent-002/pom.xml +++ /dev/null @@ -1,50 +0,0 @@ - - 4.0.0 - - - localhost - dummy-parent - 1.0 - - - localhost - it-201 - 1.0 - pom - update-parent within range - - - - - - maven-clean-plugin - 2.2 - - - maven-deploy-plugin - 2.3 - - - maven-install-plugin - 2.2 - - - maven-site-plugin - 2.0 - - - - - - @project.groupId@ - @project.artifactId@ - @project.version@ - - [,3.0-!) - - - - - - diff --git a/src/it/it-update-parent-002/verify.bsh b/src/it/it-update-parent-002/verify.bsh deleted file mode 100644 index 7c158490d8..0000000000 --- a/src/it/it-update-parent-002/verify.bsh +++ /dev/null @@ -1,33 +0,0 @@ -import java.io.*; -import java.util.regex.*; - -try -{ - File file = new File( basedir, "pom.xml" ); - - BufferedReader in = new BufferedReader( new InputStreamReader( new FileInputStream( file ), "UTF-8" ) ); - StringBuilder buf = new StringBuilder(); - String line = in.readLine(); - while ( line != null ) - { - buf.append( line ); - buf.append( " " ); - line = in.readLine(); - } - - Pattern p = Pattern.compile( "\\Q\\E.*\\Q\\E\\s*2\\.0\\s*\\Q\\E.*\\Q\\E" ); - Matcher m = p.matcher( buf.toString() ); - if ( !m.find() ) - { - System.out.println( "Did not update parent to version 2.0" ); - return false; - } - System.out.println( m.group( 0 ) ); -} -catch( Throwable t ) -{ - t.printStackTrace(); - return false; -} - -return true; diff --git a/src/it/it-update-parent-003/invoker.properties b/src/it/it-update-parent-003/invoker.properties deleted file mode 100644 index be7a896ce6..0000000000 --- a/src/it/it-update-parent-003/invoker.properties +++ /dev/null @@ -1 +0,0 @@ -invoker.goals=${project.groupId}:${project.artifactId}:${project.version}:update-parent diff --git a/src/it/it-update-parent-003/pom.xml b/src/it/it-update-parent-003/pom.xml deleted file mode 100644 index 03ca6fd7e2..0000000000 --- a/src/it/it-update-parent-003/pom.xml +++ /dev/null @@ -1,50 +0,0 @@ - - 4.0.0 - - - localhost - dummy-parent - 2.0 - - - localhost - it-201 - 1.0 - pom - update-parent within range - - - - - - maven-clean-plugin - 2.2 - - - maven-deploy-plugin - 2.3 - - - maven-install-plugin - 2.2 - - - maven-site-plugin - 2.0 - - - - - - @project.groupId@ - @project.artifactId@ - @project.version@ - - [,3.0-!) - - - - - - diff --git a/src/it/it-update-parent-003/verify.bsh b/src/it/it-update-parent-003/verify.bsh deleted file mode 100644 index d38f93b00c..0000000000 --- a/src/it/it-update-parent-003/verify.bsh +++ /dev/null @@ -1,32 +0,0 @@ -import java.io.*; -import java.util.regex.*; - -try -{ - File file = new File( basedir, "pom.xml" ); - - BufferedReader in = new BufferedReader( new InputStreamReader( new FileInputStream( file ), "UTF-8" ) ); - StringBuilder buf = new StringBuilder(); - String line = in.readLine(); - while ( line != null ) - { - buf.append( line ); - buf.append( " " ); - line = in.readLine(); - } - - Pattern p = Pattern.compile( "\\Q\\E.*\\Q\\E\\s*2\\.0\\s*\\Q\\E.*\\Q\\E" ); - Matcher m = p.matcher( buf.toString() ); - if ( !m.find() ) - { - System.out.println( "Updated parent" ); - return false; - } -} -catch( Throwable t ) -{ - t.printStackTrace(); - return false; -} - -return true; 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..43ca78b36f 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( "dummy-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() ); + } }