From 1af04db192365f97442a1ae9fb3a118749b9c762 Mon Sep 17 00:00:00 2001 From: Steve Elliott Date: Thu, 23 Jul 2026 15:15:49 -0400 Subject: [PATCH] Route addToRootPom=true pins to the reactor root in UpgradeTransitiveDependencyVersion Previously addToRootPom=true dropped every pin in a multi-module reactor when the transitive was held only by a child module. Two things combined to hide the write: UpgradeTransitiveDependencyVersion bailed at the reactor root because the root itself has no matching transitive of its own, and AddManagedDependency's write gate refused to write on the child because the child was not in the rootPoms set. Give UpgradeTransitiveDependencyVersion a real scanner: for every pom that holds a matching transitive, walk up parentPomIsProjectPom to find the reactor root's GAV and record the coordinate against it in AddManagedDependency.Scanned. In the visitor phase, when addToRootPom=true, fire only on reactor roots and pin every coordinate the scanner collected against that root. Non-root behavior stays identical for addToRootPom=null/false. --- .../maven/AddManagedDependency.java | 7 ++ .../UpgradeTransitiveDependencyVersion.java | 55 ++++++++++++++- ...pgradeTransitiveDependencyVersionTest.java | 67 +++++++++++++++++++ 3 files changed, 128 insertions(+), 1 deletion(-) diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/AddManagedDependency.java b/rewrite-maven/src/main/java/org/openrewrite/maven/AddManagedDependency.java index 8cef451465d..d54da62f958 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/AddManagedDependency.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/AddManagedDependency.java @@ -29,8 +29,11 @@ import org.openrewrite.xml.tree.Xml; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.Set; import static java.util.Objects.requireNonNull; @@ -182,6 +185,10 @@ public String getInstanceNameSuffix() { public static class Scanned { boolean usingType; List rootPoms = new ArrayList<>(); + // Populated by callers (e.g. UpgradeTransitiveDependencyVersion.getScanner) when + // addToRootPom=true and a transitive was found in a non-root pom under a reactor root. + // Keyed by the reactor root's GAV; values are the coordinates the writer should pin there. + Map> reactorRootTransitives = new HashMap<>(); } @Override diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/UpgradeTransitiveDependencyVersion.java b/rewrite-maven/src/main/java/org/openrewrite/maven/UpgradeTransitiveDependencyVersion.java index 38ecc660061..caf39b2ff1e 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/UpgradeTransitiveDependencyVersion.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/UpgradeTransitiveDependencyVersion.java @@ -21,8 +21,10 @@ import org.jspecify.annotations.Nullable; import org.openrewrite.*; import org.openrewrite.maven.table.MavenMetadataFailures; +import org.openrewrite.maven.tree.GroupArtifact; import org.openrewrite.maven.tree.MavenResolutionResult; import org.openrewrite.maven.tree.ResolvedDependency; +import org.openrewrite.maven.tree.ResolvedGroupArtifactVersion; import org.openrewrite.semver.Semver; import org.openrewrite.xml.tree.Xml; @@ -169,7 +171,37 @@ public AddManagedDependency.Scanned getInitialValue(ExecutionContext ctx) { @Override public TreeVisitor getScanner(AddManagedDependency.Scanned acc) { - return addManagedDependency().getScanner(acc); + TreeVisitor addManagedDependencyScanner = addManagedDependency().getScanner(acc); + if (!Boolean.TRUE.equals(addToRootPom)) { + return addManagedDependencyScanner; + } + // When adding to the reactor root, record for each root the coordinates any pom under it + // holds transitively. The visitor phase reads this map to write the pins in one place + // instead of the pom that happens to hold each transitive. + return new MavenIsoVisitor() { + @Override + public Xml.Document visitDocument(Xml.Document document, ExecutionContext ctx) { + addManagedDependencyScanner.visit(document, ctx); + MavenResolutionResult mrr = getResolutionResult(); + Set matchingDependencies = mrr.findDependencies(groupId, artifactId, null) + .stream() + .filter(ResolvedDependency::isTransitive) + .collect(toCollection(LinkedHashSet::new)); + if (matchingDependencies.isEmpty()) { + return document; + } + MavenResolutionResult current = mrr; + while (current.parentPomIsProjectPom()) { + current = current.getParent(); + } + ResolvedGroupArtifactVersion rootGav = current.getPom().getGav(); + Set coords = acc.reactorRootTransitives.computeIfAbsent(rootGav, k -> new LinkedHashSet<>()); + for (ResolvedDependency dep : matchingDependencies) { + coords.add(new GroupArtifact(dep.getGroupId(), dep.getArtifactId())); + } + return document; + } + }; } @Override @@ -177,6 +209,27 @@ public TreeVisitor getVisitor(AddManagedDependency.Scanned return new MavenIsoVisitor() { @Override public Xml.Document visitDocument(Xml.Document document, ExecutionContext ctx) { + if (Boolean.TRUE.equals(addToRootPom)) { + // Only fire on the reactor root; write every coordinate recorded against it by + // the scanner. Skip non-root poms even if they hold the transitive - the point + // of addToRootPom is to centralize the pin. + MavenResolutionResult mrr = getResolutionResult(); + if (mrr.parentPomIsProjectPom()) { + return document; + } + Set coords = acc.reactorRootTransitives.get(mrr.getPom().getGav()); + if (coords == null || coords.isEmpty()) { + return document; + } + Xml.Document d = document; + for (GroupArtifact coord : coords) { + d = (Xml.Document) addManagedDependency(coord.getGroupId(), coord.getArtifactId()) + .getVisitor(acc) + .visitNonNull(d, ctx); + } + return d; + } + Set matchingDependencies = getResolutionResult().findDependencies(groupId, artifactId, null) .stream() .filter(ResolvedDependency::isTransitive) diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/UpgradeTransitiveDependencyVersionTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/UpgradeTransitiveDependencyVersionTest.java index e07e648ff0b..8b2c8dcb91b 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/UpgradeTransitiveDependencyVersionTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/UpgradeTransitiveDependencyVersionTest.java @@ -381,4 +381,71 @@ void doesNotAddManagedDependencyToChildModuleWhenInheritedFromParent() { ) ); } + + @Test + void addsManagedDependencyToReactorRootWhenAddToRootPomAndOnlyChildHoldsTheTransitive() { + rewriteRun( + spec -> spec.recipe(new UpgradeTransitiveDependencyVersion( + "com.fasterxml*", "jackson-core", "2.12.5", null, null, null, null, null, null, true, null)), + mavenProject("parent", + pomXml( + """ + + 4.0.0 + com.example + parent + 1.0.0 + pom + + child + + + """, + """ + + 4.0.0 + com.example + parent + 1.0.0 + pom + + child + + + + + com.fasterxml.jackson.core + jackson-core + 2.12.5 + + + + + """ + ), + mavenProject("child", + pomXml( + """ + + 4.0.0 + + com.example + parent + 1.0.0 + + child + + + org.openrewrite + rewrite-java + 7.0.0 + + + + """ + ) + ) + ) + ); + } }