diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategy.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategy.java index 3b0dfa65381e..9a3a7f86c133 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategy.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategy.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.apache.maven.api.RemoteRepository; import org.apache.maven.api.Session; @@ -100,6 +101,12 @@ public class PluginUpgradeStrategy extends AbstractUpgradeStrategy { "3.0.0", MAVEN_4_COMPATIBILITY_REASON)); + private static final List PLUGIN_DEPENDENCY_UPGRADES = List.of(new PluginUpgrade( + "org.codehaus.mojo", + "extra-enforcer-rules", + "1.4", + "Versions before 1.4 use a removed DependencyGraphBuilder API incompatible with Maven 4")); + private Session session; @Inject @@ -281,6 +288,8 @@ private boolean upgradePluginsInSection( } } } + + hasUpgrades |= upgradePluginDependencies(pluginElement, namespace, pomDocument, sectionName, context); } return hasUpgrades; @@ -373,6 +382,57 @@ private boolean upgradePropertyVersion( return false; } + /** + * Upgrades plugin dependencies (e.g., extra-enforcer-rules inside maven-enforcer-plugin). + */ + private boolean upgradePluginDependencies( + Element pluginElement, + Namespace namespace, + Document pomDocument, + String sectionName, + UpgradeContext context) { + Element dependenciesElement = pluginElement.getChild("dependencies", namespace); + if (dependenciesElement == null) { + return false; + } + + Map depUpgrades = getPluginDependencyUpgradesMap(); + boolean hasUpgrades = false; + + List depElements = dependenciesElement.getChildren("dependency", namespace); + for (Element depElement : depElements) { + String groupId = getChildText(depElement, GROUP_ID, namespace); + String artifactId = getChildText(depElement, ARTIFACT_ID, namespace); + + if (groupId != null && artifactId != null) { + String depKey = groupId + ":" + artifactId; + PluginUpgradeInfo upgrade = depUpgrades.get(depKey); + + if (upgrade != null) { + if (upgradePluginVersion( + depElement, + namespace, + upgrade, + pomDocument, + sectionName + "/plugin/dependencies", + context)) { + hasUpgrades = true; + } + } + } + } + + return hasUpgrades; + } + + private Map getPluginDependencyUpgradesMap() { + return PLUGIN_DEPENDENCY_UPGRADES.stream() + .collect(Collectors.toMap( + upgrade -> upgrade.groupId() + ":" + upgrade.artifactId(), + upgrade -> + new PluginUpgradeInfo(upgrade.groupId(), upgrade.artifactId(), upgrade.minVersion()))); + } + /** * Simple version comparison to check if current version is below minimum version. * This is a basic implementation that works for most Maven plugin versions. diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategyTest.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategyTest.java index ada85cdf0e67..4b891b8baf54 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategyTest.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategyTest.java @@ -428,6 +428,93 @@ void shouldNotUpgradeWhenPropertyNotFound() throws Exception { } } + @Nested + @DisplayName("Plugin Dependency Upgrades") + class PluginDependencyUpgradeTests { + + @Test + @DisplayName("should upgrade extra-enforcer-rules dependency when below minimum") + void shouldUpgradeExtraEnforcerRulesDependency() throws Exception { + String pomXml = """ + + + 4.0.0 + test + test + 1.0.0 + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.5.0 + + + org.codehaus.mojo + extra-enforcer-rules + 1.0-beta-4 + + + + + + + """; + + Document document = saxBuilder.build(new StringReader(pomXml)); + Map pomMap = Map.of(Paths.get("pom.xml"), document); + + UpgradeContext context = createMockContext(); + UpgradeResult result = strategy.doApply(context, pomMap); + + assertTrue(result.success(), "Plugin dependency upgrade should succeed"); + assertTrue(result.modifiedCount() > 0, "Should have upgraded extra-enforcer-rules"); + + String xml = new XMLOutputter().outputString(document); + assertTrue(xml.contains("1.4"), "extra-enforcer-rules should be upgraded to 1.4"); + assertFalse(xml.contains("1.0-beta-4"), "Old version should be gone"); + } + + @Test + @DisplayName("should not upgrade extra-enforcer-rules when version is already sufficient") + void shouldNotUpgradeExtraEnforcerRulesWhenSufficient() throws Exception { + String pomXml = """ + + + 4.0.0 + test + test + 1.0.0 + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.5.0 + + + org.codehaus.mojo + extra-enforcer-rules + 1.8.0 + + + + + + + """; + + Document document = saxBuilder.build(new StringReader(pomXml)); + Map pomMap = Map.of(Paths.get("pom.xml"), document); + + UpgradeContext context = createMockContext(); + strategy.doApply(context, pomMap); + + String xml = new XMLOutputter().outputString(document); + assertTrue(xml.contains("1.8.0"), "Version 1.8.0 should be preserved"); + } + } + @Nested @DisplayName("Plugin Management") class PluginManagementTests {