2121import org .openrewrite .*;
2222import org .openrewrite .gradle .marker .GradleDependencyConfiguration ;
2323import org .openrewrite .gradle .marker .GradleProject ;
24+ import org .openrewrite .internal .ExceptionUtils ;
2425import org .openrewrite .java .dependencies .table .DependencyListReport ;
2526import org .openrewrite .marker .Markers ;
26- import org .openrewrite .maven .tree .GroupArtifactVersion ;
27- import org .openrewrite .maven .tree .MavenResolutionResult ;
28- import org .openrewrite .maven .tree .ResolvedDependency ;
29- import org .openrewrite .maven .tree .ResolvedGroupArtifactVersion ;
27+ import org .openrewrite .maven .MavenDownloadingException ;
28+ import org .openrewrite .maven .MavenExecutionContextView ;
29+ import org .openrewrite .maven .MavenSettings ;
30+ import org .openrewrite .maven .internal .MavenPomDownloader ;
31+ import org .openrewrite .maven .table .MavenMetadataFailures ;
32+ import org .openrewrite .maven .tree .*;
3033
3134import java .util .HashSet ;
35+ import java .util .Optional ;
3236import java .util .Set ;
3337
38+ import static java .util .Collections .emptyMap ;
39+
3440@ Value
3541@ EqualsAndHashCode (callSuper = false )
3642public class DependencyList extends Recipe {
3743
3844 transient DependencyListReport report = new DependencyListReport (this );
45+ transient MavenMetadataFailures metadataFailures = new MavenMetadataFailures (this );
3946
4047 @ Option (displayName = "Scope" ,
4148 description = "The scope of the dependencies to include in the report." ,
@@ -49,6 +56,13 @@ public class DependencyList extends Recipe {
4956 example = "true" )
5057 boolean includeTransitive ;
5158
59+ @ Option (displayName = "Validate dependencies are resolvable" ,
60+ description = "When enabled the recipe will attempt to download every dependency it encounters, reporting on any failures. " +
61+ "This can be useful for identifying dependencies that have become unavailable since an LST was produced." ,
62+ valid = {"true" , "false" },
63+ example = "true" )
64+ boolean validateResolvable ;
65+
5266 /**
5367 * Freestanding gradle script plugins get assigned the same GradleProject marker with the build script in the project.
5468 * Keep track of the ones which have been seen to minimize duplicate entries in the report.
@@ -79,16 +93,16 @@ public TreeVisitor<?, ExecutionContext> getVisitor() {
7993 m .findFirst (GradleProject .class )
8094 .filter (gradle -> seenGradleProjects .add (new GroupArtifactVersion (gradle .getGroup (), gradle .getName (), gradle .getVersion ())))
8195 .ifPresent (gradle -> {
82- GradleDependencyConfiguration conf = gradle .getConfiguration (scope .asGradleConfigurationName ());
83- if (conf != null ) {
84- for (ResolvedDependency dep : conf .getResolved ()) {
85- if (dep .getDepth () > 0 ) {
86- continue ;
96+ GradleDependencyConfiguration conf = gradle .getConfiguration (scope .asGradleConfigurationName ());
97+ if (conf != null ) {
98+ for (ResolvedDependency dep : conf .getResolved ()) {
99+ if (dep .getDepth () > 0 ) {
100+ continue ;
101+ }
102+ insertDependency (ctx , gradle , seen , dep , true );
103+ }
87104 }
88- insertDependency (ctx , gradle , seen , dep , true );
89- }
90- }
91- });
105+ });
92106 m .findFirst (MavenResolutionResult .class ).ifPresent (maven -> {
93107 for (ResolvedDependency dep : maven .getDependencies ().get (scope .asMavenScope ())) {
94108 if (dep .getDepth () > 0 ) {
@@ -106,6 +120,19 @@ private void insertDependency(ExecutionContext ctx, GradleProject gradle, Set<Re
106120 if (!seen .add (dep .getGav ())) {
107121 return ;
108122 }
123+ String resolutionFailure = "" ;
124+ if (validateResolvable ) {
125+ try {
126+ //noinspection DataFlowIssue
127+ metadataFailures .insertRows (ctx , () -> new MavenPomDownloader (
128+ emptyMap (), ctx ,
129+ null ,
130+ null )
131+ .downloadMetadata (new GroupArtifact (gradle .getGroup (), gradle .getName ()), null , gradle .getMavenRepositories ()));
132+ } catch (MavenDownloadingException e ) {
133+ resolutionFailure = ExceptionUtils .sanitizeStackTrace (e , RecipeScheduler .class );
134+ }
135+ }
109136 report .insertRow (ctx , new DependencyListReport .Row (
110137 "Gradle" ,
111138 gradle .getGroup (),
@@ -114,7 +141,8 @@ private void insertDependency(ExecutionContext ctx, GradleProject gradle, Set<Re
114141 dep .getGroupId (),
115142 dep .getArtifactId (),
116143 dep .getVersion (),
117- direct
144+ direct ,
145+ resolutionFailure
118146 ));
119147 if (includeTransitive ) {
120148 for (ResolvedDependency transitive : dep .getDependencies ()) {
@@ -127,6 +155,24 @@ private void insertDependency(ExecutionContext ctx, MavenResolutionResult maven,
127155 if (!seen .add (dep .getGav ())) {
128156 return ;
129157 }
158+ String resolutionFailure = "" ;
159+ if (validateResolvable ) {
160+ try {
161+ MavenExecutionContextView mctx = MavenExecutionContextView .view (ctx );
162+ metadataFailures .insertRows (ctx , () -> new MavenPomDownloader (
163+ emptyMap (), ctx ,
164+ mctx .getSettings () == null ? maven .getMavenSettings () :
165+ maven .getMavenSettings () == null ? mctx .getSettings () :
166+ mctx .getSettings ().merge (maven .getMavenSettings ()),
167+ Optional .ofNullable (mctx .getSettings ())
168+ .map (MavenSettings ::getActiveProfiles )
169+ .map (MavenSettings .ActiveProfiles ::getActiveProfiles )
170+ .orElse (maven .getActiveProfiles ()))
171+ .downloadMetadata (new GroupArtifact (maven .getPom ().getGroupId (), maven .getPom ().getArtifactId ()), null , maven .getPom ().getRepositories ()));
172+ } catch (MavenDownloadingException e ) {
173+ resolutionFailure = ExceptionUtils .sanitizeStackTrace (e , RecipeScheduler .class );
174+ }
175+ }
130176 report .insertRow (ctx , new DependencyListReport .Row (
131177 "Maven" ,
132178 maven .getPom ().getGroupId (),
@@ -135,7 +181,8 @@ private void insertDependency(ExecutionContext ctx, MavenResolutionResult maven,
135181 dep .getGroupId (),
136182 dep .getArtifactId (),
137183 dep .getVersion (),
138- direct
184+ direct ,
185+ resolutionFailure
139186 ));
140187 if (includeTransitive ) {
141188 for (ResolvedDependency transitive : dep .getDependencies ()) {
0 commit comments