diff --git a/lib/index.ts b/lib/index.ts index 2ce3763..32bb94a 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -51,6 +51,13 @@ export interface PluginMetadata { // TODO(BST-542): remove, DepRoot.targetFile to be used instead // Note: can be missing, see targetFileFilteredForCompatibility targetFile?: string; + + // Plugin-specific metadata + meta?: { + // If we don't return the results for all dependency roots (subprojects), + // still record their names to warn the user about them not being scanned + allDepRootNames?: string[]; + }; } export interface DepDict { @@ -90,7 +97,7 @@ export async function inspect(root, targetFile, options?: SingleRootInspectOptio if (subProject) { subProject = subProject.trim(); } - const plugin = { + const plugin: PluginMetadata = { name: 'bundled:gradle', runtime: 'unknown', targetFile: targetFileFilteredForCompatibility(targetFile), @@ -104,9 +111,14 @@ export async function inspect(root, targetFile, options?: SingleRootInspectOptio depRoots: await getAllDepsAllProjects(root, targetFile, options), }; } + const depTreeAndDepRootNames = await getAllDepsOneProject(root, targetFile, options, subProject); + if (depTreeAndDepRootNames.allDepRootNames) { + plugin.meta = plugin.meta || {}; + plugin.meta.allDepRootNames = depTreeAndDepRootNames.allDepRootNames; + } return { plugin, - package: await getAllDepsOneProject(root, targetFile, options, subProject), + package: depTreeAndDepRootNames.depTree, }; } @@ -150,23 +162,31 @@ function extractJsonFromScriptOutput(stdoutText: string): JsonDepsScriptResult { return JSON.parse(jsonLine!); } -async function getAllDepsOneProject(root, targetFile, options, subProject): Promise { +async function getAllDepsOneProject(root, targetFile, options, subProject): + Promise<{depTree: DepTree, allDepRootNames: string[]}> { const packageName = path.basename(root); const allProjectDeps = await getAllDeps(root, targetFile, options); + const allDepRootNames = Object.keys(allProjectDeps.projects); let depDict = {} as DepDict; if (subProject) { - return getDepsSubProject(root, subProject, allProjectDeps); + return { + depTree: getDepsSubProject(root, subProject, allProjectDeps), + allDepRootNames, + }; } depDict = allProjectDeps.projects[allProjectDeps.defaultProject].depDict; return { - dependencies: depDict, - name: packageName, - // TODO: extract from project - // https://snyksec.atlassian.net/browse/BST-558 - version: '0.0.0', - packageFormatVersion, + depTree: { + dependencies: depDict, + name: packageName, + // TODO: extract from project + // https://snyksec.atlassian.net/browse/BST-558 + version: '0.0.0', + packageFormatVersion, + }, + allDepRootNames, }; } diff --git a/test/system/multi-module.test.ts b/test/system/multi-module.test.ts index 76d9aa2..19ebe13 100644 --- a/test/system/multi-module.test.ts +++ b/test/system/multi-module.test.ts @@ -8,6 +8,7 @@ test('multi-project, explicitly targeting a subproject build file', async (t) => path.join(fixtureDir('multi-project'), 'subproj', 'build.gradle')); t.equals(result.package.name, '.', 'root project is "."'); + t.deepEqual(result.plugin.meta!.allDepRootNames, ['subproj']); t.equal(result.package .dependencies!['com.android.tools.build:builder'] @@ -25,6 +26,7 @@ test('multi-project, ran from root, targeting subproj', async (t) => { 'subproj/build.gradle'); t.equals(result.package.name, 'multi-project', 'root project is "multi-project"'); + t.deepEqual(result.plugin.meta!.allDepRootNames, ['subproj']); t.equal(result.package .dependencies!['com.android.tools.build:builder'] @@ -42,6 +44,7 @@ test('multi-project, ran from a subproject directory', async (t) => { 'build.gradle'); t.equals(result.package.name, 'subproj', 'root project is "subproj"'); + t.deepEqual(result.plugin.meta!.allDepRootNames, ['subproj']); t.equal(result.package .dependencies!['com.android.tools.build:builder'] @@ -62,6 +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.equal(result.package .dependencies!['com.android.tools.build:builder'] @@ -78,6 +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.notOk(result.package.dependencies); }); @@ -86,6 +91,7 @@ test('multi-project: using gradle 3.0.0 via wrapper', async (t) => { path.join(fixtureDir('multi-project-gradle-3'), 'build.gradle')); t.match(result.package.name, '.', 'returned project name is not sub-project'); + t.deepEqual(result.plugin.meta!.allDepRootNames, ['root-proj', 'subproj']); t.notOk(result.package.dependencies); }); @@ -103,6 +109,9 @@ test('multi-project: only sub-project has deps and they are returned space needs const result = await inspect('.', path.join(fixtureDir('multi-project'), 'build.gradle'), options); + + t.deepEqual(result.plugin.meta!.allDepRootNames, ['root-proj', 'subproj']); + t.match(result.package.name, '/subproj', 'sub project name is included in the root pkg name'); @@ -161,11 +170,11 @@ test('multi-project: parallel with multiDepRoots produces multiple results with names.add(p.depTree.name); } t.deepEqual(names, new Set([ - 'multi-project-parallel', - 'multi-project-parallel/subproj0', - 'multi-project-parallel/subproj1', - 'multi-project-parallel/subproj2', - 'multi-project-parallel/subproj3', + 'multi-project-parallel', + 'multi-project-parallel/subproj0', + 'multi-project-parallel/subproj1', + 'multi-project-parallel/subproj2', + 'multi-project-parallel/subproj3', 'multi-project-parallel/subproj4'])); });