From ecd15b074e7a3136fd086816cddb4ea5986ec304 Mon Sep 17 00:00:00 2001 From: Slawomir Jaranowski Date: Mon, 26 Feb 2024 00:30:59 +0100 Subject: [PATCH] Use new Enforcer Api --- versions-enforcer/pom.xml | 1 + .../enforcer/MaxDependencyUpdates.java | 127 ++++----- .../versions/enforcer/PluginLogWrapper.java | 109 +++++++ .../enforcer/MaxDependencyUpdatesTest.java | 269 ------------------ .../enforcer/MaxDependencyUpdatesTest.java | 258 +++++++++++++++++ .../mojo/versions/utils/MockUtils.java | 44 ++- 6 files changed, 454 insertions(+), 354 deletions(-) rename versions-enforcer/src/main/java/org/{apache/maven/plugins => codehaus/mojo/versions}/enforcer/MaxDependencyUpdates.java (78%) create mode 100644 versions-enforcer/src/main/java/org/codehaus/mojo/versions/enforcer/PluginLogWrapper.java delete mode 100644 versions-enforcer/src/test/java/org/apache/maven/plugins/enforcer/MaxDependencyUpdatesTest.java create mode 100644 versions-enforcer/src/test/java/org/codehaus/mojo/versions/enforcer/MaxDependencyUpdatesTest.java diff --git a/versions-enforcer/pom.xml b/versions-enforcer/pom.xml index c363b01bde..2bac0ac5c7 100644 --- a/versions-enforcer/pom.xml +++ b/versions-enforcer/pom.xml @@ -13,6 +13,7 @@ Enforcer rules using Versions Maven Plugin + ${maven-enforcer-plugin.version} diff --git a/versions-enforcer/src/main/java/org/apache/maven/plugins/enforcer/MaxDependencyUpdates.java b/versions-enforcer/src/main/java/org/codehaus/mojo/versions/enforcer/MaxDependencyUpdates.java similarity index 78% rename from versions-enforcer/src/main/java/org/apache/maven/plugins/enforcer/MaxDependencyUpdates.java rename to versions-enforcer/src/main/java/org/codehaus/mojo/versions/enforcer/MaxDependencyUpdates.java index 9ec90f8bc2..e851c34ddb 100644 --- a/versions-enforcer/src/main/java/org/apache/maven/plugins/enforcer/MaxDependencyUpdates.java +++ b/versions-enforcer/src/main/java/org/codehaus/mojo/versions/enforcer/MaxDependencyUpdates.java @@ -1,4 +1,4 @@ -package org.apache.maven.plugins.enforcer; +package org.codehaus.mojo.versions.enforcer; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,20 +18,21 @@ * under the License. */ +import javax.inject.Inject; +import javax.inject.Named; + import java.util.Arrays; -import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; import org.apache.maven.artifact.versioning.ArtifactVersion; -import org.apache.maven.enforcer.rule.api.EnforcerLevel; -import org.apache.maven.enforcer.rule.api.EnforcerRule; -import org.apache.maven.enforcer.rule.api.EnforcerRule2; +import org.apache.maven.enforcer.rule.api.AbstractEnforcerRule; +import org.apache.maven.enforcer.rule.api.EnforcerRuleError; import org.apache.maven.enforcer.rule.api.EnforcerRuleException; -import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Dependency; import org.apache.maven.plugin.MojoExecution; @@ -46,8 +47,6 @@ import org.codehaus.mojo.versions.api.VersionsHelper; import org.codehaus.mojo.versions.model.RuleSet; import org.codehaus.mojo.versions.utils.DependencyComparator; -import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException; -import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; @@ -62,7 +61,8 @@ import static org.codehaus.mojo.versions.utils.MavenProjectUtils.extractDependenciesFromPlugins; import static org.codehaus.mojo.versions.utils.MavenProjectUtils.extractPluginDependenciesFromPluginsInPluginManagement; -public class MaxDependencyUpdates implements EnforcerRule2 { +@Named("maxDependencyUpdates") +public class MaxDependencyUpdates extends AbstractEnforcerRule { /** * Maximum allowed number of updates. * @@ -232,7 +232,7 @@ public class MaxDependencyUpdates implements EnforcerRule2 { * version numbers. The URI could be either a Wagon URI or a classpath URI * (e.g. classpath:///package/sub/package/rules.xml). * - * 2.14.0 + * @since 2.14.0 */ private String rulesUri; @@ -254,81 +254,78 @@ public class MaxDependencyUpdates implements EnforcerRule2 { */ protected boolean allowSnapshots; - /** - * Retrieves the maven project from metadata - * @param ruleHelper EnforcerRuleHelper object - * @return maven project - */ - private static MavenProject getMavenProject(EnforcerRuleHelper ruleHelper) { - try { - return (MavenProject) ruleHelper.evaluate("${project}"); - } catch (ExpressionEvaluationException e) { - throw new RuntimeException("Cannot evaluate project metadata", e); - } + private final MavenProject project; + + private final RepositorySystem repositorySystem; + + private final org.eclipse.aether.RepositorySystem aetherRepositorySystem; + + private final Map wagonMap; + + private final MavenSession mavenSession; + + private final MojoExecution mojoExecution; + + @Inject + public MaxDependencyUpdates( + MavenProject project, + RepositorySystem repositorySystem, + org.eclipse.aether.RepositorySystem aetherRepositorySystem, + Map wagonMap, + MavenSession mavenSession, + MojoExecution mojoExecution) { + this.project = project; + this.repositorySystem = repositorySystem; + this.aetherRepositorySystem = aetherRepositorySystem; + this.wagonMap = wagonMap; + this.mavenSession = mavenSession; + this.mojoExecution = mojoExecution; } /** * Creates the VersionsHelper object - * @param ruleHelper EnforcerRuleHelper object * @return VersionsHelper object */ - @SuppressWarnings("unchecked") - private static VersionsHelper createVersionsHelper( - EnforcerRuleHelper ruleHelper, String serverId, String rulesUri, RuleSet ruleSet) { + private VersionsHelper createVersionsHelper(String serverId, String rulesUri, RuleSet ruleSet) + throws EnforcerRuleError { try { return new DefaultVersionsHelper.Builder() - .withRepositorySystem(ruleHelper.getComponent(RepositorySystem.class)) - .withAetherRepositorySystem(ruleHelper.getComponent(org.eclipse.aether.RepositorySystem.class)) - .withWagonMap(ruleHelper.getComponentMap(Wagon.class.getName()).entrySet().stream() - .filter(e -> e.getValue() instanceof Wagon) - .collect(HashMap::new, (m, e) -> m.put(e.getKey(), (Wagon) e.getValue()), HashMap::putAll)) + .withRepositorySystem(repositorySystem) + .withAetherRepositorySystem(aetherRepositorySystem) + .withWagonMap(wagonMap) .withServerId(serverId) .withRulesUri(rulesUri) .withRuleSet(ruleSet) .withIgnoredVersions(null) - .withLog(ruleHelper.getLog()) - .withMavenSession((MavenSession) ruleHelper.evaluate("${session}")) - .withMojoExecution((MojoExecution) ruleHelper.evaluate("${mojoExecution}")) + .withLog(new PluginLogWrapper(getLog())) + .withMavenSession(mavenSession) + .withMojoExecution(mojoExecution) .build(); - } catch (ExpressionEvaluationException e) { - throw new RuntimeException("Cannot evaluate project metadata", e); - } catch (ComponentLookupException | MojoExecutionException e) { - throw new RuntimeException("Cannot resolve dependency", e); + } catch (MojoExecutionException e) { + throw new EnforcerRuleError("Cannot resolve dependency", e); } } @Override - public boolean isCacheable() { - return false; - } - - @Override - public boolean isResultValid(EnforcerRule enforcerRule) { - return false; - } + public void execute() throws EnforcerRuleException { - @Override - public String getCacheId() { - return "Does not matter as not cacheable"; - } + PluginLogWrapper pluginLog = new PluginLogWrapper(getLog()); - @Override - public void execute(EnforcerRuleHelper ruleHelper) throws EnforcerRuleException { VersionsHelper versionsHelper = - createVersionsHelper(ruleHelper, serverId != null ? serverId : "serverId", rulesUri, ruleSet); - MavenProject project = getMavenProject(ruleHelper); + createVersionsHelper(serverId != null ? serverId : "serverId", rulesUri, ruleSet); + Set dependencies = new TreeSet<>(DependencyComparator.INSTANCE); if (processDependencyManagement) { try { dependencies.addAll(filterDependencies( extractDependenciesFromDependencyManagement( - project, processDependencyManagementTransitive, ruleHelper.getLog()), + project, processDependencyManagementTransitive, pluginLog), dependencyManagementIncludes, dependencyManagementExcludes, "Dependency Management", - ruleHelper.getLog())); + pluginLog)); } catch (VersionRetrievalException e) { - throw new EnforcerRuleException(e.getMessage()); + throw new EnforcerRuleError(e.getMessage()); } } if (processPluginDependencies) { @@ -337,7 +334,7 @@ public void execute(EnforcerRuleHelper ruleHelper) throws EnforcerRuleException pluginDependencyIncludes, pluginDependencyExcludes, "Plugin Dependencies", - ruleHelper.getLog())); + pluginLog)); } if (processPluginDependenciesInPluginManagement) { dependencies.addAll(filterDependencies( @@ -345,15 +342,11 @@ public void execute(EnforcerRuleHelper ruleHelper) throws EnforcerRuleException pluginManagementDependencyIncludes, pluginManagementDependencyExcludes, "Plugin Management Dependencies", - ruleHelper.getLog())); + pluginLog)); } if (processDependencies) { dependencies.addAll(filterDependencies( - project.getDependencies(), - dependencyIncludes, - dependencyExcludes, - "Dependencies", - ruleHelper.getLog())); + project.getDependencies(), dependencyIncludes, dependencyExcludes, "Dependencies", pluginLog)); } try { Optional ignoredSegment = ignoreSubIncrementalUpdates @@ -379,13 +372,7 @@ public void execute(EnforcerRuleHelper ruleHelper) throws EnforcerRuleException .collect(Collectors.joining(", "))); } } catch (VersionRetrievalException e) { - throw new RuntimeException(e.getMessage(), e); + throw new EnforcerRuleError(e); } } - - @Override - public EnforcerLevel getLevel() { - // all reported items should be treated as errors - return EnforcerLevel.ERROR; - } } diff --git a/versions-enforcer/src/main/java/org/codehaus/mojo/versions/enforcer/PluginLogWrapper.java b/versions-enforcer/src/main/java/org/codehaus/mojo/versions/enforcer/PluginLogWrapper.java new file mode 100644 index 0000000000..54ac62df3e --- /dev/null +++ b/versions-enforcer/src/main/java/org/codehaus/mojo/versions/enforcer/PluginLogWrapper.java @@ -0,0 +1,109 @@ +package org.codehaus.mojo.versions.enforcer; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +import org.apache.maven.enforcer.rule.api.EnforcerLogger; +import org.apache.maven.plugin.logging.Log; + +/** + * Wrapper used to pass {@link EnforcerLogger} as Maven plugin {@link Log}. + */ +class PluginLogWrapper implements Log { + + private final EnforcerLogger logger; + + PluginLogWrapper(EnforcerLogger logger) { + this.logger = logger; + } + + @Override + public boolean isDebugEnabled() { + return logger.isDebugEnabled(); + } + + @Override + public void debug(CharSequence charSequence) { + logger.debug(charSequence); + } + + @Override + public void debug(CharSequence charSequence, Throwable throwable) { + logger.debug(charSequence + throwableToString(throwable)); + } + + @Override + public void debug(Throwable throwable) { + logger.debug(throwableToString(throwable)); + } + + @Override + public boolean isInfoEnabled() { + return logger.isInfoEnabled(); + } + + @Override + public void info(CharSequence charSequence) { + logger.info(charSequence); + } + + @Override + public void info(CharSequence charSequence, Throwable throwable) { + + logger.info(charSequence + throwableToString(throwable)); + } + + @Override + public void info(Throwable throwable) { + logger.info(throwableToString(throwable)); + } + + @Override + public boolean isWarnEnabled() { + return logger.isWarnEnabled(); + } + + @Override + public void warn(CharSequence charSequence) { + logger.warn(charSequence); + } + + @Override + public void warn(CharSequence charSequence, Throwable throwable) { + logger.warn(charSequence + throwableToString(throwable)); + } + + @Override + public void warn(Throwable throwable) { + logger.warn(throwableToString(throwable)); + } + + @Override + public boolean isErrorEnabled() { + return logger.isErrorEnabled(); + } + + @Override + public void error(CharSequence charSequence) { + logger.error(charSequence); + } + + @Override + public void error(CharSequence charSequence, Throwable throwable) { + logger.error(charSequence + throwableToString(throwable)); + } + + @Override + public void error(Throwable throwable) { + logger.error(throwableToString(throwable)); + } + + private String throwableToString(Throwable throwable) { + if (throwable != null) { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + throwable.printStackTrace(new PrintStream(stream)); + return System.lineSeparator() + stream; + } + return ""; + } +} diff --git a/versions-enforcer/src/test/java/org/apache/maven/plugins/enforcer/MaxDependencyUpdatesTest.java b/versions-enforcer/src/test/java/org/apache/maven/plugins/enforcer/MaxDependencyUpdatesTest.java deleted file mode 100644 index 09ad456716..0000000000 --- a/versions-enforcer/src/test/java/org/apache/maven/plugins/enforcer/MaxDependencyUpdatesTest.java +++ /dev/null @@ -1,269 +0,0 @@ -package org.apache.maven.plugins.enforcer; -/* - * 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.util.HashMap; - -import org.apache.maven.enforcer.rule.api.EnforcerRuleException; -import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper; -import org.apache.maven.plugin.MojoExecution; -import org.apache.maven.project.MavenProject; -import org.apache.maven.repository.RepositorySystem; -import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException; -import org.codehaus.plexus.component.repository.exception.ComponentLookupException; -import org.junit.Test; -import org.mockito.ArgumentMatchers; - -import static java.util.Arrays.asList; -import static java.util.Collections.singletonList; -import static java.util.Collections.singletonMap; -import static org.codehaus.mojo.versions.utils.DependencyBuilder.dependencyWith; -import static org.codehaus.mojo.versions.utils.MockUtils.mockAetherRepositorySystem; -import static org.codehaus.mojo.versions.utils.MockUtils.mockMavenSession; -import static org.codehaus.mojo.versions.utils.MockUtils.mockRepositorySystem; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class MaxDependencyUpdatesTest { - private static EnforcerRuleHelper mockRuleHelper( - MavenProject mavenProject, org.eclipse.aether.RepositorySystem aetherRepositorySystem) - throws ExpressionEvaluationException, ComponentLookupException { - EnforcerRuleHelper ruleHelper = mock(EnforcerRuleHelper.class); - when(ruleHelper.evaluate(anyString())) - .then((a) -> "${project}".equals(a.getArgument(0)) - ? mavenProject - : "${session}".equals(a.getArgument(0)) - ? mockMavenSession() - : "${mojoExecution}".equals(a.getArgument(0)) ? mock(MojoExecution.class) : null); - when(ruleHelper.getComponent(ArgumentMatchers.>any())) - .then((a) -> a.getArgument(0) == RepositorySystem.class - ? mockRepositorySystem() - : a.getArgument(0) == org.eclipse.aether.RepositorySystem.class - ? aetherRepositorySystem - : null); - return ruleHelper; - } - - @Test - public void testRuleFailsByMaxUpdatesExceeded() throws ExpressionEvaluationException, ComponentLookupException { - EnforcerRuleHelper ruleHelper = mockRuleHelper( - new MavenProject() { - { - setDependencies(asList( - dependencyWith("group", "artifactA", "1.0.0"), - dependencyWith("group", "artifactB", "1.0.0"))); - } - }, - mockAetherRepositorySystem(new HashMap() { - { - put("artifactA", new String[] {"1.0.0", "2.0.0"}); - put("artifactB", new String[] {"1.0.0", "2.0.0"}); - } - })); - - try { - new MaxDependencyUpdates() { - { - maxUpdates = 1; - } - }.execute(ruleHelper); - - fail("EnforcerRuleException should have been thrown"); - } catch (EnforcerRuleException e) { - assertThat(e.getMessage(), containsString("More than 1 upgradable artifacts detected")); - } - } - - @Test - public void testRulePassesByMaxUpdatesNotExceeded() throws ExpressionEvaluationException, ComponentLookupException { - EnforcerRuleHelper ruleHelper = mockRuleHelper( - new MavenProject() { - { - setDependencies(singletonList(dependencyWith("group", "artifactA", "1.0.0"))); - } - }, - mockAetherRepositorySystem(singletonMap("artifactA", new String[] {"1.0.0", "2.0.0"}))); - - try { - new MaxDependencyUpdates() { - { - maxUpdates = 1; - } - }.execute(ruleHelper); - } catch (EnforcerRuleException e) { - fail("No EnforcerRuleException should have been thrown"); - } - } - - @Test - public void testRulePassesByMaxUpdatesNotExceededDependencyIncludes() - throws ExpressionEvaluationException, ComponentLookupException { - EnforcerRuleHelper ruleHelper = mockRuleHelper( - new MavenProject() { - { - setDependencies(asList( - dependencyWith("group", "artifactA", "1.0.0"), - dependencyWith("group", "artifactB", "1.0.0"))); - } - }, - mockAetherRepositorySystem(new HashMap() { - { - put("artifactA", new String[] {"1.0.0", "2.0.0"}); - put("artifactB", new String[] {"1.0.0"}); - } - })); - - try { - new MaxDependencyUpdates() { - { - dependencyIncludes = singletonList("group:artifactB"); - } - }.execute(ruleHelper); - } catch (EnforcerRuleException e) { - fail("No EnforcerRuleException should have been thrown"); - } - } - - @Test - public void testRulePassesByMaxUpdatesNotExceededDependencyExcludes() - throws ExpressionEvaluationException, ComponentLookupException { - EnforcerRuleHelper ruleHelper = mockRuleHelper( - new MavenProject() { - { - setDependencies(asList( - dependencyWith("group", "artifactA", "1.0.0"), - dependencyWith("group", "artifactB", "1.0.0"))); - } - }, - mockAetherRepositorySystem(new HashMap() { - { - put("artifactA", new String[] {"1.0.0", "2.0.0"}); - put("artifactB", new String[] {"1.0.0"}); - } - })); - - try { - new MaxDependencyUpdates() { - { - dependencyExcludes = singletonList("group:artifactA"); - } - }.execute(ruleHelper); - } catch (EnforcerRuleException e) { - fail("No EnforcerRuleException should have been thrown"); - } - } - - @Test - public void testRulePassesByMaxUpdatesNotExceededDependencyIncludesExcludes() - throws ExpressionEvaluationException, ComponentLookupException { - EnforcerRuleHelper ruleHelper = mockRuleHelper( - new MavenProject() { - { - setDependencies(asList( - dependencyWith("group", "artifactA", "1.0.0"), - dependencyWith("group", "artifactB", "1.0.0"))); - } - }, - mockAetherRepositorySystem(new HashMap() { - { - put("artifactA", new String[] {"1.0.0", "2.0.0"}); - put("artifactB", new String[] {"1.0.0"}); - } - })); - - try { - new MaxDependencyUpdates() { - { - dependencyIncludes = singletonList("group:*"); - dependencyExcludes = singletonList("group:artifactA"); - } - }.execute(ruleHelper); - } catch (EnforcerRuleException e) { - fail("No EnforcerRuleException should have been thrown"); - } - } - - @Test - public void testIgnoreSubIncrementalUpdates() throws ExpressionEvaluationException, ComponentLookupException { - EnforcerRuleHelper ruleHelper = mockRuleHelper( - new MavenProject() { - { - setDependencies(singletonList(dependencyWith("group", "artifactA", "1.0.0"))); - } - }, - mockAetherRepositorySystem(singletonMap("artifactA", new String[] {"1.0.0", "1.0.0-1"}))); - - try { - new MaxDependencyUpdates() { - { - ignoreSubIncrementalUpdates = true; - } - }.execute(ruleHelper); - } catch (EnforcerRuleException e) { - fail("No EnforcerRuleException should have been thrown"); - } - } - - @Test - public void testIgnoreIncrementalUpdates() throws ExpressionEvaluationException, ComponentLookupException { - EnforcerRuleHelper ruleHelper = mockRuleHelper( - new MavenProject() { - { - setDependencies(singletonList(dependencyWith("group", "artifactA", "1.0.0"))); - } - }, - mockAetherRepositorySystem(singletonMap("artifactA", new String[] {"1.0.0", "1.0.0-1", "1.0.1"}))); - - try { - new MaxDependencyUpdates() { - { - ignoreIncrementalUpdates = true; - } - }.execute(ruleHelper); - } catch (EnforcerRuleException e) { - fail("No EnforcerRuleException should have been thrown"); - } - } - - @Test - public void testIgnoreMinorUpdates() throws ExpressionEvaluationException, ComponentLookupException { - EnforcerRuleHelper ruleHelper = mockRuleHelper( - new MavenProject() { - { - setDependencies(asList(dependencyWith("group", "artifactA", "1.0.0"))); - } - }, - mockAetherRepositorySystem( - singletonMap("artifactA", new String[] {"1.0.0", "1.0.0-1", "1.0.1", "1.1.0"}))); - - try { - new MaxDependencyUpdates() { - { - ignoreMinorUpdates = true; - } - }.execute(ruleHelper); - } catch (EnforcerRuleException e) { - fail("No EnforcerRuleException should have been thrown"); - } - } -} diff --git a/versions-enforcer/src/test/java/org/codehaus/mojo/versions/enforcer/MaxDependencyUpdatesTest.java b/versions-enforcer/src/test/java/org/codehaus/mojo/versions/enforcer/MaxDependencyUpdatesTest.java new file mode 100644 index 0000000000..d7219d2cd4 --- /dev/null +++ b/versions-enforcer/src/test/java/org/codehaus/mojo/versions/enforcer/MaxDependencyUpdatesTest.java @@ -0,0 +1,258 @@ +package org.codehaus.mojo.versions.enforcer; +/* + * 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.util.HashMap; + +import org.apache.maven.enforcer.rule.api.EnforcerLogger; +import org.apache.maven.enforcer.rule.api.EnforcerRuleException; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.project.MavenProject; +import org.apache.maven.repository.RepositorySystem; +import org.codehaus.mojo.versions.utils.DependencyBuilder; +import org.codehaus.mojo.versions.utils.MockUtils; +import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException; +import org.codehaus.plexus.component.repository.exception.ComponentLookupException; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class MaxDependencyUpdatesTest { + + @Mock + private EnforcerLogger enforcerLogger; + + @Mock + private MavenProject project; + + @Mock + private MavenSession mavenSession; + + @Mock + private RepositorySystem repositorySystem; + + @Mock + private org.eclipse.aether.RepositorySystem aetherRepositorySystem; + + @InjectMocks + private MaxDependencyUpdates maxDependencyUpdates; + + @Before + public void setup() { + maxDependencyUpdates.setLog(enforcerLogger); + MockUtils.prepareRepositorySystemMock(repositorySystem); + } + + @Test + public void testRuleFailsByMaxUpdatesExceeded() throws ExpressionEvaluationException, ComponentLookupException { + when(project.getDependencies()) + .thenReturn(asList( + DependencyBuilder.newBuilder() + .withGroupId("group") + .withArtifactId("artifactA") + .withVersion("1.0.0") + .build(), + DependencyBuilder.newBuilder() + .withGroupId("group") + .withArtifactId("artifactB") + .withVersion("1.0.0") + .build())); + + MockUtils.prepareAetherRepositorySystemMockForVersionRange( + aetherRepositorySystem, new HashMap() { + { + put("artifactA", new String[] {"1.0.0", "2.0.0"}); + put("artifactB", new String[] {"1.0.0", "2.0.0"}); + } + }); + + try { + maxDependencyUpdates.maxUpdates = 1; + maxDependencyUpdates.execute(); + + fail("EnforcerRuleException should have been thrown"); + } catch (EnforcerRuleException e) { + assertThat(e.getMessage(), containsString("More than 1 upgradable artifacts detected")); + } + } + + @Test + public void testRulePassesByMaxUpdatesNotExceeded() throws Exception { + + when(project.getDependencies()) + .thenReturn(singletonList(DependencyBuilder.newBuilder() + .withGroupId("group") + .withArtifactId("artifactA") + .withVersion("1.0.0") + .build())); + + MockUtils.prepareAetherRepositorySystemMockForVersionRange( + aetherRepositorySystem, singletonMap("artifactA", new String[] {"1.0.0", "2.0.0"})); + + maxDependencyUpdates.maxUpdates = 1; + maxDependencyUpdates.execute(); + } + + @Test + public void testRulePassesByMaxUpdatesNotExceededDependencyIncludes() throws Exception { + + when(project.getDependencies()) + .thenReturn(asList( + DependencyBuilder.newBuilder() + .withGroupId("group") + .withArtifactId("artifactA") + .withVersion("1.0.0") + .build(), + DependencyBuilder.newBuilder() + .withGroupId("group") + .withArtifactId("artifactB") + .withVersion("1.0.0") + .build())); + + MockUtils.prepareAetherRepositorySystemMockForVersionRange( + aetherRepositorySystem, new HashMap() { + { + put("artifactA", new String[] {"1.0.0", "2.0.0"}); + put("artifactB", new String[] {"1.0.0"}); + } + }); + + maxDependencyUpdates.dependencyIncludes = singletonList("group:artifactB"); + maxDependencyUpdates.execute(); + } + + @Test + public void testRulePassesByMaxUpdatesNotExceededDependencyExcludes() throws Exception { + + when(project.getDependencies()) + .thenReturn(asList( + DependencyBuilder.newBuilder() + .withGroupId("group") + .withArtifactId("artifactA") + .withVersion("1.0.0") + .build(), + DependencyBuilder.newBuilder() + .withGroupId("group") + .withArtifactId("artifactB") + .withVersion("1.0.0") + .build())); + + MockUtils.prepareAetherRepositorySystemMockForVersionRange( + aetherRepositorySystem, new HashMap() { + { + put("artifactA", new String[] {"1.0.0", "2.0.0"}); + put("artifactB", new String[] {"1.0.0"}); + } + }); + + maxDependencyUpdates.dependencyExcludes = singletonList("group:artifactA"); + maxDependencyUpdates.execute(); + } + + @Test + public void testRulePassesByMaxUpdatesNotExceededDependencyIncludesExcludes() throws Exception { + + when(project.getDependencies()) + .thenReturn(asList( + DependencyBuilder.newBuilder() + .withGroupId("group") + .withArtifactId("artifactA") + .withVersion("1.0.0") + .build(), + DependencyBuilder.newBuilder() + .withGroupId("group") + .withArtifactId("artifactB") + .withVersion("1.0.0") + .build())); + + MockUtils.prepareAetherRepositorySystemMockForVersionRange( + aetherRepositorySystem, new HashMap() { + { + put("artifactA", new String[] {"1.0.0", "2.0.0"}); + put("artifactB", new String[] {"1.0.0"}); + } + }); + + maxDependencyUpdates.dependencyIncludes = singletonList("group:*"); + maxDependencyUpdates.dependencyExcludes = singletonList("group:artifactA"); + maxDependencyUpdates.execute(); + } + + @Test + public void testIgnoreSubIncrementalUpdates() throws Exception { + + when(project.getDependencies()) + .thenReturn(singletonList(DependencyBuilder.newBuilder() + .withGroupId("group") + .withArtifactId("artifactA") + .withVersion("1.0.0") + .build())); + + MockUtils.prepareAetherRepositorySystemMockForVersionRange( + aetherRepositorySystem, singletonMap("artifactA", new String[] {"1.0.0", "1.0.0-1"})); + + maxDependencyUpdates.ignoreSubIncrementalUpdates = true; + maxDependencyUpdates.execute(); + } + + @Test + public void testIgnoreIncrementalUpdates() throws Exception { + when(project.getDependencies()) + .thenReturn(singletonList(DependencyBuilder.newBuilder() + .withGroupId("group") + .withArtifactId("artifactA") + .withVersion("1.0.0") + .build())); + + MockUtils.prepareAetherRepositorySystemMockForVersionRange( + aetherRepositorySystem, singletonMap("artifactA", new String[] {"1.0.0", "1.0.0-1", "1.0.1"})); + + maxDependencyUpdates.ignoreIncrementalUpdates = true; + maxDependencyUpdates.execute(); + } + + @Test + public void testIgnoreMinorUpdates() throws Exception { + + when(project.getDependencies()) + .thenReturn(singletonList(DependencyBuilder.newBuilder() + .withGroupId("group") + .withArtifactId("artifactA") + .withVersion("1.0.0") + .build())); + + MockUtils.prepareAetherRepositorySystemMockForVersionRange( + aetherRepositorySystem, singletonMap("artifactA", new String[] {"1.0.0", "1.0.0-1", "1.0.1", "1.1.0"})); + + maxDependencyUpdates.ignoreMinorUpdates = true; + maxDependencyUpdates.execute(); + } +} diff --git a/versions-test/src/main/java/org/codehaus/mojo/versions/utils/MockUtils.java b/versions-test/src/main/java/org/codehaus/mojo/versions/utils/MockUtils.java index e08b9322ab..aea5a1d439 100644 --- a/versions-test/src/main/java/org/codehaus/mojo/versions/utils/MockUtils.java +++ b/versions-test/src/main/java/org/codehaus/mojo/versions/utils/MockUtils.java @@ -74,20 +74,9 @@ public static org.eclipse.aether.RepositorySystem mockAetherRepositorySystem() { */ public static org.eclipse.aether.RepositorySystem mockAetherRepositorySystem(Map versionMap) { org.eclipse.aether.RepositorySystem repositorySystem = mock(org.eclipse.aether.RepositorySystem.class); + prepareAetherRepositorySystemMockForVersionRange(repositorySystem, versionMap); + try { - when(repositorySystem.resolveVersionRange(any(), any(VersionRangeRequest.class))) - .then(invocation -> { - VersionRangeRequest request = invocation.getArgument(1); - return versionMap.entrySet().stream() - .filter(e -> - e.getKey().equals(request.getArtifact().getArtifactId())) - .findAny() - .map(e -> Arrays.stream(e.getValue()) - .map(VersionStub::new) - .collect(() -> new ArrayList(), ArrayList::add, ArrayList::addAll)) - .map(versions -> new VersionRangeResult(request).setVersions(versions)) - .orElse(null); // should tell us if we haven't populated all cases in the test - }); when(repositorySystem.resolveArtifact(any(RepositorySystemSession.class), any(ArtifactRequest.class))) .then(invocation -> { ArtifactRequest request = invocation.getArgument(1); @@ -101,13 +90,34 @@ public static org.eclipse.aether.RepositorySystem mockAetherRepositorySystem(Map copiedArtifact.setFile(mock(File.class)); return new ArtifactResult(request).setArtifact(copiedArtifact); }); - } catch (VersionRangeResolutionException | ArtifactResolutionException e) { + } catch (ArtifactResolutionException e) { throw new RuntimeException(e); } return repositorySystem; } + public static void prepareAetherRepositorySystemMockForVersionRange( + org.eclipse.aether.RepositorySystem repositorySystem, Map versionMap) { + try { + when(repositorySystem.resolveVersionRange(any(), any(VersionRangeRequest.class))) + .then(invocation -> { + VersionRangeRequest request = invocation.getArgument(1); + return versionMap.entrySet().stream() + .filter(e -> + e.getKey().equals(request.getArtifact().getArtifactId())) + .findAny() + .map(e -> Arrays.stream(e.getValue()) + .map(VersionStub::new) + .collect(() -> new ArrayList(), ArrayList::add, ArrayList::addAll)) + .map(versions -> new VersionRangeResult(request).setVersions(versions)) + .orElse(null); // should tell us if we haven't populated all cases in the test + }); + } catch (VersionRangeResolutionException e) { + throw new RuntimeException(e); + } + } + public static I18N mockI18N() { I18N i18n = mock(I18N.class); when(i18n.getString(anyString(), any(), anyString())).thenAnswer(invocation -> invocation.getArgument(2)); @@ -128,6 +138,11 @@ public static SiteTool mockSiteTool() { public static RepositorySystem mockRepositorySystem() { RepositorySystem repositorySystem = mock(RepositorySystem.class); + prepareRepositorySystemMock(repositorySystem); + return repositorySystem; + } + + public static void prepareRepositorySystemMock(RepositorySystem repositorySystem) { when(repositorySystem.createDependencyArtifact(any(Dependency.class))).thenAnswer(invocation -> { Dependency dependency = invocation.getArgument(0); return new DefaultArtifact( @@ -139,7 +154,6 @@ public static RepositorySystem mockRepositorySystem() { dependency.getClassifier(), new DefaultArtifactHandlerStub("default")); }); - return repositorySystem; } /**