Skip to content

Commit fb6b847

Browse files
committed
feat: add mavenDebugOutput option for logging raw Maven command output
Introduced `mavenDebugOutput` boolean option to enable logging of raw Maven command output during execution.
1 parent 2d0e29b commit fb6b847

5 files changed

Lines changed: 127 additions & 18 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ const result = await inspect(rootPath, targetFile, options);
4848
| `allProjects` | boolean | `false` | Include all projects in multi-module builds |
4949
| `mavenAggregateProject` | boolean | `false` | Treat as Maven aggregate project |
5050
| `mavenVerboseIncludeAllVersions` | boolean | `false` | Include all dependency versions in verbose mode |
51+
| `mavenDebugOutput` | boolean | `false` | Log raw Maven command output to debug |
5152
| `includeProvenance` | boolean | `false` | Generate cryptographic fingerprints for artifacts to prove origin |
5253
| `fingerprintAlgorithm` | string | `'sha1'` | Hash algorithm ('sha1', 'sha256', 'sha512') |
5354
| `mavenRepository` | string | - | Custom Maven repository path |

lib/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export interface MavenOptions extends legacyPlugin.BaseInspectOptions {
4545
mavenRepository?: string;
4646
showMavenBuildScope?: boolean;
4747
mavenSkipWrapper?: boolean;
48+
mavenDebugOutput?: boolean;
4849
}
4950

