Skip to content

Commit

Permalink
Merge pull request #1328 from snyk/feat/enable-kotlin-gradle-all-proj…
Browse files Browse the repository at this point in the history
…ects

Feat: enable kotlin gradle all projects
  • Loading branch information
lili2311 committed Aug 17, 2020
2 parents 2e8c8cd + 7dfc027 commit fcc157d
Show file tree
Hide file tree
Showing 13 changed files with 373 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/lib/detect.ts
Expand Up @@ -57,6 +57,7 @@ export const AUTO_DETECTABLE_FILES: string[] = [
'requirements.txt',
'build.sbt',
'build.gradle',
'build.gradle.kts',
];

// when file is specified with --file, we look it up here
Expand Down
17 changes: 15 additions & 2 deletions src/lib/find-files.ts
Expand Up @@ -193,7 +193,11 @@ function shouldSkipAddingFile(
): boolean {
if (['gradle'].includes(packageManager) && filePath) {
const rootGradleFile = filteredFiles
.filter((targetFile) => targetFile.endsWith('build.gradle'))
.filter(
(targetFile) =>
targetFile.endsWith('build.gradle') ||
targetFile.endsWith('build.gradle.kts'),
)
.filter((targetFile) => {
const parsedPath = pathLib.parse(targetFile);
const relativePath = pathLib.relative(parsedPath.dir, filePath);
Expand Down Expand Up @@ -238,7 +242,7 @@ function chooseBestManifest(
}
case 'cocoapods': {
debug(
'Encountered multiple cocoapod manifest files, defaulting to Podfile',
'Encountered multiple cocoapods manifest files, defaulting to Podfile',
);
const defaultManifest = files.filter((path) =>
['Podfile'].includes(path.base),
Expand All @@ -252,6 +256,15 @@ function chooseBestManifest(
)[0];
return defaultManifest.path;
}
case 'gradle': {
debug(
'Encountered multiple gradle manifest files, defaulting to build.gradle',
);
const defaultManifest = files.filter((path) =>
['build.gradle'].includes(path.base),
)[0];
return defaultManifest.path;
}
default: {
return null;
}
Expand Down
104 changes: 103 additions & 1 deletion test/acceptance/cli-monitor/cli-monitor.all-projects.spec.ts
Expand Up @@ -801,7 +801,6 @@ export const AllProjectsTests: AcceptanceTests = {
};
},
};
const spyPlugin = sinon.spy(plugin, 'inspect');
const loadPlugin = sinon.stub(params.plugins, 'loadPlugin');
t.teardown(loadPlugin.restore);
loadPlugin.withArgs('gradle').returns(plugin);
Expand Down Expand Up @@ -842,5 +841,108 @@ export const AllProjectsTests: AcceptanceTests = {
);
});
},
'`monitor kotlin-monorepo --all-projects` scans kotlin files': (
params,
utils,
) => async (t) => {
utils.chdirWorkspaces();
const simpleGradleGraph = depGraphLib.createFromJSON({
schemaVersion: '1.2.0',
pkgManager: {
name: 'gradle',
},
pkgs: [
{
id: 'gradle-monorepo@0.0.0',
info: {
name: 'gradle-monorepo',
version: '0.0.0',
},
},
],
graph: {
rootNodeId: 'root-node',
nodes: [
{
nodeId: 'root-node',
pkgId: 'gradle-monorepo@0.0.0',
deps: [],
},
],
},
});
const plugin = {
async inspect() {
return {
plugin: {
name: 'bundled:gradle',
runtime: 'unknown',
meta: {},
},
scannedProjects: [
{
meta: {
gradleProjectName: 'root-proj',
versionBuildInfo: {
gradleVersion: '6.5',
},
},
depGraph: simpleGradleGraph,
},
{
meta: {
gradleProjectName: 'root-proj/subproj',
versionBuildInfo: {
gradleVersion: '6.5',
},
},
depGraph: simpleGradleGraph,
},
],
};
},
};
const loadPlugin = sinon.stub(params.plugins, 'loadPlugin');
t.teardown(loadPlugin.restore);
loadPlugin.withArgs('gradle').returns(plugin);
loadPlugin.callThrough();

const result = await params.cli.monitor('kotlin-monorepo', {
allProjects: true,
detectionDepth: 3,
});
t.ok(loadPlugin.withArgs('rubygems').calledOnce, 'calls rubygems plugin');
t.ok(loadPlugin.withArgs('gradle').calledOnce, 'calls gradle plugin');

t.match(
result,
'gradle/graph/some/project-id',
'gradle project was monitored',
);
t.match(
result,
'rubygems/graph/some/project-id',
'rubygems project was monitored',
);
// Pop one extra call to server and filter out call to `featureFlag` endpoint
const requests = params.server
.popRequests(4)
.filter((req) => req.url.includes('/monitor/'));
t.equal(requests.length, 3, 'correct amount of monitor requests');
requests.forEach((req) => {
t.match(
req.url,
/\/api\/v1\/monitor\/(rubygems\/graph|gradle\/graph)/,
'puts at correct url',
);
t.notOk(req.body.targetFile, "doesn't send the targetFile");
t.equal(req.method, 'PUT', 'makes PUT request');
t.equal(
req.headers['x-snyk-cli-version'],
params.versionNumber,
'sends version number',
);
});
},
},
};
119 changes: 117 additions & 2 deletions test/acceptance/cli-test/cli-test.all-projects.spec.ts
@@ -1,12 +1,127 @@
import { AcceptanceTests } from './cli-test.acceptance.test';
import { getWorkspaceJSON } from '../workspace-helper';
import * as path from 'path';
import * as sinon from 'sinon';
import * as depGraphLib from '@snyk/dep-graph';
import { CommandResult } from '../../../src/cli/commands/types';
import { AcceptanceTests } from './cli-test.acceptance.test';
import { getWorkspaceJSON } from '../workspace-helper';

