58
58
*/
59
59
public abstract class CheckBom extends DefaultTask {
60
60
61
- private final Provider <ResolvedBom > resolvedBom ;
62
-
63
- private final ConfigurationContainer configurations ;
64
-
65
- private final DependencyHandler dependencies ;
66
-
67
61
private final BomExtension bom ;
68
62
69
- private final BomResolver bomResolver ;
63
+ private final List < LibraryCheck > checks ;
70
64
71
65
@ Inject
72
66
public CheckBom (BomExtension bom ) {
73
- this .configurations = getProject ().getConfigurations ();
74
- this .dependencies = getProject ().getDependencies ();
67
+ ConfigurationContainer configurations = getProject ().getConfigurations ();
68
+ DependencyHandler dependencies = getProject ().getDependencies ();
69
+ Provider <ResolvedBom > resolvedBom = getResolvedBomFile ().map (RegularFile ::getAsFile ).map (ResolvedBom ::readFrom );
70
+ this .checks = List .of (new CheckExclusions (configurations , dependencies ), new CheckProhibitedVersions (),
71
+ new CheckVersionAlignment (),
72
+ new CheckDependencyManagementAlignment (resolvedBom , configurations , dependencies ));
75
73
this .bom = bom ;
76
- this .resolvedBom = getResolvedBomFile ().map (RegularFile ::getAsFile ).map (ResolvedBom ::readFrom );
77
- this .bomResolver = new BomResolver (this .configurations , this .dependencies );
78
74
}
79
75
80
76
@ InputFile
81
77
@ PathSensitive (PathSensitivity .RELATIVE )
82
- abstract RegularFileProperty getResolvedBomFile ();
78
+ public abstract RegularFileProperty getResolvedBomFile ();
83
79
84
80
@ TaskAction
85
81
void checkBom () {
86
82
List <String > errors = new ArrayList <>();
87
83
for (Library library : this .bom .getLibraries ()) {
88
- checkLibrary (library , errors );
84
+ errors . addAll ( checkLibrary (library ) );
89
85
}
90
86
if (!errors .isEmpty ()) {
91
87
System .out .println ();
@@ -95,165 +91,229 @@ void checkBom() {
95
91
}
96
92
}
97
93
98
- private void checkLibrary (Library library , List < String > errors ) {
94
+ private List < String > checkLibrary (Library library ) {
99
95
List <String > libraryErrors = new ArrayList <>();
100
- checkExclusions (library , libraryErrors );
101
- checkProhibitedVersions (library , libraryErrors );
102
- checkVersionAlignment (library , libraryErrors );
103
- checkDependencyManagementAlignment (library , libraryErrors );
96
+ this .checks .stream ().flatMap ((check ) -> check .check (library ).stream ()).forEach (libraryErrors ::add );
97
+ List <String > errors = new ArrayList <>();
104
98
if (!libraryErrors .isEmpty ()) {
105
99
errors .add (library .getName ());
106
100
for (String libraryError : libraryErrors ) {
107
101
errors .add (" - " + libraryError );
108
102
}
109
103
}
104
+ return errors ;
105
+ }
106
+
107
+ private interface LibraryCheck {
108
+
109
+ List <String > check (Library library );
110
+
110
111
}
111
112
112
- private void checkExclusions (Library library , List <String > errors ) {
113
- for (Group group : library .getGroups ()) {
114
- for (Module module : group .getModules ()) {
115
- if (!module .getExclusions ().isEmpty ()) {
116
- checkExclusions (group .getId (), module , library .getVersion ().getVersion (), errors );
113
+ private static final class CheckExclusions implements LibraryCheck {
114
+
115
+ private final ConfigurationContainer configurations ;
116
+
117
+ private final DependencyHandler dependencies ;
118
+
119
+ private CheckExclusions (ConfigurationContainer configurations , DependencyHandler dependencies ) {
120
+ this .configurations = configurations ;
121
+ this .dependencies = dependencies ;
122
+ }
123
+
124
+ @ Override
125
+ public List <String > check (Library library ) {
126
+ List <String > errors = new ArrayList <>();
127
+ for (Group group : library .getGroups ()) {
128
+ for (Module module : group .getModules ()) {
129
+ if (!module .getExclusions ().isEmpty ()) {
130
+ checkExclusions (group .getId (), module , library .getVersion ().getVersion (), errors );
131
+ }
117
132
}
118
133
}
134
+ return errors ;
119
135
}
120
- }
121
136
122
- private void checkExclusions (String groupId , Module module , DependencyVersion version , List <String > errors ) {
123
- Set <String > resolved = this .configurations
124
- .detachedConfiguration (this .dependencies .create (groupId + ":" + module .getName () + ":" + version ))
125
- .getResolvedConfiguration ()
126
- .getResolvedArtifacts ()
127
- .stream ()
128
- .map ((artifact ) -> artifact .getModuleVersion ().getId ())
129
- .map ((id ) -> id .getGroup () + ":" + id .getModule ().getName ())
130
- .collect (Collectors .toSet ());
131
- Set <String > exclusions = module .getExclusions ()
132
- .stream ()
133
- .map ((exclusion ) -> exclusion .getGroupId () + ":" + exclusion .getArtifactId ())
134
- .collect (Collectors .toSet ());
135
- Set <String > unused = new TreeSet <>();
136
- for (String exclusion : exclusions ) {
137
- if (!resolved .contains (exclusion )) {
138
- if (exclusion .endsWith (":*" )) {
139
- String group = exclusion .substring (0 , exclusion .indexOf (':' ) + 1 );
140
- if (resolved .stream ().noneMatch ((candidate ) -> candidate .startsWith (group ))) {
137
+ private void checkExclusions (String groupId , Module module , DependencyVersion version , List <String > errors ) {
138
+ Set <String > resolved = this .configurations
139
+ .detachedConfiguration (this .dependencies .create (groupId + ":" + module .getName () + ":" + version ))
140
+ .getResolvedConfiguration ()
141
+ .getResolvedArtifacts ()
142
+ .stream ()
143
+ .map ((artifact ) -> artifact .getModuleVersion ().getId ())
144
+ .map ((id ) -> id .getGroup () + ":" + id .getModule ().getName ())
145
+ .collect (Collectors .toSet ());
146
+ Set <String > exclusions = module .getExclusions ()
147
+ .stream ()
148
+ .map ((exclusion ) -> exclusion .getGroupId () + ":" + exclusion .getArtifactId ())
149
+ .collect (Collectors .toSet ());
150
+ Set <String > unused = new TreeSet <>();
151
+ for (String exclusion : exclusions ) {
152
+ if (!resolved .contains (exclusion )) {
153
+ if (exclusion .endsWith (":*" )) {
154
+ String group = exclusion .substring (0 , exclusion .indexOf (':' ) + 1 );
155
+ if (resolved .stream ().noneMatch ((candidate ) -> candidate .startsWith (group ))) {
156
+ unused .add (exclusion );
157
+ }
158
+ }
159
+ else {
141
160
unused .add (exclusion );
142
161
}
143
162
}
144
- else {
145
- unused .add (exclusion );
146
- }
163
+ }
164
+ exclusions .removeAll (resolved );
165
+ if (!unused .isEmpty ()) {
166
+ errors .add ("Unnecessary exclusions on " + groupId + ":" + module .getName () + ": " + exclusions );
147
167
}
148
168
}
149
- exclusions .removeAll (resolved );
150
- if (!unused .isEmpty ()) {
151
- errors .add ("Unnecessary exclusions on " + groupId + ":" + module .getName () + ": " + exclusions );
152
- }
169
+
153
170
}
154
171
155
- private void checkProhibitedVersions (Library library , List <String > errors ) {
156
- ArtifactVersion currentVersion = new DefaultArtifactVersion (library .getVersion ().getVersion ().toString ());
157
- for (ProhibitedVersion prohibited : library .getProhibitedVersions ()) {
158
- if (prohibited .isProhibited (library .getVersion ().getVersion ().toString ())) {
159
- errors .add ("Current version " + currentVersion + " is prohibited" );
160
- }
161
- else {
162
- VersionRange versionRange = prohibited .getRange ();
163
- if (versionRange != null ) {
164
- for (Restriction restriction : versionRange .getRestrictions ()) {
165
- ArtifactVersion upperBound = restriction .getUpperBound ();
166
- if (upperBound == null ) {
167
- return ;
168
- }
169
- int comparison = currentVersion .compareTo (upperBound );
170
- if ((restriction .isUpperBoundInclusive () && comparison <= 0 )
171
- || ((!restriction .isUpperBoundInclusive ()) && comparison < 0 )) {
172
- return ;
173
- }
172
+ private static final class CheckProhibitedVersions implements LibraryCheck {
173
+
174
+ @ Override
175
+ public List <String > check (Library library ) {
176
+ List <String > errors = new ArrayList <>();
177
+ ArtifactVersion currentVersion = new DefaultArtifactVersion (library .getVersion ().getVersion ().toString ());
178
+ for (ProhibitedVersion prohibited : library .getProhibitedVersions ()) {
179
+ if (prohibited .isProhibited (library .getVersion ().getVersion ().toString ())) {
180
+ errors .add ("Current version " + currentVersion + " is prohibited" );
181
+ }
182
+ else {
183
+ VersionRange versionRange = prohibited .getRange ();
184
+ if (versionRange != null ) {
185
+ check (currentVersion , versionRange , errors );
174
186
}
175
- errors .add ("Version range " + versionRange + " is ineffective as the current version, "
176
- + currentVersion + ", is greater than its upper bound" );
177
187
}
178
188
}
189
+ return errors ;
179
190
}
180
- }
181
191
182
- private void checkVersionAlignment (Library library , List <String > errors ) {
183
- VersionAlignment versionAlignment = library .getVersionAlignment ();
184
- if (versionAlignment == null ) {
185
- return ;
192
+ private void check (ArtifactVersion currentVersion , VersionRange versionRange , List <String > errors ) {
193
+ for (Restriction restriction : versionRange .getRestrictions ()) {
194
+ ArtifactVersion upperBound = restriction .getUpperBound ();
195
+ if (upperBound == null ) {
196
+ return ;
197
+ }
198
+ int comparison = currentVersion .compareTo (upperBound );
199
+ if ((restriction .isUpperBoundInclusive () && comparison <= 0 )
200
+ || ((!restriction .isUpperBoundInclusive ()) && comparison < 0 )) {
201
+ return ;
202
+ }
203
+ }
204
+ errors .add ("Version range " + versionRange + " is ineffective as the current version, " + currentVersion
205
+ + ", is greater than its upper bound" );
186
206
}
187
- Set <String > alignedVersions = versionAlignment .resolve ();
188
- if (alignedVersions .size () == 1 ) {
189
- String alignedVersion = alignedVersions .iterator ().next ();
190
- if (!alignedVersion .equals (library .getVersion ().getVersion ().toString ())) {
191
- errors .add ("Version " + library .getVersion ().getVersion () + " is misaligned. It should be "
192
- + alignedVersion + "." );
207
+
208
+ }
209
+
210
+ private static final class CheckVersionAlignment implements LibraryCheck {
211
+
212
+ @ Override
213
+ public List <String > check (Library library ) {
214
+ List <String > errors = new ArrayList <>();
215
+ VersionAlignment versionAlignment = library .getVersionAlignment ();
216
+ if (versionAlignment != null ) {
217
+ check (versionAlignment , library , errors );
193
218
}
219
+ return errors ;
194
220
}
195
- else {
196
- if (alignedVersions .isEmpty ()) {
197
- errors .add ("Version alignment requires a single version but none were found." );
221
+
222
+ private void check (VersionAlignment versionAlignment , Library library , List <String > errors ) {
223
+ Set <String > alignedVersions = versionAlignment .resolve ();
224
+ if (alignedVersions .size () == 1 ) {
225
+ String alignedVersion = alignedVersions .iterator ().next ();
226
+ if (!alignedVersion .equals (library .getVersion ().getVersion ().toString ())) {
227
+ errors .add ("Version " + library .getVersion ().getVersion () + " is misaligned. It should be "
228
+ + alignedVersion + "." );
229
+ }
198
230
}
199
231
else {
200
- errors .add ("Version alignment requires a single version but " + alignedVersions .size () + " were found: "
201
- + alignedVersions + "." );
232
+ if (alignedVersions .isEmpty ()) {
233
+ errors .add ("Version alignment requires a single version but none were found." );
234
+ }
235
+ else {
236
+ errors .add ("Version alignment requires a single version but " + alignedVersions .size ()
237
+ + " were found: " + alignedVersions + "." );
238
+ }
202
239
}
203
240
}
204
- }
205
241
206
- private void checkDependencyManagementAlignment (Library library , List <String > errors ) {
207
- String alignsWithBom = library .getAlignsWithBom ();
208
- if (alignsWithBom == null ) {
209
- return ;
210
- }
211
- Bom mavenBom = this .bomResolver .resolveMavenBom (alignsWithBom + ":" + library .getVersion ().getVersion ());
212
- ResolvedBom resolvedBom = this .resolvedBom .get ();
213
- Optional <ResolvedLibrary > resolvedLibrary = resolvedBom .libraries ()
214
- .stream ()
215
- .filter ((candidate ) -> candidate .name ().equals (library .getName ()))
216
- .findFirst ();
217
- if (!resolvedLibrary .isPresent ()) {
218
- throw new RuntimeException ("Library '%s' not found in resolved bom" .formatted (library .getName ()));
219
- }
220
- checkDependencyManagementAlignment (resolvedLibrary .get (), mavenBom , errors );
221
242
}
222
243
223
- private void checkDependencyManagementAlignment (ResolvedLibrary library , Bom mavenBom , List <String > errors ) {
224
- List <Id > managedByLibrary = library .managedDependencies ();
225
- List <Id > managedByBom = managedDependenciesOf (mavenBom );
244
+ private static final class CheckDependencyManagementAlignment implements LibraryCheck {
226
245
227
- List <Id > missing = new ArrayList <>(managedByBom );
228
- missing .removeAll (managedByLibrary );
246
+ private final Provider <ResolvedBom > resolvedBom ;
229
247
230
- List <Id > unexpected = new ArrayList <>(managedByLibrary );
231
- unexpected .removeAll (managedByBom );
232
- if (missing .isEmpty () && unexpected .isEmpty ()) {
233
- return ;
248
+ private final BomResolver bomResolver ;
249
+
250
+ private CheckDependencyManagementAlignment (Provider <ResolvedBom > resolvedBom ,
251
+ ConfigurationContainer configurations , DependencyHandler dependencies ) {
252
+ this .resolvedBom = resolvedBom ;
253
+ this .bomResolver = new BomResolver (configurations , dependencies );
234
254
}
235
- String error = "Dependency management does not align with " + mavenBom .id () + ":" ;
236
- if (!missing .isEmpty ()) {
237
- error = error + "%n - Missing:%n %s" .formatted (String .join ("\n " ,
238
- missing .stream ().map ((dependency ) -> dependency .toString ()).toList ()));
255
+
256
+ @ Override
257
+ 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 ;
239
267
}
240
- if (!unexpected .isEmpty ()) {
241
- error = error + "%n - Unexpected:%n %s" .formatted (String .join ("\n " ,
242
- unexpected .stream ().map ((dependency ) -> dependency .toString ()).toList ()));
268
+
269
+ private ResolvedLibrary getResolvedLibrary (Library library ) {
270
+ ResolvedBom resolvedBom = this .resolvedBom .get ();
271
+ Optional <ResolvedLibrary > resolvedLibrary = resolvedBom .libraries ()
272
+ .stream ()
273
+ .filter ((candidate ) -> candidate .name ().equals (library .getName ()))
274
+ .findFirst ();
275
+ if (!resolvedLibrary .isPresent ()) {
276
+ throw new RuntimeException ("Library '%s' not found in resolved bom" .formatted (library .getName ()));
277
+ }
278
+ return resolvedLibrary .get ();
243
279
}
244
- errors .add (error );
245
- }
246
280
247
- private List <Id > managedDependenciesOf (Bom mavenBom ) {
248
- List <Id > managedDependencies = new ArrayList <>();
249
- managedDependencies .addAll (mavenBom .managedDependencies ());
250
- if (mavenBom .parent () != null ) {
251
- managedDependencies .addAll (managedDependenciesOf (mavenBom .parent ()));
281
+ private void checkDependencyManagementAlignment (ResolvedLibrary library , Bom mavenBom , List <String > errors ) {
282
+ List <Id > managedByLibrary = library .managedDependencies ();
283
+ List <Id > managedByBom = managedDependenciesOf (mavenBom );
284
+
285
+ List <Id > missing = new ArrayList <>(managedByBom );
286
+ missing .removeAll (managedByLibrary );
287
+
288
+ List <Id > unexpected = new ArrayList <>(managedByLibrary );
289
+ unexpected .removeAll (managedByBom );
290
+ if (missing .isEmpty () && unexpected .isEmpty ()) {
291
+ return ;
292
+ }
293
+ String error = "Dependency management does not align with " + mavenBom .id () + ":" ;
294
+ if (!missing .isEmpty ()) {
295
+ error = error + "%n - Missing:%n %s" .formatted (String .join ("\n " ,
296
+ missing .stream ().map ((dependency ) -> dependency .toString ()).toList ()));
297
+ }
298
+ if (!unexpected .isEmpty ()) {
299
+ error = error + "%n - Unexpected:%n %s" .formatted (String .join ("\n " ,
300
+ unexpected .stream ().map ((dependency ) -> dependency .toString ()).toList ()));
301
+ }
302
+ errors .add (error );
252
303
}
253
- for (Bom importedBom : mavenBom .importedBoms ()) {
254
- managedDependencies .addAll (managedDependenciesOf (importedBom ));
304
+
305
+ private List <Id > managedDependenciesOf (Bom mavenBom ) {
306
+ List <Id > managedDependencies = new ArrayList <>();
307
+ managedDependencies .addAll (mavenBom .managedDependencies ());
308
+ if (mavenBom .parent () != null ) {
309
+ managedDependencies .addAll (managedDependenciesOf (mavenBom .parent ()));
310
+ }
311
+ for (Bom importedBom : mavenBom .importedBoms ()) {
312
+ managedDependencies .addAll (managedDependenciesOf (importedBom ));
313
+ }
314
+ return managedDependencies ;
255
315
}
256
- return managedDependencies ;
316
+
257
317
}
258
318
259
319
}
0 commit comments