@nx/maven 22.7.0-beta.0 → 22.7.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,9 @@
1
1
  import { MavenAnalysisData, MavenPluginOptions } from './types';
2
+ /**
3
+ * Cancel any in-flight Maven analysis process.
4
+ * Safe to call even if nothing is running.
5
+ */
6
+ export declare function cancelPendingMavenAnalysis(): void;
2
7
  /**
3
8
  * Run Maven analysis using our Kotlin analyzer plugin
4
9
  */
@@ -1 +1 @@
1
- {"version":3,"file":"maven-analyzer.d.ts","sourceRoot":"","sources":["../../src/plugins/maven-analyzer.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAGhE;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,iBAAiB,CAAC,CAyH5B"}
1
+ {"version":3,"file":"maven-analyzer.d.ts","sourceRoot":"","sources":["../../src/plugins/maven-analyzer.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAQhE;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,IAAI,CAKjD;AAaD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,iBAAiB,CAAC,CA4J5B"}
@@ -1,12 +1,38 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cancelPendingMavenAnalysis = cancelPendingMavenAnalysis;
3
4
  exports.runMavenAnalysis = runMavenAnalysis;
5
+ const tslib_1 = require("tslib");
4
6
  const path_1 = require("path");
5
7
  const fs_1 = require("fs");
6
8
  const child_process_1 = require("child_process");
7
9
  const devkit_1 = require("@nx/devkit");
10
+ const devkit_internals_1 = require("nx/src/devkit-internals");
8
11
  const cache_directory_1 = require("nx/src/utils/cache-directory");
9
12
  const detect_maven_executable_1 = require("../utils/detect-maven-executable");
13
+ const tree_kill_1 = tslib_1.__importDefault(require("tree-kill"));
14
+ const DEFAULT_ANALYSIS_TIMEOUT_SECONDS = (0, devkit_internals_1.isCI)() ? 600 : 120;
15
+ let currentAbortController;
16
+ /**
17
+ * Cancel any in-flight Maven analysis process.
18
+ * Safe to call even if nothing is running.
19
+ */
20
+ function cancelPendingMavenAnalysis() {
21
+ if (currentAbortController) {
22
+ currentAbortController.abort('cancelled');
23
+ currentAbortController = undefined;
24
+ }
25
+ }
26
+ function getAnalysisTimeoutMs() {
27
+ const envTimeout = process.env.NX_MAVEN_ANALYSIS_TIMEOUT;
28
+ if (envTimeout) {
29
+ const parsed = Number(envTimeout);
30
+ if (!Number.isNaN(parsed) && parsed > 0) {
31
+ return parsed * 1000;
32
+ }
33
+ }
34
+ return DEFAULT_ANALYSIS_TIMEOUT_SECONDS * 1000;
35
+ }
10
36
  /**
11
37
  * Run Maven analysis using our Kotlin analyzer plugin
12
38
  */
@@ -40,64 +66,97 @@ async function runMavenAnalysis(workspaceRoot, options) {
40
66
  if (isVerbose) {
41
67
  console.error(`Running Maven analyzer with verbose logging: ${mavenExecutable} ${mavenArgs.join(' ')}`);
42
68
  }
69
+ // Cancel any in-flight Maven process from a previous call, then create a fresh controller.
70
+ cancelPendingMavenAnalysis();
71
+ const controller = new AbortController();
72
+ currentAbortController = controller;
73
+ const signal = controller.signal;
74
+ const timeoutMs = getAnalysisTimeoutMs();
75
+ const timeoutSeconds = timeoutMs / 1000;
76
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
43
77
  // Run Maven plugin
44
78
  devkit_1.logger.verbose(`[Maven Analyzer] Spawning Maven process...`);
45
- await new Promise((resolve, reject) => {
46
- const child = (0, child_process_1.spawn)(mavenExecutable, mavenArgs, {
47
- cwd: workspaceRoot,
48
- windowsHide: true,
49
- shell: true,
50
- stdio: 'pipe', // Always use pipe so we can control output
51
- });
52
- devkit_1.logger.verbose(`[Maven Analyzer] Process spawned with PID: ${child.pid}`);
53
- let stdout = '';
54
- let stderr = '';
55
- // In verbose mode, forward output to console in real-time
56
- if (isVerbose) {
57
- child.stdout?.on('data', (data) => {
58
- const text = data.toString();
59
- stdout += text;
60
- process.stdout.write(text); // Forward to stdout
61
- });
62
- child.stderr?.on('data', (data) => {
63
- const text = data.toString();
64
- stderr += text;
65
- process.stderr.write(text); // Forward to stderr
66
- });
67
- }
68
- else {
69
- child.stdout?.on('data', (data) => {
70
- const text = data.toString();
71
- stdout += text;
72
- devkit_1.logger.verbose(`[Maven Analyzer] Stdout chunk: ${text.trim()}`);
79
+ try {
80
+ await new Promise((resolve, reject) => {
81
+ const child = (0, child_process_1.spawn)(mavenExecutable, mavenArgs, {
82
+ cwd: workspaceRoot,
83
+ windowsHide: true,
84
+ shell: true,
85
+ stdio: 'pipe', // Always use pipe so we can control output
73
86
  });
74
- child.stderr?.on('data', (data) => {
75
- const text = data.toString();
76
- stderr += text;
77
- devkit_1.logger.verbose(`[Maven Analyzer] Stderr chunk: ${text.trim()}`);
78
- });
79
- }
80
- child.on('close', (code) => {
81
- devkit_1.logger.verbose(`[Maven Analyzer] Process closed with code: ${code}`);
82
- if (code === 0) {
83
- devkit_1.logger.verbose(`[Maven Analyzer] Maven analysis completed successfully`);
84
- resolve();
87
+ // Use tree-kill on abort to kill the entire process tree
88
+ const onAbort = () => {
89
+ if (child.pid) {
90
+ (0, tree_kill_1.default)(child.pid);
91
+ }
92
+ };
93
+ signal.addEventListener('abort', onAbort, { once: true });
94
+ devkit_1.logger.verbose(`[Maven Analyzer] Process spawned with PID: ${child.pid}`);
95
+ let stdout = '';
96
+ let stderr = '';
97
+ // In verbose mode, forward output to console in real-time
98
+ if (isVerbose) {
99
+ child.stdout?.on('data', (data) => {
100
+ const text = data.toString();
101
+ stdout += text;
102
+ process.stdout.write(text); // Forward to stdout
103
+ });
104
+ child.stderr?.on('data', (data) => {
105
+ const text = data.toString();
106
+ stderr += text;
107
+ process.stderr.write(text); // Forward to stderr
108
+ });
85
109
  }
86
110
  else {
87
- let errorMsg = `Maven analysis failed with code ${code}`;
88
- if (stderr)
89
- errorMsg += `\nStderr: ${stderr}`;
90
- if (stdout && !isVerbose)
91
- errorMsg += `\nStdout: ${stdout}`;
92
- console.error(`[Maven Analyzer] Error: ${errorMsg}`);
93
- reject(new Error(errorMsg));
111
+ child.stdout?.on('data', (data) => {
112
+ const text = data.toString();
113
+ stdout += text;
114
+ devkit_1.logger.verbose(`[Maven Analyzer] Stdout chunk: ${text.trim()}`);
115
+ });
116
+ child.stderr?.on('data', (data) => {
117
+ const text = data.toString();
118
+ stderr += text;
119
+ devkit_1.logger.verbose(`[Maven Analyzer] Stderr chunk: ${text.trim()}`);
120
+ });
94
121
  }
122
+ child.on('close', (code) => {
123
+ signal.removeEventListener('abort', onAbort);
124
+ devkit_1.logger.verbose(`[Maven Analyzer] Process closed with code: ${code}`);
125
+ if (code === 0) {
126
+ devkit_1.logger.verbose(`[Maven Analyzer] Maven analysis completed successfully`);
127
+ resolve();
128
+ }
129
+ else {
130
+ let errorMsg = `Maven analysis failed with code ${code}`;
131
+ if (stderr)
132
+ errorMsg += `\nStderr: ${stderr}`;
133
+ if (stdout && !isVerbose)
134
+ errorMsg += `\nStdout: ${stdout}`;
135
+ console.error(`[Maven Analyzer] Error: ${errorMsg}`);
136
+ reject(new Error(errorMsg));
137
+ }
138
+ });
139
+ child.on('error', (error) => {
140
+ signal.removeEventListener('abort', onAbort);
141
+ console.error(`[Maven Analyzer] Process error: ${error.message}`);
142
+ reject(new Error(`Failed to spawn Maven process: ${error.message}`));
143
+ });
95
144
  });
96
- child.on('error', (error) => {
97
- console.error(`[Maven Analyzer] Process error: ${error.message}`);
98
- reject(new Error(`Failed to spawn Maven process: ${error.message}`));
99
- });
100
- });
145
+ }
146
+ catch (e) {
147
+ if (signal.reason === 'cancelled') {
148
+ throw new Error('Maven analysis was cancelled');
149
+ }
150
+ if (signal.aborted) {
151
+ throw new Error(`Maven analysis timed out after ${timeoutSeconds} ${timeoutSeconds === 1 ? 'second' : 'seconds'}.\n` +
152
+ ` 1. If the issue persists, set the environment variable NX_MAVEN_ANALYSIS_TIMEOUT to a higher value (in seconds) to increase the timeout.\n` +
153
+ ` 2. If the issue still persists, set NX_MAVEN_DISABLE=true to disable the Maven plugin entirely.`);
154
+ }
155
+ throw e;
156
+ }
157
+ finally {
158
+ clearTimeout(timer);
159
+ }
101
160
  // Read and parse the JSON output
102
161
  devkit_1.logger.verbose(`[Maven Analyzer] Checking for output file: ${outputFile}`);
103
162
  if (!(0, fs_1.existsSync)(outputFile)) {
@@ -1 +1 @@
1
- {"version":3,"file":"nodes.d.ts","sourceRoot":"","sources":["../../src/plugins/nodes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,aAAa,EAAa,MAAM,YAAY,CAAC;AAE3E,OAAO,EAAmB,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAW9D;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC,kBAAkB,CAoEzD,CAAC"}
1
+ {"version":3,"file":"nodes.d.ts","sourceRoot":"","sources":["../../src/plugins/nodes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,aAAa,EAAa,MAAM,YAAY,CAAC;AAE3E,OAAO,EAAmB,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAW9D;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC,kBAAkB,CA+EzD,CAAC"}
@@ -42,10 +42,20 @@ exports.createNodes = [
42
42
  let mavenData = isVerbose ? null : mavenCache.get(hash);
43
43
  // If no cached data or cache is stale, run fresh Maven analysis
44
44
  if (!mavenData) {
45
- mavenData = await (0, maven_analyzer_1.runMavenAnalysis)(context.workspaceRoot, {
46
- ...opts,
47
- verbose: isVerbose,
48
- });
45
+ try {
46
+ mavenData = await (0, maven_analyzer_1.runMavenAnalysis)(context.workspaceRoot, {
47
+ ...opts,
48
+ verbose: isVerbose,
49
+ });
50
+ }
51
+ catch (e) {
52
+ if (e instanceof Error &&
53
+ e.message === 'Maven analysis was cancelled') {
54
+ // Cancelled by a newer createNodes call — silently return empty
55
+ return [];
56
+ }
57
+ throw e;
58
+ }
49
59
  // Cache the results with the hash
50
60
  mavenCache.set(hash, mavenData);
51
61
  }
@@ -50,7 +50,7 @@ function isMaven4(workspaceRoot) {
50
50
  function detectMavenExecutable(workspaceRoot) {
51
51
  // First priority: Check for Maven Daemon
52
52
  try {
53
- (0, child_process_1.execSync)('mvnd --version', { stdio: 'pipe' });
53
+ (0, child_process_1.execSync)('mvnd --version', { stdio: 'pipe', windowsHide: true });
54
54
  devkit_1.logger.verbose(`[Maven] Found Maven Daemon, using: mvnd`);
55
55
  return 'mvnd';
56
56
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/maven",
3
- "version": "22.7.0-beta.0",
3
+ "version": "22.7.0-beta.10",
4
4
  "private": false,
5
5
  "description": "Nx plugin for Maven integration",
6
6
  "repository": {
@@ -13,6 +13,7 @@
13
13
  },
14
14
  "homepage": "https://nx.dev",
15
15
  "main": "./dist/index.js",
16
+ "type": "commonjs",
16
17
  "types": "./dist/index.d.ts",
17
18
  "exports": {
18
19
  ".": {
@@ -46,8 +47,9 @@
46
47
  "author": "Victor Savkin",
47
48
  "license": "MIT",
48
49
  "dependencies": {
49
- "@nx/devkit": "22.7.0-beta.0",
50
+ "@nx/devkit": "22.7.0-beta.10",
50
51
  "@xmldom/xmldom": "^0.8.10",
52
+ "tree-kill": "^1.2.2",
51
53
  "tslib": "^2.3.0"
52
54
  },
53
55
  "devDependencies": {
@@ -56,7 +58,7 @@
56
58
  "@types/xmldom": "^0.1.34",
57
59
  "jest": "^30.0.2",
58
60
  "memfs": "^4.9.2",
59
- "nx": "22.7.0-beta.0",
61
+ "nx": "22.7.0-beta.10",
60
62
  "ts-jest": "^29.4.0",
61
63
  "typescript": "~5.9.2"
62
64
  },