Skip to content

Commit

Permalink
fix: handle circular dependencies in Gradle scans (#62)
Browse files Browse the repository at this point in the history
  • Loading branch information
kyegupov authored Apr 16, 2019
1 parent 57b0985 commit 26406d7
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 9 deletions.
20 changes: 13 additions & 7 deletions lib/init.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,22 @@ allprojects { everyProj ->
task snykResolvedDepsJson {
def onlyConf = project.hasProperty('configuration') ? configuration : null

// currentChain is a protection against dependency cycles, which are perfectly normal in Java/Gradle world
def depsToDict
depsToDict = { deps ->
depsToDict = { Iterable deps, Set currentChain ->
def res = [:]
deps.each { d ->
def row = ['name': "$d.moduleGroup:$d.moduleName", 'version': d.moduleVersion]
def subDeps = depsToDict(d.children)
if (subDeps.size() > 0) {
row['dependencies'] = subDeps
def depName = "$d.moduleGroup:$d.moduleName"
if (!currentChain.contains(depName)) {
def row = ['name': depName, 'version': d.moduleVersion]
currentChain.add(depName)
def subDeps = depsToDict(d.children, currentChain)
currentChain.remove(depName)
if (subDeps.size() > 0) {
row['dependencies'] = subDeps
}
res[row['name']] = row
}
res[row['name']] = row
}
return res
}
Expand Down Expand Up @@ -84,7 +90,7 @@ allprojects { everyProj ->
if (snykConf != null) {
projectsDict[proj.name] = [
'targetFile': findProject(proj.path).buildFile.toString(),
'depDict': depsToDict(snykConf.resolvedConfiguration.firstLevelModuleDependencies)
'depDict': depsToDict(snykConf.resolvedConfiguration.firstLevelModuleDependencies, new HashSet())
]
} else {
projectsDict[proj.name] = [
Expand Down
15 changes: 15 additions & 0 deletions test/fixtures/multi-project-dependency-cycle/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apply plugin: 'java'
apply plugin: 'maven'

group = 'com.github.jitpack'

sourceCompatibility = 1.8 // java 8
targetCompatibility = 1.8

repositories {
mavenCentral()
}

dependencies {
compile project(':subproj')
}
5 changes: 5 additions & 0 deletions test/fixtures/multi-project-dependency-cycle/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
rootProject.name = 'root-proj'

include 'subproj'


50 changes: 50 additions & 0 deletions test/fixtures/multi-project-dependency-cycle/subproj/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
apply plugin: 'java'
apply plugin: 'maven'

group = 'com.github.jitpack'

sourceCompatibility = 1.8 // java 8
targetCompatibility = 1.8

repositories {
mavenCentral()
}

dependencies {
compile 'com.google.guava:guava:18.0'
compile 'batik:batik-dom:1.6'
compile 'commons-discovery:commons-discovery:0.2'
compileOnly 'axis:axis:1.3'
compile 'com.android.tools.build:builder:2.3.0'
compile project(':')
}

task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
}

task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}

artifacts {
archives sourcesJar
archives javadocJar
}

// To specify a license in the pom:
install {
repositories.mavenInstaller {
pom.project {
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
distribution 'repo'
}
}
}
}
}
56 changes: 54 additions & 2 deletions test/system/multi-module.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ test('multi-project: only sub-project has deps, none returned for main', async (
path.join(fixtureDir('multi-project'), 'build.gradle'));
t.match(result.package.name, '.',
'returned project name is not sub-project');
t.deepEqual(result.plugin.meta!.allDepRootNames, ['root-proj', 'subproj']);
t.deepEqual(result.plugin.meta!.allDepRootNames, ['root-proj', 'subproj']);
t.notOk(result.package.dependencies);
});

Expand Down Expand Up @@ -204,4 +204,56 @@ test('multi-project: multiDepRoots + configuration', async (t) => {
// t.match(p.targetFile, 'subproj' + dirSep + 'build.gradle', 'correct targetFile for the main depRoot');
}
}
});
});

test('multi-project-dependency-cycle: scanning the main project works fine', async (t) => {
const result = await inspect('.',
path.join(fixtureDir('multi-project-dependency-cycle'), 'build.gradle'),
{});
t.equal(result.package.name, '.', 'root project name is "."');
t.deepEqual(result.plugin.meta!.allDepRootNames, ['root-proj', 'subproj']);

t.equal(result.package
.dependencies!['com.github.jitpack:subproj']
.dependencies!['com.github.jitpack:root-proj'].version,
"unspecified",
'dependency cycle is returned in the results');

t.notOk(result.package
.dependencies!['com.github.jitpack:subproj']
.dependencies!['com.github.jitpack:root-proj'].dependencies,
'dependency cycle is terminated');

t.equal(result.package
.dependencies!['com.github.jitpack:subproj']
.dependencies!['com.android.tools.build:builder']
.dependencies!['com.android.tools:sdklib']
.dependencies!['com.android.tools:repository']
.dependencies!['com.android.tools:common']
.dependencies!['com.android.tools:annotations'].version,
'25.3.0',
'a dependency chain is found through subproj dependency');
});

test('multi-project-dependency-cycle: scanning all subprojects works fine', async (t) => {
const result = await inspect('.',
path.join(fixtureDir('multi-project-dependency-cycle'), 'build.gradle'),
{multiDepRoots: true});
// It's an array, so we have to scan
t.equal(result.depRoots.length, 2);
for (const p of result.depRoots) {
if (p.depTree.name === '.') {
t.equal(p.depTree
.dependencies!['com.github.jitpack:subproj']
.dependencies!['com.github.jitpack:root-proj'].version,
"unspecified",
'dependency cycle is returned for the main');
} else {
t.equal(p.depTree
.dependencies!['com.github.jitpack:root-proj']
.dependencies!['com.github.jitpack:subproj'].version,
"unspecified",
'dependency cycle is returned for the subproj');
}
}
});

0 comments on commit 26406d7

Please sign in to comment.