|
1 | 1 | /*
|
2 |
| - * Copyright 2012-2024 the original author or authors. |
| 2 | + * Copyright 2012-2025 the original author or authors. |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
16 | 16 |
|
17 | 17 | package org.springframework.boot.build.bom;
|
18 | 18 |
|
19 |
| -import java.io.File; |
20 | 19 | import java.util.ArrayList;
|
21 | 20 | import java.util.List;
|
| 21 | +import java.util.Optional; |
22 | 22 | import java.util.Set;
|
23 | 23 | import java.util.TreeSet;
|
24 | 24 | import java.util.stream.Collectors;
|
|
32 | 32 | import org.gradle.api.DefaultTask;
|
33 | 33 | import org.gradle.api.GradleException;
|
34 | 34 | import org.gradle.api.artifacts.ConfigurationContainer;
|
35 |
| -import org.gradle.api.artifacts.ResolvedArtifact; |
36 | 35 | import org.gradle.api.artifacts.dsl.DependencyHandler;
|
| 36 | +import org.gradle.api.file.RegularFile; |
| 37 | +import org.gradle.api.file.RegularFileProperty; |
| 38 | +import org.gradle.api.provider.Provider; |
| 39 | +import org.gradle.api.tasks.InputFile; |
| 40 | +import org.gradle.api.tasks.PathSensitive; |
| 41 | +import org.gradle.api.tasks.PathSensitivity; |
37 | 42 | import org.gradle.api.tasks.TaskAction;
|
38 | 43 |
|
39 | 44 | import org.springframework.boot.build.bom.Library.Group;
|
40 | 45 | import org.springframework.boot.build.bom.Library.Module;
|
41 | 46 | import org.springframework.boot.build.bom.Library.ProhibitedVersion;
|
42 | 47 | import org.springframework.boot.build.bom.Library.VersionAlignment;
|
43 |
| -import org.springframework.boot.build.bom.ManagedDependencies.Difference; |
| 48 | +import org.springframework.boot.build.bom.ResolvedBom.Bom; |
| 49 | +import org.springframework.boot.build.bom.ResolvedBom.Id; |
| 50 | +import org.springframework.boot.build.bom.ResolvedBom.ResolvedLibrary; |
44 | 51 | import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
|
45 | 52 |
|
46 | 53 | /**
|
|
51 | 58 | */
|
52 | 59 | public abstract class CheckBom extends DefaultTask {
|
53 | 60 |
|
| 61 | + private final Provider<ResolvedBom> resolvedBom; |
| 62 | + |
54 | 63 | private final ConfigurationContainer configurations;
|
55 | 64 |
|
56 | 65 | private final DependencyHandler dependencies;
|
57 | 66 |
|
58 | 67 | private final BomExtension bom;
|
59 | 68 |
|
| 69 | + private final BomResolver bomResolver; |
| 70 | + |
60 | 71 | @Inject
|
61 | 72 | public CheckBom(BomExtension bom) {
|
62 |
| - this.bom = bom; |
63 | 73 | this.configurations = getProject().getConfigurations();
|
64 | 74 | this.dependencies = getProject().getDependencies();
|
| 75 | + this.bom = bom; |
| 76 | + this.resolvedBom = getResolvedBomFile().map(RegularFile::getAsFile).map(ResolvedBom::readFrom); |
| 77 | + this.bomResolver = new BomResolver(this.configurations, this.dependencies); |
65 | 78 | }
|
66 | 79 |
|
| 80 | + @InputFile |
| 81 | + @PathSensitive(PathSensitivity.RELATIVE) |
| 82 | + abstract RegularFileProperty getResolvedBomFile(); |
| 83 | + |
67 | 84 | @TaskAction
|
68 | 85 | void checkBom() {
|
69 | 86 | List<String> errors = new ArrayList<>();
|
@@ -191,35 +208,52 @@ private void checkDependencyManagementAlignment(Library library, List<String> er
|
191 | 208 | if (alignsWithBom == null) {
|
192 | 209 | return;
|
193 | 210 | }
|
194 |
| - File bom = resolveBom(library, alignsWithBom); |
195 |
| - ManagedDependencies managedByBom = ManagedDependencies.ofBom(bom); |
196 |
| - ManagedDependencies managedByLibrary = ManagedDependencies.ofLibrary(library); |
197 |
| - Difference diff = managedByBom.diff(managedByLibrary); |
198 |
| - if (!diff.isEmpty()) { |
199 |
| - String error = "Dependency management does not align with " + library.getAlignsWithBom() + ":"; |
200 |
| - if (!diff.missing().isEmpty()) { |
201 |
| - error = error + "%n - Missing:%n %s" |
202 |
| - .formatted(String.join("\n ", diff.missing())); |
203 |
| - } |
204 |
| - if (!diff.unexpected().isEmpty()) { |
205 |
| - error = error + "%n - Unexpected:%n %s" |
206 |
| - .formatted(String.join("\n ", diff.unexpected())); |
207 |
| - } |
208 |
| - errors.add(error); |
| 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())); |
209 | 219 | }
|
| 220 | + checkDependencyManagementAlignment(resolvedLibrary.get(), mavenBom, errors); |
210 | 221 | }
|
211 | 222 |
|
212 |
| - private File resolveBom(Library library, String alignsWithBom) { |
213 |
| - String coordinates = alignsWithBom + ":" + library.getVersion().getVersion() + "@pom"; |
214 |
| - Set<ResolvedArtifact> artifacts = this.configurations |
215 |
| - .detachedConfiguration(this.dependencies.create(coordinates)) |
216 |
| - .getResolvedConfiguration() |
217 |
| - .getResolvedArtifacts(); |
218 |
| - if (artifacts.size() != 1) { |
219 |
| - throw new IllegalStateException("Expected a single artifact but '%s' resolved to %d artifacts" |
220 |
| - .formatted(coordinates, artifacts.size())); |
| 223 | + private void checkDependencyManagementAlignment(ResolvedLibrary library, Bom mavenBom, List<String> errors) { |
| 224 | + List<Id> managedByLibrary = library.managedDependencies(); |
| 225 | + List<Id> managedByBom = managedDependenciesOf(mavenBom); |
| 226 | + |
| 227 | + List<Id> missing = new ArrayList<>(managedByBom); |
| 228 | + missing.removeAll(managedByLibrary); |
| 229 | + |
| 230 | + List<Id> unexpected = new ArrayList<>(managedByLibrary); |
| 231 | + unexpected.removeAll(managedByBom); |
| 232 | + if (missing.isEmpty() && unexpected.isEmpty()) { |
| 233 | + return; |
| 234 | + } |
| 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())); |
| 239 | + } |
| 240 | + if (!unexpected.isEmpty()) { |
| 241 | + error = error + "%n - Unexpected:%n %s".formatted(String.join("\n ", |
| 242 | + unexpected.stream().map((dependency) -> dependency.toString()).toList())); |
| 243 | + } |
| 244 | + errors.add(error); |
| 245 | + } |
| 246 | + |
| 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())); |
| 252 | + } |
| 253 | + for (Bom importedBom : mavenBom.importedBoms()) { |
| 254 | + managedDependencies.addAll(managedDependenciesOf(importedBom)); |
221 | 255 | }
|
222 |
| - return artifacts.iterator().next().getFile(); |
| 256 | + return managedDependencies; |
223 | 257 | }
|
224 | 258 |
|
225 | 259 | }
|
0 commit comments