diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/bf/DependencyResolutionSkipper.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/bf/DependencyResolutionSkipper.java index c27c15f4e..2e5213924 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/bf/DependencyResolutionSkipper.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/bf/DependencyResolutionSkipper.java @@ -250,6 +250,12 @@ private CacheManager(Function keyFunction) { } boolean isVersionConflict(DependencyNode node) { + if (isRangeDependency(node)) { + // A version range can select a different version than one already seen. Resolve it so its + // dependencies are available to the conflict resolver. + return false; + } + String ga = keyFunction.apply(node.getArtifact()); if (winnerGAs.containsKey(ga)) { Artifact result = winnerGAs.get(ga); @@ -261,12 +267,20 @@ boolean isVersionConflict(DependencyNode node) { void cacheWinner(DependencyNode node) { winners.put(node.getArtifact(), node); - winnerGAs.put(keyFunction.apply(node.getArtifact()), node.getArtifact()); + // A range candidate is not a reliable winner for the versionless key. + if (!isRangeDependency(node)) { + winnerGAs.put(keyFunction.apply(node.getArtifact()), node.getArtifact()); + } } boolean isDuplicate(DependencyNode node) { return winners.containsKey(node.getArtifact()); } + + private static boolean isRangeDependency(DependencyNode node) { + return node.getVersionConstraint() != null + && node.getVersionConstraint().getRange() != null; + } } private static final class CoordinateManager { diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/bf/BfWithSkipperDependencyCollectorTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/bf/BfWithSkipperDependencyCollectorTest.java index 4876e40d5..583984520 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/bf/BfWithSkipperDependencyCollectorTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/bf/BfWithSkipperDependencyCollectorTest.java @@ -140,6 +140,26 @@ void testPoolCacheTransparencyWithTransitiveDependencyManager() throws Dependenc "c under b-alt should have d as a child"); } + @Test + void testVersionRangeCandidateDependenciesAreNotSkipped() throws DependencyCollectionException { + collector = setupCollector(newReader("maven13430/")); + + CollectResult result = collector.collectDependencies( + session, + new CollectRequest(newDep("maven13430:root:ext:1", "compile"), Collections.singletonList(repository))); + + assertEquals(0, result.getExceptions().size()); + + DependencyNode rangeCandidate = path(result.getRoot(), 0, 0); + assertEquals("library", rangeCandidate.getArtifact().getArtifactId()); + assertEquals("3", rangeCandidate.getArtifact().getVersion()); + assertTrue( + rangeCandidate.getChildren().stream() + .anyMatch( + node -> "range-asset".equals(node.getArtifact().getArtifactId())), + "dependencies of the resolved version-range candidate must be collected"); + } + @Test void testSkipperWithDifferentExclusion() throws DependencyCollectionException { collector = setupCollector(newReader("managed/")); diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/bf/DependencyResolutionSkipperTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/bf/DependencyResolutionSkipperTest.java index 3f6f5cd9a..b971a2443 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/bf/DependencyResolutionSkipperTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/bf/DependencyResolutionSkipperTest.java @@ -30,6 +30,7 @@ import org.eclipse.aether.graph.DependencyNode; import org.eclipse.aether.internal.test.util.TestVersion; import org.eclipse.aether.internal.test.util.TestVersionConstraint; +import org.eclipse.aether.util.version.GenericVersionScheme; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -101,6 +102,29 @@ void testSkipVersionConflict() { } } + @Test + void testVersionRangeDoesNotReplaceVersionlessWinner() throws Exception { + DependencyNode pinned = makeDependencyNode("some-group", "A", "1.0"); + DefaultDependencyNode ranged = (DefaultDependencyNode) makeDependencyNode("some-group", "A", "3.0"); + ranged.setVersionConstraint(new GenericVersionScheme().parseVersionConstraint("[2.0,4.0)")); + DependencyNode pinnedAgain = makeDependencyNode("some-group", "A", "1.0"); + + try (DependencyResolutionSkipper.DefaultDependencyResolutionSkipper skipper = + DependencyResolutionSkipper.defaultGACESkipper()) { + assertFalse(skipper.skipResolution(pinned, new ArrayList<>())); + skipper.cache(pinned, new ArrayList<>()); + + assertFalse(skipper.skipResolution(ranged, new ArrayList<>())); + skipper.cache(ranged, new ArrayList<>()); + + assertTrue(skipper.skipResolution(pinnedAgain, new ArrayList<>())); + DependencyResolutionSkipper.DependencyResolutionResult result = + skipper.getResults().get(pinnedAgain); + assertTrue(result.skippedAsDuplicate); + assertFalse(result.skippedAsVersionConflict); + } + } + @Test void testSkipDeeperDuplicateNode() { // A -> B diff --git a/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_library_1.ini b/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_library_1.ini new file mode 100644 index 000000000..61a252c23 --- /dev/null +++ b/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_library_1.ini @@ -0,0 +1 @@ +[dependencies] diff --git a/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_library_2.ini b/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_library_2.ini new file mode 100644 index 000000000..61a252c23 --- /dev/null +++ b/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_library_2.ini @@ -0,0 +1 @@ +[dependencies] diff --git a/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_library_3.ini b/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_library_3.ini new file mode 100644 index 000000000..dad0a3c16 --- /dev/null +++ b/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_library_3.ini @@ -0,0 +1,2 @@ +[dependencies] +maven13430:range-asset:ext:1 diff --git a/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_parent_1.ini b/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_parent_1.ini new file mode 100644 index 000000000..792ffd505 --- /dev/null +++ b/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_parent_1.ini @@ -0,0 +1,2 @@ +[dependencies] +maven13430:library:ext:[2,4) diff --git a/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_range-asset_1.ini b/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_range-asset_1.ini new file mode 100644 index 000000000..61a252c23 --- /dev/null +++ b/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_range-asset_1.ini @@ -0,0 +1 @@ +[dependencies] diff --git a/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_root_1.ini b/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_root_1.ini new file mode 100644 index 000000000..6fc4dfa04 --- /dev/null +++ b/maven-resolver-impl/src/test/resources/artifact-descriptions/maven13430/maven13430_root_1.ini @@ -0,0 +1,3 @@ +[dependencies] +maven13430:parent:ext:1 +maven13430:library:ext:1