diff --git a/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyResolver.java b/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyResolver.java index 73439b34..879adcaa 100644 --- a/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyResolver.java +++ b/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyResolver.java @@ -391,16 +391,16 @@ public void log() { public void resolveDependencies() { var enforcedConstraints = getBomConstraints(config.getProjectBom()); - projectBomConstraints = new HashSet<>(enforcedConstraints.size()); - for (Dependency d : enforcedConstraints) { - projectBomConstraints.add(toCoords(d.getArtifact())); - } if (artifactConstraintsProvider == null) { for (var bomCoords : config.getNonProjectBoms()) { enforcedConstraints.addAll(getBomConstraints(bomCoords)); } artifactConstraintsProvider = t -> enforcedConstraints; } + projectBomConstraints = new HashSet<>(enforcedConstraints.size()); + for (Dependency d : enforcedConstraints) { + projectBomConstraints.add(toCoords(d.getArtifact())); + } for (DependencyTreeVisitor v : treeVisitors) { v.beforeAllRoots(); @@ -408,13 +408,13 @@ public void resolveDependencies() { for (ArtifactCoords coords : getProjectArtifacts()) { if (isIncluded(coords) || !isExcluded(coords)) { - processRootArtifact(coords, artifactConstraintsProvider.apply(coords)); + processRootArtifact(coords); } } for (ArtifactCoords coords : toSortedCoords(config.getIncludeArtifacts())) { if (isIncluded(coords) || !isExcluded(coords)) { - processRootArtifact(coords, artifactConstraintsProvider.apply(coords)); + processRootArtifact(coords); } } @@ -528,8 +528,9 @@ protected Iterable getProjectArtifacts() { return result; } - private void processRootArtifact(ArtifactCoords rootArtifact, List managedDeps) { + private void processRootArtifact(ArtifactCoords rootArtifact) { + final List managedDeps = artifactConstraintsProvider.apply(rootArtifact); final DependencyNode root = collectDependencies(rootArtifact, managedDeps); if (root == null) { // couldn't be resolved diff --git a/domino/api/src/test/java/io/quarkus/domino/BasicBomBasedProjectDependencyTest.java b/domino/api/src/test/java/io/quarkus/domino/BasicBomBasedProjectDependencyTest.java index 007ccb0d..fa5aebb8 100644 --- a/domino/api/src/test/java/io/quarkus/domino/BasicBomBasedProjectDependencyTest.java +++ b/domino/api/src/test/java/io/quarkus/domino/BasicBomBasedProjectDependencyTest.java @@ -44,7 +44,7 @@ static void prepareRepo() { .setRepoUrl("https://acme.org/lib") .setTag("1.0"); var acmeParent = acmeProject.createParentPom("acme-parent"); - acmeParent.addBomModule("acme-bom") + acmeParent.addPomModule("acme-bom") .addVersionConstraint("acme-common") .addVersionConstraint("acme-lib") .addVersionConstraint("org.bar", "bar-lib", "1.0"); diff --git a/domino/api/src/test/java/io/quarkus/domino/NonCorePlatformMemberDependenciesTest.java b/domino/api/src/test/java/io/quarkus/domino/NonCorePlatformMemberDependenciesTest.java new file mode 100644 index 00000000..b64e6e83 --- /dev/null +++ b/domino/api/src/test/java/io/quarkus/domino/NonCorePlatformMemberDependenciesTest.java @@ -0,0 +1,232 @@ +package io.quarkus.domino; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +import io.quarkus.bom.decomposer.ReleaseId; +import io.quarkus.bom.decomposer.ReleaseIdFactory; +import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import io.quarkus.domino.test.repo.TestArtifactRepo; +import io.quarkus.domino.test.repo.TestProject; +import io.quarkus.maven.dependency.ArtifactCoords; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +public class NonCorePlatformMemberDependenciesTest { + + @TempDir + static Path testRepoDir; + static MavenArtifactResolver artifactResolver; + static Map> releaseAssertions; + + @BeforeAll + static void prepareRepo() { + var testRepo = TestArtifactRepo.of(testRepoDir); + artifactResolver = testRepo.getArtifactResolver(); + + var byteUtilsProject = TestProject.of("org.bytes", "1.0") + .setRepoUrl("https://bytes.org/code") + .setTag("1.0"); + var byteUtilsLib = byteUtilsProject.createMainModule("byte-utils"); + + var commonsIoProject = TestProject.of("org.commons.io", "1.0") + .setRepoUrl("https://commons.org/code/io") + .setTag("1.0"); + var commonsIoLib = commonsIoProject.createMainModule("commons-io") + .addDependency(byteUtilsLib); + + var quarkusProject = TestProject.of("io.quarkus", "1.0") + .setRepoUrl("https://quarkus.io/code") + .setTag("1.0"); + var quarkusParent = quarkusProject.createParentPom("quarkus-parent"); + var quarkusBom = quarkusParent.addPomModule("quarkus-bom") + .addVersionConstraint("quarkus-core"); + var quarkusBuildParent = quarkusParent.addPomModule("quarkus-build-parent") + .importBom(quarkusBom); + var quarkusCore = quarkusBuildParent.addModule("quarkus-core") + .addDependency(commonsIoLib); + + var filesLibProject = TestProject.of("org.files", "1.0") + .setRepoUrl("https://files.org/code") + .setTag("1.0"); + var filesLib = filesLibProject.createMainModule("file-utils"); + + var xmlLibProject = TestProject.of("org.xml", "1.0") + .setRepoUrl("https://xml.org/code") + .setTag("1.0"); + var xmlLib = xmlLibProject.createMainModule("xml-lib") + .addDependency(filesLib); + + var camelProject = TestProject.of("org.camel", "1.0") + .setRepoUrl("https://camel.org/code") + .setTag("1.0"); + var camelParent = camelProject.createParentPom("camel-parent"); + var camelBom = camelParent.addPomModule("camel-bom") + .addVersionConstraint("camel-core") + .addVersionConstraint("camel-xml-lib") + .addVersionConstraint(xmlLib) + .addVersionConstraint(commonsIoLib); + var camelBuildParent = camelParent.addPomModule("camel-build-parent") + .importBom(camelBom); + var camelCore = camelBuildParent.addModule("camel-core") + .addDependency(quarkusCore); + var camelXmlLib = camelBuildParent.addModule("camel-xml-lib") + .addManagedDependency(camelCore) + .addManagedDependency(xmlLib); + + testRepo.install(quarkusProject) + .install(camelProject) + .install(filesLibProject) + .install(xmlLibProject) + .install(commonsIoProject) + .install(byteUtilsProject); + + releaseAssertions = Map.> of( + ReleaseIdFactory.forScmAndTag("https://quarkus.io/code", "1.0"), + release -> { + assertThat(release.id()).isEqualTo(ReleaseIdFactory.forScmAndTag("https://quarkus.io/code", "1.0")); + assertThat(release.getArtifacts()).hasSize(4); + assertThat(release.getArtifacts()).containsKey(ArtifactCoords.pom("io.quarkus", "quarkus-parent", "1.0")); + assertThat(release.getArtifacts()).containsKey(ArtifactCoords.pom("io.quarkus", "quarkus-bom", "1.0")); + assertThat(release.getArtifacts()) + .containsKey(ArtifactCoords.pom("io.quarkus", "quarkus-build-parent", "1.0")); + assertThat(release.getArtifacts()).containsKey(ArtifactCoords.jar("io.quarkus", "quarkus-core", "1.0")); + assertThat(release.getDependencies()).hasSize(1); + }, + ReleaseIdFactory.forScmAndTag("https://camel.org/code", "1.0"), + release -> { + assertThat(release.id()).isEqualTo(ReleaseIdFactory.forScmAndTag("https://camel.org/code", "1.0")); + assertThat(release.getArtifacts()).hasSize(5); + assertThat(release.getArtifacts()).containsKey(ArtifactCoords.pom("org.camel", "camel-parent", "1.0")); + assertThat(release.getArtifacts()).containsKey(ArtifactCoords.pom("org.camel", "camel-bom", "1.0")); + assertThat(release.getArtifacts()) + .containsKey(ArtifactCoords.pom("org.camel", "camel-build-parent", "1.0")); + assertThat(release.getArtifacts()).containsKey(ArtifactCoords.jar("org.camel", "camel-core", "1.0")); + assertThat(release.getArtifacts()).containsKey(ArtifactCoords.jar("org.camel", "camel-xml-lib", "1.0")); + assertThat(release.getDependencies()).hasSize(2); + }, + ReleaseIdFactory.forScmAndTag("https://xml.org/code", "1.0"), + release -> { + assertThat(release.id()).isEqualTo(ReleaseIdFactory.forScmAndTag("https://xml.org/code", "1.0")); + assertThat(release.getArtifacts()).hasSize(1); + assertThat(release.getArtifacts()).containsKey(ArtifactCoords.jar("org.xml", "xml-lib", "1.0")); + }, + ReleaseIdFactory.forScmAndTag("https://commons.org/code/io", "1.0"), + release -> { + assertThat(release.id()).isEqualTo(ReleaseIdFactory.forScmAndTag("https://commons.org/code/io", "1.0")); + assertThat(release.getArtifacts()).hasSize(1); + assertThat(release.getArtifacts()).containsKey(ArtifactCoords.jar("org.commons.io", "commons-io", "1.0")); + }, + ReleaseIdFactory.forScmAndTag("https://bytes.org/code", "1.0"), + release -> { + assertThat(release.id()).isEqualTo(ReleaseIdFactory.forScmAndTag("https://bytes.org/code", "1.0")); + assertThat(release.getArtifacts()).hasSize(1); + assertThat(release.getArtifacts()).containsKey(ArtifactCoords.jar("org.bytes", "byte-utils", "1.0")); + assertThat(release.getDependencies()).isEmpty(); + }, + ReleaseIdFactory.forScmAndTag("https://files.org/code", "1.0"), + release -> { + assertThat(release.id()).isEqualTo(ReleaseIdFactory.forScmAndTag("https://files.org/code", "1.0")); + assertThat(release.getArtifacts()).hasSize(1); + assertThat(release.getArtifacts()).containsKey(ArtifactCoords.jar("org.files", "file-utils", "1.0")); + assertThat(release.getDependencies()).isEmpty(); + }); + } + + private static ProjectDependencyConfig.Mutable newDependencyConfig() { + return ProjectDependencyConfig.builder() + .setWarnOnMissingScm(true) + .setLegacyScmLocator(true) + .setProjectBom(ArtifactCoords.pom("org.camel", "camel-bom", "1.0")) + .setNonProjectBoms(List.of(ArtifactCoords.pom("io.quarkus", "quarkus-bom", "1.0"))); + } + + @Test + public void managedOnly() { + + var depConfig = newDependencyConfig() + .setIncludeNonManaged(false) + .setProjectArtifacts(List.of( + ArtifactCoords.jar("org.camel", "camel-core", "1.0"), + ArtifactCoords.jar("org.camel", "camel-xml-lib", "1.0"))); + + var rc = ProjectDependencyResolver.builder() + .setArtifactResolver(artifactResolver) + .setDependencyConfig(depConfig.build()) + .build() + .getReleaseCollection(); + assertThat(rc).isNotNull(); + + var releaseAssertions = new HashMap>(); + releaseAssertions.computeIfAbsent(ReleaseIdFactory.forScmAndTag("https://quarkus.io/code", "1.0"), + k -> NonCorePlatformMemberDependenciesTest.releaseAssertions.get(k)); + releaseAssertions.computeIfAbsent(ReleaseIdFactory.forScmAndTag("https://camel.org/code", "1.0"), + k -> NonCorePlatformMemberDependenciesTest.releaseAssertions.get(k)); + releaseAssertions.computeIfAbsent(ReleaseIdFactory.forScmAndTag("https://xml.org/code", "1.0"), + k -> NonCorePlatformMemberDependenciesTest.releaseAssertions.get(k)); + releaseAssertions.computeIfAbsent(ReleaseIdFactory.forScmAndTag("https://commons.org/code/io", "1.0"), + k -> NonCorePlatformMemberDependenciesTest.releaseAssertions.get(k)); + + assertReleaseDependencies(rc, releaseAssertions); + } + + @Test + public void completeTree() { + + var depConfig = newDependencyConfig() + .setProjectArtifacts(List.of( + ArtifactCoords.jar("org.camel", "camel-core", "1.0"), + ArtifactCoords.jar("org.camel", "camel-xml-lib", "1.0"))); + + var rc = ProjectDependencyResolver.builder() + .setArtifactResolver(artifactResolver) + .setDependencyConfig(depConfig.build()) + .build() + .getReleaseCollection(); + assertThat(rc).isNotNull(); + + var releaseAssertions = new HashMap>(); + releaseAssertions.computeIfAbsent(ReleaseIdFactory.forScmAndTag("https://quarkus.io/code", "1.0"), + k -> NonCorePlatformMemberDependenciesTest.releaseAssertions.get(k)); + releaseAssertions.computeIfAbsent(ReleaseIdFactory.forScmAndTag("https://camel.org/code", "1.0"), + k -> NonCorePlatformMemberDependenciesTest.releaseAssertions.get(k)); + releaseAssertions.computeIfAbsent(ReleaseIdFactory.forScmAndTag("https://xml.org/code", "1.0"), + k -> NonCorePlatformMemberDependenciesTest.releaseAssertions.get(k)); + releaseAssertions.computeIfAbsent(ReleaseIdFactory.forScmAndTag("https://commons.org/code/io", "1.0"), + k -> NonCorePlatformMemberDependenciesTest.releaseAssertions.get(k)); + releaseAssertions.computeIfAbsent(ReleaseIdFactory.forScmAndTag("https://bytes.org/code", "1.0"), + k -> NonCorePlatformMemberDependenciesTest.releaseAssertions.get(k)); + releaseAssertions.computeIfAbsent(ReleaseIdFactory.forScmAndTag("https://files.org/code", "1.0"), + k -> NonCorePlatformMemberDependenciesTest.releaseAssertions.get(k)); + + assertReleaseDependencies(rc, releaseAssertions); + } + + private static void assertReleaseDependencies(ReleaseCollection rc, + HashMap> releaseAssertions) { + for (ReleaseRepo r : rc.getReleases()) { + var assertions = releaseAssertions.remove(r.id()); + if (assertions == null) { + fail("Unexpected release " + r.id()); + } else { + assertions.accept(r); + } + } + + if (!releaseAssertions.isEmpty()) { + var i = releaseAssertions.keySet().iterator(); + var sb = new StringBuilder(); + sb.append("Missing release(s): ").append(i.next()); + while (i.hasNext()) { + sb.append(", ").append(i.next()); + } + fail(sb.toString()); + } + } +} diff --git a/domino/api/src/test/java/io/quarkus/domino/test/repo/TestModule.java b/domino/api/src/test/java/io/quarkus/domino/test/repo/TestModule.java index 87e16bcc..aaec90fb 100644 --- a/domino/api/src/test/java/io/quarkus/domino/test/repo/TestModule.java +++ b/domino/api/src/test/java/io/quarkus/domino/test/repo/TestModule.java @@ -117,7 +117,7 @@ public TestModule addModule(String artifactId) { return module; } - public TestModule addBomModule(String artifactId) { + public TestModule addPomModule(String artifactId) { return addModule(artifactId).setPackaging(ArtifactCoords.TYPE_POM); } @@ -125,6 +125,11 @@ public TestModule addDependency(String artifactId) { return addDependency(ArtifactCoords.jar(getGroupId(), artifactId, getVersion()), JavaScopes.COMPILE); } + public TestModule addDependency(TestModule module) { + return addDependency(ArtifactCoords.jar(module.getGroupId(), module.getArtifactId(), module.getVersion()), + JavaScopes.COMPILE); + } + public TestModule addDependency(String groupId, String artifactId, String version) { return addDependency(ArtifactCoords.jar(groupId, artifactId, version), JavaScopes.COMPILE); } @@ -137,10 +142,19 @@ public TestModule addDependency(ArtifactCoords coords, String scope) { return this; } + public TestModule addManagedDependency(TestModule module) { + return addDependency(ArtifactCoords.jar(module.getGroupId(), module.getArtifactId(), null), JavaScopes.COMPILE); + } + public TestModule addVersionConstraint(String artifactId) { return addVersionConstraint(ArtifactCoords.jar(getGroupId(), artifactId, getVersion()), JavaScopes.COMPILE); } + public TestModule addVersionConstraint(TestModule module) { + return addVersionConstraint(ArtifactCoords.jar(module.getGroupId(), module.getArtifactId(), module.getVersion()), + JavaScopes.COMPILE); + } + public TestModule addVersionConstraint(String groupId, String artifactId, String version) { return addVersionConstraint(ArtifactCoords.jar(groupId, artifactId, version), JavaScopes.COMPILE); } @@ -153,6 +167,10 @@ public TestModule addVersionConstraint(ArtifactCoords coords, String scope) { return this; } + public TestModule importBom(TestModule module) { + return importBom(module.getGroupId(), module.getArtifactId(), module.getVersion()); + } + public TestModule importBom(String artifactId) { return addVersionConstraint(ArtifactCoords.pom(getGroupId(), artifactId, getVersion()), "import"); }