Repository: mojohaus/versions
Pull request #1161 (2024-10-17 16:19:31)

Bump org.codehaus.groovy:groovy-all from 2.0.0 to 2.4.21 in /versions-maven-plugin/src/it/it-property-updates-report-002-slow
Bumps [org.codehaus.groovy:groovy-all](https://github.com/apache/groovy) from 2.0.0 to 2.4.21.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a href="https://github.com/apache/groovy/commits">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.codehaus.groovy:groovy-all&package-manager=maven&previous-version=2.0.0&new-version=2.4.21)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/mojohaus/versions/network/alerts).

</details>


Patch:
diff --git a/pom.xml b/pom.xml
index b434e9ac..8c21f6c7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -131,7 +131,7 @@
     <fluidoVersion>${maven-fluido-skin.version}</fluidoVersion>
     <modelloNamespaceRuleVersion>2.1.0</modelloNamespaceRuleVersion>
     <modelloNamespaceReportVersion>2.0.0</modelloNamespaceReportVersion>
-    <byteBuddyVersion>1.15.4</byteBuddyVersion>
+    <byteBuddyVersion>1.15.7</byteBuddyVersion>
     <!-- use the same version as in Maven core -->
     <mavenResolverVersion>1.4.1</mavenResolverVersion>
 
diff --git a/versions-common/src/main/java/org/codehaus/mojo/versions/utils/MavenProjectUtils.java b/versions-common/src/main/java/org/codehaus/mojo/versions/utils/MavenProjectUtils.java
index 730ee44e..8cef7d27 100644
--- a/versions-common/src/main/java/org/codehaus/mojo/versions/utils/MavenProjectUtils.java
+++ b/versions-common/src/main/java/org/codehaus/mojo/versions/utils/MavenProjectUtils.java
@@ -32,6 +32,7 @@ import org.codehaus.mojo.versions.api.VersionRetrievalException;
 
 import static java.util.Collections.emptyList;
 import static java.util.Optional.ofNullable;
+import static org.apache.commons.lang3.StringUtils.startsWith;
 
 /**
  * Utility methods for extracting dependencies from a {@link org.apache.maven.project.MavenProject}
@@ -39,6 +40,7 @@ import static java.util.Optional.ofNullable;
 public class MavenProjectUtils {
     /**
      * Retrieves dependencies from the plugins section
+     *
      * @param project {@link MavenProject} instance
      * @return set of {@link Dependency} objects
      * or an empty set if none have been retrieveddependencies or an empty set if none have been retrieved
@@ -56,9 +58,10 @@ public class MavenProjectUtils {
 
     /**
      * Retrieves dependencies from plugin management
+     *
      * @param project {@link MavenProject} instance
      * @return set of {@link Dependency} objects
-     * or an empty set if none have been retrieveddependencies or an empty set if none have been retrieved
+     *         or an empty set if none have been retrieveddependencies or an empty set if none have been retrieved
      */
     public static Set<Dependency> extractDependenciesFromPlugins(MavenProject project) {
         return project.getBuildPlugins().stream()
@@ -71,14 +74,15 @@ public class MavenProjectUtils {
      * Retrieves dependencies from the dependency management of the project
      * as well as its immediate parent project.
      *
-     * @param project {@link MavenProject} instance
+     * @param project                               {@link MavenProject} instance
      * @param processDependencyManagementTransitive if {@code true}, the original model will be considered
      *                                              instead of the interpolated model, which does not contain
      *                                              imported dependencies
-     * @param log {@link Log} instance (may not be null)
+     * @param log                                   {@link Log} instance (may not be null)
      * @return set of {@link Dependency} objects
      * @throws VersionRetrievalException thrown if version information retrieval fails
-     * or an empty set if none have been retrieveddependencies or an empty set if none have been retrieved
+     *                                   or an empty set if none have been retrieveddependencies or an empty set if none
+     *                                   have been retrieved
      */
     public static Set<Dependency> extractDependenciesFromDependencyManagement(
             MavenProject project, boolean processDependencyManagementTransitive, Log log)
@@ -119,8 +123,8 @@ public class MavenProjectUtils {
                         throw new VersionRetrievalException(message);
                     }
                 } else {
-                    dependency = interpolateVersion(dependency, project);
-                    dependencyManagement.add(dependency);
+                    dependencyManagement.remove(dependency);
+                    dependencyManagement.add(interpolateVersion(dependency, project));
                 }
             }
         }
