@nx/gradle 23.0.0-beta.4 → 23.0.0-beta.5

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/gradle",
3
- "version": "23.0.0-beta.4",
3
+ "version": "23.0.0-beta.5",
4
4
  "private": false,
5
5
  "description": "The Nx Plugin for Gradle allows Gradle tasks to be run through Nx",
6
6
  "repository": {
@@ -40,13 +40,13 @@
40
40
  "migrations": "./migrations.json"
41
41
  },
42
42
  "dependencies": {
43
- "@nx/devkit": "23.0.0-beta.4",
43
+ "@nx/devkit": "23.0.0-beta.5",
44
44
  "toml-eslint-parser": "^0.10.0",
45
45
  "tree-kill": "^1.2.2",
46
46
  "tslib": "^2.3.0"
47
47
  },
48
48
  "devDependencies": {
49
- "nx": "23.0.0-beta.4"
49
+ "nx": "23.0.0-beta.5"
50
50
  },
51
51
  "publishConfig": {
52
52
  "access": "public"
@@ -1,9 +1,12 @@
1
1
  import { ExecutorContext, ProjectGraphProjectNode, TaskGraph } from '@nx/devkit';
2
2
  import { RunCommandsOptions } from 'nx/src/executors/run-commands/run-commands.impl';
3
- import { BatchResults } from 'nx/src/tasks-runner/batch/batch-messages';
3
+ import { TaskResult } from 'nx/src/config/misc-interfaces';
4
4
  import { GradleExecutorSchema } from './schema';
5
5
  export declare const batchRunnerPath: string;
6
- export default function gradleBatch(taskGraph: TaskGraph, inputs: Record<string, GradleExecutorSchema>, overrides: RunCommandsOptions, context: ExecutorContext): Promise<BatchResults>;
6
+ export default function gradleBatch(taskGraph: TaskGraph, inputs: Record<string, GradleExecutorSchema>, overrides: RunCommandsOptions, context: ExecutorContext): AsyncGenerator<{
7
+ task: string;
8
+ result: TaskResult;
9
+ }>;
7
10
  export declare function getGradlewTasksToRun(taskIds: string[], taskGraph: TaskGraph, inputs: Record<string, GradleExecutorSchema>, nodes: Record<string, ProjectGraphProjectNode>, fullTaskGraph?: TaskGraph): {
8
11
  gradlewTasksToRun: Record<string, GradleExecutorSchema>;
9
12
  excludeTasks: Set<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"gradle-batch.impl.d.ts","sourceRoot":"","sources":["../../../../../../packages/gradle/src/executors/gradle/gradle-batch.impl.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EAEf,uBAAuB,EACvB,SAAS,EAEV,MAAM,YAAY,CAAC;AACpB,OAAO,EAEL,kBAAkB,EACnB,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAC;AACxE,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAahD,eAAO,MAAM,eAAe,QAG3B,CAAC;AAEF,wBAA8B,WAAW,CACvC,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,EAC5C,SAAS,EAAE,kBAAkB,EAC7B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,YAAY,CAAC,CAkEvB;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,EAC5C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAC9C,aAAa,GAAE,SAAqB;;;;EA0DrC"}
1
+ {"version":3,"file":"gradle-batch.impl.d.ts","sourceRoot":"","sources":["../../../../../../packages/gradle/src/executors/gradle/gradle-batch.impl.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EAEf,uBAAuB,EACvB,SAAS,EAEV,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AACrF,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAahD,eAAO,MAAM,eAAe,QAG3B,CAAC;AAEF,wBAA+B,WAAW,CACxC,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,EAC5C,SAAS,EAAE,kBAAkB,EAC7B,OAAO,EAAE,eAAe,GACvB,cAAc,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC,CA8EtD;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,EAC5C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAC9C,aAAa,GAAE,SAAqB;;;;EA0DrC"}
@@ -7,47 +7,60 @@ const devkit_1 = require("@nx/devkit");
7
7
  const exec_gradle_1 = require("../../utils/exec-gradle");
8
8
  const path_1 = require("path");
9
9
  const child_process_1 = require("child_process");
10
+ const readline_1 = require("readline");
10
11
  const get_exclude_task_1 = require("./get-exclude-task");
11
12
  exports.batchRunnerPath = (0, path_1.join)(__dirname, '../../../batch-runner/build/libs/gradle-batch-runner-all.jar');
12
- async function gradleBatch(taskGraph, inputs, overrides, context) {
13
+ async function* gradleBatch(taskGraph, inputs, overrides, context) {
14
+ const projectName = taskGraph.tasks[taskGraph.roots[0]]?.target?.project;
15
+ const projectRoot = context.projectGraph.nodes[projectName]?.data?.root ?? '';
16
+ const customGradleExecutableDirectory = (0, exec_gradle_1.getCustomGradleExecutableDirectoryFromPlugin)(context.nxJsonConfiguration);
17
+ let gradlewPath = (0, exec_gradle_1.findGradlewFile)((0, path_1.join)(projectRoot, 'project.json'), devkit_1.workspaceRoot, customGradleExecutableDirectory);
18
+ gradlewPath = (0, path_1.join)(context.root, gradlewPath);
19
+ const root = (0, path_1.dirname)(gradlewPath);
20
+ // set args with passed in args and overrides in command line
21
+ const input = inputs[taskGraph.roots[0]];
22
+ const args = typeof input.args === 'string'
23
+ ? input.args.trim().split(' ')
24
+ : Array.isArray(input.args)
25
+ ? input.args
26
+ : [];
27
+ if (overrides.__overrides_unparsed__.length) {
28
+ args.push(...overrides.__overrides_unparsed__);
29
+ }
30
+ const taskIds = Object.keys(taskGraph.tasks);
31
+ const { gradlewTasksToRun, excludeTasks, excludeTestTasks } = getGradlewTasksToRun(taskIds, taskGraph, inputs, context.projectGraph.nodes, context.taskGraph ?? taskGraph);
32
+ const yielded = new Set();
13
33
  try {
14
- const projectName = taskGraph.tasks[taskGraph.roots[0]]?.target?.project;
15
- let projectRoot = context.projectGraph.nodes[projectName]?.data?.root ?? '';
16
- const customGradleExecutableDirectory = (0, exec_gradle_1.getCustomGradleExecutableDirectoryFromPlugin)(context.nxJsonConfiguration);
17
- let gradlewPath = (0, exec_gradle_1.findGradlewFile)((0, path_1.join)(projectRoot, 'project.json'), devkit_1.workspaceRoot, customGradleExecutableDirectory);
18
- gradlewPath = (0, path_1.join)(context.root, gradlewPath);
19
- const root = (0, path_1.dirname)(gradlewPath);
20
- const input = inputs[taskGraph.roots[0]];
21
- let args = typeof input.args === 'string'
22
- ? input.args.trim().split(' ')
23
- : Array.isArray(input.args)
24
- ? input.args
25
- : [];
26
- if (overrides.__overrides_unparsed__.length) {
27
- args.push(...overrides.__overrides_unparsed__);
34
+ for await (const event of streamTasksInBatch(gradlewTasksToRun, excludeTasks, excludeTestTasks, args, root)) {
35
+ yielded.add(event.task);
36
+ yield event;
28
37
  }
29
- const taskIds = Object.keys(taskGraph.tasks);
30
- const { gradlewTasksToRun, excludeTasks, excludeTestTasks } = getGradlewTasksToRun(taskIds, taskGraph, inputs, context.projectGraph.nodes, context.taskGraph ?? taskGraph);
31
- const batchResults = await runTasksInBatch(gradlewTasksToRun, excludeTasks, excludeTestTasks, args, root);
32
- taskIds.forEach((taskId) => {
33
- if (!batchResults[taskId]) {
34
- batchResults[taskId] = {
35
- success: false,
36
- terminalOutput: `Gradlew batch failed`,
37
- };
38
- }
39
- });
40
- return batchResults;
41
38
  }
42
39
  catch (e) {
43
40
  devkit_1.output.error({
44
41
  title: `Gradlew batch failed`,
45
42
  bodyLines: [e.toString()],
46
43
  });
47
- return taskGraph.roots.reduce((acc, key) => {
48
- acc[key] = { success: false, terminalOutput: e.toString() };
49
- return acc;
50
- }, {});
44
+ for (const taskId of taskIds) {
45
+ if (!yielded.has(taskId)) {
46
+ yielded.add(taskId);
47
+ yield {
48
+ task: taskId,
49
+ result: { success: false, terminalOutput: e.toString() },
50
+ };
51
+ }
52
+ }
53
+ return;
54
+ }
55
+ // Any tasks the batch runner did not report on are treated as failed so Nx
56
+ // does not hang waiting for results.
57
+ for (const taskId of taskIds) {
58
+ if (!yielded.has(taskId)) {
59
+ yield {
60
+ task: taskId,
61
+ result: { success: false, terminalOutput: `Gradlew batch failed` },
62
+ };
63
+ }
51
64
  }
52
65
  }
53
66
  function getGradlewTasksToRun(taskIds, taskGraph, inputs, nodes, fullTaskGraph = taskGraph) {
@@ -88,7 +101,7 @@ function getGradlewTasksToRun(taskIds, taskGraph, inputs, nodes, fullTaskGraph =
88
101
  excludeTestTasks,
89
102
  };
90
103
  }
91
- async function runTasksInBatch(gradlewTasksToRun, excludeTasks, excludeTestTasks, args, root) {
104
+ async function* streamTasksInBatch(gradlewTasksToRun, excludeTasks, excludeTestTasks, args, root) {
92
105
  const gradlewBatchStart = performance.mark(`gradlew-batch:start`);
93
106
  const debugOptions = (process.env.NX_GRADLE_BATCH_DEBUG ?? '').trim();
94
107
  const spawnArgs = [
@@ -102,30 +115,73 @@ async function runTasksInBatch(gradlewTasksToRun, excludeTasks, excludeTestTasks
102
115
  `--excludeTestTasks=${Array.from(excludeTestTasks).join(',')}`,
103
116
  ...(process.env.NX_VERBOSE_LOGGING === 'true' ? [] : ['--quiet']),
104
117
  ];
105
- // Use 'inherit' for stderr so Gradle output (tee'd to System.err
106
- // by TeeOutputStream) flows to the terminal in real-time.
107
- // stdout is piped to capture the JSON batch results.
108
- const batchResults = await new Promise((resolve, reject) => {
109
- const cp = (0, child_process_1.spawn)('java', spawnArgs, {
110
- cwd: devkit_1.workspaceRoot,
111
- windowsHide: true,
112
- env: process.env,
113
- stdio: ['pipe', 'pipe', 'inherit'],
114
- });
115
- const chunks = [];
116
- cp.stdout.on('data', (chunk) => chunks.push(chunk));
118
+ // stderr is inherited so Gradle output (tee'd to System.err by TeeOutputStream)
119
+ // and logger output flow to the terminal in real-time.
120
+ // stdout is piped so we can read NX_RESULT lines emitted per task.
121
+ const cp = (0, child_process_1.spawn)('java', spawnArgs, {
122
+ cwd: devkit_1.workspaceRoot,
123
+ windowsHide: true,
124
+ env: process.env,
125
+ stdio: ['pipe', 'pipe', 'inherit'],
126
+ });
127
+ const exit = new Promise((resolve, reject) => {
117
128
  cp.on('error', reject);
118
- cp.on('close', (code) => {
119
- if (code !== 0) {
120
- reject(new Error(`Gradle batch runner exited with code ${code}`));
129
+ cp.on('close', (code) => resolve(code ?? 0));
130
+ });
131
+ const rl = (0, readline_1.createInterface)({ input: cp.stdout, crlfDelay: Infinity });
132
+ // Drain stdout into a queue eagerly. Yielding inside the readline loop creates
133
+ // back-pressure: if the consumer is slow, `yield` blocks, readline pauses, the
134
+ // OS pipe between Java and Node fills, and Java's NX_RESULT println blocks on
135
+ // a full pipe — the JVM hangs even though all task work is done.
136
+ const queue = [];
137
+ let notifyAvailable = null;
138
+ let readerClosed = false;
139
+ rl.on('line', (line) => {
140
+ if (!line.startsWith('NX_RESULT:'))
141
+ return;
142
+ try {
143
+ const data = JSON.parse(line.slice('NX_RESULT:'.length));
144
+ queue.push({
145
+ task: data.task,
146
+ result: {
147
+ success: data.result.success ?? false,
148
+ terminalOutput: data.result.terminalOutput ?? '',
149
+ startTime: data.result.startTime,
150
+ endTime: data.result.endTime,
151
+ },
152
+ });
153
+ }
154
+ catch (e) {
155
+ console.error('[Gradle Batch] Failed to parse result line:', line, e);
156
+ return;
157
+ }
158
+ notifyAvailable?.();
159
+ notifyAvailable = null;
160
+ });
161
+ rl.on('close', () => {
162
+ readerClosed = true;
163
+ notifyAvailable?.();
164
+ notifyAvailable = null;
165
+ });
166
+ try {
167
+ while (!readerClosed || queue.length > 0) {
168
+ if (queue.length > 0) {
169
+ yield queue.shift();
121
170
  }
122
171
  else {
123
- resolve(Buffer.concat(chunks).toString());
172
+ await new Promise((resolve) => {
173
+ notifyAvailable = resolve;
174
+ });
124
175
  }
125
- });
126
- });
176
+ }
177
+ }
178
+ finally {
179
+ rl.close();
180
+ }
181
+ const code = await exit;
127
182
  const gradlewBatchEnd = performance.mark(`gradlew-batch:end`);
128
183
  performance.measure(`gradlew-batch`, gradlewBatchStart.name, gradlewBatchEnd.name);
129
- const gradlewBatchResults = JSON.parse(batchResults);
130
- return gradlewBatchResults;
184
+ if (code !== 0) {
185
+ throw new Error(`Gradle batch runner exited with code ${code}`);
186
+ }
131
187
  }