Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolves #899: Corrected the invocation of Resolver to retrieve the timestamped snapshot version #901

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions versions-maven-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,14 @@
! Not deleting as it might be helpful with assessing performance measurements.
-->
<pomExclude>it-property-updates-report-002-slow/*</pomExclude>
<!--
! The below test is testing Resolver's resolveVersion being able
! to find a timestamped version of a snapshot. Disabled as it's not using
! the mrm-maven-plugin, and so depends on external artifacts; also:
! it's actually testing Resolver and not the plugin itself.
! It's there for debugging purposes if something goes wrong.
-->
<pomExclude>it-lock-snapshots-junit/*</pomExclude>
</pomExcludes>
<postBuildHookScript>verify</postBuildHookScript>
<filterProperties>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
invoker.goals = ${project.groupId}:${project.artifactId}:${project.version}:lock-snapshots
20 changes: 20 additions & 0 deletions versions-maven-plugin/src/it/it-lock-snapshots-junit5/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<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-lock-snapshots-001</artifactId>
<version>1.0</version>
<packaging>pom</packaging>

<dependencies>
<dependency>
<!-- Can't get mrm-maven-plugin to provide maven-metadata -->
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>5.0-SNAPSHOT</version>
<type>pom</type>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def project = new XmlSlurper().parse( new File( basedir, 'pom.xml' ) )

assert !( project.dependencies.dependency.version =~ /-SNAPSHOT/ )
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand All @@ -39,9 +40,12 @@
import org.apache.maven.repository.RepositorySystem;
import org.apache.maven.wagon.Wagon;
import org.codehaus.mojo.versions.api.PomHelper;
import org.codehaus.mojo.versions.api.VersionsHelper;
import org.codehaus.mojo.versions.api.recording.ChangeRecorder;
import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.VersionRequest;
import org.eclipse.aether.resolution.VersionResolutionException;
import org.eclipse.aether.resolution.VersionResult;

/**
* Attempts to resolve unlocked snapshot dependency versions to the locked timestamp versions used in the build. For
Expand Down Expand Up @@ -96,13 +100,13 @@ protected void update(ModifiedPomXMLEventReader pom)
if (getProject().getParent() != null && isProcessingParent()) {
lockParentSnapshot(pom, getProject().getParent());
}
} catch (IOException e) {
} catch (IOException | VersionResolutionException e) {
throw new MojoExecutionException(e.getMessage(), e);
}
}

private void lockSnapshots(ModifiedPomXMLEventReader pom, Collection<Dependency> dependencies)
throws XMLStreamException, MojoExecutionException {
protected void lockSnapshots(ModifiedPomXMLEventReader pom, Collection<Dependency> dependencies)
throws XMLStreamException, MojoExecutionException, VersionResolutionException {
for (Dependency dep : dependencies) {
if (isExcludeReactor() && isProducedByReactor(dep)) {
getLog().info("Ignoring reactor dependency: " + toString(dep));
Expand All @@ -121,24 +125,26 @@ private void lockSnapshots(ModifiedPomXMLEventReader pom, Collection<Dependency>
String version = dep.getVersion();
Matcher versionMatcher = TIMESTAMPED_SNAPSHOT_REGEX.matcher(version);
if (versionMatcher.find() && versionMatcher.end() == version.length()) {
String lockedVersion = resolveSnapshotVersion(dep);
if (!version.equals(lockedVersion)) {
Optional<String> lockedVersion = resolveSnapshotVersion(dep);
if (lockedVersion.isPresent()) {
if (PomHelper.setDependencyVersion(
pom,
dep.getGroupId(),
dep.getArtifactId(),
version,
lockedVersion,
lockedVersion.get(),
getProject().getModel())) {
getLog().info("Locked " + toString(dep) + " to version " + lockedVersion);
getLog().info("Locked " + toString(dep) + " to version " + lockedVersion.get());
}
} else {
getLog().info("No timestamped version for " + toString(dep) + " found.");
}
}
}
}

private void lockParentSnapshot(ModifiedPomXMLEventReader pom, MavenProject parent)
throws XMLStreamException, MojoExecutionException {
protected void lockParentSnapshot(ModifiedPomXMLEventReader pom, MavenProject parent)
throws XMLStreamException, VersionResolutionException {
if (parent == null) {
getLog().info("Project does not have a parent");
return;
Expand All @@ -154,65 +160,46 @@ private void lockParentSnapshot(ModifiedPomXMLEventReader pom, MavenProject pare

Matcher versionMatcher = TIMESTAMPED_SNAPSHOT_REGEX.matcher(parentVersion);
if (versionMatcher.find() && versionMatcher.end() == parentVersion.length()) {
String lockedParentVersion = resolveSnapshotVersion(parentArtifact);
if (!parentVersion.equals(lockedParentVersion)) {
if (PomHelper.setProjectParentVersion(pom, lockedParentVersion)) {
getLog().info("Locked parent " + parentArtifact + " to version " + lockedParentVersion);
Optional<String> lockedParentVersion = resolveSnapshotVersion(parentArtifact);
if (lockedParentVersion.isPresent()) {
if (PomHelper.setProjectParentVersion(pom, lockedParentVersion.get())) {
getLog().info("Locked parent " + parentArtifact + " to version " + lockedParentVersion.get());
}
} else {
getLog().info("No timestamped version for " + parentArtifact + " found.");
}
}
}

/**
* Determine the timestamp version of the snapshot artifact used in the build.
*
* @param artifact
* @return The timestamp version if exists, otherwise the original snapshot artifact version is returned.
* @param artifact artifact for which to retrieve the locked version
* @return The timestamp version if exists, otherwise {@link Optional#empty()}
* @throws VersionResolutionException thrown if version resolution fails
*/
private String resolveSnapshotVersion(Artifact artifact) {
private Optional<String> resolveSnapshotVersion(Artifact artifact) throws VersionResolutionException {
getLog().debug("Resolving snapshot version for artifact: " + artifact);

String lockedVersion = artifact.getVersion();

try {
aetherRepositorySystem.resolveArtifact(
session.getRepositorySession(),
new ArtifactRequest(
RepositoryUtils.toArtifact(artifact),
getProject().getRemoteProjectRepositories(),
getClass().getName()));

lockedVersion = artifact.getVersion();
} catch (Exception e) {
getLog().error(e);
}
return lockedVersion;
VersionResult versionResult = aetherRepositorySystem.resolveVersion(
session.getRepositorySession(),
new VersionRequest(
RepositoryUtils.toArtifact(artifact),
getProject().getRemoteProjectRepositories(),
getClass().getSimpleName()));
return Optional.ofNullable(versionResult.getVersion())
.filter(v -> !String.valueOf(artifact.getVersion()).equals(v));
}

/**
* Determine the timestamp version of the snapshot dependency used in the build.
*
* @param dep
* @return The timestamp version if exists, otherwise the original snapshot dependency version is returned.
* @param dep dependency for which to retrieve the locked version
* @return The timestamp version if exists, otherwise {@link Optional#empty()}
* @throws MojoExecutionException thrown if retrieval of {@link VersionsHelper} fails
* @throws VersionResolutionException thrown if version resolution fails
*/
private String resolveSnapshotVersion(Dependency dep) {
getLog().debug("Resolving snapshot version for dependency: " + dep);

String lockedVersion = dep.getVersion();

try {
Artifact depArtifact = getHelper().createDependencyArtifact(dep);
aetherRepositorySystem.resolveArtifact(
session.getRepositorySession(),
new ArtifactRequest(
RepositoryUtils.toArtifact(depArtifact),
getProject().getRemoteProjectRepositories(),
getClass().getName()));

lockedVersion = depArtifact.getVersion();
} catch (Exception e) {
getLog().error(e);
}
return lockedVersion;
private Optional<String> resolveSnapshotVersion(Dependency dep)
throws MojoExecutionException, VersionResolutionException {
return resolveSnapshotVersion(getHelper().createDependencyArtifact(dep));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package org.codehaus.mojo.versions;
/*
* Copyright MojoHaus and Contributors
*
* Licensed 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 javax.xml.stream.XMLStreamException;

import java.util.List;
import java.util.function.UnaryOperator;

import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.testing.stubs.DefaultArtifactHandlerStub;
import org.apache.maven.project.MavenProject;
import org.codehaus.mojo.versions.api.PomHelper;
import org.codehaus.mojo.versions.utils.DependencyBuilder;
import org.codehaus.mojo.versions.utils.MockUtils;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.resolution.VersionRequest;
import org.eclipse.aether.resolution.VersionResolutionException;
import org.eclipse.aether.resolution.VersionResult;
import org.junit.Test;
import org.mockito.MockedStatic;

import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;

/**
* Unit tests for {@link LockSnapshotsMojo}
*/
public class LockSnapshotsMojoTest {

private LockSnapshotsMojo createMojo(RepositorySystem repositorySystem) {
return new LockSnapshotsMojo(null, repositorySystem, null, null) {
{
reactorProjects = emptyList();
project = new MavenProject(new Model() {
{
setGroupId("default-group");
setArtifactId("default-project");
setVersion("1.0-SNAPSHOT");
}

@Override
public void setDependencies(List<Dependency> dependencies) {
super.setDependencies(singletonList(
DependencyBuilder.dependencyWith("default-group", "default-artifact", "1.0-SNAPSHOT")));
}
});
session = MockUtils.mockMavenSession();
}
};
}

private RepositorySystem mockRepositorySystem(UnaryOperator<String> versionProducer)
throws VersionResolutionException {
RepositorySystem repositorySystem = mock(RepositorySystem.class);
when(repositorySystem.resolveVersion(any(), any())).then(i -> {
VersionRequest request = i.getArgument(1);
return new VersionResult(request)
.setVersion(versionProducer.apply(request.getArtifact().getVersion()));
});
return repositorySystem;
}

@Test
public void testNoTimestampedDependencyFoundNull()
throws XMLStreamException, MojoExecutionException, VersionResolutionException {
RepositorySystem repositorySystem = mockRepositorySystem(v -> null);

LockSnapshotsMojo mojo = createMojo(repositorySystem);
try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
pomHelper
.when(() -> PomHelper.setDependencyVersion(any(), any(), any(), any(), any(), any()))
.thenThrow(new RuntimeException("Not supposed to modify the dependency"));
mojo.lockSnapshots(null, mojo.project.getDependencies());
}
}

@Test
public void testNoTimestampedDependencyFoundSameVersion()
throws XMLStreamException, MojoExecutionException, VersionResolutionException {
RepositorySystem repositorySystem = mockRepositorySystem(UnaryOperator.identity());

LockSnapshotsMojo mojo = createMojo(repositorySystem);
try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
pomHelper
.when(() -> PomHelper.setDependencyVersion(any(), any(), any(), any(), any(), any()))
.thenThrow(new RuntimeException("Not supposed to modify the dependency"));
mojo.lockSnapshots(null, mojo.project.getDependencies());
}
}

@Test
public void testNoTimestampedParentFoundNull()
throws XMLStreamException, MojoExecutionException, VersionResolutionException {
RepositorySystem repositorySystem = mockRepositorySystem(v -> null);

LockSnapshotsMojo mojo = createMojo(repositorySystem);
try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
pomHelper
.when(() -> PomHelper.setProjectParentVersion(any(), any()))
.thenThrow(new RuntimeException("Not supposed to modify the parent"));
mojo.lockParentSnapshot(
null,
new MavenProject(new Model() {
{
setGroupId("default-group");
setArtifactId("default-parent");
setVersion("1.0-SNAPSHOT");
}
}) {
{
setArtifact(new DefaultArtifact(
"default-group",
"default-parent",
"1.0-SNAPSHOT",
"compile",
"pom",
null,
new DefaultArtifactHandlerStub("jar")));
}
});
}
}

@Test
public void testNoTimestampedParentFoundSameVersion()
throws XMLStreamException, MojoExecutionException, VersionResolutionException {
RepositorySystem repositorySystem = mockRepositorySystem(UnaryOperator.identity());

LockSnapshotsMojo mojo = createMojo(repositorySystem);
try (MockedStatic<PomHelper> pomHelper = mockStatic(PomHelper.class)) {
pomHelper
.when(() -> PomHelper.setProjectParentVersion(any(), any()))
.thenThrow(new RuntimeException("Not supposed to modify the parent"));
mojo.lockParentSnapshot(
null,
new MavenProject(new Model() {
{
setGroupId("default-group");
setArtifactId("default-parent");
setVersion("1.0-SNAPSHOT");
}
}) {
{
setArtifact(new DefaultArtifact(
"default-group",
"default-parent",
"1.0-SNAPSHOT",
"compile",
"pom",
null,
new DefaultArtifactHandlerStub("jar")));
}
});
}
}
}