@@ -131,22 +135,24 @@ public class MavenProjectUtils {
      * Attempts to interpolate the version from model properties.
      *
      * @param dependency the dependency
-     * @param project the maven project
+     * @param project    the maven project
      * @return the dependency with interpolated property (as far as possible)
      * @since 2.14.0
      */
     public static Dependency interpolateVersion(final Dependency dependency, final MavenProject project) {
-
         // resolve version from model properties if necessary (e.g. "${mycomponent.myversion}"
-        if (dependency.getVersion().startsWith("${")) {
-            final String resolvedVersion = project.getOriginalModel()
-                    .getProperties()
-                    .getProperty(dependency
-                            .getVersion()
-                            .substring(2, dependency.getVersion().length() - 1));
-            if (resolvedVersion != null && !resolvedVersion.isEmpty()) {
-                dependency.setVersion(resolvedVersion);
-            }
+        if (startsWith(dependency.getVersion(), "${")) {
+            return ofNullable(project.getOriginalModel()
+                            .getProperties()
+                            .getProperty(dependency
+                                    .getVersion()
+                                    .substring(2, dependency.getVersion().length() - 1)))
+                    .map(v -> {
+                        Dependency result = dependency.clone();
+                        result.setVersion(v);
+                        return result;
+                    })
+                    .orElse(dependency);
         }
         return dependency;
     }
diff --git a/versions-maven-plugin/src/it/it-property-updates-report-002-slow/pom.xml b/versions-maven-plugin/src/it/it-property-updates-report-002-slow/pom.xml
index 6bbf96a5..5bba05df 100644
--- a/versions-maven-plugin/src/it/it-property-updates-report-002-slow/pom.xml
+++ b/versions-maven-plugin/src/it/it-property-updates-report-002-slow/pom.xml
@@ -19,7 +19,7 @@
     <jackson.version>2.6.7.3</jackson.version>
     <mariadb-client.version>2.4.3</mariadb-client.version>
     <postgresql-client.version>42.7.2</postgresql-client.version>
-    <groovy.version>2.0.0</groovy.version>
+    <groovy.version>2.4.21</groovy.version>
   </properties>
 
   <dependencyManagement>
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractDependencyUpdatesReportMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractDependencyUpdatesReportMojo.java
index e4370618..a2a359b0 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractDependencyUpdatesReportMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractDependencyUpdatesReportMojo.java
@@ -33,6 +33,7 @@ import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
 import org.apache.maven.artifact.versioning.ArtifactVersion;
 import org.apache.maven.doxia.sink.Sink;
 import org.apache.maven.model.Dependency;
+import org.apache.maven.model.DependencyManagement;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.reporting.MavenReportException;
@@ -47,6 +48,7 @@ import org.codehaus.plexus.i18n.I18N;
 import org.eclipse.aether.RepositorySystem;
 
 import static java.util.Collections.emptyMap;
+import static java.util.Optional.ofNullable;
 import static org.codehaus.mojo.versions.utils.MavenProjectUtils.interpolateVersion;
 import static org.codehaus.mojo.versions.utils.MiscUtils.filter;
 
@@ -189,29 +191,29 @@ public abstract class AbstractDependencyUpdatesReportMojo extends AbstractVersio
             MavenProject project, Set<Dependency> dependencyManagementCollector) throws MavenReportException {
         if (processDependencyManagementTransitive) {
             if (hasDependencyManagement(project)) {
-                for (Dependency dep : project.getDependencyManagement().getDependencies()) {
-                    getLog().debug("Dpmg: " + dep.getGroupId() + ":" + dep.getArtifactId() + ":" + dep.getVersion()
-                            + ":" + dep.getType() + ":" + dep.getScope());
+                if (getLog().isDebugEnabled()) {
+                    project.getDependencyManagement().getDependencies().forEach(dep -> getLog().debug(
+                                    "Dpmg: " + dep.getGroupId() + ":" + dep.getArtifactId() + ":" + dep.getVersion()
+                                            + ":" + dep.getType() + ":" + dep.getScope()));
                 }
                 dependencyManagementCollector.addAll(
                         project.getDependencyManagement().getDependencies());
             }
         } else {
-            if (project.getOriginalModel().getDependencyManagement() != null
-                    && project.getOriginalModel().getDependencyManagement().getDependencies() != null) {
-                // Using the original model to getModel the original dependencyManagement entries and
-                // not the interpolated model.
-                // TODO: I'm not 100% sure if this will work correctly in all cases.
-                for (Dependency dep :
-                        project.getOriginalModel().getDependencyManagement().getDependencies()) {
-                    dep = interpolateVersion(dep, project);
-
-                    getLog().debug("Original Dpmg: " + dep.getGroupId() + ":" + dep.getArtifactId() + ":"
-                            + dep.getVersion() + ":" + dep.getType() + ":" + dep.getScope());
-                }
-                dependencyManagementCollector.addAll(
-                        project.getOriginalModel().getDependencyManagement().getDependencies());
-            }
+            // Using the original model to getModel the original dependencyManagement entries and
+            // not the interpolated model.
+            // TODO: I'm not 100% sure if this will work correctly in all cases.
+            ofNullable(project.getOriginalModel().getDependencyManagement())
+                    .map(DependencyManagement::getDependencies)
+                    .ifPresent(list -> list.stream()
+                            .map(dep -> interpolateVersion(dep, project))
+                            .peek(dep -> {
+                                if (getLog().isDebugEnabled()) {
+                                    getLog().debug("Original Dpmg: " + dep.getGroupId() + ":" + dep.getArtifactId()
+                                            + ":" + dep.getVersion() + ":" + dep.getType() + ":" + dep.getScope());
+                                }
+                            })
+                            .forEach(dependencyManagementCollector::add));
         }
     }
 
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/CompareDependenciesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/CompareDependenciesMojo.java
index cb0c3f80..d0ed1430 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/CompareDependenciesMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/CompareDependenciesMojo.java
@@ -264,7 +264,9 @@ public class CompareDependenciesMojo extends AbstractVersionsDependencyUpdaterMo
                 PomHelper.createProjectBuilderRequest(
                         session,
                         r -> r.setProcessPlugins(false),
-                        r -> r.setRemoteRepositories(session.getCurrentProject().getPluginArtifactRepositories())));
+                        r -> r.setRemoteRepositories(session.getCurrentProject().getRemoteArtifactRepositories()),
+                        r -> r.setPluginArtifactRepositories(
+                                session.getCurrentProject().getPluginArtifactRepositories())));
         if (!result.getProblems().isEmpty()) {
             getLog().warn("Problems encountered during construction of the POM for " + remoteArtifact.toString());
             result.getProblems().forEach(p -> getLog().warn("\t" + p.getMessage()));
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPluginUpdatesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPluginUpdatesMojo.java
index b62ea37f..c2411fd6 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPluginUpdatesMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPluginUpdatesMojo.java
@@ -632,7 +632,9 @@ public class DisplayPluginUpdatesMojo extends AbstractVersionsDisplayMojo {
                 PomHelper.createProjectBuilderRequest(
                         session,
                         r -> r.setProcessPlugins(false),
-                        r -> r.setRemoteRepositories(session.getCurrentProject().getPluginArtifactRepositories())));
+                        r -> r.setRemoteRepositories(session.getCurrentProject().getRemoteArtifactRepositories()),
+                        r -> r.setPluginArtifactRepositories(
+                                session.getCurrentProject().getPluginArtifactRepositories())));
         if (!result.getProblems().isEmpty()) {
             getLog().warn("Problems encountered during construction of the plugin POM for " + probe.toString());
             result.getProblems().forEach(p -> getLog().warn("\t" + p.getMessage()));
diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetMojo.java
index 2be7d472..b1b9fef9 100644
--- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetMojo.java
+++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetMojo.java
@@ -345,7 +345,7 @@ public class SetMojo extends AbstractVersionsUpdaterMojo {
             // so that the main project can be selected
             Model rootModel = reactorModels.get(session.getCurrentProject().getFile());
             if (groupId == null) {
-                groupId = rootModel.getGroupId();
+                groupId = PomHelper.getGroupId(rootModel);
             }
             if (artifactId == null) {
                 artifactId = rootModel.getArtifactId();


Test patch:
diff --git a/versions-common/src/test/java/org/codehaus/mojo/versions/utils/MavenProjectUtilsTest.java b/versions-common/src/test/java/org/codehaus/mojo/versions/utils/MavenProjectUtilsTest.java
new file mode 100644
index 00000000..e24c5da6
--- /dev/null
+++ b/versions-common/src/test/java/org/codehaus/mojo/versions/utils/MavenProjectUtilsTest.java
@@ -0,0 +1,88 @@
+package org.codehaus.mojo.versions.utils;
+
+import java.util.Properties;
+
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Model;
+import org.apache.maven.project.MavenProject;
+import org.junit.jupiter.api.Test;
+
+import static org.codehaus.mojo.versions.utils.MavenProjectUtils.interpolateVersion;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.hamcrest.core.Is.is;
+
+public class MavenProjectUtilsTest {
+
+    @Test
+    public void testInterpolateVersion() {
+        Dependency dep = DependencyBuilder.newBuilder()
+                .withGroupId("groupA")
+                .withArtifactId("artifactA")
+                .withVersion("${param}")
+                .build();
+        MavenProject proj = new MavenProject() {
+            {
+                setOriginalModel(new Model() {
+                    {
+                        setProperties(new Properties() {
+                            {
+                                setProperty("param", "1.0.0");
+                            }
+                        });
+                    }
+                });
+            }
+        };
+        Dependency result = interpolateVersion(dep, proj);
+        assertThat(result.getVersion(), is("1.0.0"));
+    }
+
+    @Test
+    public void testImmutability() {
+        Dependency dep = DependencyBuilder.newBuilder()
+                .withGroupId("groupA")
+                .withArtifactId("artifactA")
+                .withVersion("${param}")
+                .build();
+        MavenProject proj = new MavenProject() {
+            {
+                setOriginalModel(new Model() {
+                    {
+                        setProperties(new Properties() {
+                            {
+                                setProperty("param", "1.0.0");
+                            }
+                        });
+                    }
+                });
+            }
+        };
+        assertThat(interpolateVersion(dep, proj), not(sameInstance(dep)));
+    }
+
+    @Test
+    public void testVersionlessDependency() {
+        Dependency dep = DependencyBuilder.newBuilder()
+                .withGroupId("groupA")
+                .withArtifactId("artifactA")
+                .build();
+        MavenProject proj = new MavenProject() {
+            {
+                setOriginalModel(new Model() {
+                    {
+                        setProperties(new Properties() {
+                            {
+                                setProperty("param", "1.0.0");
+                            }
+                        });
+                    }
+                });
+            }
+        };
+        Dependency result = interpolateVersion(dep, proj);
+        assertThat(result.getVersion(), nullValue());
+    }
+}
diff --git a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/DependencyUpdatesReportMojoTest.java b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/DependencyUpdatesReportMojoTest.java
index 1795bd5b..3f50cd90 100644
--- a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/DependencyUpdatesReportMojoTest.java
+++ b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/DependencyUpdatesReportMojoTest.java
@@ -364,4 +364,15 @@ public class DependencyUpdatesReportMojoTest {
         String output = os.toString();
         assertThat(output, Matchers.stringContainsInOrder("artifactA", "1.0.0", "artifactB", "1.2.3"));
     }
+
+    @Test
+    public void testVersionlessDependency() throws IOException, MavenReportException {
+        OutputStream os = new ByteArrayOutputStream();
+        SinkFactory sinkFactory = new Xhtml5SinkFactory();
+        new TestDependencyUpdatesReportMojo()
+                .withOriginalDependencyManagement(dependencyOf("artifactA", null))
+                .withProcessDependencyManagement(true)
+                .withProcessDependencyManagementTransitive(false)
+                .generate(sinkFactory.createSink(os), sinkFactory, Locale.getDefault());
+    }
 }
diff --git a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/SetMojoTest.java b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/SetMojoTest.java
index 898d895b..73038277 100644
--- a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/SetMojoTest.java
+++ b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/SetMojoTest.java
@@ -6,14 +6,17 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import org.apache.commons.lang3.tuple.Triple;
 import org.apache.maven.model.Model;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugin.testing.AbstractMojoTestCase;
 import org.apache.maven.plugin.testing.MojoRule;
 import org.apache.maven.project.MavenProject;
+import org.codehaus.mojo.versions.utils.TestLog;
 import org.codehaus.mojo.versions.utils.TestUtils;
 import org.junit.After;
 import org.junit.Before;
@@ -231,4 +234,18 @@ public class SetMojoTest extends AbstractMojoTestCase {
                 String.join("", Files.readAllLines(tempDir.resolve("child-webapp/pom.xml"))),
                 matchesRegex(".*\\Q<artifactId>child-webapp</artifactId>\\E\\s*" + "\\Q<version>1.0</version>\\E.*"));
     }
+
+    @Test
+    public void testIssue1137() throws Exception {
+        TestUtils.copyDir(Paths.get("src/test/resources/org/codehaus/mojo/set/issue-1137"), tempDir);
+        TestLog testLog = new TestLog();
+        SetMojo mojo =
+                (SetMojo) mojoRule.lookupConfiguredMojo(tempDir.resolve("child").toFile(), "set");
+        setVariableValueToObject(mojo, "newVersion", "1.1");
+        setVariableValueToObject(mojo, "log", testLog);
+        mojo.execute();
+        assertThat(
+                testLog.getLoggedMessages().stream().map(Triple::getMiddle).collect(Collectors.joining("\n")),
+                not(containsString("Processing change of null:child")));
+    }
 }
