|
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