Skip to content

Commit 9fa4e0d

Browse files
committed
Merge branch '3.3.x' into 3.4.x
2 parents 7f971d2 + 9cd6af9 commit 9fa4e0d

File tree

1 file changed

+189
-129
lines changed
  • buildSrc/src/main/java/org/springframework/boot/build/bom

1 file changed

+189
-129
lines changed

buildSrc/src/main/java/org/springframework/boot/build/bom/CheckBom.java

+189-129
Original file line numberDiff line numberDiff line change
@@ -58,34 +58,30 @@
5858
*/
5959
public abstract class CheckBom extends DefaultTask {
6060

61-
private final Provider<ResolvedBom> resolvedBom;
62-
63-
private final ConfigurationContainer configurations;
64-
65-
private final DependencyHandler dependencies;
66-
6761
private final BomExtension bom;
6862

69-
private final BomResolver bomResolver;
63+
private final List<LibraryCheck> checks;
7064

7165
@Inject
7266
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));
7573
this.bom = bom;
76-
this.resolvedBom = getResolvedBomFile().map(RegularFile::getAsFile).map(ResolvedBom::readFrom);
77-
this.bomResolver = new BomResolver(this.configurations, this.dependencies);
7874
}
7975

8076
@InputFile
8177
@PathSensitive(PathSensitivity.RELATIVE)
82-
abstract RegularFileProperty getResolvedBomFile();
78+
public abstract RegularFileProperty getResolvedBomFile();
8379

8480
@TaskAction
8581
void checkBom() {
8682
List<String> errors = new ArrayList<>();
8783
for (Library library : this.bom.getLibraries()) {
88-
checkLibrary(library, errors);
84+
errors.addAll(checkLibrary(library));
8985
}
9086
if (!errors.isEmpty()) {
9187
System.out.println();
@@ -95,165 +91,229 @@ void checkBom() {
9591
}
9692
}
9793

98-
private void checkLibrary(Library library, List<String> errors) {
94+
private List<String> checkLibrary(Library library) {
9995
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<>();
10498
if (!libraryErrors.isEmpty()) {
10599
errors.add(library.getName());
106100
for (String libraryError : libraryErrors) {
107101
errors.add(" - " + libraryError);
108102
}
109103
}
104+
return errors;
105+
}
106+
107+
private interface LibraryCheck {
108+
109+
List<String> check(Library library);
110+
110111
}
111112

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+
}
117132
}
118133
}
134+
return errors;
119135
}
120-
}
121136

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 {
141160
unused.add(exclusion);
142161
}
143162
}
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);
147167
}
148168
}
149-
exclusions.removeAll(resolved);
150-
if (!unused.isEmpty()) {
151-
errors.add("Unnecessary exclusions on " + groupId + ":" + module.getName() + ": " + exclusions);
152-
}
169+
153170
}
154171

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);
174186
}
175-
errors.add("Version range " + versionRange + " is ineffective as the current version, "
176-
+ currentVersion + ", is greater than its upper bound");
177187
}
178188
}
189+
return errors;
179190
}
180-
}
181191

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");
186206
}
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);
193218
}
219+
return errors;
194220
}
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+
}
198230
}
199231
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+
}
202239
}
203240
}
204-
}
205241

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);
221242
}
222243

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 {
226245

227-
List<Id> missing = new ArrayList<>(managedByBom);
228-
missing.removeAll(managedByLibrary);
246+
private final Provider<ResolvedBom> resolvedBom;
229247

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);
234254
}
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;
239267
}
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();
243279
}
244-
errors.add(error);
245-
}
246280

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);
252303
}
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;
255315
}
256-
return managedDependencies;
316+
257317
}
258318

259319
}

0 commit comments

Comments
 (0)