export const AllProjectsTests: AcceptanceTests = {
language: 'Mixed',
tests: {
'`test kotlin-monorepo --all-projects` scans kotlin files': (
params,
utils,
) => async (t) => {
utils.chdirWorkspaces();
const simpleGradleGraph = depGraphLib.createFromJSON({
schemaVersion: '1.2.0',
pkgManager: {
name: 'gradle',
},
pkgs: [
{
id: 'gradle-monorepo@0.0.0',
info: {
name: 'gradle-monorepo',
version: '0.0.0',
},
},
],
graph: {
rootNodeId: 'root-node',
nodes: [
{
nodeId: 'root-node',
pkgId: 'gradle-monorepo@0.0.0',
deps: [],
},
],
},
});
const plugin = {
async inspect() {
return {
plugin: {
name: 'bundled:gradle',
runtime: 'unknown',
meta: {},
},
scannedProjects: [
{
meta: {
gradleProjectName: 'root-proj',
versionBuildInfo: {
gradleVersion: '6.5',
},
},
depGraph: simpleGradleGraph,
},
{
meta: {
gradleProjectName: 'root-proj/subproj',
versionBuildInfo: {
gradleVersion: '6.5',
},
},
depGraph: simpleGradleGraph,
},
],
};
},
};
const loadPlugin = sinon.stub(params.plugins, 'loadPlugin');
t.teardown(loadPlugin.restore);
loadPlugin.withArgs('gradle').returns(plugin);
loadPlugin.callThrough();

const result: CommandResult = await params.cli.test('kotlin-monorepo', {
allProjects: true,
detectionDepth: 3,
});
t.ok(loadPlugin.withArgs('rubygems').calledOnce, 'calls rubygems plugin');
t.ok(loadPlugin.withArgs('gradle').calledOnce, 'calls gradle plugin');

params.server.popRequests(2).forEach((req) => {
t.equal(req.method, 'POST', 'makes POST request');
t.equal(
req.headers['x-snyk-cli-version'],
params.versionNumber,
'sends version number',
);
t.match(req.url, '/api/v1/test-dep-graph', 'posts to correct url');
t.ok(req.body.depGraph, 'body contains depGraph');
t.match(
req.body.depGraph.pkgManager.name,
/(gradle|rubygems)/,
'depGraph has package manager',
);
});
t.match(
result.getDisplayResults(),
'Tested 3 projects',
'Detected 3 projects',
);
t.match(
result.getDisplayResults(),
'Package manager: rubygems',
'contains package manager rubygems',
);
t.match(
result.getDisplayResults(),
'Package manager: gradle',
'contains package manager gradle',
);
t.match(
result.getDisplayResults(),
'Target file: Gemfile.lock',
'contains target file Gemfile.lock',
);
t.match(
result.getDisplayResults(),
'Target file: build.gradle.kts',
'contains target file build.gradle.kts',
);
},
'`test yarn-out-of-sync` out of sync fails': (params, utils) => async (
t,
) => {
Expand Down
4 changes: 4 additions & 0 deletions test/acceptance/workspaces/kotlin-monorepo/Gemfile
@@ -0,0 +1,4 @@
source :rubygems

gem "json"
gem "lynx", "0.4.0"
15 changes: 15 additions & 0 deletions test/acceptance/workspaces/kotlin-monorepo/Gemfile.lock
@@ -0,0 +1,15 @@
GEM
remote: http://rubygems.org/
specs:
json (2.0.2)
lynx (0.4.0)

PLATFORMS
ruby

DEPENDENCIES
json
lynx (= 0.4.0)

BUNDLED WITH
1.13.5
@@ -0,0 +1 @@
// I will be mocked
@@ -0,0 +1 @@
// I will be mocked
17 changes: 17 additions & 0 deletions test/find-files.test.ts
Expand Up @@ -20,6 +20,8 @@ test('find all files in test fixture', async (t) => {
path.join(testFixture, 'golang', 'golang-app', 'Gopkg.toml'),
path.join(testFixture, 'golang', 'golang-gomodules', 'go.mod'),
path.join(testFixture, 'gradle', 'build.gradle'),
path.join(testFixture, 'gradle-kts', 'build.gradle.kts'),
path.join(testFixture, 'gradle-and-kotlin', 'build.gradle'),
path.join(testFixture, 'gradle-multiple', 'gradle/build.gradle'),
path.join(testFixture, 'gradle-multiple', 'gradle-another/build.gradle'),
path.join(testFixture, 'maven', 'pom.xml'),
Expand Down Expand Up @@ -52,6 +54,8 @@ test('find all files in test fixture ignoring node_modules', async (t) => {
path.join(testFixture, 'golang', 'golang-app', 'Gopkg.toml'),
path.join(testFixture, 'golang', 'golang-gomodules', 'go.mod'),
path.join(testFixture, 'gradle', 'build.gradle'),
path.join(testFixture, 'gradle-kts', 'build.gradle.kts'),
path.join(testFixture, 'gradle-and-kotlin', 'build.gradle'),
path.join(testFixture, 'gradle-multiple', 'gradle/build.gradle'),
path.join(testFixture, 'gradle-multiple', 'gradle-another/build.gradle'),
path.join(testFixture, 'maven', 'pom.xml'),
Expand Down Expand Up @@ -100,6 +104,19 @@ test('find package-lock.json file in test fixture (ignore package.json in the sa
t.same(result, expected, 'should return expected file');
});

test('find build.gradle file in test fixture (ignore build.gradle in the same folder)', async (t) => {
const buildGradle = path.join(testFixture, 'gradle-and-kotlin');

const result = await find(
buildGradle,
[],
['build.gradle.kts', 'build.gradle'],
1,
);
const expected = [path.join(buildGradle, 'build.gradle')];
t.same(result, expected, 'should return expected file');
});

test('find Gemfile.lock file in test fixture (ignore Gemfile in the same folder)', async (t) => {
const npmLockfilePath = path.join(testFixture, 'ruby');

Expand Down
Empty file.
33 changes: 33 additions & 0 deletions test/fixtures/find-files/gradle-and-kotlin/build.gradle.kts
@@ -0,0 +1,33 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
val kotlinVersion = "1.3.21"
id("org.jetbrains.kotlin.jvm") version kotlinVersion
id("org.jetbrains.kotlin.plugin.spring") version kotlinVersion
id("org.jetbrains.kotlin.plugin.jpa") version kotlinVersion
}

version = "1.0.0-SNAPSHOT"

tasks.withType<KotlinCompile> {
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = listOf("-Xjsr305=strict")
}
}

tasks.withType<Test> {
useJUnitPlatform()
}

repositories {
mavenCentral()
}

dependencies {
// Removed Spring because too heavy
compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
testCompile("org.jetbrains.kotlin:kotlin-reflect") {
exclude(module = "junit")
}
}

0 comments on commit fcc157d

Please sign in to comment.