diff --git a/src/main/java/org/openrewrite/java/dependencies/DependencyResolutionDiagnostic.java b/src/main/java/org/openrewrite/java/dependencies/DependencyResolutionDiagnostic.java index 1f32af1..c464edd 100644 --- a/src/main/java/org/openrewrite/java/dependencies/DependencyResolutionDiagnostic.java +++ b/src/main/java/org/openrewrite/java/dependencies/DependencyResolutionDiagnostic.java @@ -23,8 +23,8 @@ import org.openrewrite.groovy.GroovyIsoVisitor; import org.openrewrite.groovy.tree.G; import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.java.dependencies.table.GradleDependencyConfigurationErrors; import org.openrewrite.java.dependencies.table.RepositoryAccessibilityReport; -import org.openrewrite.marker.SearchResult; import org.openrewrite.maven.internal.MavenPomDownloader; import org.openrewrite.maven.tree.MavenRepository; import org.openrewrite.maven.tree.MavenResolutionResult; @@ -40,6 +40,7 @@ public class DependencyResolutionDiagnostic extends ScanningRecipe { transient RepositoryAccessibilityReport report = new RepositoryAccessibilityReport(this); + transient GradleDependencyConfigurationErrors gradleErrors = new GradleDependencyConfigurationErrors(this); @Override public String getDisplayName() { @@ -48,9 +49,15 @@ public String getDisplayName() { @Override public String getDescription() { - return "Recipes which manipulate dependencies must be able to successfully access the repositories used by the " + - "project and retrieve dependency metadata from them. This recipe lists the repositories that were found " + - "and whether or not dependency metadata could successfully be resolved from them."; + return "Recipes which manipulate dependencies must be able to successfully access the artifact repositories " + + "and resolve dependencies from them. This recipe produces two data tables used to understand the state " + + "of dependency resolution.\n\n" + + "The Repository accessibility report lists all the artifact repositories known to the project and whether" + + "they respond to network access. The network access is attempted while the recipe is run and so is " + + "representative of current conditions.\n\n" + + "The Gradle dependency configuration errors lists all the dependency configurations that failed to " + + "resolve one or more dependencies when the project was parsed. This is representative of conditions at " + + "the time the LST was parsed."; } public static class Accumulator { @@ -168,11 +175,7 @@ public G.CompilationUnit visitCompilationUnit(G.CompilationUnit cu, ExecutionCon if (conf.getExceptionType() == null) { continue; } - g = SearchResult.found(g, "Found Gradle dependency configuration which failed to resolve during parsing: " + - conf.getName() + ": " + conf.getExceptionType() + " - " + conf.getMessage()); - // If one configuration failed to resolve, others likely failed and probably for the same reasons - // Record only first failure to reduce noise - break; + gradleErrors.insertRow(ctx, new GradleDependencyConfigurationErrors.Row(gp.getPath(), conf.getName(), conf.getExceptionType(), conf.getMessage())); } return g; diff --git a/src/main/java/org/openrewrite/java/dependencies/table/GradleDependencyConfigurationErrors.java b/src/main/java/org/openrewrite/java/dependencies/table/GradleDependencyConfigurationErrors.java new file mode 100644 index 0000000..64c91eb --- /dev/null +++ b/src/main/java/org/openrewrite/java/dependencies/table/GradleDependencyConfigurationErrors.java @@ -0,0 +1,35 @@ +package org.openrewrite.java.dependencies.table; + +import lombok.Value; +import org.openrewrite.Column; +import org.openrewrite.DataTable; +import org.openrewrite.Recipe; + +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. " + + "Partial success/failure is common, a failure in this list does not mean that every dependency failed to resolve."); + } + + @Value + public static class Row { + @Column(displayName = "Project path", + description = "The path of the project which contains the dependency configuration.") + String projectPath; + + @Column(displayName = "Configuration name", + description = "The name of the dependency configuration which failed to resolve.") + String configurationName; + + @Column(displayName = "Exception type", + description = "The type of exception encountered when attempting to resolve the dependency configuration.") + String exceptionType; + + @Column(displayName = "Error message", + description = "The error message encountered when attempting to resolve the dependency configuration.") + String exceptionMessage; + } +} diff --git a/src/test/java/org/openrewrite/java/dependencies/DependencyResolutionDiagnosticTest.java b/src/test/java/org/openrewrite/java/dependencies/DependencyResolutionDiagnosticTest.java index 0c50fc8..70788ee 100644 --- a/src/test/java/org/openrewrite/java/dependencies/DependencyResolutionDiagnosticTest.java +++ b/src/test/java/org/openrewrite/java/dependencies/DependencyResolutionDiagnosticTest.java @@ -37,6 +37,8 @@ public void defaults(RecipeSpec spec) { void gradle() { rewriteRun( spec -> spec.beforeRecipe(withToolingApi()) + // It is a limitation of the tooling API which prevents configuration-granularity error information from being collected. + // So the GradleDependencyConfigurationErrors table will never be populated in unit tests. .dataTable(RepositoryAccessibilityReport.Row.class, rows -> { assertThat(rows).hasSize(4); assertThat(rows).contains( @@ -63,26 +65,7 @@ void gradle() { dependencies { implementation("org.openrewrite.nonexistent:nonexistent:0.0.0") } - """ - // It is a limitation of the tooling API which prevents configuration-granularity error information from being collected. - // When run with real Gradle this recipe _should_ produce the following result, included here for documentation. -// ,""" -// ~~(Found Gradle dependency configuration which failed to resolve during parsing)~~>plugins { -// id("java") -// } -// repositories { -// mavenLocal() -// mavenCentral() -// maven { -// url "https://nonexistent.moderne.io/maven2" -// } -// } -// -// dependencies { -// implementation("org.openrewrite.nonexistent:nonexistent:0.0.0") -// } -// """ - ) + """) ); }