diff --git a/src/main/java/org/openrewrite/java/dependencies/RelocatedDependencyCheck.java b/src/main/java/org/openrewrite/java/dependencies/RelocatedDependencyCheck.java index 528b1d7..d1ca175 100644 --- a/src/main/java/org/openrewrite/java/dependencies/RelocatedDependencyCheck.java +++ b/src/main/java/org/openrewrite/java/dependencies/RelocatedDependencyCheck.java @@ -25,6 +25,7 @@ import org.openrewrite.internal.lang.Nullable; import org.openrewrite.java.MethodMatcher; import org.openrewrite.java.dependencies.oldgroupids.Migration; +import org.openrewrite.java.dependencies.table.RelocatedDependencyReport; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; import org.openrewrite.marker.SearchResult; @@ -40,6 +41,8 @@ import java.util.Optional; public class RelocatedDependencyCheck extends ScanningRecipe { + transient RelocatedDependencyReport report = new RelocatedDependencyReport(this); + @Override public String getDisplayName() { return "Find relocated dependencies"; @@ -50,7 +53,8 @@ public String getDescription() { //language=markdown return "Find Maven and Gradle dependencies and Maven plugins that have relocated to a new `groupId` or `artifactId`. " + "Relocation information comes from the [oga-maven-plugin](https://github.com/jonathanlermitage/oga-maven-plugin/) " + - "maintained by Jonathan Lermitage, Filipe Roque and others."; + "maintained by Jonathan Lermitage, Filipe Roque and others. " + + "This recipe makes no changes to any source file."; } @Value @@ -129,32 +133,32 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu Expression firstMethodArgument = methodArguments.get(0); if (firstMethodArgument instanceof J.Literal) { J.Literal literal = (J.Literal) firstMethodArgument; - mi = searchInLiteral(literal, mi); + mi = searchInLiteral(literal, mi, ctx); } else if (firstMethodArgument instanceof G.GString) { G.GString gString = (G.GString) firstMethodArgument; List strings = gString.getStrings(); if (!strings.isEmpty() && strings.get(0) instanceof J.Literal) { - mi = searchInLiteral((J.Literal) strings.get(0), mi); + mi = searchInLiteral((J.Literal) strings.get(0), mi, ctx); } } else if (firstMethodArgument instanceof G.MapEntry) { - mi = searchInGMapEntry(methodArguments, mi); + mi = searchInGMapEntry(methodArguments, mi, ctx); } } return mi; } - private J.MethodInvocation searchInLiteral(J.Literal literal, J.MethodInvocation mi) { + private J.MethodInvocation searchInLiteral(J.Literal literal, J.MethodInvocation mi, ExecutionContext ctx) { String gav = (String) literal.getValue(); assert gav != null; String[] parts = gav.split(":"); if (gav.length() >= 2) { - mi = maybeAddComment(acc, mi, parts[0], parts[1]); + mi = maybeAddComment(acc, mi, parts[0], parts[1], ctx); } return mi; } - private J.MethodInvocation searchInGMapEntry(List methodArguments, J.MethodInvocation mi) { + private J.MethodInvocation searchInGMapEntry(List methodArguments, J.MethodInvocation mi, ExecutionContext ctx) { String groupId = null; String artifactId = null; for (Expression e : methodArguments) { @@ -197,7 +201,7 @@ private J.MethodInvocation searchInGMapEntry(List methodArguments, J } } if (groupId != null) { - mi = maybeAddComment(acc, mi, groupId, artifactId); + mi = maybeAddComment(acc, mi, groupId, artifactId, ctx); } return mi; } @@ -205,7 +209,7 @@ private J.MethodInvocation searchInGMapEntry(List methodArguments, J }; } - private static TreeVisitor mavenVisitor(Accumulator acc) { + private TreeVisitor mavenVisitor(Accumulator acc) { final XPathMatcher dependencyMatcher = new XPathMatcher("//dependencies/dependency"); return new MavenIsoVisitor() { @Override @@ -217,13 +221,13 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) { if (optionalGroupId.isPresent()) { String groupId = optionalGroupId.get(); String artifactId = optionalArtifactId.orElse(null); - tag = maybeAddComment(acc, tag, groupId, artifactId); + tag = maybeAddComment(acc, tag, groupId, artifactId, ctx); } } else if (isPluginTag()) { if (optionalArtifactId.isPresent()) { String groupId = tag.getChildValue("groupId").orElse("org.apache.maven.plugins"); String artifactId = optionalArtifactId.get(); - tag = maybeAddComment(acc, tag, groupId, artifactId); + tag = maybeAddComment(acc, tag, groupId, artifactId, ctx); } } return tag; @@ -232,20 +236,27 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) { }; } - private static T maybeAddComment(Accumulator acc, T tree, String groupId, @Nullable String artifactId) { + private T maybeAddComment(Accumulator acc, T tree, String groupId, @Nullable String artifactId, ExecutionContext ctx) { Relocation relocation = acc.getMigrations().get(new GroupArtifact(groupId, artifactId)); if (relocation != null) { + GroupArtifact relocatedGA = relocation.getTo(); String commentText = String.format("Relocated to %s%s%s", - relocation.getTo().getGroupId(), - Optional.ofNullable(relocation.getTo().getArtifactId()).map(a -> ":" + a).orElse(""), + relocatedGA.getGroupId(), + Optional.ofNullable(relocatedGA.getArtifactId()).map(a -> ":" + a).orElse(""), relocation.getContext() == null ? "" : " as per \"" + relocation.getContext() + "\""); + report.insertRow(ctx, new RelocatedDependencyReport.Row( + groupId, + artifactId, + relocatedGA.getGroupId(), + relocatedGA.getArtifactId(), + relocation.getContext())); return SearchResult.found(tree, commentText); } if (artifactId == null) { return tree; } // Try again without artifactId - return maybeAddComment(acc, tree, groupId, null); + return maybeAddComment(acc, tree, groupId, null, ctx); } } diff --git a/src/main/java/org/openrewrite/java/dependencies/table/DependencyListReport.java b/src/main/java/org/openrewrite/java/dependencies/table/DependencyListReport.java index 5f3e643..cf9590a 100644 --- a/src/main/java/org/openrewrite/java/dependencies/table/DependencyListReport.java +++ b/src/main/java/org/openrewrite/java/dependencies/table/DependencyListReport.java @@ -15,13 +15,14 @@ */ package org.openrewrite.java.dependencies.table; +import com.fasterxml.jackson.annotation.JsonIgnoreType; import lombok.Value; import org.openrewrite.Column; import org.openrewrite.DataTable; import org.openrewrite.Recipe; +@JsonIgnoreType public class DependencyListReport extends DataTable { - public DependencyListReport(Recipe recipe) { super(recipe, "Dependency report", diff --git a/src/main/java/org/openrewrite/java/dependencies/table/GradleDependencyConfigurationErrors.java b/src/main/java/org/openrewrite/java/dependencies/table/GradleDependencyConfigurationErrors.java index bc0a65b..371a3f0 100644 --- a/src/main/java/org/openrewrite/java/dependencies/table/GradleDependencyConfigurationErrors.java +++ b/src/main/java/org/openrewrite/java/dependencies/table/GradleDependencyConfigurationErrors.java @@ -15,14 +15,14 @@ */ package org.openrewrite.java.dependencies.table; +import com.fasterxml.jackson.annotation.JsonIgnoreType; import lombok.Value; import org.openrewrite.Column; import org.openrewrite.DataTable; import org.openrewrite.Recipe; +@JsonIgnoreType public class GradleDependencyConfigurationErrors extends DataTable { - - public GradleDependencyConfigurationErrors(Recipe recipe) { super(recipe, "Gradle dependency configuration errors", "Records Gradle dependency configurations which failed to resolve during parsing. " + diff --git a/src/main/java/org/openrewrite/java/dependencies/table/RelocatedDependencyReport.java b/src/main/java/org/openrewrite/java/dependencies/table/RelocatedDependencyReport.java new file mode 100644 index 0000000..2d696e5 --- /dev/null +++ b/src/main/java/org/openrewrite/java/dependencies/table/RelocatedDependencyReport.java @@ -0,0 +1,56 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed 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 + *

+ * https://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. + */ +package org.openrewrite.java.dependencies.table; + +import com.fasterxml.jackson.annotation.JsonIgnoreType; +import lombok.Value; +import org.openrewrite.Column; +import org.openrewrite.DataTable; +import org.openrewrite.Recipe; +import org.openrewrite.internal.lang.Nullable; + +@JsonIgnoreType +public class RelocatedDependencyReport extends DataTable { + public RelocatedDependencyReport(Recipe recipe) { + super(recipe, + "Relocated dependencies", + "A list of dependencies in use that have relocated."); + } + + @Value + public static class Row { + @Column(displayName = "Dependency group id", + description = "The Group ID of the dependency in use.") + String dependencyGroupId; + @Column(displayName = "Dependency artifact id", + description = "The Artifact ID of the dependency in use.") + @Nullable + String dependencyArtifactId; + + @Column(displayName = "Relocated dependency group id", + description = "The Group ID of the relocated dependency.") + String relocatedGroupId; + @Column(displayName = "Relocated ependency artifact id", + description = "The Artifact ID of the relocated dependency.") + @Nullable + String relocatedArtifactId; + + @Column(displayName = "Context", + description = "Context for the relocation, if any.") + @Nullable + String context; + } +} diff --git a/src/main/java/org/openrewrite/java/dependencies/table/RepositoryAccessibilityReport.java b/src/main/java/org/openrewrite/java/dependencies/table/RepositoryAccessibilityReport.java index 2fde99e..3077b95 100644 --- a/src/main/java/org/openrewrite/java/dependencies/table/RepositoryAccessibilityReport.java +++ b/src/main/java/org/openrewrite/java/dependencies/table/RepositoryAccessibilityReport.java @@ -15,12 +15,14 @@ */ package org.openrewrite.java.dependencies.table; +import com.fasterxml.jackson.annotation.JsonIgnoreType; import lombok.Value; import org.openrewrite.Column; import org.openrewrite.DataTable; import org.openrewrite.Recipe; import org.openrewrite.internal.lang.Nullable; +@JsonIgnoreType public class RepositoryAccessibilityReport extends DataTable { public RepositoryAccessibilityReport(Recipe recipe) { diff --git a/src/test/java/org/openrewrite/java/dependencies/RelocatedDependencyCheckTest.java b/src/test/java/org/openrewrite/java/dependencies/RelocatedDependencyCheckTest.java index 110361f..30436cd 100644 --- a/src/test/java/org/openrewrite/java/dependencies/RelocatedDependencyCheckTest.java +++ b/src/test/java/org/openrewrite/java/dependencies/RelocatedDependencyCheckTest.java @@ -22,6 +22,7 @@ import org.openrewrite.java.dependencies.RelocatedDependencyCheck.Accumulator; import org.openrewrite.java.dependencies.RelocatedDependencyCheck.GroupArtifact; import org.openrewrite.java.dependencies.RelocatedDependencyCheck.Relocation; +import org.openrewrite.java.dependencies.table.RelocatedDependencyReport; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; @@ -54,6 +55,10 @@ class Maven { @DocumentExample void findRelocatedMavenDependencies() { rewriteRun( + recipe -> recipe.dataTable(RelocatedDependencyReport.Row.class, rows -> assertThat(rows).containsExactly( + new RelocatedDependencyReport.Row("commons-lang", "commons-lang", "org.apache.commons", "commons-lang3", null), + new RelocatedDependencyReport.Row("org.codehaus.groovy", null, "org.apache.groovy", null, null) + )), //language=xml pomXml( """ @@ -97,7 +102,6 @@ void findRelocatedMavenDependencies() { """ ) - ); } @@ -207,17 +211,20 @@ class Gradle { @Test void findRelocatedGradleDependencies() { rewriteRun( + recipe -> recipe.dataTable(RelocatedDependencyReport.Row.class, rows -> assertThat(rows).containsExactly( + new RelocatedDependencyReport.Row("commons-lang", "commons-lang", "org.apache.commons", "commons-lang3", null), + new RelocatedDependencyReport.Row("commons-lang", "commons-lang", "org.apache.commons", "commons-lang3", null), + new RelocatedDependencyReport.Row("org.codehaus.groovy", null, "org.apache.groovy", null, null) + )), //language=groovy buildGradle( """ plugins { id "java-library" } - repositories { mavenCentral() } - def groovyVersion = "2.5.6" dependencies { implementation "commons-lang:commons-lang:2.6" @@ -229,11 +236,9 @@ void findRelocatedGradleDependencies() { plugins { id "java-library" } - repositories { mavenCentral() } - def groovyVersion = "2.5.6" dependencies { /*~~(Relocated to org.apache.commons:commons-lang3)~~>*/implementation "commons-lang:commons-lang:2.6"