Skip to content

Commit

Permalink
fix: make the injected script scan only one sub-project (#67)
Browse files Browse the repository at this point in the history
  • Loading branch information
kyegupov authored May 17, 2019
1 parent 4900529 commit 19b56c4
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 11 deletions.
19 changes: 16 additions & 3 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,17 @@ export interface MultiRootsInspectOptions extends BaseInspectOptions {
// Dep roots correspond to sub-projects in Gradle or projects in a Yark workspace.
// Eventually, this flag will be an implicit default.
// For now, plugins return SingleDepRootResult by default.

// TODO(kyegupov): this should be renamed to allSubProjects,
// see https://github.com/snyk/snyk-cli-interface/blob/master/lib/legacy/plugin.ts
multiDepRoots: true;
}

function isMultiSubProject(options: SingleRootInspectOptions | MultiRootsInspectOptions):
options is MultiRootsInspectOptions {
return (options as MultiRootsInspectOptions).multiDepRoots;
}

// Legacy result type. Will be deprecated soon.
export interface SingleDepRootResult {
plugin: PluginMetadata;
Expand Down Expand Up @@ -102,7 +110,7 @@ export async function inspect(root, targetFile, options?: SingleRootInspectOptio
runtime: 'unknown',
targetFile: targetFileFilteredForCompatibility(targetFile),
};
if ((options as MultiRootsInspectOptions).multiDepRoots) {
if (isMultiSubProject(options)) {
if (subProject) {
throw new Error('gradle-sub-project flag is incompatible with multiDepRoots');
}
Expand Down Expand Up @@ -227,7 +235,8 @@ async function getAllDepsAllProjects(root, targetFile, options): Promise<DepRoot
});
}

async function getAllDeps(root, targetFile, options): Promise<JsonDepsScriptResult> {
async function getAllDeps(root, targetFile, options: SingleRootInspectOptions | MultiRootsInspectOptions):
Promise<JsonDepsScriptResult> {
const args = buildArgs(root, targetFile, options.args);

let tmpInitGradle: tmp.SynchrounousResult | null = null;
Expand Down Expand Up @@ -257,6 +266,10 @@ async function getAllDeps(root, targetFile, options): Promise<JsonDepsScriptResu
throw error;
}

if (!isMultiSubProject(options)) {
args.push('-PonlySubProject=' + (options['gradle-sub-project'] || '.'));
}

args.push('-I ' + initGradlePath);

// There might be a --configuration option in 'args'.
Expand Down Expand Up @@ -352,7 +365,7 @@ function getCommand(root, targetFile) {
return 'gradle';
}

function buildArgs(root, targetFile, gradleArgs: string[]) {
function buildArgs(root, targetFile, gradleArgs?: string[]) {
const args: string[] = [];
args.push('snykResolvedDepsJson', '-q');
if (targetFile) {
Expand Down
15 changes: 12 additions & 3 deletions lib/init.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import groovy.json.JsonOutput

// CLI usages:
// gradle -q -I init.gradle snykResolvedDepsJson
// gradle -q -I init.gradle snykResolvedDepsJson -Pconfiguration=specificConf
// gradle -q -I init.gradle snykResolvedDepsJson -Pconfiguration=specificConf -PonlySubProject=sub-project

// (-q to have clean output, -P supplies args as per https://stackoverflow.com/a/48370451)

Expand Down Expand Up @@ -45,6 +45,7 @@ import groovy.json.JsonOutput
def snykMergedDepsConfExecuted = false
allprojects { everyProj ->
task snykResolvedDepsJson {
def onlyProj = project.hasProperty('onlySubProject') ? onlySubProject : null
def onlyConf = project.hasProperty('configuration') ? configuration : null

// currentChain is a protection against dependency cycles, which are perfectly normal in Java/Gradle world
Expand All @@ -69,9 +70,17 @@ allprojects { everyProj ->

doLast { task ->
def projectsDict = [:]
def result = ['defaultProject': task.project.name, 'projects': projectsDict]
def defaultProjectName = task.project.name
def result = ['defaultProject': defaultProjectName, 'projects': projectsDict]
if (!snykMergedDepsConfExecuted) {
allprojects.each { proj ->

def shouldScanProject = {
onlyProj == null ||
(onlyProj == '.' && it.name == defaultProjectName) ||
it.name == onlyProj
}

allprojects.findAll(shouldScanProject).each { proj ->
def snykConf = null
if (proj.configurations.size() > 0) {
if (onlyConf != null) {
Expand Down
4 changes: 4 additions & 0 deletions test/fixtures/api-configuration/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
apply plugin: 'java-library'

repositories {
mavenCentral()
}

dependencies {
api 'commons-httpclient:commons-httpclient:3.1'
}
Empty file.
6 changes: 6 additions & 0 deletions test/fixtures/multi-project-some-unscannable/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
rootProject.name = 'root-proj'

include 'subproj'
include 'subproj-fail'


Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
apply plugin: 'java'
apply plugin: 'maven'

group = 'com.github.jitpack'

sourceCompatibility = 1.8 // java 8
targetCompatibility = 1.8

repositories {
mavenCentral()
}

dependencies {
compile 'private.inaccessible:dependency:42.1337'
}

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
}
49 changes: 49 additions & 0 deletions test/fixtures/multi-project-some-unscannable/subproj/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
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'
}

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'
}
}
}
}
}
46 changes: 41 additions & 5 deletions test/system/multi-module.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ test('multi-project: only sub-project has deps and they are returned', async (t)
options);
t.match(result.package.name, '/subproj',
'sub project name is included in the root pkg name');
t.deepEqual(result.plugin.meta!.allDepRootNames, ['root-proj', 'subproj']);
t.deepEqual(result.plugin.meta!.allDepRootNames, ['subproj']);

t.equal(result.package
.dependencies!['com.android.tools.build:builder']
Expand All @@ -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']);
t.notOk(result.package.dependencies);
});

Expand All @@ -91,7 +91,7 @@ test('multi-project: using gradle via wrapper', async (t) => {
path.join(fixtureDir('multi-project gradle wrapper'), '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']);
t.notOk(result.package.dependencies);
});

Expand All @@ -110,7 +110,7 @@ test('multi-project: only sub-project has deps and they are returned space needs
path.join(fixtureDir('multi-project'), 'build.gradle'),
options);

t.deepEqual(result.plugin.meta!.allDepRootNames, ['root-proj', 'subproj']);
t.deepEqual(result.plugin.meta!.allDepRootNames, ['subproj']);

t.match(result.package.name, '/subproj',
'sub project name is included in the root pkg name');
Expand Down Expand Up @@ -154,6 +154,42 @@ test('multi-project: deps for both projects are returned with multiDepRoots flag
}
});

test('single-project: array of one is returned with multiDepRoots flag', async (t) => {
const result = await inspect('.',
path.join(fixtureDir('api-configuration'), 'build.gradle'), {multiDepRoots: true});
t.equal(result.depRoots.length, 1);
t.equal(result.depRoots[0].depTree.name, '.');
t.ok(result.depRoots[0].depTree.dependencies!['commons-httpclient:commons-httpclient']);
});

test('multi-project-some-unscannable: multiDepRoots fails', async (t) => {
t.rejects(inspect('.',
path.join(fixtureDir('multi-project-some-unscannable'), 'build.gradle'), {multiDepRoots: true}));
});

test('multi-project-some-unscannable: gradle-sub-project for a good subproject works', async (t) => {
const options = {
'gradle-sub-project': 'subproj ',
};
const result = await inspect('.',
path.join(fixtureDir('multi-project-some-unscannable'), 'build.gradle'),
options);

t.deepEqual(result.plugin.meta!.allDepRootNames, ['subproj']);

t.match(result.package.name, '/subproj',
'sub project name is included in the root pkg name');

t.equal(result.package
.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',
'correct version found');
});

test('multiDepRoots incompatible with gradle-sub-project', (t) => {
t.plan(1);
t.rejects(inspect('.',
Expand Down Expand Up @@ -211,7 +247,7 @@ test('multi-project-dependency-cycle: scanning the main project works fine', asy
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.deepEqual(result.plugin.meta!.allDepRootNames, ['root-proj']);

t.equal(result.package
.dependencies!['com.github.jitpack:subproj']
Expand Down

0 comments on commit 19b56c4

Please sign in to comment.