5051
function buildFingerprintOptions(
@@ -79,6 +80,7 @@ export async function inspect(
7980
scanAllUnmanaged: false,
8081
'print-graph': false,
8182
mavenVerboseIncludeAllVersions: false,
83+
mavenDebugOutput: false,
8284
};
8385
}
8486
const fingerprintOptions = buildFingerprintOptions(options);
@@ -138,6 +140,8 @@ export async function inspect(
138140
args.includes('-Dverbose=true') ||
139141
!!options['print-graph'];
140142

143+
const logMavenOutput = !!options.mavenDebugOutput;
144+
141145
let executionResult;
142146
try {
143147
// Execute Maven pipeline (resolve + tree)
@@ -146,6 +150,7 @@ export async function inspect(
146150
options.mavenAggregateProject,
147151
verboseEnabled,
148152
args,
153+
logMavenOutput,
149154
);
150155
debug(
151156
`Verbose enabled with all versions: ${options.mavenVerboseIncludeAllVersions}`,
@@ -193,7 +198,7 @@ export async function inspect(
193198
...{ scannedProjects },
194199
};
195200
} catch (err) {
196-
if (executionResult) {
201+
if (executionResult && !logMavenOutput) {
197202
debug(`>>> Output from mvn: ${executionResult.dependencyTreeResult}`);
198203
}
199204

lib/maven/dependency-resolve.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ import { debug } from '../index';
44
import { MavenContext } from './context';
55
import { MAVEN_DEPENDENCY_PLUGIN_VERSION } from './version';
66

7+
export interface MavenDependencyResolveResult {
8+
dependencyResolveResult: string;
9+
command: string;
10+
args: string[];
11+
}
12+
713
export function buildArgs(
814
context: MavenContext,
915
mavenArgs: string[],
@@ -55,7 +61,7 @@ export async function executeMavenDependencyResolve(
5561
mavenAggregateProject: boolean,
5662
args: string[],
5763
pluginVersion: string = MAVEN_DEPENDENCY_PLUGIN_VERSION,
58-
): Promise<string> {
64+
): Promise<MavenDependencyResolveResult> {
5965
const mvnArgs = buildArgs(
6066
context,
6167
args,
@@ -67,9 +73,19 @@ export async function executeMavenDependencyResolve(
6773
debug(`Maven working directory: ${context.workingDirectory}`);
6874

6975
try {
70-
return await subProcess.execute(context.command, mvnArgs, {
71-
cwd: context.workingDirectory,
72-
});
76+
const dependencyResolveResult = await subProcess.execute(
77+
context.command,
78+
mvnArgs,
79+
{
80+
cwd: context.workingDirectory,
81+
},
82+
);
83+
84+
return {
85+
dependencyResolveResult,
86+
command: context.command,
87+
args: mvnArgs,
88+
};
7389
} catch (error) {
7490
debug(
7591
`dependency:resolve execution failed - command: ${

lib/maven/executor.ts

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { executeMavenDependencyResolve } from './dependency-resolve';
1+
import {
2+
executeMavenDependencyResolve,
3+
MavenDependencyResolveResult,
4+
} from './dependency-resolve';
25
import { executeMavenDependencyTree } from './dependency-tree';
36
import { MavenContext } from './context';
47
import { getMavenVersion, selectPluginVersion } from './version';
@@ -33,6 +36,22 @@ export interface MavenExecutionResult {
3336
args: string[];
3437
}
3538

39+
function logMavenCommandOutput(
40+
phase: string,
41+
command: string,
42+
args: string[],
43+
output: string,
44+
) {
45+
if (!output) {
46+
debug(
47+
`>>> Maven ${phase} output (${command} ${args.join(' ')}): <no output>`,
48+
);
49+
return;
50+
}
51+
52+
debug(`>>> Maven ${phase} output (${command} ${args.join(' ')}):`, output);
53+
}
54+
3655
/**
3756
* Execute the optimal Maven pipeline: dependency:tree (required) + dependency:resolve (conditional)
3857
*
@@ -44,6 +63,7 @@ export async function executeMavenPipeline(
4463
mavenAggregateProject = false,
4564
verboseEnabled: boolean,
4665
args: string[],
66+
logMavenOutput = false,
4767
): Promise<MavenExecutionResult> {
4868
// Get Maven version to select appropriate maven-dependency-plugin version
4969
// This is used for verbose mode (dependency:tree) and dependency:resolve
@@ -61,6 +81,15 @@ export async function executeMavenPipeline(
6181
explicitPluginVersion,
6282
);
6383

84+
if (logMavenOutput) {
85+
logMavenCommandOutput(
86+
'dependency:tree',
87+
treeResult.command,
88+
treeResult.args,
89+
treeResult.dependencyTreeResult,
90+
);
91+
}
92+
6493
const hasMetaversions = detectMetaversions(treeResult.dependencyTreeResult);
6594
debug(`Metaversions detected: ${hasMetaversions}`);
6695

@@ -69,16 +98,29 @@ export async function executeMavenPipeline(
6998
if (hasMetaversions) {
7099
try {
71100
debug('Running dependency:resolve for metaversion resolution');
72-
const resolveResult = await executeMavenDependencyResolve(
73-
context,
74-
mavenAggregateProject,
75-
args,
76-
explicitPluginVersion,
77-
);
78-
debug(`Resolve result: ${resolveResult}`);
101+
const resolveResult: MavenDependencyResolveResult =
102+
await executeMavenDependencyResolve(
103+
context,
104+
mavenAggregateProject,
105+
args,
106+
explicitPluginVersion,
107+
);
108+
109+
if (logMavenOutput) {
110+
logMavenCommandOutput(
111+
'dependency:resolve',
112+
resolveResult.command,
113+
resolveResult.args,
114+
resolveResult.dependencyResolveResult,
115+
);
116+
} else {
117+
debug(`Resolve result: ${resolveResult.dependencyResolveResult}`);
118+
}
79119

80120
// Parse immediately and fail fast if there's an issue
81-
versionResolver = createVersionResolver(resolveResult);
121+
versionResolver = createVersionResolver(
122+
resolveResult.dependencyResolveResult,
123+
);
82124
} catch (err) {
83125
debug(`Version resolution failed: ${err}`);
84126
// Graceful degradation using no-op version resolver

tests/jest/functional/maven/executor.spec.ts

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { executeMavenPipeline } from '../../../../lib/maven/executor';
2+
import * as plugin from '../../../../lib';
23
import * as dependencyTree from '../../../../lib/maven/dependency-tree';
34
import * as dependencyResolve from '../../../../lib/maven/dependency-resolve';
45
import * as version from '../../../../lib/maven/version';
@@ -98,9 +99,13 @@ describe('executeMavenPipeline conditional logic', () => {
9899
});
99100

100101
// Mock resolve result with resolved versions
101-
mockExecuteMavenDependencyResolve.mockResolvedValue(`[INFO] The following files have been resolved:
102+
mockExecuteMavenDependencyResolve.mockResolvedValue({
103+
dependencyResolveResult: `[INFO] The following files have been resolved:
102104
[INFO] junit:junit:jar:4.13.2:test -- module junit [auto]
103-
[INFO] org.slf4j:slf4j-api:jar:1.7.36:compile -- module org.slf4j.api`);
105+
[INFO] org.slf4j:slf4j-api:jar:1.7.36:compile -- module org.slf4j.api`,
106+
command: 'mvn',
107+
args: ['dependency:resolve', '--batch-mode'],
108+
});
104109

105110
const result = await executeMavenPipeline(context, false, false, []);
106111

@@ -167,8 +172,12 @@ describe('executeMavenPipeline conditional logic', () => {
167172
args: ['test-compile', 'dependency:tree', '--batch-mode'],
168173
});
169174

170-
mockExecuteMavenDependencyResolve.mockResolvedValue(`[INFO] The following files have been resolved:
171-
[INFO] com.example:module-a:jar:1.0.0:compile -- module com.example.module.a`);
175+
mockExecuteMavenDependencyResolve.mockResolvedValue({
176+
dependencyResolveResult: `[INFO] The following files have been resolved:
177+
[INFO] com.example:module-a:jar:1.0.0:compile -- module com.example.module.a`,
178+
command: 'mvn',
179+
args: ['dependency:resolve', '--batch-mode'],
180+
});
172181

173182
const result = await executeMavenPipeline(context, true, false, [
174183
'-Pprofile',
@@ -192,4 +201,40 @@ describe('executeMavenPipeline conditional logic', () => {
192201

193202
expect(result.versionResolver).not.toBe(NO_OP_VERSION_RESOLVER);
194203
});
204+
205+
test('should log mvn output when requested', async () => {
206+
mockExecuteMavenDependencyTree.mockResolvedValue({
207+
dependencyTreeResult: `digraph "com.example:test:jar:1.0.0" {
208+
"com.example:test:jar:1.0.0" -> "junit:junit:jar:RELEASE:test" ;
209+
}`,
210+
command: 'mvn',
211+
args: ['dependency:tree', '--batch-mode'],
212+
});
213+
214+
mockExecuteMavenDependencyResolve.mockResolvedValue({
215+
dependencyResolveResult: `[INFO] Resolved artifacts
216+
[INFO] junit:junit:jar:4.13.2:test`,
217+
command: 'mvn',
218+
args: ['dependency:resolve', '--batch-mode'],
219+
});
220+
221+
const debugSpy = jest
222+
.spyOn(plugin, 'debug')
223+
.mockImplementation(() => undefined);
224+
225+
try {
226+
await executeMavenPipeline(context, false, false, [], true);
227+
228+
expect(debugSpy).toHaveBeenCalledWith(
229+
expect.stringContaining('dependency:tree output'),
230+
expect.stringContaining('digraph "com.example:test:jar:1.0.0"'),
231+
);
232+
expect(debugSpy).toHaveBeenCalledWith(
233+
expect.stringContaining('dependency:resolve output'),
234+
expect.stringContaining('Resolved artifacts'),
235+
);
236+
} finally {
237+
debugSpy.mockRestore();
238+
}
239+
});
195240
});

0 commit comments

Comments
 (0)