mirror of
https://github.com/rife2/bld
synced 2026-07-25 00:47:47 +02:00
Apply BOMs across scopes like classpaths and harden overrides and publishing
Some checks are pending
bld-ci / build (./bld, 17, macos-latest, false) (push) Waiting to run
bld-ci / build (./bld, 21, macos-latest, false) (push) Waiting to run
bld-ci / build (./bld, 25, macos-latest, false) (push) Waiting to run
bld-ci / build (./bld, 26, macos-latest, false) (push) Waiting to run
bld-ci / build (.\bld.bat, 17, windows-latest, false) (push) Waiting to run
bld-ci / build (.\bld.bat, 21, windows-latest, false) (push) Waiting to run
bld-ci / build (.\bld.bat, 25, windows-latest, false) (push) Waiting to run
bld-ci / build (.\bld.bat, 26, windows-latest, false) (push) Waiting to run
bld-ci / build (unittests, password, unittests, mariadb:10.9, mysql:8, gvenzl/oracle-free:latest, gvenzl/oracle-xe:18-slim, postgres:15, ./bld, 17, ubuntu-latest, true) (push) Waiting to run
bld-ci / build (unittests, password, unittests, mariadb:10.9, mysql:8, gvenzl/oracle-free:latest, gvenzl/oracle-xe:18-slim, postgres:15, ./bld, 21, ubuntu-latest, true) (push) Waiting to run
bld-ci / build (unittests, password, unittests, mariadb:10.9, mysql:8, gvenzl/oracle-free:latest, gvenzl/oracle-xe:18-slim, postgres:15, ./bld, 25, ubuntu-latest, true) (push) Waiting to run
bld-ci / build (unittests, password, unittests, mariadb:10.9, mysql:8, gvenzl/oracle-free:latest, gvenzl/oracle-xe:18-slim, postgres:15, ./bld, 26, ubuntu-latest, true) (push) Waiting to run
javadocs-pages / deploy (push) Waiting to run
Some checks are pending
bld-ci / build (./bld, 17, macos-latest, false) (push) Waiting to run
bld-ci / build (./bld, 21, macos-latest, false) (push) Waiting to run
bld-ci / build (./bld, 25, macos-latest, false) (push) Waiting to run
bld-ci / build (./bld, 26, macos-latest, false) (push) Waiting to run
bld-ci / build (.\bld.bat, 17, windows-latest, false) (push) Waiting to run
bld-ci / build (.\bld.bat, 21, windows-latest, false) (push) Waiting to run
bld-ci / build (.\bld.bat, 25, windows-latest, false) (push) Waiting to run
bld-ci / build (.\bld.bat, 26, windows-latest, false) (push) Waiting to run
bld-ci / build (unittests, password, unittests, mariadb:10.9, mysql:8, gvenzl/oracle-free:latest, gvenzl/oracle-xe:18-slim, postgres:15, ./bld, 17, ubuntu-latest, true) (push) Waiting to run
bld-ci / build (unittests, password, unittests, mariadb:10.9, mysql:8, gvenzl/oracle-free:latest, gvenzl/oracle-xe:18-slim, postgres:15, ./bld, 21, ubuntu-latest, true) (push) Waiting to run
bld-ci / build (unittests, password, unittests, mariadb:10.9, mysql:8, gvenzl/oracle-free:latest, gvenzl/oracle-xe:18-slim, postgres:15, ./bld, 25, ubuntu-latest, true) (push) Waiting to run
bld-ci / build (unittests, password, unittests, mariadb:10.9, mysql:8, gvenzl/oracle-free:latest, gvenzl/oracle-xe:18-slim, postgres:15, ./bld, 26, ubuntu-latest, true) (push) Waiting to run
javadocs-pages / deploy (push) Waiting to run
This commit is contained in:
parent
49e21cfeb8
commit
c9298d3de6
|
|
@ -1032,9 +1032,10 @@ public class BaseProject extends BuildExecutor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new bill of materials instance from a string representation.
|
* Creates a new bill of materials instance from a string representation.
|
||||||
* The format is {@code groupId:artifactId:version:classifier}.
|
* The format is {@code groupId:artifactId:version}.
|
||||||
* The {@code version} and {@code classifier} are optional, and an
|
* The {@code version} is optional, and an optional {@code @bom} or
|
||||||
* optional {@code @bom} or {@code @pom} type suffix is accepted.
|
* {@code @pom} type suffix is accepted. BOMs can't have classifiers,
|
||||||
|
* strings that contain one are rejected.
|
||||||
* <p>
|
* <p>
|
||||||
* If the string can't be successfully parsed, {@code null} will be returned.
|
* If the string can't be successfully parsed, {@code null} will be returned.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -24,24 +24,21 @@ import java.util.regex.Pattern;
|
||||||
*/
|
*/
|
||||||
public class Bom extends Dependency {
|
public class Bom extends Dependency {
|
||||||
public Bom(String groupId, String artifactId) {
|
public Bom(String groupId, String artifactId) {
|
||||||
this(groupId, artifactId, null, null);
|
this(groupId, artifactId, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bom(String groupId, String artifactId, Version version) {
|
public Bom(String groupId, String artifactId, Version version) {
|
||||||
this(groupId, artifactId, version, null);
|
super(groupId, artifactId, version, null, TYPE_BOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bom(String groupId, String artifactId, Version version, String classifier) {
|
private static final Pattern BOM_PATTERN = Pattern.compile("^(?<groupId>[^:@]+):(?<artifactId>[^:@]+)(?::(?<version>[^:@]+))?(?:@(?:bom|pom))?$");
|
||||||
super(groupId, artifactId, version, classifier, TYPE_BOM);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Pattern BOM_PATTERN = Pattern.compile("^(?<groupId>[^:@]+):(?<artifactId>[^:@]+)(?::(?<version>[^:@]+)(?::(?<classifier>[^:@]+))?)?(?:@(?:bom|pom))?$");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a BOM from a string representation.
|
* Parses a BOM from a string representation.
|
||||||
* The format is {@code groupId:artifactId:version:classifier}.
|
* The format is {@code groupId:artifactId:version}.
|
||||||
* The {@code version} and {@code classifier} are optional, and an
|
* The {@code version} is optional, and an optional {@code @bom} or
|
||||||
* optional {@code @bom} or {@code @pom} type suffix is accepted.
|
* {@code @pom} type suffix is accepted. BOMs can't have classifiers,
|
||||||
|
* strings that contain one are rejected.
|
||||||
* <p>
|
* <p>
|
||||||
* If the string can't be successfully parsed, {@code null} will be returned.
|
* If the string can't be successfully parsed, {@code null} will be returned.
|
||||||
*
|
*
|
||||||
|
|
@ -63,8 +60,7 @@ public class Bom extends Dependency {
|
||||||
var groupId = matcher.group("groupId");
|
var groupId = matcher.group("groupId");
|
||||||
var artifactId = matcher.group("artifactId");
|
var artifactId = matcher.group("artifactId");
|
||||||
var version = Version.parse(matcher.group("version"));
|
var version = Version.parse(matcher.group("version"));
|
||||||
var classifier = matcher.group("classifier");
|
|
||||||
|
|
||||||
return new Bom(groupId, artifactId, version, classifier);
|
return new Bom(groupId, artifactId, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,28 +68,72 @@ public class DependencyScopes extends LinkedHashMap<Scope, DependencySet> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the version-less dependencies that are not covered by the
|
* Returns the BOMs that apply to the version resolution of a particular
|
||||||
* BOMs that are declared in their scope.
|
* scope.
|
||||||
* <p>
|
* <p>
|
||||||
* Scopes that don't declare any BOMs are not considered, their
|
* BOMs follow the same scope composition as the classpaths: the
|
||||||
|
* {@code compile} scope BOMs also apply to the {@code provided},
|
||||||
|
* {@code runtime} and {@code test} scopes, and the {@code runtime} and
|
||||||
|
* {@code provided} scope BOMs also apply to the {@code test} scope.
|
||||||
|
* The BOMs are returned in classpath order, for the {@code test} scope
|
||||||
|
* that is {@code compile}, {@code provided}, {@code runtime},
|
||||||
|
* {@code test}, and this order determines their precedence when
|
||||||
|
* several manage the same dependency.
|
||||||
|
* <p>
|
||||||
|
* The {@code standalone} scope only uses its own BOMs, and its BOMs
|
||||||
|
* deliberately never apply to any other scope.
|
||||||
|
*
|
||||||
|
* @param scope the scope to retrieve the applicable BOMs for
|
||||||
|
* @return the BOMs that apply to the scope's version resolution
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
public List<Bom> effectiveBoms(Scope scope) {
|
||||||
|
var boms = new ArrayList<Bom>();
|
||||||
|
for (var bom_scope : bomScopes(scope)) {
|
||||||
|
var scoped_dependencies = get(bom_scope);
|
||||||
|
if (scoped_dependencies != null) {
|
||||||
|
boms.addAll(scoped_dependencies.boms());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return boms;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Scope[] bomScopes(Scope scope) {
|
||||||
|
return switch (scope) {
|
||||||
|
case provided -> new Scope[]{Scope.compile, Scope.provided};
|
||||||
|
case runtime -> new Scope[]{Scope.compile, Scope.runtime};
|
||||||
|
case test -> new Scope[]{Scope.compile, Scope.provided, Scope.runtime, Scope.test};
|
||||||
|
default -> new Scope[]{scope};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the version-less dependencies that are not covered by the
|
||||||
|
* BOMs that apply to their scope.
|
||||||
|
* <p>
|
||||||
|
* Scopes that no BOMs apply to are not considered, their
|
||||||
* version-less dependencies simply resolve to the latest version.
|
* version-less dependencies simply resolve to the latest version.
|
||||||
|
* Dependencies whose version is supplied by a {@code bld.override}
|
||||||
|
* property are not reported either.
|
||||||
*
|
*
|
||||||
* @param properties the properties to use to get artifacts
|
* @param properties the properties to use to get artifacts
|
||||||
* @param retriever the retriever to use to get artifacts
|
* @param retriever the retriever to use to get artifacts
|
||||||
* @param repositories the repositories to use for the BOM resolution
|
* @param repositories the repositories to use for the BOM resolution
|
||||||
* @return the version-less dependencies that no BOM in their scope covers
|
* @return the version-less dependencies that no applicable BOM covers
|
||||||
* @since 2.4.0
|
* @since 2.4.0
|
||||||
*/
|
*/
|
||||||
public List<Dependency> versionlessDependenciesWithoutBom(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
|
public List<Dependency> versionlessDependenciesWithoutBom(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
|
||||||
var result = new ArrayList<Dependency>();
|
var result = new ArrayList<Dependency>();
|
||||||
for (var scoped_dependencies : values()) {
|
for (var entry : entrySet()) {
|
||||||
if (scoped_dependencies.boms().isEmpty()) {
|
var effective_boms = effectiveBoms(entry.getKey());
|
||||||
|
if (effective_boms.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var resolution = new VersionResolution(properties, retriever, repositories, scoped_dependencies.boms());
|
var resolution = new VersionResolution(properties, retriever, repositories, effective_boms);
|
||||||
for (var dependency : scoped_dependencies) {
|
for (var dependency : entry.getValue()) {
|
||||||
if (dependency.version().equals(VersionNumber.UNKNOWN) &&
|
if (dependency.version().equals(VersionNumber.UNKNOWN) &&
|
||||||
!resolution.bomVersions().containsKey(dependency.toArtifactString()) &&
|
!resolution.coversDependency(dependency) &&
|
||||||
|
!resolution.versionOverrides().containsKey(dependency.toArtifactString()) &&
|
||||||
!result.contains(dependency)) {
|
!result.contains(dependency)) {
|
||||||
result.add(dependency);
|
result.add(dependency);
|
||||||
}
|
}
|
||||||
|
|
@ -109,6 +153,7 @@ public class DependencyScopes extends LinkedHashMap<Scope, DependencySet> {
|
||||||
*/
|
*/
|
||||||
public DependencySet resolveCompileDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
|
public DependencySet resolveCompileDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
|
||||||
return resolveScopedDependencies(properties, retriever, repositories,
|
return resolveScopedDependencies(properties, retriever, repositories,
|
||||||
|
Scope.compile,
|
||||||
new Scope[]{Scope.compile},
|
new Scope[]{Scope.compile},
|
||||||
new Scope[]{Scope.compile},
|
new Scope[]{Scope.compile},
|
||||||
null);
|
null);
|
||||||
|
|
@ -125,6 +170,7 @@ public class DependencyScopes extends LinkedHashMap<Scope, DependencySet> {
|
||||||
*/
|
*/
|
||||||
public DependencySet resolveProvidedDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
|
public DependencySet resolveProvidedDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
|
||||||
return resolveScopedDependencies(properties, retriever, repositories,
|
return resolveScopedDependencies(properties, retriever, repositories,
|
||||||
|
Scope.provided,
|
||||||
new Scope[]{Scope.provided},
|
new Scope[]{Scope.provided},
|
||||||
new Scope[]{Scope.compile, Scope.runtime},
|
new Scope[]{Scope.compile, Scope.runtime},
|
||||||
null);
|
null);
|
||||||
|
|
@ -141,6 +187,7 @@ public class DependencyScopes extends LinkedHashMap<Scope, DependencySet> {
|
||||||
*/
|
*/
|
||||||
public DependencySet resolveRuntimeDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
|
public DependencySet resolveRuntimeDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
|
||||||
return resolveScopedDependencies(properties, retriever, repositories,
|
return resolveScopedDependencies(properties, retriever, repositories,
|
||||||
|
Scope.runtime,
|
||||||
new Scope[]{Scope.compile, Scope.runtime},
|
new Scope[]{Scope.compile, Scope.runtime},
|
||||||
new Scope[]{Scope.compile, Scope.runtime},
|
new Scope[]{Scope.compile, Scope.runtime},
|
||||||
resolveCompileDependencies(properties, retriever, repositories));
|
resolveCompileDependencies(properties, retriever, repositories));
|
||||||
|
|
@ -157,6 +204,7 @@ public class DependencyScopes extends LinkedHashMap<Scope, DependencySet> {
|
||||||
*/
|
*/
|
||||||
public DependencySet resolveStandaloneDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
|
public DependencySet resolveStandaloneDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
|
||||||
return resolveScopedDependencies(properties, retriever, repositories,
|
return resolveScopedDependencies(properties, retriever, repositories,
|
||||||
|
Scope.standalone,
|
||||||
new Scope[]{Scope.standalone},
|
new Scope[]{Scope.standalone},
|
||||||
new Scope[]{Scope.compile, Scope.runtime},
|
new Scope[]{Scope.compile, Scope.runtime},
|
||||||
null);
|
null);
|
||||||
|
|
@ -173,22 +221,21 @@ public class DependencyScopes extends LinkedHashMap<Scope, DependencySet> {
|
||||||
*/
|
*/
|
||||||
public DependencySet resolveTestDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
|
public DependencySet resolveTestDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
|
||||||
return resolveScopedDependencies(properties, retriever, repositories,
|
return resolveScopedDependencies(properties, retriever, repositories,
|
||||||
|
Scope.test,
|
||||||
new Scope[]{Scope.test},
|
new Scope[]{Scope.test},
|
||||||
new Scope[]{Scope.compile, Scope.runtime},
|
new Scope[]{Scope.compile, Scope.runtime},
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DependencySet resolveScopedDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories, Scope[] resolvedScopes, Scope[] transitiveScopes, DependencySet excluded) {
|
private DependencySet resolveScopedDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories, Scope scope, Scope[] resolvedScopes, Scope[] transitiveScopes, DependencySet excluded) {
|
||||||
var roots = new ArrayList<Dependency>();
|
var roots = new ArrayList<Dependency>();
|
||||||
var boms = new ArrayList<Bom>();
|
for (var resolved_scope : resolvedScopes) {
|
||||||
for (var scope : resolvedScopes) {
|
var scoped_dependencies = get(resolved_scope);
|
||||||
var scoped_dependencies = get(scope);
|
|
||||||
if (scoped_dependencies != null) {
|
if (scoped_dependencies != null) {
|
||||||
roots.addAll(scoped_dependencies);
|
roots.addAll(scoped_dependencies);
|
||||||
boms.addAll(scoped_dependencies.boms());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var resolution = new VersionResolution(properties, retriever, repositories, boms);
|
var resolution = new VersionResolution(properties, retriever, repositories, effectiveBoms(scope));
|
||||||
var dependencies = new ParallelDependencyResolver(resolution, retriever, repositories).resolveAllDependencies(roots, transitiveScopes);
|
var dependencies = new ParallelDependencyResolver(resolution, retriever, repositories).resolveAllDependencies(roots, transitiveScopes);
|
||||||
if (excluded != null) {
|
if (excluded != null) {
|
||||||
dependencies.removeAll(excluded);
|
dependencies.removeAll(excluded);
|
||||||
|
|
|
||||||
|
|
@ -148,11 +148,15 @@ public class VersionResolution {
|
||||||
this(base, resolveBomVersions(base, retriever, repositories, boms));
|
this(base, resolveBomVersions(base, retriever, repositories, boms));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns a resolution that additionally imports the provided BOMs,
|
||||||
|
// versions that are already imported take precedence over the new ones
|
||||||
VersionResolution withBoms(ArtifactRetriever retriever, List<Repository> repositories, Collection<Bom> boms) {
|
VersionResolution withBoms(ArtifactRetriever retriever, List<Repository> repositories, Collection<Bom> boms) {
|
||||||
if (boms == null || boms.isEmpty()) {
|
if (boms == null || boms.isEmpty()) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
return new VersionResolution(this, retriever, repositories, boms);
|
var merged = new HashMap<>(resolveBomVersions(this, retriever, repositories, boms));
|
||||||
|
merged.putAll(bomVersions_);
|
||||||
|
return new VersionResolution(this, merged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, Version> resolveBomVersions(VersionResolution resolution, ArtifactRetriever retriever, List<Repository> repositories, Collection<Bom> boms) {
|
private static Map<String, Version> resolveBomVersions(VersionResolution resolution, ArtifactRetriever retriever, List<Repository> repositories, Collection<Bom> boms) {
|
||||||
|
|
@ -163,7 +167,7 @@ public class VersionResolution {
|
||||||
for (var managed : pom.getManagedDependencies()) {
|
for (var managed : pom.getManagedDependencies()) {
|
||||||
if (managed.version() != null && !managed.version().isBlank()) {
|
if (managed.version() != null && !managed.version().isBlank()) {
|
||||||
var dependency = managed.convertToDependency();
|
var dependency = managed.convertToDependency();
|
||||||
bom_versions.putIfAbsent(dependency.toArtifactString(), dependency.version());
|
bom_versions.putIfAbsent(managedKey(dependency), dependency.version());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -171,6 +175,20 @@ public class VersionResolution {
|
||||||
return bom_versions;
|
return bom_versions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// builds the identity that dependency management entries are matched
|
||||||
|
// on, mirroring Maven this includes the type and the classifier, the
|
||||||
|
// modular and forced-classpath JAR types match the plain jar entries
|
||||||
|
// that BOMs manage
|
||||||
|
private static String managedKey(Dependency dependency) {
|
||||||
|
var type = dependency.type();
|
||||||
|
if (type == null || type.isBlank() ||
|
||||||
|
Dependency.TYPE_MODULAR_JAR.equals(type) ||
|
||||||
|
Dependency.TYPE_CLASSPATH_JAR.equals(type)) {
|
||||||
|
type = Dependency.TYPE_JAR;
|
||||||
|
}
|
||||||
|
return dependency.toArtifactString() + ":" + type + ":" + dependency.classifier();
|
||||||
|
}
|
||||||
|
|
||||||
private static int parseParallelism(HierarchicalProperties properties, String property, int defaultValue) {
|
private static int parseParallelism(HierarchicalProperties properties, String property, int defaultValue) {
|
||||||
if (properties != null) {
|
if (properties != null) {
|
||||||
var parallelism = properties.getValueString(property);
|
var parallelism = properties.getValueString(property);
|
||||||
|
|
@ -198,7 +216,7 @@ public class VersionResolution {
|
||||||
return overridden;
|
return overridden;
|
||||||
}
|
}
|
||||||
if (VersionNumber.UNKNOWN.equals(original.version())) {
|
if (VersionNumber.UNKNOWN.equals(original.version())) {
|
||||||
var bom_version = bomVersions_.get(original.toArtifactString());
|
var bom_version = bomVersions_.get(managedKey(original));
|
||||||
if (bom_version != null) {
|
if (bom_version != null) {
|
||||||
return bom_version;
|
return bom_version;
|
||||||
}
|
}
|
||||||
|
|
@ -239,7 +257,7 @@ public class VersionResolution {
|
||||||
public Dependency overrideDeclaredDependency(Dependency declared) {
|
public Dependency overrideDeclaredDependency(Dependency declared) {
|
||||||
var overridden = versionOverrides_.get(declared.toArtifactString());
|
var overridden = versionOverrides_.get(declared.toArtifactString());
|
||||||
if (overridden == null && VersionNumber.UNKNOWN.equals(declared.version())) {
|
if (overridden == null && VersionNumber.UNKNOWN.equals(declared.version())) {
|
||||||
overridden = bomVersions_.get(declared.toArtifactString());
|
overridden = bomVersions_.get(managedKey(declared));
|
||||||
}
|
}
|
||||||
if (overridden == null) {
|
if (overridden == null) {
|
||||||
return declared;
|
return declared;
|
||||||
|
|
@ -264,7 +282,7 @@ public class VersionResolution {
|
||||||
public Dependency overrideTransitiveDependency(Dependency transitive) {
|
public Dependency overrideTransitiveDependency(Dependency transitive) {
|
||||||
var overridden = versionOverrides_.get(transitive.toArtifactString());
|
var overridden = versionOverrides_.get(transitive.toArtifactString());
|
||||||
if (overridden == null) {
|
if (overridden == null) {
|
||||||
overridden = bomVersions_.get(transitive.toArtifactString());
|
overridden = bomVersions_.get(managedKey(transitive));
|
||||||
}
|
}
|
||||||
if (overridden == null) {
|
if (overridden == null) {
|
||||||
return transitive;
|
return transitive;
|
||||||
|
|
@ -292,10 +310,27 @@ public class VersionResolution {
|
||||||
return versionOverrides_;
|
return versionOverrides_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether a bill of materials supplies the version of a
|
||||||
|
* particular dependency.
|
||||||
|
* <p>
|
||||||
|
* The dependency identity takes the group, artifact, type and
|
||||||
|
* classifier into account, mirroring Maven's dependency management.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency to check
|
||||||
|
* @return {@code true} when a BOM manages the dependency's version;
|
||||||
|
* {@code false} otherwise
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
public boolean coversDependency(Dependency dependency) {
|
||||||
|
return bomVersions_.containsKey(managedKey(dependency));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the map of versions that were imported from bills of
|
* Returns the map of versions that were imported from bills of
|
||||||
* materials, where the key is the name of the dependency and the value
|
* materials, where the key is the dependency identity composed of the
|
||||||
* is the managed version.
|
* group, artifact, type and classifier, and the value is the managed
|
||||||
|
* version.
|
||||||
*
|
*
|
||||||
* @return the map of BOM versions
|
* @return the map of BOM versions
|
||||||
* @since 2.4.0
|
* @since 2.4.0
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
|
||||||
* @since 1.5.21
|
* @since 1.5.21
|
||||||
*/
|
*/
|
||||||
protected String executeGenerateCompileDependencies() {
|
protected String executeGenerateCompileDependencies() {
|
||||||
var compile_tree = dependencies().scope(compile).generateTransitiveDependencyTree(new VersionResolution(properties()), artifactRetriever(), repositories(), compile);
|
var compile_tree = dependencies().scope(compile).generateTransitiveDependencyTree(new VersionResolution(properties(), artifactRetriever(), repositories(), dependencies().effectiveBoms(compile)), artifactRetriever(), repositories(), compile);
|
||||||
if (compile_tree.isEmpty()) {
|
if (compile_tree.isEmpty()) {
|
||||||
compile_tree = "no dependencies" + System.lineSeparator();
|
compile_tree = "no dependencies" + System.lineSeparator();
|
||||||
}
|
}
|
||||||
|
|
@ -191,7 +191,7 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
|
||||||
* @since 1.7.3
|
* @since 1.7.3
|
||||||
*/
|
*/
|
||||||
protected String executeGenerateProvidedDependencies() {
|
protected String executeGenerateProvidedDependencies() {
|
||||||
var provided_tree = dependencies().scope(provided).generateTransitiveDependencyTree(new VersionResolution(properties()), artifactRetriever(), repositories(), compile, runtime);
|
var provided_tree = dependencies().scope(provided).generateTransitiveDependencyTree(new VersionResolution(properties(), artifactRetriever(), repositories(), dependencies().effectiveBoms(provided)), artifactRetriever(), repositories(), compile, runtime);
|
||||||
if (provided_tree.isEmpty()) {
|
if (provided_tree.isEmpty()) {
|
||||||
provided_tree = "no dependencies" + System.lineSeparator();
|
provided_tree = "no dependencies" + System.lineSeparator();
|
||||||
}
|
}
|
||||||
|
|
@ -204,7 +204,7 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
|
||||||
* @since 1.5.21
|
* @since 1.5.21
|
||||||
*/
|
*/
|
||||||
protected String executeGenerateRuntimeDependencies() {
|
protected String executeGenerateRuntimeDependencies() {
|
||||||
var runtime_tree = dependencies().scope(runtime).generateTransitiveDependencyTree(new VersionResolution(properties()), artifactRetriever(), repositories(), compile, runtime);
|
var runtime_tree = dependencies().scope(runtime).generateTransitiveDependencyTree(new VersionResolution(properties(), artifactRetriever(), repositories(), dependencies().effectiveBoms(runtime)), artifactRetriever(), repositories(), compile, runtime);
|
||||||
if (runtime_tree.isEmpty()) {
|
if (runtime_tree.isEmpty()) {
|
||||||
runtime_tree = "no dependencies" + System.lineSeparator();
|
runtime_tree = "no dependencies" + System.lineSeparator();
|
||||||
}
|
}
|
||||||
|
|
@ -217,7 +217,7 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
|
||||||
* @since 1.7.3
|
* @since 1.7.3
|
||||||
*/
|
*/
|
||||||
protected String executeGenerateTestDependencies() {
|
protected String executeGenerateTestDependencies() {
|
||||||
var test_tree = dependencies().scope(test).generateTransitiveDependencyTree(new VersionResolution(properties()), artifactRetriever(), repositories(), compile, runtime);
|
var test_tree = dependencies().scope(test).generateTransitiveDependencyTree(new VersionResolution(properties(), artifactRetriever(), repositories(), dependencies().effectiveBoms(test)), artifactRetriever(), repositories(), compile, runtime);
|
||||||
if (test_tree.isEmpty()) {
|
if (test_tree.isEmpty()) {
|
||||||
test_tree = "no dependencies" + System.lineSeparator();
|
test_tree = "no dependencies" + System.lineSeparator();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import java.security.*;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
|
@ -106,45 +107,96 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Part of the {@link #execute} operation, resolves the versions of
|
* Part of the {@link #execute} operation, freezes the versions of
|
||||||
* dependencies that were declared without one and that are not covered
|
* dependencies that were declared without one, so that the published
|
||||||
* by a BOM in the same scope, so that the published POM is always
|
* POM is always complete.
|
||||||
* complete.
|
|
||||||
* <p>
|
* <p>
|
||||||
* BOMs that were declared without a version are resolved to their
|
* Dependencies that are covered by a BOM that applies to their scope
|
||||||
* latest version too.
|
* stay version-less, the dependency management imports of the POM
|
||||||
|
* supply their versions. They are frozen anyway when the flattened
|
||||||
|
* dependency management of the POM would supply a different version
|
||||||
|
* than the BOMs that apply to their scope, or when a
|
||||||
|
* {@code bld.override} property supplies their version, since the POM
|
||||||
|
* can't reflect either. Uncovered dependencies are frozen to their
|
||||||
|
* latest version.
|
||||||
|
* <p>
|
||||||
|
* BOMs that were declared without a version are frozen too, to their
|
||||||
|
* {@code bld.override} version or to their latest version.
|
||||||
*
|
*
|
||||||
* @since 2.4.0
|
* @since 2.4.0
|
||||||
*/
|
*/
|
||||||
protected void executeResolveVersionlessDependencies() {
|
protected void executeResolveVersionlessDependencies() {
|
||||||
|
// freeze the versions of the declared BOMs, a version from a
|
||||||
|
// bld.override property is used by the build itself and takes
|
||||||
|
// precedence, version-less BOMs resolve to their latest version
|
||||||
|
var base_resolution = new VersionResolution(properties());
|
||||||
|
for (var scope : List.of(Scope.compile, Scope.runtime, Scope.provided)) {
|
||||||
|
var scoped_dependencies = dependencies().get(scope);
|
||||||
|
if (scoped_dependencies == null || scoped_dependencies.boms().isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var declared_boms = List.copyOf(scoped_dependencies.boms());
|
||||||
|
scoped_dependencies.boms().clear();
|
||||||
|
for (var bom : declared_boms) {
|
||||||
|
var version = base_resolution.overrideVersion(bom);
|
||||||
|
if (version.equals(VersionNumber.UNKNOWN)) {
|
||||||
|
version = new DependencyResolver(base_resolution, artifactRetriever(), dependencyRepositories(), bom).latestVersion();
|
||||||
|
}
|
||||||
|
if (!version.equals(bom.version())) {
|
||||||
|
bom = new Bom(bom.groupId(), bom.artifactId(), version);
|
||||||
|
}
|
||||||
|
scoped_dependencies.boms().add(bom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the published POM flattens all the BOM imports into a single
|
||||||
|
// dependency management list, compute the versions that this list
|
||||||
|
// supplies so that scoped differences can be frozen explicitly
|
||||||
|
var flattened_boms = new LinkedHashMap<String, Bom>();
|
||||||
|
for (var scope : List.of(Scope.compile, Scope.runtime, Scope.provided)) {
|
||||||
|
var scoped_dependencies = dependencies().get(scope);
|
||||||
|
if (scoped_dependencies != null) {
|
||||||
|
for (var bom : scoped_dependencies.boms()) {
|
||||||
|
flattened_boms.putIfAbsent(bom.toArtifactString(), bom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var flattened_resolution = new VersionResolution(properties(), artifactRetriever(), dependencyRepositories(), flattened_boms.values());
|
||||||
|
|
||||||
|
// freeze the versions of version-less dependencies that no
|
||||||
|
// applicable BOM covers
|
||||||
for (var scope : List.of(Scope.compile, Scope.runtime, Scope.provided)) {
|
for (var scope : List.of(Scope.compile, Scope.runtime, Scope.provided)) {
|
||||||
var scoped_dependencies = dependencies().get(scope);
|
var scoped_dependencies = dependencies().get(scope);
|
||||||
if (scoped_dependencies == null) {
|
if (scoped_dependencies == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve the versions of BOMs that were declared without one
|
var resolution = new VersionResolution(properties(), artifactRetriever(), dependencyRepositories(), dependencies().effectiveBoms(scope));
|
||||||
if (!scoped_dependencies.boms().isEmpty()) {
|
|
||||||
var base_resolution = new VersionResolution(properties());
|
|
||||||
var declared_boms = List.copyOf(scoped_dependencies.boms());
|
|
||||||
scoped_dependencies.boms().clear();
|
|
||||||
for (var bom : declared_boms) {
|
|
||||||
if (bom.version().equals(VersionNumber.UNKNOWN)) {
|
|
||||||
var latest = new DependencyResolver(base_resolution, artifactRetriever(), dependencyRepositories(), bom).latestVersion();
|
|
||||||
bom = new Bom(bom.groupId(), bom.artifactId(), latest, bom.classifier());
|
|
||||||
}
|
|
||||||
scoped_dependencies.boms().add(bom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var resolution = new VersionResolution(properties(), artifactRetriever(), dependencyRepositories(), scoped_dependencies.boms());
|
|
||||||
for (var dependency : List.copyOf(scoped_dependencies)) {
|
for (var dependency : List.copyOf(scoped_dependencies)) {
|
||||||
if (dependency.version().equals(VersionNumber.UNKNOWN) &&
|
if (!dependency.version().equals(VersionNumber.UNKNOWN)) {
|
||||||
!resolution.bomVersions().containsKey(dependency.toArtifactString())) {
|
continue;
|
||||||
var latest = new DependencyResolver(resolution, artifactRetriever(), dependencyRepositories(), dependency).latestVersion();
|
|
||||||
scoped_dependencies.add(new Dependency(dependency.groupId(), dependency.artifactId(), latest,
|
|
||||||
dependency.classifier(), dependency.type(), dependency.exclusions(), dependency.parent()));
|
|
||||||
}
|
}
|
||||||
|
// a version from a bld.override property is used by the
|
||||||
|
// build itself, it's frozen into the POM even when a BOM
|
||||||
|
// covers the dependency since the import can't reflect it
|
||||||
|
var version = resolution.versionOverrides().get(dependency.toArtifactString());
|
||||||
|
if (version == null) {
|
||||||
|
if (resolution.coversDependency(dependency)) {
|
||||||
|
// the dependency can only stay version-less when the
|
||||||
|
// flattened dependency management of the POM supplies
|
||||||
|
// the same version as the BOMs that apply to its scope
|
||||||
|
var scoped_version = resolution.overrideVersion(dependency);
|
||||||
|
if (scoped_version.equals(flattened_resolution.overrideVersion(dependency))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
version = scoped_version;
|
||||||
|
} else {
|
||||||
|
version = new DependencyResolver(resolution, artifactRetriever(), dependencyRepositories(), dependency).latestVersion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scoped_dependencies.add(new Dependency(dependency.groupId(), dependency.artifactId(), version,
|
||||||
|
dependency.classifier(), dependency.type(), dependency.exclusions(), dependency.parent()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,16 +42,21 @@ public class UpdatesOperation extends AbstractOperation<UpdatesOperation> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// dependencies that are declared without a version and that are
|
// dependencies that are declared without a version and that are
|
||||||
// covered by a BOM in the same scope have their version governed
|
// covered by a BOM that applies to their scope have their version
|
||||||
// by that BOM, the BOM update itself carries their update signal
|
// pinned by that BOM, the BOM update itself carries their update
|
||||||
var scope_resolution = new VersionResolution(properties(), artifactRetriever(), repositories(), scoped_dependencies.boms());
|
// signal, unless a bld.override supplies the version and takes
|
||||||
|
// that control away from the BOM
|
||||||
|
var scope_resolution = new VersionResolution(properties(), artifactRetriever(), repositories(), dependencies_.effectiveBoms(entry.getKey()));
|
||||||
for (var dependency : scoped_dependencies) {
|
for (var dependency : scoped_dependencies) {
|
||||||
if (VersionNumber.UNKNOWN.equals(dependency.version()) &&
|
if (VersionNumber.UNKNOWN.equals(dependency.version()) &&
|
||||||
scope_resolution.bomVersions().containsKey(dependency.toArtifactString())) {
|
scope_resolution.coversDependency(dependency) &&
|
||||||
|
!scope_resolution.versionOverrides().containsKey(dependency.toArtifactString())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
scopes.add(entry.getKey());
|
scopes.add(entry.getKey());
|
||||||
dependencies.add(dependency);
|
// an overridden version is the one the build uses, it's the
|
||||||
|
// baseline that update checks compare against
|
||||||
|
dependencies.add(scope_resolution.overrideDependency(dependency));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,8 +68,7 @@ public class UpdatesOperation extends AbstractOperation<UpdatesOperation> {
|
||||||
var latest = latest_versions.get(i);
|
var latest = latest_versions.get(i);
|
||||||
if (latest.compareTo(dependency.version()) > 0) {
|
if (latest.compareTo(dependency.version()) > 0) {
|
||||||
if (dependency instanceof Bom) {
|
if (dependency instanceof Bom) {
|
||||||
result.scope(scopes.get(i)).include(new Bom(dependency.groupId(), dependency.artifactId(), latest,
|
result.scope(scopes.get(i)).include(new Bom(dependency.groupId(), dependency.artifactId(), latest));
|
||||||
dependency.classifier()));
|
|
||||||
} else {
|
} else {
|
||||||
result.scope(scopes.get(i)).include(new Dependency(dependency.groupId(), dependency.artifactId(), latest,
|
result.scope(scopes.get(i)).include(new Dependency(dependency.groupId(), dependency.artifactId(), latest,
|
||||||
dependency.classifier(), dependency.type()));
|
dependency.classifier(), dependency.type()));
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,8 @@ public class TestBom {
|
||||||
assertEquals(new Bom("com.example", "bom1", new VersionNumber(1, 2, 3)), Bom.parse("com.example:bom1:1.2.3"));
|
assertEquals(new Bom("com.example", "bom1", new VersionNumber(1, 2, 3)), Bom.parse("com.example:bom1:1.2.3"));
|
||||||
assertEquals(new Bom("com.example", "bom1", new VersionNumber(1, 2, 3)), Bom.parse("com.example:bom1:1.2.3@bom"));
|
assertEquals(new Bom("com.example", "bom1", new VersionNumber(1, 2, 3)), Bom.parse("com.example:bom1:1.2.3@bom"));
|
||||||
assertEquals(new Bom("com.example", "bom1", new VersionNumber(1, 2, 3)), Bom.parse("com.example:bom1:1.2.3@pom"));
|
assertEquals(new Bom("com.example", "bom1", new VersionNumber(1, 2, 3)), Bom.parse("com.example:bom1:1.2.3@pom"));
|
||||||
assertEquals(new Bom("com.example", "bom1", new VersionNumber(1, 2, 3), "classifier1"), Bom.parse("com.example:bom1:1.2.3:classifier1"));
|
// BOMs can't have classifiers, POM imports don't support them
|
||||||
|
assertNull(Bom.parse("com.example:bom1:1.2.3:classifier1"));
|
||||||
assertNull(Bom.parse(null));
|
assertNull(Bom.parse(null));
|
||||||
assertNull(Bom.parse(""));
|
assertNull(Bom.parse(""));
|
||||||
assertNull(Bom.parse("not@a@bom"));
|
assertNull(Bom.parse("not@a@bom"));
|
||||||
|
|
@ -287,14 +288,20 @@ public class TestBom {
|
||||||
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)))
|
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)))
|
||||||
.include(new Dependency("com.example", "a"))
|
.include(new Dependency("com.example", "a"))
|
||||||
.include(new Dependency("com.example", "f"));
|
.include(new Dependency("com.example", "f"));
|
||||||
scopes.scope(Scope.test)
|
scopes.scope(Scope.standalone)
|
||||||
// no BOMs in this scope : it's not reported on
|
// no BOMs apply to this scope : it's not reported on
|
||||||
.include(new Dependency("com.example", "f"));
|
.include(new Dependency("com.example", "f"));
|
||||||
|
|
||||||
// only the dependency that the BOM doesn't cover is reported
|
// only the dependency that the BOM doesn't cover is reported
|
||||||
assertEquals(List.of(new Dependency("com.example", "f")),
|
assertEquals(List.of(new Dependency("com.example", "f")),
|
||||||
scopes.versionlessDependenciesWithoutBom(new HierarchicalProperties(), retriever, repositories));
|
scopes.versionlessDependenciesWithoutBom(new HierarchicalProperties(), retriever, repositories));
|
||||||
|
|
||||||
|
// a bld.override that supplies the version prevents the report
|
||||||
|
var override_properties = new HierarchicalProperties();
|
||||||
|
override_properties.put(VersionResolution.PROPERTY_OVERRIDE_PREFIX, "com.example:f:2.2.0");
|
||||||
|
assertEquals(List.of(),
|
||||||
|
scopes.versionlessDependenciesWithoutBom(override_properties, retriever, repositories));
|
||||||
|
|
||||||
var resolved = scopes.resolveCompileDependencies(new HierarchicalProperties(), retriever, repositories);
|
var resolved = scopes.resolveCompileDependencies(new HierarchicalProperties(), retriever, repositories);
|
||||||
|
|
||||||
// covered by the BOM : the BOM version applies
|
// covered by the BOM : the BOM version applies
|
||||||
|
|
@ -312,7 +319,7 @@ public class TestBom {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testBomScopeIsolation() throws Exception {
|
void testBomScopeInheritance() throws Exception {
|
||||||
var server = createArtifactServer(Map.of(
|
var server = createArtifactServer(Map.of(
|
||||||
"bom1:1.0.0", bomPom("bom1", "1.0.0", managed("a", "1.4.0")),
|
"bom1:1.0.0", bomPom("bom1", "1.0.0", managed("a", "1.4.0")),
|
||||||
"a:1.4.0", pom("a", "1.4.0", ""),
|
"a:1.4.0", pom("a", "1.4.0", ""),
|
||||||
|
|
@ -324,22 +331,168 @@ public class TestBom {
|
||||||
scopes.scope(compile)
|
scopes.scope(compile)
|
||||||
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)))
|
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)))
|
||||||
.include(new Dependency("com.example", "a"));
|
.include(new Dependency("com.example", "a"));
|
||||||
|
scopes.scope(Scope.provided)
|
||||||
|
.include(new Dependency("com.example", "a"));
|
||||||
scopes.scope(Scope.test)
|
scopes.scope(Scope.test)
|
||||||
.include(new Dependency("com.example", "a"));
|
.include(new Dependency("com.example", "a"));
|
||||||
|
scopes.scope(Scope.standalone)
|
||||||
|
.include(new Dependency("com.example", "a"));
|
||||||
|
|
||||||
// the compile scope BOM applies to the compile scope resolution
|
var properties = new HierarchicalProperties();
|
||||||
var compile_resolved = scopes.resolveCompileDependencies(new HierarchicalProperties(), ArtifactRetriever.cachingInstance(), serverRepositories(server));
|
var retriever = ArtifactRetriever.cachingInstance();
|
||||||
|
var repositories = serverRepositories(server);
|
||||||
|
|
||||||
|
// the compile scope BOM applies to the compile scope resolution,
|
||||||
|
// and follows the classpath composition into the provided and
|
||||||
|
// test scope resolutions
|
||||||
|
var compile_resolved = scopes.resolveCompileDependencies(properties, retriever, repositories);
|
||||||
assertEquals(Version.parse("1.4.0"), compile_resolved.get(new Dependency("com.example", "a")).version());
|
assertEquals(Version.parse("1.4.0"), compile_resolved.get(new Dependency("com.example", "a")).version());
|
||||||
|
var provided_resolved = scopes.resolveProvidedDependencies(properties, retriever, repositories);
|
||||||
|
assertEquals(Version.parse("1.4.0"), provided_resolved.get(new Dependency("com.example", "a")).version());
|
||||||
|
var test_resolved = scopes.resolveTestDependencies(properties, retriever, repositories);
|
||||||
|
assertEquals(Version.parse("1.4.0"), test_resolved.get(new Dependency("com.example", "a")).version());
|
||||||
|
|
||||||
// and doesn't leak into the test scope resolution, whose version
|
// the standalone scope is its own world, its version stays
|
||||||
// stays unknown and falls back to the latest from the metadata
|
// unknown and falls back to the latest from the metadata
|
||||||
var test_resolved = scopes.resolveTestDependencies(new HierarchicalProperties(), ArtifactRetriever.cachingInstance(), serverRepositories(server));
|
var standalone_resolved = scopes.resolveStandaloneDependencies(properties, retriever, repositories);
|
||||||
assertEquals(VersionNumber.UNKNOWN, test_resolved.get(new Dependency("com.example", "a")).version());
|
assertEquals(VersionNumber.UNKNOWN, standalone_resolved.get(new Dependency("com.example", "a")).version());
|
||||||
} finally {
|
} finally {
|
||||||
server.stop(0);
|
server.stop(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testBomScopeInheritanceIsDirectional() throws Exception {
|
||||||
|
var server = createArtifactServer(Map.of(
|
||||||
|
"bom1:1.0.0", bomPom("bom1", "1.0.0", managed("a", "1.4.0")),
|
||||||
|
"a:1.4.0", pom("a", "1.4.0", ""),
|
||||||
|
"a:2.2.0", pom("a", "2.2.0", "")),
|
||||||
|
Map.of("a", metadata("a", "2.2.0", "1.4.0", "2.2.0")));
|
||||||
|
server.start();
|
||||||
|
try {
|
||||||
|
var scopes = new DependencyScopes();
|
||||||
|
scopes.scope(Scope.test)
|
||||||
|
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)))
|
||||||
|
.include(new Dependency("com.example", "a"));
|
||||||
|
scopes.scope(compile)
|
||||||
|
.include(new Dependency("com.example", "a"));
|
||||||
|
|
||||||
|
var properties = new HierarchicalProperties();
|
||||||
|
var retriever = ArtifactRetriever.cachingInstance();
|
||||||
|
var repositories = serverRepositories(server);
|
||||||
|
|
||||||
|
// a test scope BOM applies to the test scope resolution
|
||||||
|
var test_resolved = scopes.resolveTestDependencies(properties, retriever, repositories);
|
||||||
|
assertEquals(Version.parse("1.4.0"), test_resolved.get(new Dependency("com.example", "a")).version());
|
||||||
|
|
||||||
|
// but never reaches back into the compile scope resolution
|
||||||
|
var compile_resolved = scopes.resolveCompileDependencies(properties, retriever, repositories);
|
||||||
|
assertEquals(VersionNumber.UNKNOWN, compile_resolved.get(new Dependency("com.example", "a")).version());
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testBomPrecedenceAcrossScopes() throws Exception {
|
||||||
|
var server = createArtifactServer(Map.of(
|
||||||
|
"bom1:1.0.0", bomPom("bom1", "1.0.0", managed("a", "1.4.0")),
|
||||||
|
"bom2:1.0.0", bomPom("bom2", "1.0.0", managed("a", "2.2.0")),
|
||||||
|
"a:1.4.0", pom("a", "1.4.0", ""),
|
||||||
|
"a:2.2.0", pom("a", "2.2.0", "")),
|
||||||
|
Map.of("a", metadata("a", "2.2.0", "1.4.0", "2.2.0")));
|
||||||
|
server.start();
|
||||||
|
try {
|
||||||
|
var scopes = new DependencyScopes();
|
||||||
|
scopes.scope(compile)
|
||||||
|
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)));
|
||||||
|
scopes.scope(Scope.test)
|
||||||
|
.include(new Bom("com.example", "bom2", new VersionNumber(1, 0, 0)))
|
||||||
|
.include(new Dependency("com.example", "a"));
|
||||||
|
|
||||||
|
// when several applicable BOMs manage the same dependency, the
|
||||||
|
// first one in classpath composition order determines the version
|
||||||
|
var test_resolved = scopes.resolveTestDependencies(new HierarchicalProperties(), ArtifactRetriever.cachingInstance(), serverRepositories(server));
|
||||||
|
assertEquals(Version.parse("1.4.0"), test_resolved.get(new Dependency("com.example", "a")).version());
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUncoveredReportingFollowsScopeComposition() throws Exception {
|
||||||
|
var server = createArtifactServer(Map.of(
|
||||||
|
"bom1:1.0.0", bomPom("bom1", "1.0.0", managed("a", "1.4.0"))),
|
||||||
|
Map.of());
|
||||||
|
server.start();
|
||||||
|
try {
|
||||||
|
var scopes = new DependencyScopes();
|
||||||
|
scopes.scope(compile)
|
||||||
|
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)));
|
||||||
|
scopes.scope(Scope.test)
|
||||||
|
// covered through scope composition by the compile scope BOM
|
||||||
|
.include(new Dependency("com.example", "a"))
|
||||||
|
// not covered by any applicable BOM
|
||||||
|
.include(new Dependency("com.example", "g"));
|
||||||
|
|
||||||
|
assertEquals(List.of(new Dependency("com.example", "g")),
|
||||||
|
scopes.versionlessDependenciesWithoutBom(new HierarchicalProperties(), ArtifactRetriever.cachingInstance(), serverRepositories(server)));
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testBomIdentityIncludesTypeAndClassifier() throws Exception {
|
||||||
|
var server = createArtifactServer(Map.of(
|
||||||
|
"bom1:1.0.0", bomPom("bom1", "1.0.0",
|
||||||
|
managedTyped("a", "1.5.0", "test-jar", null) +
|
||||||
|
managedTyped("b", "1.6.0", "jar", "linux-x86_64") +
|
||||||
|
managed("b", "1.4.0"))),
|
||||||
|
Map.of());
|
||||||
|
server.start();
|
||||||
|
try {
|
||||||
|
var resolution = new VersionResolution(new HierarchicalProperties(), ArtifactRetriever.cachingInstance(), serverRepositories(server),
|
||||||
|
List.of(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0))));
|
||||||
|
|
||||||
|
// a test-jar entry doesn't cover the regular jar dependency
|
||||||
|
assertFalse(resolution.coversDependency(new Dependency("com.example", "a")));
|
||||||
|
// entries with the same identifiers but different classifiers
|
||||||
|
// are managed independently
|
||||||
|
assertEquals(Version.parse("1.4.0"), resolution.overrideDeclaredDependency(new Dependency("com.example", "b")).version());
|
||||||
|
assertEquals(Version.parse("1.6.0"), resolution.overrideDeclaredDependency(new Dependency("com.example", "b", null, "linux-x86_64")).version());
|
||||||
|
// the modular and forced-classpath JAR types match the plain
|
||||||
|
// jar entries of the BOM
|
||||||
|
assertEquals(Version.parse("1.4.0"), resolution.overrideDeclaredDependency(new Dependency("com.example", "b", null, null, Dependency.TYPE_MODULAR_JAR)).version());
|
||||||
|
assertEquals(Version.parse("1.4.0"), resolution.overrideDeclaredDependency(new Dependency("com.example", "b", null, null, Dependency.TYPE_CLASSPATH_JAR)).version());
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEffectiveBomsComposition() {
|
||||||
|
var compile_bom = new Bom("com.example", "compile-bom", new VersionNumber(1, 0, 0));
|
||||||
|
var runtime_bom = new Bom("com.example", "runtime-bom", new VersionNumber(2, 0, 0));
|
||||||
|
var provided_bom = new Bom("com.example", "provided-bom", new VersionNumber(3, 0, 0));
|
||||||
|
var test_bom = new Bom("com.example", "test-bom", new VersionNumber(4, 0, 0));
|
||||||
|
var standalone_bom = new Bom("com.example", "standalone-bom", new VersionNumber(5, 0, 0));
|
||||||
|
|
||||||
|
var scopes = new DependencyScopes();
|
||||||
|
scopes.scope(compile).include(compile_bom);
|
||||||
|
scopes.scope(Scope.runtime).include(runtime_bom);
|
||||||
|
scopes.scope(Scope.provided).include(provided_bom);
|
||||||
|
scopes.scope(Scope.test).include(test_bom);
|
||||||
|
scopes.scope(Scope.standalone).include(standalone_bom);
|
||||||
|
|
||||||
|
assertEquals(List.of(compile_bom), scopes.effectiveBoms(compile));
|
||||||
|
assertEquals(List.of(compile_bom, provided_bom), scopes.effectiveBoms(Scope.provided));
|
||||||
|
assertEquals(List.of(compile_bom, runtime_bom), scopes.effectiveBoms(Scope.runtime));
|
||||||
|
// the test scope order matches the test classpath order
|
||||||
|
assertEquals(List.of(compile_bom, provided_bom, runtime_bom, test_bom), scopes.effectiveBoms(Scope.test));
|
||||||
|
assertEquals(List.of(standalone_bom), scopes.effectiveBoms(Scope.standalone));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testMissingBomFailsLoudly() throws Exception {
|
void testMissingBomFailsLoudly() throws Exception {
|
||||||
var server = createArtifactServer(Map.of());
|
var server = createArtifactServer(Map.of());
|
||||||
|
|
@ -452,7 +605,7 @@ public class TestBom {
|
||||||
assertNotSame(base, resolution);
|
assertNotSame(base, resolution);
|
||||||
assertEquals(base.versionOverrides(), resolution.versionOverrides());
|
assertEquals(base.versionOverrides(), resolution.versionOverrides());
|
||||||
assertEquals(3, resolution.transferParallelism());
|
assertEquals(3, resolution.transferParallelism());
|
||||||
assertEquals(Map.of("com.example:a", Version.parse("1.4.0")), resolution.bomVersions());
|
assertEquals(Map.of("com.example:a:jar:", Version.parse("1.4.0")), resolution.bomVersions());
|
||||||
|
|
||||||
// a declared dependency without version is filled in from the BOM
|
// a declared dependency without version is filled in from the BOM
|
||||||
assertEquals(Version.parse("1.4.0"), resolution.overrideDeclaredDependency(new Dependency("com.example", "a")).version());
|
assertEquals(Version.parse("1.4.0"), resolution.overrideDeclaredDependency(new Dependency("com.example", "a")).version());
|
||||||
|
|
@ -584,6 +737,42 @@ public class TestBom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testProjectUpdatesWithBomAndOverride() throws Exception {
|
||||||
|
var server = createArtifactServer(Map.of(
|
||||||
|
"bom1:1.0.0", bomPom("bom1", "1.0.0", managed("a", "1.4.0"))),
|
||||||
|
Map.of("bom1", metadata("bom1", "1.0.0", "1.0.0", "1.0.0"),
|
||||||
|
"a", metadata("a", "9.9.9", "1.4.0", "9.9.9")));
|
||||||
|
server.start();
|
||||||
|
var tmp = Files.createTempDirectory("bomupdatesoverride").toFile();
|
||||||
|
try {
|
||||||
|
var project = new BomProject(tmp, transferRepository(server));
|
||||||
|
project.properties().put(VersionResolution.PROPERTY_OVERRIDE_PREFIX, "com.example:a:1.4.0");
|
||||||
|
project.dependencies().scope(compile)
|
||||||
|
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)))
|
||||||
|
.include(new Dependency("com.example", "a"));
|
||||||
|
|
||||||
|
var original_out = System.out;
|
||||||
|
var captured = new java.io.ByteArrayOutputStream();
|
||||||
|
System.setOut(new java.io.PrintStream(captured, true));
|
||||||
|
int status;
|
||||||
|
try {
|
||||||
|
status = project.execute(new String[]{"updates"});
|
||||||
|
} finally {
|
||||||
|
System.setOut(original_out);
|
||||||
|
}
|
||||||
|
var output = captured.toString();
|
||||||
|
|
||||||
|
assertEquals(0, status);
|
||||||
|
// the override takes the version control away from the BOM,
|
||||||
|
// the dependency is checked individually against the override
|
||||||
|
assertTrue(output.contains("com.example:a:9.9.9"), output);
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
FileUtils.deleteDirectory(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static class BomProject extends rife.bld.Project {
|
static class BomProject extends rife.bld.Project {
|
||||||
BomProject(File tmp, Repository repository) {
|
BomProject(File tmp, Repository repository) {
|
||||||
workDirectory = tmp;
|
workDirectory = tmp;
|
||||||
|
|
@ -692,6 +881,10 @@ public class TestBom {
|
||||||
project.dependencies().scope(compile)
|
project.dependencies().scope(compile)
|
||||||
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)))
|
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)))
|
||||||
.include(new Dependency("com.example", "a"));
|
.include(new Dependency("com.example", "a"));
|
||||||
|
project.dependencies().scope(Scope.test)
|
||||||
|
// covered through scope composition by the compile scope BOM,
|
||||||
|
// must not be reported individually either
|
||||||
|
.include(new Dependency("com.example", "a"));
|
||||||
|
|
||||||
var original_out = System.out;
|
var original_out = System.out;
|
||||||
var captured = new java.io.ByteArrayOutputStream();
|
var captured = new java.io.ByteArrayOutputStream();
|
||||||
|
|
@ -729,6 +922,9 @@ public class TestBom {
|
||||||
project.dependencies().scope(compile)
|
project.dependencies().scope(compile)
|
||||||
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)))
|
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)))
|
||||||
.include(new Dependency("com.example", "a"));
|
.include(new Dependency("com.example", "a"));
|
||||||
|
project.dependencies().scope(Scope.test)
|
||||||
|
// covered through scope composition by the compile scope BOM
|
||||||
|
.include(new Dependency("com.example", "a"));
|
||||||
|
|
||||||
var original_out = System.out;
|
var original_out = System.out;
|
||||||
var captured = new java.io.ByteArrayOutputStream();
|
var captured = new java.io.ByteArrayOutputStream();
|
||||||
|
|
@ -742,9 +938,13 @@ public class TestBom {
|
||||||
var output = captured.toString();
|
var output = captured.toString();
|
||||||
|
|
||||||
assertEquals(0, status);
|
assertEquals(0, status);
|
||||||
// the tree reflects the BOM version, not the latest version
|
// the trees reflect the BOM version, not the latest version,
|
||||||
|
// in the compile scope as well as in the test scope that the
|
||||||
|
// compile scope BOM also applies to
|
||||||
assertTrue(output.contains("com.example:a:1.4.0"), output);
|
assertTrue(output.contains("com.example:a:1.4.0"), output);
|
||||||
assertFalse(output.contains("com.example:a:2.2.0"), output);
|
assertFalse(output.contains("com.example:a:2.2.0"), output);
|
||||||
|
var test_tree = output.substring(output.indexOf("test:"));
|
||||||
|
assertTrue(test_tree.contains("com.example:a:1.4.0"), output);
|
||||||
} finally {
|
} finally {
|
||||||
server.stop(0);
|
server.stop(0);
|
||||||
FileUtils.deleteDirectory(tmp);
|
FileUtils.deleteDirectory(tmp);
|
||||||
|
|
@ -925,6 +1125,13 @@ public class TestBom {
|
||||||
return dependency(artifact, version);
|
return dependency(artifact, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String managedTyped(String artifact, String version, String type, String classifier) {
|
||||||
|
return "<dependency><groupId>com.example</groupId><artifactId>" + artifact + "</artifactId><version>" + version + "</version>" +
|
||||||
|
"<type>" + type + "</type>" +
|
||||||
|
(classifier == null ? "" : "<classifier>" + classifier + "</classifier>") +
|
||||||
|
"</dependency>";
|
||||||
|
}
|
||||||
|
|
||||||
private static String pom(String artifact, String version, String dependencies) {
|
private static String pom(String artifact, String version, String dependencies) {
|
||||||
return """
|
return """
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
|
||||||
|
|
@ -799,6 +799,182 @@ public class TestPublishOperation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testResolveVersionlessDependenciesWithOverrides()
|
||||||
|
throws Exception {
|
||||||
|
var poms = java.util.Map.of(
|
||||||
|
"bom1:1.0.0", """
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>bom1</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency><groupId>com.example</groupId><artifactId>a</artifactId><version>1.4.0</version></dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
</project>""",
|
||||||
|
"bom2:2.5.0", """
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>bom2</artifactId>
|
||||||
|
<version>2.5.0</version>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency><groupId>com.example</groupId><artifactId>d</artifactId><version>4.0.0</version></dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
</project>""");
|
||||||
|
var metadata = java.util.Map.of(
|
||||||
|
"b", """
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<metadata>
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>b</artifactId>
|
||||||
|
<versioning>
|
||||||
|
<latest>2.2.0</latest>
|
||||||
|
<release>2.2.0</release>
|
||||||
|
<versions><version>2.2.0</version></versions>
|
||||||
|
</versioning>
|
||||||
|
</metadata>""");
|
||||||
|
var server = com.sun.net.httpserver.HttpServer.create(new java.net.InetSocketAddress("localhost", 0), 0);
|
||||||
|
server.createContext("/", exchange -> {
|
||||||
|
var segments = exchange.getRequestURI().getPath().split("/");
|
||||||
|
var filename = segments[segments.length - 1];
|
||||||
|
String content = null;
|
||||||
|
if (filename.endsWith(".pom") && segments.length >= 3) {
|
||||||
|
content = poms.get(segments[segments.length - 3] + ":" + segments[segments.length - 2]);
|
||||||
|
} else if (filename.equals("maven-metadata.xml") && segments.length >= 2) {
|
||||||
|
content = metadata.get(segments[segments.length - 2]);
|
||||||
|
}
|
||||||
|
if (content == null) {
|
||||||
|
exchange.sendResponseHeaders(404, -1);
|
||||||
|
} else {
|
||||||
|
var body = content.getBytes();
|
||||||
|
exchange.sendResponseHeaders(200, body.length);
|
||||||
|
exchange.getResponseBody().write(body);
|
||||||
|
}
|
||||||
|
exchange.close();
|
||||||
|
});
|
||||||
|
server.start();
|
||||||
|
try {
|
||||||
|
var properties = new rife.ioc.HierarchicalProperties();
|
||||||
|
properties.put(VersionResolution.PROPERTY_OVERRIDE_PREFIX,
|
||||||
|
"com.example:a:1.9.9,com.example:b:1.1.1,com.example:bom2:2.5.0");
|
||||||
|
|
||||||
|
var scopes = new DependencyScopes();
|
||||||
|
scopes.scope(Scope.compile)
|
||||||
|
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)))
|
||||||
|
.include(new Dependency("com.example", "a"))
|
||||||
|
.include(new Dependency("com.example", "b"));
|
||||||
|
scopes.scope(Scope.runtime)
|
||||||
|
.include(new Bom("com.example", "bom2"));
|
||||||
|
|
||||||
|
var operation = new PublishOperation()
|
||||||
|
.properties(properties)
|
||||||
|
.artifactRetriever(ArtifactRetriever.cachingInstance())
|
||||||
|
.dependencyRepositories(List.of(new Repository("http://localhost:" + server.getAddress().getPort() + "/")))
|
||||||
|
.dependencies(scopes);
|
||||||
|
operation.executeResolveVersionlessDependencies();
|
||||||
|
|
||||||
|
var compile_scope = operation.dependencies().scope(Scope.compile);
|
||||||
|
// the override is what the build resolves, it's frozen into the
|
||||||
|
// POM even though the BOM covers the dependency
|
||||||
|
assertEquals(new VersionNumber(1, 9, 9), compile_scope.get(new Dependency("com.example", "a")).version());
|
||||||
|
// an uncovered dependency freezes to its override instead of
|
||||||
|
// the latest version
|
||||||
|
assertEquals(new VersionNumber(1, 1, 1), compile_scope.get(new Dependency("com.example", "b")).version());
|
||||||
|
// a version-less BOM freezes to its override
|
||||||
|
var runtime_boms = operation.dependencies().scope(Scope.runtime).boms();
|
||||||
|
assertEquals(new Bom("com.example", "bom2", new VersionNumber(2, 5, 0)), runtime_boms.iterator().next());
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testResolveVersionlessDependenciesFreezesFlattenedConflicts()
|
||||||
|
throws Exception {
|
||||||
|
var poms = java.util.Map.of(
|
||||||
|
"bomr:1.0.0", """
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>bomr</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency><groupId>com.example</groupId><artifactId>a</artifactId><version>1.0.0</version></dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
</project>""",
|
||||||
|
"bomp:1.0.0", """
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>bomp</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency><groupId>com.example</groupId><artifactId>a</artifactId><version>2.0.0</version></dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
</project>""");
|
||||||
|
var server = com.sun.net.httpserver.HttpServer.create(new java.net.InetSocketAddress("localhost", 0), 0);
|
||||||
|
server.createContext("/", exchange -> {
|
||||||
|
var segments = exchange.getRequestURI().getPath().split("/");
|
||||||
|
var filename = segments[segments.length - 1];
|
||||||
|
String content = null;
|
||||||
|
if (filename.endsWith(".pom") && segments.length >= 3) {
|
||||||
|
content = poms.get(segments[segments.length - 3] + ":" + segments[segments.length - 2]);
|
||||||
|
}
|
||||||
|
if (content == null) {
|
||||||
|
exchange.sendResponseHeaders(404, -1);
|
||||||
|
} else {
|
||||||
|
var body = content.getBytes();
|
||||||
|
exchange.sendResponseHeaders(200, body.length);
|
||||||
|
exchange.getResponseBody().write(body);
|
||||||
|
}
|
||||||
|
exchange.close();
|
||||||
|
});
|
||||||
|
server.start();
|
||||||
|
try {
|
||||||
|
var scopes = new DependencyScopes();
|
||||||
|
scopes.scope(Scope.runtime)
|
||||||
|
.include(new Bom("com.example", "bomr", new VersionNumber(1, 0, 0)))
|
||||||
|
.include(new Dependency("com.example", "a"));
|
||||||
|
scopes.scope(Scope.provided)
|
||||||
|
.include(new Bom("com.example", "bomp", new VersionNumber(1, 0, 0)))
|
||||||
|
.include(new Dependency("com.example", "a"));
|
||||||
|
|
||||||
|
var operation = new PublishOperation()
|
||||||
|
.artifactRetriever(ArtifactRetriever.cachingInstance())
|
||||||
|
.dependencyRepositories(List.of(new Repository("http://localhost:" + server.getAddress().getPort() + "/")))
|
||||||
|
.dependencies(scopes);
|
||||||
|
operation.executeResolveVersionlessDependencies();
|
||||||
|
|
||||||
|
// the flattened dependency management of the POM imports the
|
||||||
|
// runtime BOM first and would supply 1.0.0, the runtime scope
|
||||||
|
// agrees with that so its dependency stays version-less
|
||||||
|
assertEquals(VersionNumber.UNKNOWN, operation.dependencies().scope(Scope.runtime).get(new Dependency("com.example", "a")).version());
|
||||||
|
// the provided scope resolves 2.0.0 through its own BOM, that
|
||||||
|
// conflicts with the flattened list so the version is frozen
|
||||||
|
assertEquals(new VersionNumber(2, 0, 0), operation.dependencies().scope(Scope.provided).get(new Dependency("com.example", "a")).version());
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testResolveVersionlessDependenciesUntouchedScopes() {
|
void testResolveVersionlessDependenciesUntouchedScopes() {
|
||||||
// no network access is needed when nothing has to be resolved :
|
// no network access is needed when nothing has to be resolved :
|
||||||
|
|
@ -926,6 +1102,9 @@ public class TestPublishOperation {
|
||||||
.include(new Dependency("com.example", "c", new VersionNumber(5, 0, 0)));
|
.include(new Dependency("com.example", "c", new VersionNumber(5, 0, 0)));
|
||||||
scopes.scope(Scope.runtime)
|
scopes.scope(Scope.runtime)
|
||||||
.include(new Bom("com.example", "bom2"));
|
.include(new Bom("com.example", "bom2"));
|
||||||
|
scopes.scope(Scope.provided)
|
||||||
|
// covered by the compile scope BOM through scope inheritance
|
||||||
|
.include(new Dependency("com.example", "a"));
|
||||||
|
|
||||||
var operation = new PublishOperation()
|
var operation = new PublishOperation()
|
||||||
.artifactRetriever(ArtifactRetriever.cachingInstance())
|
.artifactRetriever(ArtifactRetriever.cachingInstance())
|
||||||
|
|
@ -944,6 +1123,9 @@ public class TestPublishOperation {
|
||||||
// a version-less BOM is resolved to its latest version
|
// a version-less BOM is resolved to its latest version
|
||||||
var runtime_boms = operation.dependencies().scope(Scope.runtime).boms();
|
var runtime_boms = operation.dependencies().scope(Scope.runtime).boms();
|
||||||
assertEquals(new Bom("com.example", "bom2", new VersionNumber(3, 0, 0)), runtime_boms.iterator().next());
|
assertEquals(new Bom("com.example", "bom2", new VersionNumber(3, 0, 0)), runtime_boms.iterator().next());
|
||||||
|
// the compile scope BOM also covers the provided scope,
|
||||||
|
// its version-less dependency stays version-less
|
||||||
|
assertEquals(VersionNumber.UNKNOWN, operation.dependencies().scope(Scope.provided).get(new Dependency("com.example", "a")).version());
|
||||||
} finally {
|
} finally {
|
||||||
server.stop(0);
|
server.stop(0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue