diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependency.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependency.java index 0ff50885dee..f129f216ae6 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependency.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependency.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import lombok.EqualsAndHashCode; import lombok.Value; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import org.openrewrite.*; import org.openrewrite.gradle.marker.GradleDependencyConfiguration; @@ -36,9 +37,11 @@ import org.openrewrite.maven.MavenDownloadingException; import org.openrewrite.maven.tree.GroupArtifact; import org.openrewrite.maven.tree.GroupArtifactVersion; +import org.openrewrite.maven.tree.ResolvedDependency; import org.openrewrite.maven.tree.ResolvedGroupArtifactVersion; import org.openrewrite.semver.DependencyMatcher; import org.openrewrite.semver.Semver; +import org.openrewrite.semver.VersionComparator; import java.util.*; @@ -156,7 +159,10 @@ public Validated validate() { @Override public TreeVisitor getVisitor() { return Preconditions.check(new FindGradleProject(FindGradleProject.SearchCriteria.Marker).getVisitor(), new GroovyIsoVisitor() { - final DependencyMatcher depMatcher = requireNonNull(DependencyMatcher.build(oldGroupId + ":" + oldArtifactId).getValue()); + final DependencyMatcher oldDepMatcher = requireNonNull(DependencyMatcher.build(oldGroupId + ":" + oldArtifactId).getValue()); + final VersionComparator versionComparator = newVersion != null ? Semver.validate(newVersion, versionPattern).getValue() : null; + final DependencyMatcher newDepMatcher = new DependencyMatcher(newGroupId, newArtifactId, versionComparator); + boolean isNewDependencyPresent; GradleProject gradleProject; @@ -168,6 +174,7 @@ public G.CompilationUnit visitCompilationUnit(G.CompilationUnit cu, ExecutionCon } gradleProject = maybeGp.get(); + isNewDependencyPresent = checkForNewDependencyPresence(gradleProject, newDepMatcher); G.CompilationUnit g = super.visitCompilationUnit(cu, ctx); if (g != cu) { @@ -176,6 +183,20 @@ public G.CompilationUnit visitCompilationUnit(G.CompilationUnit cu, ExecutionCon return g; } + private boolean checkForNewDependencyPresence(GradleProject gp, DependencyMatcher dependencyMatcher) { + boolean isPresent = false; + Map nameToConfiguration = gp.getNameToConfiguration(); + for (GradleDependencyConfiguration gdc : nameToConfiguration.values()) { + List resolvedDependencies = gdc.getDirectResolved(); + isPresent = resolvedDependencies.stream() + .anyMatch(r -> dependencyMatcher.matches(r.getGroupId(), r.getArtifactId(), r.getVersion())); + if (isPresent) { + break; + } + } + return isPresent; + } + @Override public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { J.MethodInvocation m = super.visitMethodInvocation(method, ctx); @@ -198,13 +219,17 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu return m; } + @NullMarked private J.MethodInvocation updateDependency(J.MethodInvocation m, ExecutionContext ctx) { List depArgs = m.getArguments(); if (depArgs.get(0) instanceof J.Literal) { String gav = (String) ((J.Literal) depArgs.get(0)).getValue(); if (gav != null) { Dependency original = DependencyStringNotationConverter.parse(gav); - if (original != null && depMatcher.matches(original.getGroupId(), original.getArtifactId())) { + if (original != null && oldDepMatcher.matches(original.getGroupId(), original.getArtifactId())) { + if (isNewDependencyPresent) { + return null; + } Dependency updated = original; if (!StringUtils.isBlank(newGroupId) && !updated.getGroupId().equals(newGroupId)) { updated = updated.withGroupId(newGroupId); @@ -238,7 +263,10 @@ private J.MethodInvocation updateDependency(J.MethodInvocation m, ExecutionConte J.Literal literal = (J.Literal) strings.get(0); Dependency original = DependencyStringNotationConverter.parse((String) requireNonNull(literal.getValue())); - if (original != null && depMatcher.matches(original.getGroupId(), original.getArtifactId())) { + if (original != null && oldDepMatcher.matches(original.getGroupId(), original.getArtifactId())) { + if (isNewDependencyPresent) { + return null; + } Dependency updated = original; if (!StringUtils.isBlank(newGroupId) && !updated.getGroupId().equals(newGroupId)) { updated = updated.withGroupId(newGroupId); @@ -307,9 +335,12 @@ private J.MethodInvocation updateDependency(J.MethodInvocation m, ExecutionConte if (groupId == null || artifactId == null) { return m; } - if (!depMatcher.matches(groupId, artifactId)) { + if (!oldDepMatcher.matches(groupId, artifactId)) { return m; } + if (isNewDependencyPresent && oldDepMatcher.matches(groupId, artifactId)) { + return null; + } String updatedGroupId = groupId; if (!StringUtils.isBlank(newGroupId) && !updatedGroupId.equals(newGroupId)) { updatedGroupId = newGroupId; @@ -364,7 +395,7 @@ private GradleProject updateGradleModel(GradleProject gp) { for (GradleDependencyConfiguration gdc : nameToConfiguration.values()) { GradleDependencyConfiguration newGdc = gdc; newGdc = newGdc.withRequested(ListUtils.map(gdc.getRequested(), requested -> { - if (depMatcher.matches(requested.getGroupId(), requested.getArtifactId())) { + if (oldDepMatcher.matches(requested.getGroupId(), requested.getArtifactId())) { GroupArtifactVersion gav = requested.getGav(); if (newGroupId != null) { gav = gav.withGroupId(newGroupId); @@ -379,7 +410,7 @@ private GradleProject updateGradleModel(GradleProject gp) { return requested; })); newGdc = newGdc.withDirectResolved(ListUtils.map(gdc.getDirectResolved(), resolved -> { - if (depMatcher.matches(resolved.getGroupId(), resolved.getArtifactId())) { + if (oldDepMatcher.matches(resolved.getGroupId(), resolved.getArtifactId())) { ResolvedGroupArtifactVersion gav = resolved.getGav(); if (newGroupId != null) { gav = gav.withGroupId(newGroupId); diff --git a/rewrite-gradle/src/test/java/org/openrewrite/gradle/ChangeDependencyTest.java b/rewrite-gradle/src/test/java/org/openrewrite/gradle/ChangeDependencyTest.java index decf3758ce9..3e433f96c1f 100644 --- a/rewrite-gradle/src/test/java/org/openrewrite/gradle/ChangeDependencyTest.java +++ b/rewrite-gradle/src/test/java/org/openrewrite/gradle/ChangeDependencyTest.java @@ -67,6 +67,43 @@ void relocateDependency() { ); } + @Test + void removeOldDependenciesIfNewAlreadyPresents() { + rewriteRun( + spec -> spec.recipe(new ChangeDependency("commons-lang", "commons-lang", "org.apache.commons", "commons-lang3", "3.11.x", null, null)), + buildGradle( + """ + plugins { + id "java-library" + } + + repositories { + mavenCentral() + } + + dependencies { + implementation "commons-lang:commons-lang:2.6" + implementation group: "commons-lang", name: "commons-lang", version: "2.6" + implementation "org.apache.commons:commons-lang3:3.11" + } + """, + """ + plugins { + id "java-library" + } + + repositories { + mavenCentral() + } + + dependencies { + implementation "org.apache.commons:commons-lang3:3.11" + } + """ + ) + ); + } + @Test void changeGroupIdOnly() { rewriteRun(