mirror of
https://github.com/rife2/bld
synced 2026-08-04 15:07:46 +02:00
Compare commits
2 commits
2bfcc1bb78
...
f6aeaa090d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6aeaa090d | ||
|
|
734000e6dd |
|
|
@ -38,7 +38,8 @@ public class DependencyScopes extends LinkedHashMap<Scope, DependencySet> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Includes all the dependencies from another dependency scope map.
|
* Includes all the dependencies, local dependencies, local modules and
|
||||||
|
* BOMs from another dependency scope map.
|
||||||
*
|
*
|
||||||
* @param other the other map to include dependencies from
|
* @param other the other map to include dependencies from
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
|
|
@ -50,7 +51,7 @@ public class DependencyScopes extends LinkedHashMap<Scope, DependencySet> {
|
||||||
dependencies = new DependencySet();
|
dependencies = new DependencySet();
|
||||||
put(entry.getKey(), dependencies);
|
put(entry.getKey(), dependencies);
|
||||||
}
|
}
|
||||||
dependencies.addAll(entry.getValue());
|
dependencies.include(entry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,6 +67,37 @@ public class DependencyScopes extends LinkedHashMap<Scope, DependencySet> {
|
||||||
return computeIfAbsent(scope, k -> new DependencySet());
|
return computeIfAbsent(scope, k -> new DependencySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the version-less dependencies that are not covered by the
|
||||||
|
* BOMs that are declared in their scope.
|
||||||
|
* <p>
|
||||||
|
* Scopes that don't declare any BOMs are not considered, their
|
||||||
|
* version-less dependencies simply resolve to the latest version.
|
||||||
|
*
|
||||||
|
* @param properties the properties to use to get artifacts
|
||||||
|
* @param retriever the retriever to use to get artifacts
|
||||||
|
* @param repositories the repositories to use for the BOM resolution
|
||||||
|
* @return the version-less dependencies that no BOM in their scope covers
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
public List<Dependency> versionlessDependenciesWithoutBom(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
|
||||||
|
var result = new ArrayList<Dependency>();
|
||||||
|
for (var scoped_dependencies : values()) {
|
||||||
|
if (scoped_dependencies.boms().isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var resolution = new VersionResolution(properties, retriever, repositories, scoped_dependencies.boms());
|
||||||
|
for (var dependency : scoped_dependencies) {
|
||||||
|
if (dependency.version().equals(VersionNumber.UNKNOWN) &&
|
||||||
|
!resolution.bomVersions().containsKey(dependency.toArtifactString()) &&
|
||||||
|
!result.contains(dependency)) {
|
||||||
|
result.add(dependency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the transitive set of dependencies that would be used for the compile scope in a project.
|
* Returns the transitive set of dependencies that would be used for the compile scope in a project.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,23 @@ public class DependencySet extends AbstractSet<Dependency> implements Set<Depend
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public DependencySet(DependencySet other) {
|
public DependencySet(DependencySet other) {
|
||||||
|
include(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Includes all the dependencies, local dependencies, local modules and
|
||||||
|
* BOMs from another dependency set.
|
||||||
|
*
|
||||||
|
* @param other the other set to include
|
||||||
|
* @return this dependency set instance
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
public DependencySet include(DependencySet other) {
|
||||||
addAll(other);
|
addAll(other);
|
||||||
|
localDependencies_.addAll(other.localDependencies_);
|
||||||
|
localModules_.addAll(other.localModules_);
|
||||||
|
boms_.addAll(other.boms_);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
|
||||||
if (!silent()) {
|
if (!silent()) {
|
||||||
System.out.println("Analyzing dependencies...");
|
System.out.println("Analyzing dependencies...");
|
||||||
}
|
}
|
||||||
|
executeReportUncoveredDependencies();
|
||||||
executeDownloadCompileDependencies();
|
executeDownloadCompileDependencies();
|
||||||
executeDownloadProvidedDependencies();
|
executeDownloadProvidedDependencies();
|
||||||
executeDownloadRuntimeDependencies();
|
executeDownloadRuntimeDependencies();
|
||||||
|
|
@ -72,6 +73,21 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Part of the {@link #execute} operation, warns about version-less
|
||||||
|
* dependencies that are not covered by a BOM in their scope.
|
||||||
|
*
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
protected void executeReportUncoveredDependencies() {
|
||||||
|
if (silent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (var dependency : dependencies().versionlessDependenciesWithoutBom(properties(), artifactRetriever(), repositories())) {
|
||||||
|
System.out.println("Warning: '" + dependency.toArtifactString() + "' isn't covered by a BOM, its latest version will be used");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Part of the {@link #execute} operation, download the {@code compile} scope artifacts.
|
* Part of the {@link #execute} operation, download the {@code compile} scope artifacts.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
|
||||||
|
|
||||||
private ZonedDateTime moment_ = null;
|
private ZonedDateTime moment_ = null;
|
||||||
private final List<Repository> repositories_ = new ArrayList<>();
|
private final List<Repository> repositories_ = new ArrayList<>();
|
||||||
|
private final List<Repository> dependencyRepositories_ = new ArrayList<>();
|
||||||
private final DependencyScopes dependencies_ = new DependencyScopes();
|
private final DependencyScopes dependencies_ = new DependencyScopes();
|
||||||
private PublishInfo info_ = new PublishInfo();
|
private PublishInfo info_ = new PublishInfo();
|
||||||
private PublishProperties publishProperties_ = new PublishProperties();
|
private PublishProperties publishProperties_ = new PublishProperties();
|
||||||
|
|
@ -78,6 +79,7 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
|
||||||
}
|
}
|
||||||
|
|
||||||
executeValidateArtifacts();
|
executeValidateArtifacts();
|
||||||
|
executeResolveVersionlessDependencies();
|
||||||
|
|
||||||
var actual_version = info().version();
|
var actual_version = info().version();
|
||||||
|
|
||||||
|
|
@ -103,6 +105,50 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Part of the {@link #execute} operation, resolves the versions of
|
||||||
|
* dependencies that were declared without one and that are not covered
|
||||||
|
* by a BOM in the same scope, so that the published POM is always
|
||||||
|
* complete.
|
||||||
|
* <p>
|
||||||
|
* BOMs that were declared without a version are resolved to their
|
||||||
|
* latest version too.
|
||||||
|
*
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
protected void executeResolveVersionlessDependencies() {
|
||||||
|
for (var scope : List.of(Scope.compile, Scope.runtime, Scope.provided)) {
|
||||||
|
var scoped_dependencies = dependencies().get(scope);
|
||||||
|
if (scoped_dependencies == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve the versions of BOMs that were declared without one
|
||||||
|
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)) {
|
||||||
|
if (dependency.version().equals(VersionNumber.UNKNOWN) &&
|
||||||
|
!resolution.bomVersions().containsKey(dependency.toArtifactString())) {
|
||||||
|
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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Part of the {@link #execute} operation, validates the publishing artifacts.
|
* Part of the {@link #execute} operation, validates the publishing artifacts.
|
||||||
*
|
*
|
||||||
|
|
@ -625,6 +671,7 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
|
||||||
offline(project.offline());
|
offline(project.offline());
|
||||||
properties(project.properties());
|
properties(project.properties());
|
||||||
artifactRetriever(project.artifactRetriever());
|
artifactRetriever(project.artifactRetriever());
|
||||||
|
dependencyRepositories(project.repositories());
|
||||||
dependencies().include(project.dependencies());
|
dependencies().include(project.dependencies());
|
||||||
artifacts(List.of(
|
artifacts(List.of(
|
||||||
new PublishArtifact(new File(project.buildDistDirectory(), project.jarFileName()), "", TYPE_JAR),
|
new PublishArtifact(new File(project.buildDistDirectory(), project.jarFileName()), "", TYPE_JAR),
|
||||||
|
|
@ -733,6 +780,33 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a list of repositories to resolve the dependencies against.
|
||||||
|
* <p>
|
||||||
|
* These are used to resolve the versions of dependencies that were
|
||||||
|
* declared without one, they are not publication targets.
|
||||||
|
*
|
||||||
|
* @param repositories a list of repositories against which dependencies will be resolved
|
||||||
|
* @return this operation instance
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
public PublishOperation dependencyRepositories(List<Repository> repositories) {
|
||||||
|
dependencyRepositories_.addAll(repositories);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the repositories that dependencies will be resolved against.
|
||||||
|
* <p>
|
||||||
|
* This is a modifiable list that can be retrieved and changed.
|
||||||
|
*
|
||||||
|
* @return the repositories used for dependency resolution
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
public List<Repository> dependencyRepositories() {
|
||||||
|
return dependencyRepositories_;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides scoped dependencies to reference in the publication.
|
* Provides scoped dependencies to reference in the publication.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
executeReportUncoveredDependencies();
|
||||||
executePurgeCompileDependencies();
|
executePurgeCompileDependencies();
|
||||||
executePurgeProvidedDependencies();
|
executePurgeProvidedDependencies();
|
||||||
executePurgeRuntimeDependencies();
|
executePurgeRuntimeDependencies();
|
||||||
|
|
@ -64,6 +65,21 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Part of the {@link #execute} operation, warns about version-less
|
||||||
|
* dependencies that are not covered by a BOM in their scope.
|
||||||
|
*
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
protected void executeReportUncoveredDependencies() {
|
||||||
|
if (silent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (var dependency : dependencies().versionlessDependenciesWithoutBom(properties(), artifactRetriever(), repositories())) {
|
||||||
|
System.out.println("Warning: '" + dependency.toArtifactString() + "' isn't covered by a BOM, its latest version will be used");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Part of the {@link #execute} operation, purge the {@code compile} scope artifacts.
|
* Part of the {@link #execute} operation, purge the {@code compile} scope artifacts.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ import rife.tools.StringUtils;
|
||||||
import rife.tools.exceptions.FileUtilsErrorException;
|
import rife.tools.exceptions.FileUtilsErrorException;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static rife.bld.dependencies.Dependency.TYPE_JAR;
|
import static rife.bld.dependencies.Dependency.TYPE_JAR;
|
||||||
|
|
@ -152,6 +154,7 @@ public class PomBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dependencies() != null && !dependencies().isEmpty()) {
|
if (dependencies() != null && !dependencies().isEmpty()) {
|
||||||
|
addDependencyManagement(t);
|
||||||
addDependencies(t, Scope.compile);
|
addDependencies(t, Scope.compile);
|
||||||
addDependencies(t, Scope.runtime);
|
addDependencies(t, Scope.runtime);
|
||||||
addDependencies(t, Scope.provided);
|
addDependencies(t, Scope.provided);
|
||||||
|
|
@ -172,6 +175,32 @@ public class PomBuilder {
|
||||||
FileUtils.writeString(pomBuilder.build(), file);
|
FileUtils.writeString(pomBuilder.build(), file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addDependencyManagement(Template t) {
|
||||||
|
var 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) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (var bom : scoped_dependencies.boms()) {
|
||||||
|
if (!bom.version().equals(VersionNumber.UNKNOWN)) {
|
||||||
|
boms.putIfAbsent(bom.toArtifactString(), bom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (boms.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var bom : boms.values()) {
|
||||||
|
t.setValueEncoded("dependency-management-groupId", bom.groupId());
|
||||||
|
t.setValueEncoded("dependency-management-artifactId", bom.artifactId());
|
||||||
|
t.setValueEncoded("dependency-management-version", bom.version());
|
||||||
|
t.appendBlock("dependency-management", "dependency-management-entry");
|
||||||
|
}
|
||||||
|
t.setBlock("dependency-management-tag");
|
||||||
|
}
|
||||||
|
|
||||||
private void addDependencies(Template t, Scope scope) {
|
private void addDependencies(Template t, Scope scope) {
|
||||||
var scoped_dependencies = dependencies().scope(scope);
|
var scoped_dependencies = dependencies().scope(scope);
|
||||||
if (!scoped_dependencies.isEmpty()) {
|
if (!scoped_dependencies.isEmpty()) {
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,24 @@
|
||||||
</properties>
|
</properties>
|
||||||
<!--/b-->
|
<!--/b-->
|
||||||
|
|
||||||
|
<!--v dependency-management-tag--><!--/v-->
|
||||||
|
<!--b dependency-management-tag-->
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<!--v dependency-management--><!--/v-->
|
||||||
|
<!--b dependency-management-entry-->
|
||||||
|
<dependency>
|
||||||
|
<groupId><!--v dependency-management-groupId--><!--/v--></groupId>
|
||||||
|
<artifactId><!--v dependency-management-artifactId--><!--/v--></artifactId>
|
||||||
|
<version><!--v dependency-management-version--><!--/v--></version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
<!--/b-->
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
<!--/b-->
|
||||||
|
|
||||||
<!--v dependencies-tag--><!--/v-->
|
<!--v dependencies-tag--><!--/v-->
|
||||||
<!--b dependencies-tag-->
|
<!--b dependencies-tag-->
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import java.util.Map;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
import static rife.bld.dependencies.RepositoryTestHelper.getNextRepositories;
|
import static rife.bld.dependencies.RepositoryTestHelper.*;
|
||||||
import static rife.bld.dependencies.Scope.compile;
|
import static rife.bld.dependencies.Scope.compile;
|
||||||
|
|
||||||
public class TestBom {
|
public class TestBom {
|
||||||
|
|
@ -287,8 +287,16 @@ 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)
|
||||||
|
// no BOMs in this scope : it's not reported on
|
||||||
|
.include(new Dependency("com.example", "f"));
|
||||||
|
|
||||||
|
// only the dependency that the BOM doesn't cover is reported
|
||||||
|
assertEquals(List.of(new Dependency("com.example", "f")),
|
||||||
|
scopes.versionlessDependenciesWithoutBom(new HierarchicalProperties(), 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
|
||||||
assertEquals(Version.parse("1.4.0"), resolved.get(new Dependency("com.example", "a")).version());
|
assertEquals(Version.parse("1.4.0"), resolved.get(new Dependency("com.example", "a")).version());
|
||||||
// not covered by the BOM : the version stays unknown in the set,
|
// not covered by the BOM : the version stays unknown in the set,
|
||||||
|
|
@ -504,6 +512,353 @@ public class TestBom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testBomSurvivesOperationDependenciesCopy() throws Exception {
|
||||||
|
// regression test : operations copy the project's dependency scopes
|
||||||
|
// through DependencyScopes.include, which used to lose the BOMs so
|
||||||
|
// that version-less dependencies resolved to their latest versions
|
||||||
|
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();
|
||||||
|
var tmp = Files.createTempDirectory("bomcopy").toFile();
|
||||||
|
try {
|
||||||
|
var scopes = new DependencyScopes();
|
||||||
|
scopes.scope(compile)
|
||||||
|
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)))
|
||||||
|
.include(new Dependency("com.example", "a"));
|
||||||
|
|
||||||
|
var operation = new rife.bld.operations.DownloadOperation()
|
||||||
|
.artifactRetriever(ArtifactRetriever.cachingInstance())
|
||||||
|
.repositories(serverRepositories(server))
|
||||||
|
.dependencies(scopes)
|
||||||
|
.libCompileDirectory(tmp).libCompileModulesDirectory(tmp)
|
||||||
|
.libProvidedDirectory(tmp).libProvidedModulesDirectory(tmp)
|
||||||
|
.libRuntimeDirectory(tmp).libRuntimeModulesDirectory(tmp)
|
||||||
|
.libStandaloneDirectory(tmp).libStandaloneModulesDirectory(tmp)
|
||||||
|
.libTestDirectory(tmp).libTestModulesDirectory(tmp)
|
||||||
|
.silent(true);
|
||||||
|
operation.execute();
|
||||||
|
|
||||||
|
// the BOM version is downloaded, not the latest version
|
||||||
|
assertTrue(new File(tmp, "a-1.4.0.jar").exists());
|
||||||
|
assertFalse(new File(tmp, "a-2.2.0.jar").exists());
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
FileUtils.deleteDirectory(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMissingBomFailsLoudlyThroughOperation() throws Exception {
|
||||||
|
// regression test : a missing BOM also has to fail when the
|
||||||
|
// dependency scopes were copied into an operation, the BOM is
|
||||||
|
// deliberately the only artifact that is missing
|
||||||
|
var server = createArtifactServer(Map.of(
|
||||||
|
"a:1.0.0", pom("a", "1.0.0", "")));
|
||||||
|
server.start();
|
||||||
|
var tmp = Files.createTempDirectory("bommissing").toFile();
|
||||||
|
try {
|
||||||
|
var scopes = new DependencyScopes();
|
||||||
|
scopes.scope(compile)
|
||||||
|
.include(new Bom("com.example", "missing", new VersionNumber(1, 0, 0)))
|
||||||
|
.include(new Dependency("com.example", "a", new VersionNumber(1, 0, 0)));
|
||||||
|
|
||||||
|
var operation = new rife.bld.operations.DownloadOperation()
|
||||||
|
.artifactRetriever(ArtifactRetriever.cachingInstance())
|
||||||
|
.repositories(serverRepositories(server))
|
||||||
|
.dependencies(scopes)
|
||||||
|
.libCompileDirectory(tmp).libCompileModulesDirectory(tmp)
|
||||||
|
.libProvidedDirectory(tmp).libProvidedModulesDirectory(tmp)
|
||||||
|
.libRuntimeDirectory(tmp).libRuntimeModulesDirectory(tmp)
|
||||||
|
.libStandaloneDirectory(tmp).libStandaloneModulesDirectory(tmp)
|
||||||
|
.libTestDirectory(tmp).libTestModulesDirectory(tmp)
|
||||||
|
.silent(true);
|
||||||
|
|
||||||
|
assertThrows(ArtifactNotFoundException.class, operation::execute);
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
FileUtils.deleteDirectory(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class BomProject extends rife.bld.Project {
|
||||||
|
BomProject(File tmp, Repository repository) {
|
||||||
|
workDirectory = tmp;
|
||||||
|
pkg = "test.pkg";
|
||||||
|
name = "bom_project";
|
||||||
|
version = new VersionNumber(0, 0, 1);
|
||||||
|
repositories = List.of(repository);
|
||||||
|
}
|
||||||
|
|
||||||
|
void enableAutoDownloadPurge() {
|
||||||
|
autoDownloadPurge = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testProjectDownloadWithBoms() throws Exception {
|
||||||
|
var server = createArtifactServer(Map.of(
|
||||||
|
"bom1:1.0.0", bomPom("bom1", "1.0.0", managed("a", "1.4.0") + managed("b", "2.1.0")),
|
||||||
|
"a:1.4.0", pom("a", "1.4.0", ""),
|
||||||
|
"a:2.2.0", pom("a", "2.2.0", ""),
|
||||||
|
"b:2.1.0", pom("b", "2.1.0", "")),
|
||||||
|
Map.of("a", metadata("a", "2.2.0", "1.4.0", "2.2.0"),
|
||||||
|
"b", metadata("b", "2.1.0", "2.1.0")));
|
||||||
|
server.start();
|
||||||
|
var tmp = Files.createTempDirectory("bomproject").toFile();
|
||||||
|
try {
|
||||||
|
var project = new BomProject(tmp, transferRepository(server));
|
||||||
|
project.dependencies().scope(compile)
|
||||||
|
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)))
|
||||||
|
.include(new Dependency("com.example", "a"));
|
||||||
|
project.dependencies().scope(Scope.test)
|
||||||
|
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)))
|
||||||
|
.include(new Dependency("com.example", "a"))
|
||||||
|
.include(new Dependency("com.example", "b"));
|
||||||
|
|
||||||
|
assertEquals(0, project.execute(new String[]{"download"}));
|
||||||
|
|
||||||
|
// the BOM versions are downloaded in every scope,
|
||||||
|
// never the latest versions
|
||||||
|
assertTrue(new File(tmp, "lib/compile/a-1.4.0.jar").exists());
|
||||||
|
assertFalse(new File(tmp, "lib/compile/a-2.2.0.jar").exists());
|
||||||
|
assertTrue(new File(tmp, "lib/test/a-1.4.0.jar").exists());
|
||||||
|
assertFalse(new File(tmp, "lib/test/a-2.2.0.jar").exists());
|
||||||
|
assertTrue(new File(tmp, "lib/test/b-2.1.0.jar").exists());
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
FileUtils.deleteDirectory(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testProjectAutoDownloadPurgeBomUpgrade() throws Exception {
|
||||||
|
var server = createArtifactServer(Map.of(
|
||||||
|
"bom1:1.0.0", bomPom("bom1", "1.0.0", managed("a", "1.4.0")),
|
||||||
|
"bom1:2.0.0", bomPom("bom1", "2.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();
|
||||||
|
var tmp = Files.createTempDirectory("bomupgrade").toFile();
|
||||||
|
try {
|
||||||
|
var project = new BomProject(tmp, transferRepository(server));
|
||||||
|
project.enableAutoDownloadPurge();
|
||||||
|
project.dependencies().scope(compile)
|
||||||
|
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)))
|
||||||
|
.include(new Dependency("com.example", "a"));
|
||||||
|
assertEquals(0, project.execute(new String[]{"version"}));
|
||||||
|
assertTrue(new File(tmp, "lib/compile/a-1.4.0.jar").exists());
|
||||||
|
|
||||||
|
// running again with an identical BOM declaration
|
||||||
|
// doesn't invalidate the dependencies cache
|
||||||
|
project = new BomProject(tmp, transferRepository(server));
|
||||||
|
project.enableAutoDownloadPurge();
|
||||||
|
project.dependencies().scope(compile)
|
||||||
|
.include(new Bom("com.example", "bom1", new VersionNumber(1, 0, 0)))
|
||||||
|
.include(new Dependency("com.example", "a"));
|
||||||
|
assertEquals(0, project.execute(new String[]{"version"}));
|
||||||
|
assertTrue(new File(tmp, "lib/compile/a-1.4.0.jar").exists());
|
||||||
|
|
||||||
|
// upgrading the BOM version invalidates the cache,
|
||||||
|
// downloads the new version and purges the old one
|
||||||
|
project = new BomProject(tmp, transferRepository(server));
|
||||||
|
project.enableAutoDownloadPurge();
|
||||||
|
project.dependencies().scope(compile)
|
||||||
|
.include(new Bom("com.example", "bom1", new VersionNumber(2, 0, 0)))
|
||||||
|
.include(new Dependency("com.example", "a"));
|
||||||
|
assertEquals(0, project.execute(new String[]{"version"}));
|
||||||
|
assertTrue(new File(tmp, "lib/compile/a-2.2.0.jar").exists());
|
||||||
|
assertFalse(new File(tmp, "lib/compile/a-1.4.0.jar").exists());
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
FileUtils.deleteDirectory(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testProjectUpdatesWithBom() 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", "2.0.0", "1.0.0", "2.0.0"),
|
||||||
|
"a", metadata("a", "9.9.9", "1.4.0", "9.9.9")));
|
||||||
|
server.start();
|
||||||
|
var tmp = Files.createTempDirectory("bomupdates").toFile();
|
||||||
|
try {
|
||||||
|
var project = new BomProject(tmp, transferRepository(server));
|
||||||
|
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 newer BOM version is reported with its type suffix
|
||||||
|
assertTrue(output.contains("com.example:bom1:2.0.0@bom"), output);
|
||||||
|
// the version-less dependency covered by the BOM
|
||||||
|
// is not reported individually
|
||||||
|
assertFalse(output.contains("com.example:a"), output);
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
FileUtils.deleteDirectory(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testProjectDependencyTreeWithBom() 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", "")),
|
||||||
|
Map.of("a", metadata("a", "2.2.0", "1.4.0", "2.2.0")));
|
||||||
|
server.start();
|
||||||
|
var tmp = Files.createTempDirectory("bomtree").toFile();
|
||||||
|
try {
|
||||||
|
var project = new BomProject(tmp, transferRepository(server));
|
||||||
|
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[]{"dependency-tree"});
|
||||||
|
} finally {
|
||||||
|
System.setOut(original_out);
|
||||||
|
}
|
||||||
|
var output = captured.toString();
|
||||||
|
|
||||||
|
assertEquals(0, status);
|
||||||
|
// the tree reflects the BOM version, not the latest version
|
||||||
|
assertTrue(output.contains("com.example:a:1.4.0"), output);
|
||||||
|
assertFalse(output.contains("com.example:a:2.2.0"), output);
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
FileUtils.deleteDirectory(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testProjectMissingBomFails() throws Exception {
|
||||||
|
// the BOM is deliberately the only artifact that is missing
|
||||||
|
var server = createArtifactServer(Map.of(
|
||||||
|
"a:1.0.0", pom("a", "1.0.0", "")));
|
||||||
|
server.start();
|
||||||
|
var tmp = Files.createTempDirectory("bommissingproject").toFile();
|
||||||
|
try {
|
||||||
|
var project = new BomProject(tmp, transferRepository(server));
|
||||||
|
project.dependencies().scope(compile)
|
||||||
|
.include(new Bom("com.example", "missing", new VersionNumber(1, 0, 0)))
|
||||||
|
.include(new Dependency("com.example", "a", new VersionNumber(1, 0, 0)));
|
||||||
|
|
||||||
|
assertNotEquals(0, project.execute(new String[]{"download"}));
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
FileUtils.deleteDirectory(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Repository transferRepository(HttpServer server) {
|
||||||
|
return new Repository("http://localhost:" + server.getAddress().getPort() + "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testProjectDownloadVertxBom() throws Exception {
|
||||||
|
// real-world reproduction of the scenario in
|
||||||
|
// https://github.com/rife2/bld/issues/59 through a full project
|
||||||
|
var tmp = Files.createTempDirectory("bomvertx").toFile();
|
||||||
|
try {
|
||||||
|
var project = new BomProject(tmp, getNextRepository());
|
||||||
|
project.dependencies().scope(compile)
|
||||||
|
.include(new Bom("io.vertx", "vertx-stack-depchain", new VersionNumber(4, 5, 12)))
|
||||||
|
.include(new Dependency("io.vertx", "vertx-core"))
|
||||||
|
.include(new Dependency("com.fasterxml.jackson.core", "jackson-databind"));
|
||||||
|
|
||||||
|
assertEquals(0, project.execute(new String[]{"download"}));
|
||||||
|
|
||||||
|
var jars = List.of(java.util.Objects.requireNonNull(new File(tmp, "lib/compile").list()));
|
||||||
|
assertTrue(jars.contains("vertx-core-4.5.12.jar"), jars.toString());
|
||||||
|
assertTrue(jars.contains("jackson-databind-2.16.1.jar"), jars.toString());
|
||||||
|
assertTrue(jars.contains("jackson-core-2.16.1.jar"), jars.toString());
|
||||||
|
// no jackson artifact resolved to anything but the BOM version
|
||||||
|
assertEquals(0, jars.stream().filter(jar -> jar.startsWith("jackson-") && !jar.contains("2.16.1")).count(), jars.toString());
|
||||||
|
} finally {
|
||||||
|
FileUtils.deleteDirectory(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testProjectDownloadJUnitBomTestScope() throws Exception {
|
||||||
|
// real-world reproduction of the scenario reported for the
|
||||||
|
// BOMs getting lost when operations copy the project scopes
|
||||||
|
var tmp = Files.createTempDirectory("bomjunit").toFile();
|
||||||
|
try {
|
||||||
|
var project = new BomProject(tmp, getNextRepository());
|
||||||
|
project.dependencies().scope(Scope.test)
|
||||||
|
.include(new Bom("org.junit", "junit-bom", new VersionNumber(6, 1, 1)))
|
||||||
|
.include(new Dependency("org.junit.jupiter", "junit-jupiter"))
|
||||||
|
.include(new Dependency("org.junit.platform", "junit-platform-console-standalone"));
|
||||||
|
|
||||||
|
assertEquals(0, project.execute(new String[]{"download"}));
|
||||||
|
|
||||||
|
var jars = List.of(java.util.Objects.requireNonNull(new File(tmp, "lib/test").list()));
|
||||||
|
assertTrue(jars.contains("junit-jupiter-6.1.1.jar"), jars.toString());
|
||||||
|
// every artifact that junit-bom manages is pinned to the BOM version
|
||||||
|
assertEquals(0, jars.stream().filter(jar -> jar.startsWith("junit-") &&
|
||||||
|
!jar.startsWith("junit-platform-console-standalone-") &&
|
||||||
|
!jar.contains("6.1.1")).count(), jars.toString());
|
||||||
|
// junit-bom deliberately doesn't manage the console-standalone
|
||||||
|
// distribution artifact, so it resolves to its latest version
|
||||||
|
assertTrue(jars.stream().anyMatch(jar -> jar.startsWith("junit-platform-console-standalone-")), jars.toString());
|
||||||
|
} finally {
|
||||||
|
FileUtils.deleteDirectory(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testProjectUpdatesRealBom() throws Exception {
|
||||||
|
// a real-world BOM with known newer releases reports its own
|
||||||
|
// update while its covered dependencies stay silent
|
||||||
|
var tmp = Files.createTempDirectory("bomupdatesreal").toFile();
|
||||||
|
try {
|
||||||
|
var project = new BomProject(tmp, getNextRepository());
|
||||||
|
project.dependencies().scope(Scope.test)
|
||||||
|
.include(new Bom("org.junit", "junit-bom", new VersionNumber(6, 1, 1)))
|
||||||
|
.include(new Dependency("org.junit.jupiter", "junit-jupiter"));
|
||||||
|
|
||||||
|
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);
|
||||||
|
assertTrue(output.contains("org.junit:junit-bom:"), output);
|
||||||
|
assertTrue(output.contains("@bom"), output);
|
||||||
|
assertFalse(output.contains("org.junit.jupiter:junit-jupiter:"), output);
|
||||||
|
} finally {
|
||||||
|
FileUtils.deleteDirectory(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testBomVertxAcceptance() {
|
void testBomVertxAcceptance() {
|
||||||
// reproduction of the scenario in https://github.com/rife2/bld/issues/59
|
// reproduction of the scenario in https://github.com/rife2/bld/issues/59
|
||||||
|
|
|
||||||
|
|
@ -379,6 +379,39 @@ public class TestDependencySet {
|
||||||
"""), dependencies.generateTransitiveDependencyTree(VersionResolution.dummy(), ArtifactRetriever.instance(), RepositoryTestHelper.getNextRepositories(), compile, runtime));
|
"""), dependencies.generateTransitiveDependencyTree(VersionResolution.dummy(), ArtifactRetriever.instance(), RepositoryTestHelper.getNextRepositories(), compile, runtime));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCopyAndIncludePreserveAllContents() {
|
||||||
|
var set = new DependencySet()
|
||||||
|
.include(new Dependency("com.uwyn.rife2", "rife2", new VersionNumber(1, 9, 1)))
|
||||||
|
.include(new Bom("io.vertx", "vertx-stack-depchain", new VersionNumber(4, 5, 12)))
|
||||||
|
.include(new LocalDependency("lib/local.jar"))
|
||||||
|
.include(new LocalModule("lib/module.jar"));
|
||||||
|
|
||||||
|
var copy = new DependencySet(set);
|
||||||
|
assertEquals(set, copy);
|
||||||
|
assertEquals(set.boms(), copy.boms());
|
||||||
|
assertEquals(set.localDependencies(), copy.localDependencies());
|
||||||
|
assertEquals(set.localModules(), copy.localModules());
|
||||||
|
|
||||||
|
var included = new DependencySet().include(set);
|
||||||
|
assertEquals(set, included);
|
||||||
|
assertEquals(set.boms(), included.boms());
|
||||||
|
assertEquals(set.localDependencies(), included.localDependencies());
|
||||||
|
assertEquals(set.localModules(), included.localModules());
|
||||||
|
|
||||||
|
var scopes = new DependencyScopes();
|
||||||
|
scopes.scope(Scope.compile).include(set);
|
||||||
|
var scopes_copy = new DependencyScopes();
|
||||||
|
scopes_copy.include(scopes);
|
||||||
|
assertEquals(set.boms(), scopes_copy.scope(Scope.compile).boms());
|
||||||
|
assertEquals(set.localDependencies(), scopes_copy.scope(Scope.compile).localDependencies());
|
||||||
|
|
||||||
|
var scopes_ctor_copy = new DependencyScopes(scopes);
|
||||||
|
assertEquals(set.boms(), scopes_ctor_copy.scope(Scope.compile).boms());
|
||||||
|
assertEquals(set.localDependencies(), scopes_ctor_copy.scope(Scope.compile).localDependencies());
|
||||||
|
assertEquals(set.localModules(), scopes_ctor_copy.scope(Scope.compile).localModules());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testTransferIntoDirectoryParallel() throws Exception {
|
void testTransferIntoDirectoryParallel() throws Exception {
|
||||||
var max_concurrent_transfers = new AtomicInteger();
|
var max_concurrent_transfers = new AtomicInteger();
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,11 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.condition.DisabledOnOs;
|
import org.junit.jupiter.api.condition.DisabledOnOs;
|
||||||
import org.junit.jupiter.api.condition.OS;
|
import org.junit.jupiter.api.condition.OS;
|
||||||
import rife.bld.Project;
|
import rife.bld.Project;
|
||||||
|
import rife.bld.WebProject;
|
||||||
import rife.bld.blueprints.AppProjectBlueprint;
|
import rife.bld.blueprints.AppProjectBlueprint;
|
||||||
import rife.bld.dependencies.*;
|
import rife.bld.dependencies.*;
|
||||||
import rife.bld.publish.PublishArtifact;
|
import rife.bld.publish.PublishArtifact;
|
||||||
|
import rife.bld.publish.PublishInfo;
|
||||||
import rife.tools.FileUtils;
|
import rife.tools.FileUtils;
|
||||||
import rife.tools.exceptions.FileUtilsErrorException;
|
import rife.tools.exceptions.FileUtilsErrorException;
|
||||||
|
|
||||||
|
|
@ -704,4 +706,246 @@ public class TestPublishOperation {
|
||||||
FileUtils.deleteDirectory(tmp1);
|
FileUtils.deleteDirectory(tmp1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPublishLocalWithBom()
|
||||||
|
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>""");
|
||||||
|
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();
|
||||||
|
|
||||||
|
var tmp_local = Files.createTempDirectory("bomlocal").toFile();
|
||||||
|
var artifact_file = File.createTempFile("myapp", ".jar");
|
||||||
|
try {
|
||||||
|
var operation = new PublishOperation()
|
||||||
|
.artifactRetriever(ArtifactRetriever.cachingInstance())
|
||||||
|
.repositories(new Repository(tmp_local.getAbsolutePath()))
|
||||||
|
.dependencyRepositories(List.of(new Repository("http://localhost:" + server.getAddress().getPort() + "/")))
|
||||||
|
.info(new PublishInfo()
|
||||||
|
.groupId("test.pkg")
|
||||||
|
.artifactId("myapp")
|
||||||
|
.version(new VersionNumber(3, 3, 3)))
|
||||||
|
.artifacts(List.of(new PublishArtifact(artifact_file, "", "jar")));
|
||||||
|
operation.dependencies().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"));
|
||||||
|
operation.execute();
|
||||||
|
|
||||||
|
var pom = FileUtils.readString(Path.of(tmp_local.getAbsolutePath(), "test", "pkg", "myapp", "3.3.3", "myapp-3.3.3.pom").toFile());
|
||||||
|
|
||||||
|
// the BOM is imported through dependency management
|
||||||
|
assertTrue(pom.contains("<dependencyManagement>"), pom);
|
||||||
|
assertTrue(pom.contains("<artifactId>bom1</artifactId>"), pom);
|
||||||
|
assertTrue(pom.contains("<version>1.0.0</version>"), pom);
|
||||||
|
assertTrue(pom.contains("<type>pom</type>"), pom);
|
||||||
|
assertTrue(pom.contains("<scope>import</scope>"), pom);
|
||||||
|
|
||||||
|
// the covered dependency stays version-less,
|
||||||
|
// the BOM import provides its version downstream
|
||||||
|
assertTrue(pom.contains("<artifactId>a</artifactId>"), pom);
|
||||||
|
assertFalse(java.util.regex.Pattern.compile("<artifactId>a</artifactId>\\s*<version>").matcher(pom).find(), pom);
|
||||||
|
|
||||||
|
// the uncovered dependency is frozen to its resolved version
|
||||||
|
assertTrue(java.util.regex.Pattern.compile("<artifactId>b</artifactId>\\s*<version>2\\.2\\.0</version>").matcher(pom).find(), pom);
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
artifact_file.delete();
|
||||||
|
FileUtils.deleteDirectory(tmp_local);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testResolveVersionlessDependenciesUntouchedScopes() {
|
||||||
|
// no network access is needed when nothing has to be resolved :
|
||||||
|
// explicitly versioned dependencies are untouched and the test
|
||||||
|
// scope isn't part of the publication
|
||||||
|
var scopes = new DependencyScopes();
|
||||||
|
scopes.scope(Scope.compile)
|
||||||
|
.include(new Dependency("com.example", "c", new VersionNumber(5, 0, 0)));
|
||||||
|
scopes.scope(Scope.test)
|
||||||
|
.include(new Dependency("com.example", "t"));
|
||||||
|
|
||||||
|
var operation = new PublishOperation()
|
||||||
|
.dependencies(scopes);
|
||||||
|
operation.executeResolveVersionlessDependencies();
|
||||||
|
|
||||||
|
assertEquals(new VersionNumber(5, 0, 0), operation.dependencies().scope(Scope.compile).get(new Dependency("com.example", "c")).version());
|
||||||
|
assertEquals(VersionNumber.UNKNOWN, operation.dependencies().scope(Scope.test).get(new Dependency("com.example", "t")).version());
|
||||||
|
}
|
||||||
|
|
||||||
|
static class BomPublishProject extends WebProject {
|
||||||
|
BomPublishProject(File tmp) {
|
||||||
|
workDirectory = tmp;
|
||||||
|
pkg = "test.pkg";
|
||||||
|
name = "myapp";
|
||||||
|
version = new VersionNumber(0, 0, 1);
|
||||||
|
repositories = List.of(new Repository("https://example.com/resolve"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFromProjectDependencyRepositories()
|
||||||
|
throws Exception {
|
||||||
|
var tmp = Files.createTempDirectory("test").toFile();
|
||||||
|
try {
|
||||||
|
var project = new BomPublishProject(tmp);
|
||||||
|
var operation = new PublishOperation()
|
||||||
|
.fromProject(project);
|
||||||
|
assertEquals(project.repositories(), operation.dependencyRepositories());
|
||||||
|
} finally {
|
||||||
|
FileUtils.deleteDirectory(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testResolveVersionlessDependencies()
|
||||||
|
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:3.0.0", """
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>bom2</artifactId>
|
||||||
|
<version>3.0.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>""",
|
||||||
|
"bom2", """
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<metadata>
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>bom2</artifactId>
|
||||||
|
<versioning>
|
||||||
|
<latest>3.0.0</latest>
|
||||||
|
<release>3.0.0</release>
|
||||||
|
<versions><version>3.0.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 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"))
|
||||||
|
.include(new Dependency("com.example", "c", new VersionNumber(5, 0, 0)));
|
||||||
|
scopes.scope(Scope.runtime)
|
||||||
|
.include(new Bom("com.example", "bom2"));
|
||||||
|
|
||||||
|
var operation = new PublishOperation()
|
||||||
|
.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);
|
||||||
|
// covered by the BOM : stays version-less for the POM,
|
||||||
|
// the dependency management import provides the version
|
||||||
|
assertEquals(VersionNumber.UNKNOWN, compile_scope.get(new Dependency("com.example", "a")).version());
|
||||||
|
// not covered : resolved to its latest version
|
||||||
|
assertEquals(new VersionNumber(2, 2, 0), compile_scope.get(new Dependency("com.example", "b")).version());
|
||||||
|
// explicitly versioned : untouched
|
||||||
|
assertEquals(new VersionNumber(5, 0, 0), compile_scope.get(new Dependency("com.example", "c")).version());
|
||||||
|
// a version-less BOM is resolved to its latest version
|
||||||
|
var runtime_boms = operation.dependencies().scope(Scope.runtime).boms();
|
||||||
|
assertEquals(new Bom("com.example", "bom2", new VersionNumber(3, 0, 0)), runtime_boms.iterator().next());
|
||||||
|
} finally {
|
||||||
|
server.stop(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -652,4 +652,93 @@ public class TestPomBuilder {
|
||||||
</project>
|
</project>
|
||||||
""", builder.build());
|
""", builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDependencyManagementScopeBoundaries() {
|
||||||
|
var builder = new PomBuilder();
|
||||||
|
builder.dependencies().scope(Scope.provided)
|
||||||
|
.include(new Bom("org.eclipse.jetty", "jetty-bom", new VersionNumber(12, 0, 16)));
|
||||||
|
builder.dependencies().scope(Scope.test)
|
||||||
|
// the test scope isn't published, its BOMs are not emitted
|
||||||
|
.include(new Bom("org.junit", "junit-bom", new VersionNumber(6, 1, 1)));
|
||||||
|
assertEquals("""
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId></groupId>
|
||||||
|
<artifactId></artifactId>
|
||||||
|
<version></version>
|
||||||
|
<name></name>
|
||||||
|
<description></description>
|
||||||
|
<url></url>
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-bom</artifactId>
|
||||||
|
<version>12.0.16</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
|
""", builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDependencyManagement() {
|
||||||
|
var builder = new PomBuilder();
|
||||||
|
builder.dependencies().scope(Scope.compile)
|
||||||
|
.include(new Bom("io.vertx", "vertx-stack-depchain", new VersionNumber(4, 5, 12)))
|
||||||
|
.include(new Dependency("io.vertx", "vertx-core"));
|
||||||
|
builder.dependencies().scope(Scope.runtime)
|
||||||
|
// duplicate BOMs are only emitted once
|
||||||
|
.include(new Bom("io.vertx", "vertx-stack-depchain", new VersionNumber(4, 5, 12)))
|
||||||
|
.include(new Bom("org.junit", "junit-bom", new VersionNumber(6, 1, 1)));
|
||||||
|
builder.dependencies().scope(Scope.provided)
|
||||||
|
// BOMs without a version are not emitted
|
||||||
|
.include(new Bom("com.example", "versionless-bom"));
|
||||||
|
assertEquals("""
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId></groupId>
|
||||||
|
<artifactId></artifactId>
|
||||||
|
<version></version>
|
||||||
|
<name></name>
|
||||||
|
<description></description>
|
||||||
|
<url></url>
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.vertx</groupId>
|
||||||
|
<artifactId>vertx-stack-depchain</artifactId>
|
||||||
|
<version>4.5.12</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit</groupId>
|
||||||
|
<artifactId>junit-bom</artifactId>
|
||||||
|
<version>6.1.1</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.vertx</groupId>
|
||||||
|
<artifactId>vertx-core</artifactId>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
|
""", builder.build());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue