Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -182,6 +185,10 @@ public String getInstanceNameSuffix() {
public static class Scanned {
boolean usingType;
List<SourceFile> 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<ResolvedGroupArtifactVersion, Set<GroupArtifact>> reactorRootTransitives = new HashMap<>();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -169,14 +171,65 @@ public AddManagedDependency.Scanned getInitialValue(ExecutionContext ctx) {

@Override
public TreeVisitor<?, ExecutionContext> getScanner(AddManagedDependency.Scanned acc) {
return addManagedDependency().getScanner(acc);
TreeVisitor<?, ExecutionContext> 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<ExecutionContext>() {
@Override
public Xml.Document visitDocument(Xml.Document document, ExecutionContext ctx) {
addManagedDependencyScanner.visit(document, ctx);
MavenResolutionResult mrr = getResolutionResult();
Set<ResolvedDependency> 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<GroupArtifact> coords = acc.reactorRootTransitives.computeIfAbsent(rootGav, k -> new LinkedHashSet<>());
for (ResolvedDependency dep : matchingDependencies) {
coords.add(new GroupArtifact(dep.getGroupId(), dep.getArtifactId()));
}
return document;
}
};
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor(AddManagedDependency.Scanned acc) {
return new MavenIsoVisitor<ExecutionContext>() {
@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<GroupArtifact> 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<ResolvedDependency> matchingDependencies = getResolutionResult().findDependencies(groupId, artifactId, null)
.stream()
.filter(ResolvedDependency::isTransitive)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
"""
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>child</module>
</modules>
</project>
""",
"""
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>child</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.12.5</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
"""
),
mavenProject("child",
pomXml(
"""
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>child</artifactId>
<dependencies>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-java</artifactId>
<version>7.0.0</version>
</dependency>
</dependencies>
</project>
"""
)
)
)
);
}
}