Skip to content

Commit

Permalink
feat: support verbose
Browse files Browse the repository at this point in the history
Support passing -Dverbose to resolve omitted dependencies using maven-dependency-plugin.

When verbose is being used execute a specific version of the maven-dependency-plugin.
This is becuase on lower version of this plugin outputType=dot is not supported, and it will output a tree.

When verbose is on skip pruning and ensure all dependency lines are traversed fully, using breadth first, first in wins for version resolution.
  • Loading branch information
gitphill committed Mar 13, 2024
1 parent 36eb09b commit 7945576
Show file tree
Hide file tree
Showing 10 changed files with 1,031 additions and 12 deletions.
16 changes: 14 additions & 2 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,17 +158,22 @@ export async function inspect(

const mavenCommand = getCommand(root, targetFile);
const mvnWorkingDirectory = findWrapper(mavenCommand, root, targetPath);
const args = options.args || [];
const verboseEnabled =
args.includes('-Dverbose') || args.includes('-Dverbose=true');
const mvnArgs = buildArgs(
root,
mvnWorkingDirectory,
targetFile,
options.args,
options.mavenAggregateProject,
verboseEnabled,
);
let result;
try {
debug(`Maven command: ${mavenCommand} ${mvnArgs.join(' ')}`);
debug(`Maven working directory: ${mvnWorkingDirectory}`);
debug(`Verbose enabled: ${verboseEnabled}`);
result = await subProcess.execute(mavenCommand, mvnArgs, {
cwd: mvnWorkingDirectory,
});
Expand All @@ -179,7 +184,7 @@ export async function inspect(
cwd: mvnWorkingDirectory,
},
);
const parseResult = parse(result, options.dev);
const parseResult = parse(result, options.dev, verboseEnabled);
const { javaVersion, mavenVersion } = parseVersions(versionResult);
return {
plugin: {
Expand Down Expand Up @@ -212,6 +217,7 @@ export function buildArgs(
targetFile?: string,
mavenArgs?: string[] | undefined,
mavenAggregateProject = false,
verboseEnabled = false,
) {
let args: string[] = [];

Expand All @@ -222,9 +228,15 @@ export function buildArgs(
args = args.concat('test-compile');
}

// when using verbose ensure maven-dependency-plugin version 3 is used
// lower versions do not work with -DoutputType=dot
const mavenDependencyPlugin = verboseEnabled
? 'org.apache.maven.plugins:maven-dependency-plugin:3.6.1:tree'
: 'dependency:tree';

// Requires Maven >= 2.2
args = args.concat([
'dependency:tree', // use dependency plugin to display a tree of dependencies
mavenDependencyPlugin, // use dependency plugin to display a tree of dependencies
'-DoutputType=dot', // use 'dot' output format
'--batch-mode', // clean up output, disables output color and download progress
]);
Expand Down
18 changes: 13 additions & 5 deletions lib/parse/dep-graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { parseDependency } from './dependency';
export function buildDepGraph(
mavenGraph: MavenGraph,
includeTestScope = false,
verboseEnabled = false,
): DepGraph {
const { rootId, nodes } = mavenGraph;
const parsedRoot = parseId(rootId);
Expand All @@ -21,10 +22,11 @@ export function buildDepGraph(
const { id, parentId } = item;
const parsed = parseId(id);
const node = nodes[id];
if (!includeTestScope && parsed.scope === 'test' && !node.reachesProdDep)
if (!includeTestScope && parsed.scope === 'test' && !node.reachesProdDep) {
continue;
}
const visited = visitedMap[parsed.key];
if (visited) {
if (!verboseEnabled && visited) {
const prunedId = visited.id + ':pruned';
builder.addPkgNode(visited.pkgInfo, prunedId, {
labels: { pruned: 'true' },
Expand All @@ -33,10 +35,16 @@ export function buildDepGraph(
continue; // don't queue any more children
}
const parentNodeId = parentId === rootId ? builder.rootNodeId : parentId;
builder.addPkgNode(parsed.pkgInfo, id);
builder.connectDep(parentNodeId, id);
if (verboseEnabled && visited) {
// use visited node when omited dependencies found (verbose)
builder.addPkgNode(visited.pkgInfo, visited.id);
builder.connectDep(parentNodeId, visited.id);
} else {
builder.addPkgNode(parsed.pkgInfo, id);
builder.connectDep(parentNodeId, id);
visitedMap[parsed.key] = parsed;
}
queue.push(...getItems(id, node));
visitedMap[parsed.key] = parsed;
}

return builder.build();
Expand Down
14 changes: 14 additions & 0 deletions lib/parse/digraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,19 @@ function findQuotedContents(value?: string): string | null {
if (!value) return null;
const start = value.indexOf('"') + 1;
const end = value.lastIndexOf('"');
// when using -Dverbose ensure omitted reasons are parsed correctly
// https://github.com/apache/maven/blob/ab6ec5bd74af20ab429509eb56fc8e3dff4c7fc7/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultNode.java#L113
if (value.indexOf('omitted for conflict with') > -1) {
const [left] = value
.substring(start + 1, end)
.split(' - omitted for conflict with ');
return left;
}
if (value.indexOf('omitted for duplicate') > -1) {
const [left] = value
.substring(start + 1, end)
.split(' - omitted for duplicate');
return left;
}
return value.substring(start, end);
}
7 changes: 6 additions & 1 deletion lib/parse/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@ import { buildDepGraph } from './dep-graph';
export function parse(
stdout: string,
includeTestScope = false,
verboseEnabled = false,
): { scannedProjects: ScannedProject[] } {
const digraphs = parseStdout(stdout);
const mavenGraphs = parseDigraphs(digraphs);
const scannedProjects: ScannedProject[] = [];
for (const mavenGraph of mavenGraphs) {
const depGraph = buildDepGraph(mavenGraph, includeTestScope);
const depGraph = buildDepGraph(
mavenGraph,
includeTestScope,
verboseEnabled,
);
scannedProjects.push({ depGraph });
}
return {
Expand Down
238 changes: 238 additions & 0 deletions tests/fixtures/complex-aggregate-project/verbose-scan-result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
{
"scannedProjects": [
{
"depGraph": {
"schemaVersion": "1.2.0",
"pkgManager": {
"name": "maven"
},
"pkgs": [
{
"id": "io.snyk:[email protected]",
"info": {
"name": "io.snyk:aggregate-project",
"version": "1.0.0"
}
}
],
"graph": {
"rootNodeId": "root-node",
"nodes": [
{
"nodeId": "root-node",
"pkgId": "io.snyk:[email protected]",
"deps": []
}
]
}
}
},
{
"depGraph": {
"schemaVersion": "1.2.0",
"pkgManager": {
"name": "maven"
},
"pkgs": [
{
"id": "io.snyk:[email protected]",
"info": {
"name": "io.snyk:core",
"version": "1.0.0"
}
},
{
"id": "org.apache.logging.log4j:[email protected]",
"info": {
"name": "org.apache.logging.log4j:log4j-api",
"version": "2.17.2"
}
},
{
"id": "org.apache.logging.log4j:[email protected]",
"info": {
"name": "org.apache.logging.log4j:log4j-core",
"version": "2.17.2"
}
}
],
"graph": {
"rootNodeId": "root-node",
"nodes": [
{
"nodeId": "root-node",
"pkgId": "io.snyk:[email protected]",
"deps": [
{
"nodeId": "org.apache.logging.log4j:log4j-api:jar:2.17.2:compile"
},
{
"nodeId": "org.apache.logging.log4j:log4j-core:jar:2.17.2:compile"
}
]
},
{
"nodeId": "org.apache.logging.log4j:log4j-api:jar:2.17.2:compile",
"pkgId": "org.apache.logging.log4j:[email protected]",
"deps": []
},
{
"nodeId": "org.apache.logging.log4j:log4j-core:jar:2.17.2:compile",
"pkgId": "org.apache.logging.log4j:[email protected]",
"deps": [
{
"nodeId": "org.apache.logging.log4j:log4j-api:jar:2.17.2:compile"
}
]
}
]
}
}
},
{
"depGraph": {
"schemaVersion": "1.2.0",
"pkgManager": {
"name": "maven"
},
"pkgs": [
{
"id": "io.snyk:[email protected]",
"info": {
"name": "io.snyk:web",
"version": "1.0.0"
}
},
{
"id": "io.snyk:[email protected]",
"info": {
"name": "io.snyk:core",
"version": "1.0.0"
}
},
{
"id": "org.springframework:[email protected]",
"info": {
"name": "org.springframework:spring-web",
"version": "5.3.21"
}
},
{
"id": "org.apache.logging.log4j:[email protected]",
"info": {
"name": "org.apache.logging.log4j:log4j-api",
"version": "2.17.2"
}
},
{
"id": "org.apache.logging.log4j:[email protected]",
"info": {
"name": "org.apache.logging.log4j:log4j-core",
"version": "2.17.2"
}
},
{
"id": "org.springframework:[email protected]",
"info": {
"name": "org.springframework:spring-beans",
"version": "5.3.21"
}
},
{
"id": "org.springframework:[email protected]",
"info": {
"name": "org.springframework:spring-core",
"version": "5.3.21"
}
},
{
"id": "org.springframework:[email protected]",
"info": {
"name": "org.springframework:spring-jcl",
"version": "5.3.21"
}
}
],
"graph": {
"rootNodeId": "root-node",
"nodes": [
{
"nodeId": "root-node",
"pkgId": "io.snyk:[email protected]",
"deps": [
{
"nodeId": "io.snyk:core:jar:1.0.0:compile"
},
{
"nodeId": "org.springframework:spring-web:jar:5.3.21:compile"
}
]
},
{
"nodeId": "io.snyk:core:jar:1.0.0:compile",
"pkgId": "io.snyk:[email protected]",
"deps": [
{
"nodeId": "org.apache.logging.log4j:log4j-api:jar:2.17.2:compile"
},
{
"nodeId": "org.apache.logging.log4j:log4j-core:jar:2.17.2:compile"
}
]
},
{
"nodeId": "org.springframework:spring-web:jar:5.3.21:compile",
"pkgId": "org.springframework:[email protected]",
"deps": [
{
"nodeId": "org.springframework:spring-beans:jar:5.3.21:compile"
},
{
"nodeId": "org.springframework:spring-core:jar:5.3.21:compile"
}
]
},
{
"nodeId": "org.apache.logging.log4j:log4j-api:jar:2.17.2:compile",
"pkgId": "org.apache.logging.log4j:[email protected]",
"deps": []
},
{
"nodeId": "org.apache.logging.log4j:log4j-core:jar:2.17.2:compile",
"pkgId": "org.apache.logging.log4j:[email protected]",
"deps": [
{
"nodeId": "org.apache.logging.log4j:log4j-api:jar:2.17.2:compile"
}
]
},
{
"nodeId": "org.springframework:spring-beans:jar:5.3.21:compile",
"pkgId": "org.springframework:[email protected]",
"deps": [
{
"nodeId": "org.springframework:spring-core:jar:5.3.21:compile"
}
]
},
{
"nodeId": "org.springframework:spring-core:jar:5.3.21:compile",
"pkgId": "org.springframework:[email protected]",
"deps": [
{
"nodeId": "org.springframework:spring-jcl:jar:5.3.21:compile"
}
]
},
{
"nodeId": "org.springframework:spring-jcl:jar:5.3.21:compile",
"pkgId": "org.springframework:[email protected]",
"deps": []
}
]
}
}
}
]
}

Loading

0 comments on commit 7945576

Please sign in to comment.