diff --git a/src/it-repo/dummy-parent5-1.0.0.pom b/src/it-repo/dummy-parent5-1.0.0.pom new file mode 100644 index 0000000000..fa778abe72 --- /dev/null +++ b/src/it-repo/dummy-parent5-1.0.0.pom @@ -0,0 +1,10 @@ + + 4.0.0 + + localhost + dummy-parent5 + 1.0.0 + pom + + diff --git a/src/it-repo/dummy-parent5-2.0.0-rc1.pom b/src/it-repo/dummy-parent5-2.0.0-rc1.pom new file mode 100644 index 0000000000..ddaaab726e --- /dev/null +++ b/src/it-repo/dummy-parent5-2.0.0-rc1.pom @@ -0,0 +1,10 @@ + + 4.0.0 + + localhost + dummy-parent5 + 2.0.0-rc1 + pom + + diff --git a/src/it/it-resolve-ranges-issue-454/invoker.properties b/src/it/it-resolve-ranges-issue-454/invoker.properties new file mode 100644 index 0000000000..e616e229f3 --- /dev/null +++ b/src/it/it-resolve-ranges-issue-454/invoker.properties @@ -0,0 +1,2 @@ +invoker.goals = ${project.groupId}:${project.artifactId}:${project.version}:resolve-ranges +invoker.mavenOpts = -DallowMajorUpdates=false diff --git a/src/it/it-resolve-ranges-issue-454/pom.xml b/src/it/it-resolve-ranges-issue-454/pom.xml new file mode 100644 index 0000000000..7dd7e4af92 --- /dev/null +++ b/src/it/it-resolve-ranges-issue-454/pom.xml @@ -0,0 +1,20 @@ + + 4.0.0 + + localhost + test-artifact + 1.0.0 + + + [1.0.0,) + + + + localhost + dummy-parent5 + ${ver} + + + + diff --git a/src/it/it-resolve-ranges-issue-454/verify.groovy b/src/it/it-resolve-ranges-issue-454/verify.groovy new file mode 100644 index 0000000000..e9182fd7f3 --- /dev/null +++ b/src/it/it-resolve-ranges-issue-454/verify.groovy @@ -0,0 +1,3 @@ +pom = new File( basedir, "pom.xml" ).text + +assert !( pom =~ /2.0.0-rc1/ ) diff --git a/src/it/it-update-parent-issue-454/invoker.properties b/src/it/it-update-parent-issue-454/invoker.properties new file mode 100644 index 0000000000..ea39882c84 --- /dev/null +++ b/src/it/it-update-parent-issue-454/invoker.properties @@ -0,0 +1,2 @@ +invoker.goals = ${project.groupId}:${project.artifactId}:${project.version}:update-parent +invoker.mavenOpts = -DallowMajorUpdates=false diff --git a/src/it/it-update-parent-issue-454/pom.xml b/src/it/it-update-parent-issue-454/pom.xml new file mode 100644 index 0000000000..fee0e8da8f --- /dev/null +++ b/src/it/it-update-parent-issue-454/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + + test-artifact + 1.0.0 + + + localhost + dummy-parent5 + 1.0.0 + + + diff --git a/src/it/it-update-parent-issue-454/verify.groovy b/src/it/it-update-parent-issue-454/verify.groovy new file mode 100644 index 0000000000..e9182fd7f3 --- /dev/null +++ b/src/it/it-update-parent-issue-454/verify.groovy @@ -0,0 +1,3 @@ +pom = new File( basedir, "pom.xml" ).text + +assert !( pom =~ /2.0.0-rc1/ ) diff --git a/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojo.java b/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojo.java index fda3617312..9e20ce0766 100644 --- a/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojo.java +++ b/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojo.java @@ -41,7 +41,8 @@ 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.SegmentUtils; + +import static org.codehaus.mojo.versions.utils.SegmentUtils.determineUnchangedSegment; /** * Sets properties to the latest versions of specific artifacts. @@ -105,7 +106,7 @@ public class UpdatePropertiesMojo extends AbstractVersionsDependencyUpdaterMojo */ @Parameter( property = "allowMajorUpdates", defaultValue = "true" ) - protected boolean allowMajorUpdates; + protected boolean allowMajorUpdates = true; /** *

Whether to allow the minor version number to be changed.

@@ -114,8 +115,9 @@ public class UpdatePropertiesMojo extends AbstractVersionsDependencyUpdaterMojo * * @since 2.4 */ - @Parameter( property = "allowMinorUpdates", defaultValue = "true" ) - protected boolean allowMinorUpdates; + @Parameter( property = "allowMinorUpdates", + defaultValue = "true" ) + protected boolean allowMinorUpdates = true; /** *

Whether to allow the incremental version number to be changed.

@@ -127,7 +129,7 @@ public class UpdatePropertiesMojo extends AbstractVersionsDependencyUpdaterMojo */ @Parameter( property = "allowIncrementalUpdates", defaultValue = "true" ) - protected boolean allowIncrementalUpdates; + protected boolean allowIncrementalUpdates = true; // -------------------------- STATIC METHODS -------------------------- @@ -186,8 +188,8 @@ protected void update( ModifiedPomXMLEventReader pom ) if ( canUpdateProperty ) { - Optional unchangedSegment = SegmentUtils.determineUnchangedSegment( allowMajorUpdates, - allowMinorUpdates, allowIncrementalUpdates, getLog() ); + Optional unchangedSegment = determineUnchangedSegment( allowMajorUpdates, allowMinorUpdates, + allowIncrementalUpdates, getLog() ); try { ArtifactVersion targetVersion = diff --git a/src/main/java/org/codehaus/mojo/versions/UpdatePropertyMojo.java b/src/main/java/org/codehaus/mojo/versions/UpdatePropertyMojo.java index dcc1d5d5c9..4e8cecc7e4 100644 --- a/src/main/java/org/codehaus/mojo/versions/UpdatePropertyMojo.java +++ b/src/main/java/org/codehaus/mojo/versions/UpdatePropertyMojo.java @@ -62,7 +62,7 @@ public class UpdatePropertyMojo * @since 1.3 */ @Parameter( property = "property" ) - private String property = null; + protected String property = null; /** * The new version to set the property to (can be a version range to find a version within). diff --git a/src/main/java/org/codehaus/mojo/versions/api/PropertyVersions.java b/src/main/java/org/codehaus/mojo/versions/api/PropertyVersions.java index 7d4621e630..9b25e60462 100644 --- a/src/main/java/org/codehaus/mojo/versions/api/PropertyVersions.java +++ b/src/main/java/org/codehaus/mojo/versions/api/PropertyVersions.java @@ -34,16 +34,19 @@ import org.apache.maven.artifact.ArtifactUtils; import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException; 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.OverConstrainedVersionException; import org.apache.maven.artifact.versioning.Restriction; import org.apache.maven.artifact.versioning.VersionRange; import org.apache.maven.project.MavenProject; import org.codehaus.mojo.versions.Property; +import org.codehaus.mojo.versions.ordering.BoundArtifactVersion; import org.codehaus.mojo.versions.ordering.InvalidSegmentException; import org.codehaus.mojo.versions.ordering.VersionComparator; import static java.util.Optional.empty; +import static org.codehaus.mojo.versions.api.Segment.SUBINCREMENTAL; /** * Manages a property that is associated with one or more artifacts. @@ -320,22 +323,21 @@ public ArtifactVersion getNewestVersion( String currentVersion, Property propert * Retrieves the newest artifact version for the given property-denoted artifact or {@code null} if no newer * version could be found. * - * @param currentVersion current version of the artifact + * @param versionString current version of the artifact * @param property property name indicating the artifact * @param allowSnapshots whether snapshots should be considered * @param reactorProjects collection of reactor projects * @param helper VersionHelper object * @param allowDowngrade whether downgrades should be allowed - * @param unchangedSegment indicates the (0-based) most major segment which needs to stay unchanged; - * -1 means that the whole version can be changed + * @param upperBoundSegment the upper bound segment; empty() means no upper bound * @return newest artifact version fulfilling the criteria or null if no newer version could be found * @throws InvalidSegmentException thrown if the {@code unchangedSegment} is not valid (e.g. greater than the number * of segments in the version string) * @throws InvalidVersionSpecificationException thrown if the version string in the property is not valid */ - public ArtifactVersion getNewestVersion( String currentVersion, Property property, boolean allowSnapshots, + public ArtifactVersion getNewestVersion( String versionString, Property property, boolean allowSnapshots, Collection reactorProjects, VersionsHelper helper, - boolean allowDowngrade, Optional unchangedSegment ) + boolean allowDowngrade, Optional upperBoundSegment ) throws InvalidSegmentException, InvalidVersionSpecificationException { final boolean includeSnapshots = !property.isBanSnapshots() && allowSnapshots; @@ -346,24 +348,33 @@ public ArtifactVersion getNewestVersion( String currentVersion, Property propert ? VersionRange.createFromVersionSpec( property.getVersion() ) : null; helper.getLog().debug( "Property ${" + property.getName() + "}: Restricting results to " + range ); - ArtifactVersion lowerBound = helper.createArtifactVersion( currentVersion ); - if ( allowDowngrade ) - { - Optional updatedVersion = getLowerBound( lowerBound, unchangedSegment ); - lowerBound = updatedVersion.map( helper::createArtifactVersion ).orElse( null ); - } + + ArtifactVersion currentVersion = new DefaultArtifactVersion( versionString ); + ArtifactVersion lowerBound = allowDowngrade + ? getLowerBound( currentVersion, upperBoundSegment ) + .map( DefaultArtifactVersion::new ) + .orElse( null ) + : currentVersion; if ( helper.getLog().isDebugEnabled() ) { helper.getLog().debug( "lowerBoundArtifactVersion: " + lowerBound ); } - ArtifactVersion upperBound = null; - if ( unchangedSegment.isPresent() ) + ArtifactVersion upperBound = + !upperBoundSegment.isPresent() + ? null + : upperBoundSegment + .map( s -> (ArtifactVersion) new BoundArtifactVersion( currentVersion, + s.isMajorTo( SUBINCREMENTAL ) + ? Segment.of( s.value() + 1 ) + : s ) ) + .orElse( null ); + if ( helper.getLog().isDebugEnabled() ) { - upperBound = getVersionComparator().incrementSegment( lowerBound, unchangedSegment.get() ); helper.getLog().debug( "Property ${" + property.getName() + "}: upperBound is: " + upperBound ); } - Restriction restriction = new Restriction( lowerBound, false, upperBound, false ); + + Restriction restriction = new Restriction( lowerBound, allowDowngrade, upperBound, allowDowngrade ); ArtifactVersion result = getNewestVersion( range, restriction, includeSnapshots ); helper.getLog().debug( "Property ${" + property.getName() + "}: Current winner is: " + result ); diff --git a/src/test/java/org/codehaus/mojo/versions/UpdatePropertiesMojoTest.java b/src/test/java/org/codehaus/mojo/versions/UpdatePropertiesMojoTest.java new file mode 100644 index 0000000000..3877397f16 --- /dev/null +++ b/src/test/java/org/codehaus/mojo/versions/UpdatePropertiesMojoTest.java @@ -0,0 +1,70 @@ +package org.codehaus.mojo.versions; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.nio.file.Files; +import java.nio.file.Paths; + +import org.codehaus.mojo.versions.change.VersionChange; +import org.hamcrest.Matchers; +import org.junit.Test; + +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Unit tests for {@link UpdatePropertiesMojo} + */ +public class UpdatePropertiesMojoTest extends UpdatePropertiesMojoTestBase +{ + @Test + public void testAllowMajorUpdates() throws Exception + { + Files.copy( Paths.get( "src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml" ), + Paths.get( pomDir.toString(), "pom.xml" ), REPLACE_EXISTING ); + setUpMojo( "update-properties" ).execute(); + assertThat( changeRecorder.getChanges(), Matchers.hasItem( new VersionChange( "default-group", + "default-artifact", "1.0.0", "2.0.0-M1" ) ) ); + } + + @Test + public void testAllowMinorUpdates() throws Exception + { + Files.copy( Paths.get( "src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml" ), + Paths.get( pomDir.toString(), "pom.xml" ), REPLACE_EXISTING ); + UpdatePropertiesMojo mojo = setUpMojo( "update-properties" ); + mojo.allowMajorUpdates = false; + mojo.execute(); + assertThat( changeRecorder.getChanges(), Matchers.hasItem( new VersionChange( "default-group", + "default-artifact", "1.0.0", "1.1.0-alpha" ) ) ); + } + + @Test + public void testAllowIncrementalUpdates() throws Exception + { + Files.copy( Paths.get( "src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml" ), + Paths.get( pomDir.toString(), "pom.xml" ), REPLACE_EXISTING ); + UpdatePropertiesMojo mojo = setUpMojo( "update-properties" ); + mojo.allowMajorUpdates = false; + mojo.allowMinorUpdates = false; + mojo.execute(); + assertThat( changeRecorder.getChanges(), Matchers.hasItem( new VersionChange( "default-group", + "default-artifact", "1.0.0", "1.0.1-rc1" ) ) ); + } +} diff --git a/src/test/java/org/codehaus/mojo/versions/UpdatePropertiesMojoTestBase.java b/src/test/java/org/codehaus/mojo/versions/UpdatePropertiesMojoTestBase.java new file mode 100644 index 0000000000..431bc30906 --- /dev/null +++ b/src/test/java/org/codehaus/mojo/versions/UpdatePropertiesMojoTestBase.java @@ -0,0 +1,84 @@ +package org.codehaus.mojo.versions; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.nio.file.Path; +import java.util.HashMap; + +import org.apache.maven.artifact.metadata.ArtifactMetadataSource; +import org.apache.maven.plugin.Mojo; +import org.apache.maven.plugin.testing.AbstractMojoTestCase; +import org.apache.maven.plugin.testing.MojoRule; +import org.apache.maven.plugin.testing.stubs.StubArtifactRepository; +import org.codehaus.mojo.versions.utils.TestChangeRecorder; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; + +import static org.codehaus.mojo.versions.utils.MockUtils.mockArtifactMetadataSource; +import static org.codehaus.mojo.versions.utils.TestUtils.createTempDir; +import static org.codehaus.mojo.versions.utils.TestUtils.tearDownTempDir; + +/** + * Base class for {@link UpdatePropertiesMojo} and {@link UpdatePropertyMojo} test suites + */ +public abstract class UpdatePropertiesMojoTestBase extends AbstractMojoTestCase +{ + @Rule + public MojoRule mojoRule = new MojoRule( this ); + protected Path pomDir; + protected ArtifactMetadataSource artifactMetadataSource; + protected TestChangeRecorder changeRecorder; + + @Before + public void setUp() throws Exception + { + super.setUp(); + pomDir = createTempDir( "update-property" ); + changeRecorder = new TestChangeRecorder(); + artifactMetadataSource = mockArtifactMetadataSource( new HashMap() + {{ + put( "default-artifact", new String[] {"1.0.0", "1.0.1-rc1", "1.1.0-alpha", "2.0.0-M1"} ); + }} ); + } + + @After + public void tearDown() throws Exception + { + try + { + tearDownTempDir( pomDir ); + } + finally + { + super.tearDown(); + } + } + + @SuppressWarnings( "unchecked" ) + protected T setUpMojo( String goal ) throws Exception + { + T mojo = (T) mojoRule.lookupConfiguredMojo( pomDir.toFile(), goal ); + setVariableValueToObject( mojo, "localRepository", new StubArtifactRepository( pomDir.toString() ) ); + setVariableValueToObject( mojo, "artifactMetadataSource", artifactMetadataSource ); + setVariableValueToObject( mojo, "changeRecorder", changeRecorder ); + setVariableValueToObject( mojo, "generateBackupPoms", false ); + return (T) mojo; + } +} diff --git a/src/test/java/org/codehaus/mojo/versions/UpdatePropertyMojoTest.java b/src/test/java/org/codehaus/mojo/versions/UpdatePropertyMojoTest.java new file mode 100644 index 0000000000..8e1ec84eab --- /dev/null +++ b/src/test/java/org/codehaus/mojo/versions/UpdatePropertyMojoTest.java @@ -0,0 +1,74 @@ +package org.codehaus.mojo.versions; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.nio.file.Files; +import java.nio.file.Paths; + +import org.codehaus.mojo.versions.change.VersionChange; +import org.hamcrest.Matchers; +import org.junit.Test; + +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Unit tests for {@link UpdatePropertiesMojo} + */ +public class UpdatePropertyMojoTest extends UpdatePropertiesMojoTestBase +{ + @Test + public void testAllowMajorUpdates() throws Exception + { + Files.copy( Paths.get( "src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml" ), + Paths.get( pomDir.toString(), "pom.xml" ), REPLACE_EXISTING ); + UpdatePropertyMojo mojo = setUpMojo( "update-property" ); + mojo.property = "artifact-version"; + mojo.execute(); + assertThat( changeRecorder.getChanges(), Matchers.hasItem( new VersionChange( "default-group", + "default-artifact", "1.0.0", "2.0.0-M1" ) ) ); + } + + @Test + public void testAllowMinorUpdates() throws Exception + { + Files.copy( Paths.get( "src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml" ), + Paths.get( pomDir.toString(), "pom.xml" ), REPLACE_EXISTING ); + UpdatePropertyMojo mojo = setUpMojo( "update-property" ); + mojo.property = "artifact-version"; + mojo.allowMajorUpdates = false; + mojo.execute(); + assertThat( changeRecorder.getChanges(), Matchers.hasItem( new VersionChange( "default-group", + "default-artifact", "1.0.0", "1.1.0-alpha" ) ) ); + } + + @Test + public void testAllowIncrementalUpdates() throws Exception + { + Files.copy( Paths.get( "src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml" ), + Paths.get( pomDir.toString(), "pom.xml" ), REPLACE_EXISTING ); + UpdatePropertyMojo mojo = setUpMojo( "update-property" ); + mojo.property = "artifact-version"; + mojo.allowMajorUpdates = false; + mojo.allowMinorUpdates = false; + mojo.execute(); + assertThat( changeRecorder.getChanges(), Matchers.hasItem( new VersionChange( "default-group", + "default-artifact", "1.0.0", "1.0.1-rc1" ) ) ); + } +} diff --git a/src/test/java/org/codehaus/mojo/versions/utils/TestUtils.java b/src/test/java/org/codehaus/mojo/versions/utils/TestUtils.java new file mode 100644 index 0000000000..6e45c91b97 --- /dev/null +++ b/src/test/java/org/codehaus/mojo/versions/utils/TestUtils.java @@ -0,0 +1,74 @@ +package org.codehaus.mojo.versions.utils; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; + +import static java.nio.file.FileVisitResult.CONTINUE; +import static org.apache.commons.text.CaseUtils.toCamelCase; + +/** + * Auxiliary test utilities + */ +public class TestUtils +{ + /** + * Creates a temporary directory with the given name + * @param name name of the directory to create + * @return {@linkplain Path} object pointing to the directory + * @throws IOException should the I/O operation fail + */ + public static Path createTempDir( String name ) throws IOException + { + return Files.createTempDirectory( toCamelCase( name, false ) ); + } + + /** + * Deletes the given directory together with all its contents + * @param dir directory to delete + * @throws IOException should an I/O operation fail + */ + public static void tearDownTempDir( Path dir ) throws IOException + { + if ( dir != null && Files.exists( dir ) ) + { + Files.walkFileTree( dir, new SimpleFileVisitor() + { + @Override + public FileVisitResult visitFile( Path file, BasicFileAttributes attrs ) throws IOException + { + Files.delete( file ); + return CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory( Path dir, IOException exc ) throws IOException + { + Files.delete( dir ); + return CONTINUE; + } + } ); + } + } +} diff --git a/src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml b/src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml new file mode 100644 index 0000000000..58175f864e --- /dev/null +++ b/src/test/resources/org/codehaus/mojo/update-properties/issue-454-pom.xml @@ -0,0 +1,21 @@ + + 4.0.0 + + default-group + test-artifact + 1.0.0 + + + 1.0.0 + + + + + default-group + default-artifact + ${artifact-version} + + + +