Skip to content

Commit dd4d184

Browse files
authored
Fix Gradle circular dependency resolution
1 parent f4760a0 commit dd4d184

File tree

1 file changed

+25
-17
lines changed

1 file changed

+25
-17
lines changed

Diff for: build-info-extractor-gradle/src/main/groovy/org/jfrog/gradle/plugin/artifactory/extractor/listener/ArtifactoryDependencyResolutionListener.groovy

+25-17
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import static org.jfrog.build.extractor.BuildInfoExtractorUtils.getModuleIdStrin
1515
* which is used in the 'requestedBy' field of every dependency in the build info.
1616
* Does so by listening to the 'afterResolve' event of every module.
1717
*/
18+
@SuppressWarnings("unused")
1819
class ArtifactoryDependencyResolutionListener implements DependencyResolutionListener {
1920
final Map<String, Map<String, String[][]>> modulesHierarchyMap = new HashMap()
2021

@@ -33,6 +34,7 @@ class ArtifactoryDependencyResolutionListener implements DependencyResolutionLis
3334
* Handles the modules' hierarchy map update.
3435
* @param dependencies - Module's resolved dependencies.
3536
*/
37+
@SuppressWarnings("unused")
3638
void updateModulesHierarchyMap(ResolvableDependencies dependencies) {
3739
String compId = getGav(dependencies.getResolutionResult().getRoot().getModuleVersion())
3840
// If the module was already visited, update it.
@@ -53,39 +55,45 @@ class ArtifactoryDependencyResolutionListener implements DependencyResolutionLis
5355
for (DependencyResult dependency : dependencies) {
5456
// Update the map for every resolved dependency.
5557
if (dependency instanceof ResolvedDependencyResult) {
56-
String[] newDependent = getPathToRoot(dependency)
58+
List<String> newDependentsList = new ArrayList<>()
59+
populateDependentsList(dependency, newDependentsList)
5760

5861
// Add the new dependent's path to root to the 2d array.
5962
String compId = getGav(dependency.getSelected().getModuleVersion())
60-
String[][] curDependants = hierarchyMap[compId]
61-
curDependants = ArrayUtils.add(curDependants, newDependent)
62-
hierarchyMap[compId] = curDependants
63+
String[][] curDependents = hierarchyMap[compId]
64+
curDependents = ArrayUtils.add(curDependents, newDependentsList as String[])
65+
hierarchyMap[compId] = curDependents
6366
}
6467
}
6568
}
6669

6770
/**
68-
* Recursively populate a pathToRoot array of transitive dependencies.
69-
* @param dependency
70-
* @return
71+
* Recursively populate a pathToRoot list of transitive dependencies. Root is expected to be last in list.
72+
* @param dependency - To populate the dependents list for.
73+
* @param dependents - Dependents list to populate.
7174
*/
72-
private String[] getPathToRoot(ResolvedDependencyResult dependency) {
75+
private void populateDependentsList(ResolvedDependencyResult dependency, List<String> dependents) {
7376
ResolvedComponentResult from = dependency.getFrom()
7477
if (from.getDependents().isEmpty()) {
75-
// If the dependency was requested by root, return an array with the root's GAV.
78+
// If the dependency was requested by root, append the root's GAV.
7679
if (from.getSelectionReason().isExpected()) {
77-
return [getGav(from.getModuleVersion())]
80+
dependents << getGav(from.getModuleVersion())
81+
return
7882
}
7983
// Unexpected result.
80-
return new RuntimeException("Failed populating dependency parents map: dependency has no dependents and is not root.")
84+
throw new RuntimeException("Failed populating dependency parents map: dependency has no dependents and is not root.")
8185
}
82-
// Get parent's path to root, then add the parent's GAV.
83-
// We assume the first parent in the list, is the item that that triggered this dependency resolution.
86+
// We assume the first parent in the list, is the item that triggered this dependency resolution.
8487
ResolvedDependencyResult parent = from.getDependents().iterator().next()
85-
List<String> dependants = getPathToRoot(parent)
86-
// Add the current parent to the beginning of the list.
87-
dependants.add(0, getGav(parent.getSelected().getModuleVersion()))
88-
return dependants
88+
String parentGav = getGav(parent.getSelected().getModuleVersion())
89+
// Check for circular dependencies loop. We do this check to avoid an infinite loop dependencies. For example: A --> B --> C --> A...
90+
if (dependents.contains(parentGav)) {
91+
return
92+
}
93+
// Append the current parent's GAV to list.
94+
dependents << parentGav
95+
// Continue populating dependents list.
96+
populateDependentsList(parent, dependents)
8997
}
9098

9199
private static String getGav(ModuleVersionIdentifier module) {

0 commit comments

Comments
 (0)