17
17
package org .springframework .boot .build .bom ;
18
18
19
19
import java .util .ArrayList ;
20
+ import java .util .Collections ;
21
+ import java .util .HashMap ;
22
+ import java .util .LinkedHashMap ;
20
23
import java .util .List ;
24
+ import java .util .Map ;
21
25
import java .util .Optional ;
22
26
import java .util .Set ;
23
27
import java .util .TreeSet ;
42
46
import org .gradle .api .tasks .TaskAction ;
43
47
44
48
import org .springframework .boot .build .bom .Library .Group ;
49
+ import org .springframework .boot .build .bom .Library .ImportedBom ;
45
50
import org .springframework .boot .build .bom .Library .Module ;
51
+ import org .springframework .boot .build .bom .Library .PermittedDependency ;
46
52
import org .springframework .boot .build .bom .Library .ProhibitedVersion ;
47
53
import org .springframework .boot .build .bom .Library .VersionAlignment ;
48
54
import org .springframework .boot .build .bom .ResolvedBom .Bom ;
@@ -69,7 +75,8 @@ public CheckBom(BomExtension bom) {
69
75
Provider <ResolvedBom > resolvedBom = getResolvedBomFile ().map (RegularFile ::getAsFile ).map (ResolvedBom ::readFrom );
70
76
this .checks = List .of (new CheckExclusions (configurations , dependencies ), new CheckProhibitedVersions (),
71
77
new CheckVersionAlignment (),
72
- new CheckDependencyManagementAlignment (resolvedBom , configurations , dependencies ));
78
+ new CheckDependencyManagementAlignment (resolvedBom , configurations , dependencies ),
79
+ new CheckForUnwantedDependencyManagement (resolvedBom ));
73
80
this .bom = bom ;
74
81
}
75
82
@@ -241,31 +248,22 @@ private void check(VersionAlignment versionAlignment, Library library, List<Stri
241
248
242
249
}
243
250
244
- private static final class CheckDependencyManagementAlignment implements LibraryCheck {
251
+ private abstract static class ResolvedLibraryCheck implements LibraryCheck {
245
252
246
253
private final Provider <ResolvedBom > resolvedBom ;
247
254
248
- private final BomResolver bomResolver ;
249
-
250
- private CheckDependencyManagementAlignment (Provider <ResolvedBom > resolvedBom ,
251
- ConfigurationContainer configurations , DependencyHandler dependencies ) {
255
+ private ResolvedLibraryCheck (Provider <ResolvedBom > resolvedBom ) {
252
256
this .resolvedBom = resolvedBom ;
253
- this .bomResolver = new BomResolver (configurations , dependencies );
254
257
}
255
258
256
259
@ Override
257
260
public List <String > check (Library library ) {
258
- List <String > errors = new ArrayList <>();
259
- String alignsWithBom = library .getAlignsWithBom ();
260
- if (alignsWithBom != null ) {
261
- Bom mavenBom = this .bomResolver
262
- .resolveMavenBom (alignsWithBom + ":" + library .getVersion ().getVersion ());
263
- ResolvedLibrary resolvedLibrary = getResolvedLibrary (library );
264
- checkDependencyManagementAlignment (resolvedLibrary , mavenBom , errors );
265
- }
266
- return errors ;
261
+ ResolvedLibrary resolvedLibrary = getResolvedLibrary (library );
262
+ return check (library , resolvedLibrary );
267
263
}
268
264
265
+ protected abstract List <String > check (Library library , ResolvedLibrary resolvedLibrary );
266
+
269
267
private ResolvedLibrary getResolvedLibrary (Library library ) {
270
268
ResolvedBom resolvedBom = this .resolvedBom .get ();
271
269
Optional <ResolvedLibrary > resolvedLibrary = resolvedBom .libraries ()
@@ -278,6 +276,30 @@ private ResolvedLibrary getResolvedLibrary(Library library) {
278
276
return resolvedLibrary .get ();
279
277
}
280
278
279
+ }
280
+
281
+ private static final class CheckDependencyManagementAlignment extends ResolvedLibraryCheck {
282
+
283
+ private final BomResolver bomResolver ;
284
+
285
+ private CheckDependencyManagementAlignment (Provider <ResolvedBom > resolvedBom ,
286
+ ConfigurationContainer configurations , DependencyHandler dependencies ) {
287
+ super (resolvedBom );
288
+ this .bomResolver = new BomResolver (configurations , dependencies );
289
+ }
290
+
291
+ @ Override
292
+ public List <String > check (Library library , ResolvedLibrary resolvedLibrary ) {
293
+ List <String > errors = new ArrayList <>();
294
+ String alignsWithBom = library .getAlignsWithBom ();
295
+ if (alignsWithBom != null ) {
296
+ Bom mavenBom = this .bomResolver
297
+ .resolveMavenBom (alignsWithBom + ":" + library .getVersion ().getVersion ());
298
+ checkDependencyManagementAlignment (resolvedLibrary , mavenBom , errors );
299
+ }
300
+ return errors ;
301
+ }
302
+
281
303
private void checkDependencyManagementAlignment (ResolvedLibrary library , Bom mavenBom , List <String > errors ) {
282
304
List <Id > managedByLibrary = library .managedDependencies ();
283
305
List <Id > managedByBom = managedDependenciesOf (mavenBom );
@@ -316,4 +338,108 @@ private List<Id> managedDependenciesOf(Bom mavenBom) {
316
338
317
339
}
318
340
341
+ private static final class CheckForUnwantedDependencyManagement extends ResolvedLibraryCheck {
342
+
343
+ private CheckForUnwantedDependencyManagement (Provider <ResolvedBom > resolvedBom ) {
344
+ super (resolvedBom );
345
+ }
346
+
347
+ @ Override
348
+ public List <String > check (Library library , ResolvedLibrary resolvedLibrary ) {
349
+ Map <String , Set <String >> unwanted = findUnwantedDependencyManagement (library , resolvedLibrary );
350
+ List <String > errors = new ArrayList <>();
351
+ if (!unwanted .isEmpty ()) {
352
+ StringBuilder error = new StringBuilder ("Unwanted dependency management:" );
353
+ unwanted .forEach ((bom , dependencies ) -> {
354
+ error .append ("%n - %s:" .formatted (bom ));
355
+ error .append ("%n - %s" .formatted (String .join ("\n - " , dependencies )));
356
+ });
357
+ errors .add (error .toString ());
358
+ }
359
+ Map <String , Set <String >> unnecessary = findUnnecessaryPermittedDependencies (library , resolvedLibrary );
360
+ if (!unnecessary .isEmpty ()) {
361
+ StringBuilder error = new StringBuilder ("Dependencies permitted unnecessarily:" );
362
+ unnecessary .forEach ((bom , dependencies ) -> {
363
+ error .append ("%n - %s:" .formatted (bom ));
364
+ error .append ("%n - %s" .formatted (String .join ("\n - " , dependencies )));
365
+ });
366
+ errors .add (error .toString ());
367
+ }
368
+ return errors ;
369
+ }
370
+
371
+ private Map <String , Set <String >> findUnwantedDependencyManagement (Library library ,
372
+ ResolvedLibrary resolvedLibrary ) {
373
+ Map <String , Set <String >> unwanted = new LinkedHashMap <>();
374
+ for (Bom bom : resolvedLibrary .importedBoms ()) {
375
+ Set <String > notPermitted = new TreeSet <>();
376
+ Set <Id > managedDependencies = managedDependenciesOf (bom );
377
+ managedDependencies .stream ()
378
+ .filter ((dependency ) -> unwanted (bom , dependency , findPermittedDependencies (library , bom )))
379
+ .map (Id ::toString )
380
+ .forEach (notPermitted ::add );
381
+ if (!notPermitted .isEmpty ()) {
382
+ unwanted .put (bom .id ().artifactId (), notPermitted );
383
+ }
384
+ }
385
+ return unwanted ;
386
+ }
387
+
388
+ private List <PermittedDependency > findPermittedDependencies (Library library , Bom bom ) {
389
+ for (Group group : library .getGroups ()) {
390
+ for (ImportedBom importedBom : group .getBoms ()) {
391
+ if (importedBom .name ().equals (bom .id ().artifactId ()) && group .getId ().equals (bom .id ().groupId ())) {
392
+ return importedBom .permittedDependencies ();
393
+ }
394
+ }
395
+ }
396
+ return Collections .emptyList ();
397
+ }
398
+
399
+ private Set <Id > managedDependenciesOf (Bom bom ) {
400
+ Set <Id > managedDependencies = new TreeSet <>();
401
+ if (bom != null ) {
402
+ managedDependencies .addAll (bom .managedDependencies ());
403
+ managedDependencies .addAll (managedDependenciesOf (bom .parent ()));
404
+ for (Bom importedBom : bom .importedBoms ()) {
405
+ managedDependencies .addAll (managedDependenciesOf (importedBom ));
406
+ }
407
+ }
408
+ return managedDependencies ;
409
+ }
410
+
411
+ private boolean unwanted (Bom bom , Id managedDependency , List <PermittedDependency > permittedDependencies ) {
412
+ if (bom .id ().groupId ().equals (managedDependency .groupId ())
413
+ || managedDependency .groupId ().startsWith (bom .id ().groupId () + "." )) {
414
+ return false ;
415
+ }
416
+ for (PermittedDependency permittedDependency : permittedDependencies ) {
417
+ if (permittedDependency .artifactId ().equals (managedDependency .artifactId ())
418
+ && permittedDependency .groupId ().equals (managedDependency .groupId ())) {
419
+ return false ;
420
+ }
421
+ }
422
+ return true ;
423
+ }
424
+
425
+ private Map <String , Set <String >> findUnnecessaryPermittedDependencies (Library library ,
426
+ ResolvedLibrary resolvedLibrary ) {
427
+ Map <String , Set <String >> unnecessary = new HashMap <>();
428
+ for (Bom bom : resolvedLibrary .importedBoms ()) {
429
+ Set <String > permittedDependencies = findPermittedDependencies (library , bom ).stream ()
430
+ .map ((dependency ) -> dependency .groupId () + ":" + dependency .artifactId ())
431
+ .collect (Collectors .toCollection (TreeSet ::new ));
432
+ Set <String > dependencies = managedDependenciesOf (bom ).stream ()
433
+ .map ((dependency ) -> dependency .groupId () + ":" + dependency .artifactId ())
434
+ .collect (Collectors .toCollection (TreeSet ::new ));
435
+ permittedDependencies .removeAll (dependencies );
436
+ if (!permittedDependencies .isEmpty ()) {
437
+ unnecessary .put (bom .id ().artifactId (), permittedDependencies );
438
+ }
439
+ }
440
+ return unnecessary ;
441
+ }
442
+
443
+ }
444
+
319
445
}
0 commit comments