diff --git a/versions-maven-plugin/src/test/resources/org/codehaus/mojo/set/issue-1137/child/pom.xml b/versions-maven-plugin/src/test/resources/org/codehaus/mojo/set/issue-1137/child/pom.xml
new file mode 100644
index 00000000..0eb49500
--- /dev/null
+++ b/versions-maven-plugin/src/test/resources/org/codehaus/mojo/set/issue-1137/child/pom.xml
@@ -0,0 +1,11 @@
+<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>
+    <parent>
+        <groupId>group</groupId>
+        <artifactId>parent</artifactId>
+        <version>1.0</version>
+    </parent>
+    <artifactId>child</artifactId>
+    <version>1.0</version>
+</project>
diff --git a/versions-maven-plugin/src/test/resources/org/codehaus/mojo/set/issue-1137/pom.xml b/versions-maven-plugin/src/test/resources/org/codehaus/mojo/set/issue-1137/pom.xml
new file mode 100644
index 00000000..3f5b9e95
--- /dev/null
+++ b/versions-maven-plugin/src/test/resources/org/codehaus/mojo/set/issue-1137/pom.xml
@@ -0,0 +1,11 @@
+<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>group</groupId>
+    <artifactId>parent</artifactId>
+    <version>1.0</version>
+    <packaging>pom</packaging>
+    <modules>
+        <module>child</module>
+    </modules>
+</project>
diff --git a/versions-test/src/main/java/org/codehaus/mojo/versions/utils/TestLog.java b/versions-test/src/main/java/org/codehaus/mojo/versions/utils/TestLog.java
new file mode 100644
index 00000000..daef1f4f
--- /dev/null
+++ b/versions-test/src/main/java/org/codehaus/mojo/versions/utils/TestLog.java
@@ -0,0 +1,102 @@
+package org.codehaus.mojo.versions.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.tuple.Triple;
+import org.apache.maven.plugin.logging.Log;
+
+public class TestLog implements Log {
+    private final List<Triple<LogLevel, CharSequence, Throwable>> loggedMessages = new ArrayList<>();
+
+    public List<Triple<LogLevel, CharSequence, Throwable>> getLoggedMessages() {
+        return loggedMessages;
+    }
+
+    @Override
+    public boolean isDebugEnabled() {
+        return false;
+    }
+
+    @Override
+    public void debug(CharSequence charSequence) {
+        debug(charSequence, null);
+    }
+
+    @Override
+    public void debug(CharSequence charSequence, Throwable throwable) {
+        loggedMessages.add(Triple.of(LogLevel.DEBUG, charSequence, throwable));
+    }
+
+    @Override
+    public void debug(Throwable throwable) {
+        debug(null, throwable);
+    }
+
+    @Override
+    public boolean isInfoEnabled() {
+        return false;
+    }
+
+    @Override
+    public void info(CharSequence charSequence) {
+        info(charSequence, null);
+    }
+
+    @Override
+    public void info(CharSequence charSequence, Throwable throwable) {
+        loggedMessages.add(Triple.of(LogLevel.INFO, charSequence, throwable));
+    }
+
+    @Override
+    public void info(Throwable throwable) {
+        info(null, throwable);
+    }
+
+    @Override
+    public boolean isWarnEnabled() {
+        return false;
+    }
+
+    @Override
+    public void warn(CharSequence charSequence) {
+        warn(charSequence, null);
+    }
+
+    @Override
+    public void warn(CharSequence charSequence, Throwable throwable) {
+        loggedMessages.add(Triple.of(LogLevel.WARN, charSequence, throwable));
+    }
+
+    @Override
+    public void warn(Throwable throwable) {
+        warn(null, throwable);
+    }
+
+    @Override
+    public boolean isErrorEnabled() {
+        return false;
+    }
+
+    @Override
+    public void error(CharSequence charSequence) {
+        error(charSequence, null);
+    }
+
+    @Override
+    public void error(CharSequence charSequence, Throwable throwable) {
+        loggedMessages.add(Triple.of(LogLevel.ERROR, charSequence, throwable));
+    }
+
+    @Override
+    public void error(Throwable throwable) {
+        error(null, throwable);
+    }
+
+    public enum LogLevel {
+        DEBUG,
+        INFO,
+        WARN,
+        ERROR
+    }
+}