@nx/gradle 22.7.1 → 22.7.2

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": "22.7.1",
3
+ "version": "22.7.2",
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": "22.7.1",
43
+ "@nx/devkit": "22.7.2",
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": "22.7.1"
49
+ "nx": "22.7.2"
50
50
  },
51
51
  "publishConfig": {
52
52
  "access": "public"
@@ -1,18 +1,4 @@
1
- import { ProjectGraphProjectNode, Target } from '@nx/devkit';
2
- /**
3
- * Returns Gradle CLI arguments to exclude dependent tasks
4
- * that are not part of the current execution set.
5
- *
6
- * For example, if a project defines `dependsOn: ['lint']` for the `test` target,
7
- * and only `test` is running, this will return: ['lint']
8
- *
9
- * @param tasks - Set of Target to process
10
- * @param nodes - Project graph nodes
11
- * @param runningTasks - Set of Target that are currently running (won't be excluded)
12
- * @param includeDependsOnTasks - Set of Gradle task names that should be included (not excluded)
13
- * (typically provider-based dependencies that Gradle must resolve)
14
- */
15
- export declare function getExcludeTasks(tasks: Set<Target>, nodes: Record<string, ProjectGraphProjectNode>, runningTasks?: Set<Target>, includeDependsOnTasks?: Set<string>): Set<string>;
16
- export declare function getGradleTaskName(pt: Target, nodes: Record<string, ProjectGraphProjectNode>): string | null;
17
- export declare function getAllDependsOn(nodes: Record<string, ProjectGraphProjectNode>, projectName: string, targetName: string): Set<Target>;
1
+ import { ProjectGraphProjectNode, TaskGraph } from '@nx/devkit';
2
+ export declare function getExcludeTasksFromTaskGraph(taskIdsToExcludeDepsOf: Iterable<string>, runningTaskIds: Set<string>, taskGraph: TaskGraph, nodes: Record<string, ProjectGraphProjectNode>, includeDependsOnTasks?: Set<string>): Set<string>;
3
+ export declare function getAllDependsOnFromTaskGraph(startTaskIds: Iterable<string>, taskGraph: TaskGraph): Set<string>;
18
4
  //# sourceMappingURL=get-exclude-task.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-exclude-task.d.ts","sourceRoot":"","sources":["../../../../../../packages/gradle/src/executors/gradle/get-exclude-task.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,MAAM,EAEP,MAAM,YAAY,CAAC;AA+BpB;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,EAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAC9C,YAAY,GAAE,GAAG,CAAC,MAAM,CAAa,EACrC,qBAAqB,GAAE,GAAG,CAAC,MAAM,CAAa,GAC7C,GAAG,CAAC,MAAM,CAAC,CAsBb;AAED,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,GAC7C,MAAM,GAAG,IAAI,CAEf;AAED,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAC9C,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,GAAG,CAAC,MAAM,CAAC,CAgCb"}
1
+ {"version":3,"file":"get-exclude-task.d.ts","sourceRoot":"","sources":["../../../../../../packages/gradle/src/executors/gradle/get-exclude-task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAU,SAAS,EAAE,MAAM,YAAY,CAAC;AAUxE,wBAAgB,4BAA4B,CAC1C,sBAAsB,EAAE,QAAQ,CAAC,MAAM,CAAC,EACxC,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,EAC3B,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAC9C,qBAAqB,GAAE,GAAG,CAAC,MAAM,CAAa,GAC7C,GAAG,CAAC,MAAM,CAAC,CAsBb;AAED,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC9B,SAAS,EAAE,SAAS,GACnB,GAAG,CAAC,MAAM,CAAC,CAiCb"}
@@ -1,90 +1,53 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getExcludeTasks = getExcludeTasks;
4
- exports.getGradleTaskName = getGradleTaskName;
5
- exports.getAllDependsOn = getAllDependsOn;
6
- const devkit_1 = require("@nx/devkit");
7
- /**
8
- * Resolves a dependsOn entry to a Target.
9
- * Handles both string format ("target") and object format
10
- * ({ target: "name", projects?: ["proj1"] }).
11
- * For same-project object deps (no projects field), uses the owning project name.
12
- */
13
- function resolveDepToTarget(dep, owningProject) {
14
- if (typeof dep === 'string') {
15
- return { project: owningProject, target: dep };
16
- }
17
- const target = dep?.target;
18
- if (!target) {
19
- return null;
20
- }
21
- if (dep.projects) {
22
- const projectList = Array.isArray(dep.projects)
23
- ? dep.projects
24
- : [dep.projects];
25
- return {
26
- project: projectList[0] !== 'self' ? projectList[0] : owningProject,
27
- target,
28
- };
29
- }
30
- return { project: owningProject, target };
3
+ exports.getExcludeTasksFromTaskGraph = getExcludeTasksFromTaskGraph;
4
+ exports.getAllDependsOnFromTaskGraph = getAllDependsOnFromTaskGraph;
5
+ function getGradleTaskName(target, nodes) {
6
+ return nodes[target.project]?.data?.targets?.[target.target]?.options
7
+ ?.taskName;
31
8
  }
32
- /**
33
- * Returns Gradle CLI arguments to exclude dependent tasks
34
- * that are not part of the current execution set.
35
- *
36
- * For example, if a project defines `dependsOn: ['lint']` for the `test` target,
37
- * and only `test` is running, this will return: ['lint']
38
- *
39
- * @param tasks - Set of Target to process
40
- * @param nodes - Project graph nodes
41
- * @param runningTasks - Set of Target that are currently running (won't be excluded)
42
- * @param includeDependsOnTasks - Set of Gradle task names that should be included (not excluded)
43
- * (typically provider-based dependencies that Gradle must resolve)
44
- */
45
- function getExcludeTasks(tasks, nodes, runningTasks = new Set(), includeDependsOnTasks = new Set()) {
9
+ function getExcludeTasksFromTaskGraph(taskIdsToExcludeDepsOf, runningTaskIds, taskGraph, nodes, includeDependsOnTasks = new Set()) {
46
10
  const excludes = new Set();
47
- const runningKeys = new Set(Array.from(runningTasks).map(devkit_1.targetToTargetString));
48
- for (const task of tasks) {
49
- const taskDeps = nodes[task.project]?.data?.targets?.[task.target]?.dependsOn ?? [];
50
- for (const dep of taskDeps) {
51
- const depPt = resolveDepToTarget(dep, task.project);
52
- if (depPt && !runningKeys.has((0, devkit_1.targetToTargetString)(depPt))) {
53
- const gradleTaskName = getGradleTaskName(depPt, nodes);
54
- if (gradleTaskName && !includeDependsOnTasks.has(gradleTaskName)) {
55
- excludes.add(gradleTaskName);
56
- }
57
- }
11
+ const transitiveDepIds = getAllDependsOnFromTaskGraph(taskIdsToExcludeDepsOf, taskGraph);
12
+ for (const depTaskId of transitiveDepIds) {
13
+ if (runningTaskIds.has(depTaskId)) {
14
+ continue;
15
+ }
16
+ const task = taskGraph.tasks[depTaskId];
17
+ if (!task) {
18
+ continue;
19
+ }
20
+ const gradleTaskName = getGradleTaskName(task.target, nodes);
21
+ if (gradleTaskName && !includeDependsOnTasks.has(gradleTaskName)) {
22
+ excludes.add(gradleTaskName);
58
23
  }
59
24
  }
60
25
  return excludes;
61
26
  }
62
- function getGradleTaskName(pt, nodes) {
63
- return nodes[pt.project]?.data?.targets?.[pt.target]?.options?.taskName;
64
- }
65
- function getAllDependsOn(nodes, projectName, targetName) {
66
- const allDependsOn = new Set();
27
+ function getAllDependsOnFromTaskGraph(startTaskIds, taskGraph) {
67
28
  const result = new Set();
68
- const startKey = (0, devkit_1.targetToTargetString)({
69
- project: projectName,
70
- target: targetName,
71
- });
72
- const stack = [{ project: projectName, target: targetName }];
29
+ const seen = new Set();
30
+ const stack = [];
31
+ const edges = (id) => [
32
+ ...(taskGraph.dependencies[id] ?? []),
33
+ ...(taskGraph.continuousDependencies?.[id] ?? []),
34
+ ];
35
+ for (const id of startTaskIds) {
36
+ seen.add(id);
37
+ for (const dep of edges(id)) {
38
+ stack.push(dep);
39
+ }
40
+ }
73
41
  while (stack.length > 0) {
74
42
  const current = stack.pop();
75
- const key = (0, devkit_1.targetToTargetString)(current);
76
- if (!allDependsOn.has(key)) {
77
- allDependsOn.add(key);
78
- if (key !== startKey) {
79
- result.add(current);
80
- }
81
- const directDependencies = nodes[current.project]?.data?.targets?.[current.target]?.dependsOn ??
82
- [];
83
- for (const dep of directDependencies) {
84
- const depPt = resolveDepToTarget(dep, current.project);
85
- if (depPt && !allDependsOn.has((0, devkit_1.targetToTargetString)(depPt))) {
86
- stack.push(depPt);
87
- }
43
+ if (seen.has(current)) {
44
+ continue;
45
+ }
46
+ seen.add(current);
47
+ result.add(current);
48
+ for (const dep of edges(current)) {
49
+ if (!seen.has(dep)) {
50
+ stack.push(dep);
88
51
  }
89
52
  }
90
53
  }
@@ -1,13 +1,13 @@
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>;
7
- /**
8
- * Get the gradlew task ids to run
9
- */
10
- export declare function getGradlewTasksToRun(taskIds: string[], taskGraph: TaskGraph, inputs: Record<string, GradleExecutorSchema>, nodes: Record<string, ProjectGraphProjectNode>): {
6
+ export default function gradleBatch(taskGraph: TaskGraph, inputs: Record<string, GradleExecutorSchema>, overrides: RunCommandsOptions, context: ExecutorContext): AsyncGenerator<{
7
+ task: string;
8
+ result: TaskResult;
9
+ }>;
10
+ export declare function getGradlewTasksToRun(taskIds: string[], taskGraph: TaskGraph, inputs: Record<string, GradleExecutorSchema>, nodes: Record<string, ProjectGraphProjectNode>, fullTaskGraph?: TaskGraph): {
11
11
  gradlewTasksToRun: Record<string, GradleExecutorSchema>;
12
12
  excludeTasks: Set<string>;
13
13
  excludeTestTasks: 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,EAEvB,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;AAchD,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;;GAEG;AACH,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;;;;EAuE/C"}
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,CAkEtD;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,66 +7,59 @@ 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); // find gradlew near project root
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
- let 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__);
34
+ for await (const event of streamTasksInBatch(gradlewTasksToRun, excludeTasks, excludeTestTasks, args, root)) {
35
+ yielded.add(event.task);
36
+ yield event;
29
37
  }
30
- const taskIds = Object.keys(taskGraph.tasks);
31
- const { gradlewTasksToRun, excludeTasks, excludeTestTasks } = getGradlewTasksToRun(taskIds, taskGraph, inputs, context.projectGraph.nodes);
32
- const batchResults = await runTasksInBatch(gradlewTasksToRun, excludeTasks, excludeTestTasks, args, root);
33
- taskIds.forEach((taskId) => {
34
- if (!batchResults[taskId]) {
35
- batchResults[taskId] = {
36
- success: false,
37
- terminalOutput: `Gradlew batch failed`,
38
- };
39
- }
40
- });
41
- return batchResults;
42
38
  }
43
39
  catch (e) {
44
40
  devkit_1.output.error({
45
41
  title: `Gradlew batch failed`,
46
42
  bodyLines: [e.toString()],
47
43
  });
48
- return taskGraph.roots.reduce((acc, key) => {
49
- acc[key] = { success: false, terminalOutput: e.toString() };
50
- return acc;
51
- }, {});
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
+ }
52
53
  }
53
54
  }
54
- /**
55
- * Get the gradlew task ids to run
56
- */
57
- function getGradlewTasksToRun(taskIds, taskGraph, inputs, nodes) {
58
- const tasksWithExclude = new Set();
59
- const testTasksWithExclude = new Set();
60
- const tasksWithoutExclude = new Set();
55
+ function getGradlewTasksToRun(taskIds, taskGraph, inputs, nodes, fullTaskGraph = taskGraph) {
56
+ const tasksWithExcludeIds = new Set();
57
+ const testTasksWithExcludeIds = new Set();
58
+ const tasksWithoutExcludeIds = new Set();
61
59
  const gradlewTasksToRun = {};
62
60
  const includeDependsOnTasks = new Set();
63
61
  for (const taskId of taskIds) {
64
- const task = taskGraph.tasks[taskId];
65
- const input = inputs[task.id];
66
- const taskTarget = {
67
- project: task.target.project,
68
- target: task.target.target,
69
- };
62
+ const input = inputs[taskId];
70
63
  gradlewTasksToRun[taskId] = input;
71
64
  if (input.includeDependsOnTasks) {
72
65
  for (const t of input.includeDependsOnTasks) {
@@ -75,44 +68,29 @@ function getGradlewTasksToRun(taskIds, taskGraph, inputs, nodes) {
75
68
  }
76
69
  if (input.excludeDependsOn) {
77
70
  if (input.testClassName) {
78
- testTasksWithExclude.add(taskTarget);
71
+ testTasksWithExcludeIds.add(taskId);
79
72
  }
80
73
  else {
81
- tasksWithExclude.add(taskTarget);
74
+ tasksWithExcludeIds.add(taskId);
82
75
  }
83
76
  }
84
77
  else {
85
- tasksWithoutExclude.add(taskTarget);
78
+ tasksWithoutExcludeIds.add(taskId);
86
79
  }
87
80
  }
88
- const allRunning = new Set(taskIds.map((id) => ({
89
- project: taskGraph.tasks[id].target.project,
90
- target: taskGraph.tasks[id].target.target,
91
- })));
92
- for (const task of tasksWithoutExclude) {
93
- const dependencies = (0, get_exclude_task_1.getAllDependsOn)(nodes, task.project, task.target);
94
- dependencies.forEach((dep) => allRunning.add(dep));
95
- }
96
- const excludeTasks = (0, get_exclude_task_1.getExcludeTasks)(tasksWithExclude, nodes, allRunning, includeDependsOnTasks);
97
- const allTestsDependsOn = new Set();
98
- for (const task of testTasksWithExclude) {
99
- const taskDependsOn = (0, get_exclude_task_1.getAllDependsOn)(nodes, task.project, task.target);
100
- taskDependsOn.forEach((dep) => allTestsDependsOn.add(dep));
101
- }
102
- const excludeTestTasks = new Set();
103
- for (const task of allTestsDependsOn) {
104
- const gradleTaskName = (0, get_exclude_task_1.getGradleTaskName)(task, nodes);
105
- if (gradleTaskName) {
106
- excludeTestTasks.add(gradleTaskName);
107
- }
81
+ const runningTaskIds = new Set(taskIds);
82
+ for (const depId of (0, get_exclude_task_1.getAllDependsOnFromTaskGraph)(tasksWithoutExcludeIds, fullTaskGraph)) {
83
+ runningTaskIds.add(depId);
108
84
  }
85
+ const excludeTasks = (0, get_exclude_task_1.getExcludeTasksFromTaskGraph)(tasksWithExcludeIds, runningTaskIds, fullTaskGraph, nodes, includeDependsOnTasks);
86
+ const excludeTestTasks = (0, get_exclude_task_1.getExcludeTasksFromTaskGraph)(testTasksWithExcludeIds, new Set(), fullTaskGraph, nodes);
109
87
  return {
110
88
  gradlewTasksToRun,
111
89
  excludeTasks,
112
90
  excludeTestTasks,
113
91
  };
114
92
  }
115
- async function runTasksInBatch(gradlewTasksToRun, excludeTasks, excludeTestTasks, args, root) {
93
+ async function* streamTasksInBatch(gradlewTasksToRun, excludeTasks, excludeTestTasks, args, root) {
116
94
  const gradlewBatchStart = performance.mark(`gradlew-batch:start`);
117
95
  const debugOptions = (process.env.NX_GRADLE_BATCH_DEBUG ?? '').trim();
118
96
  const spawnArgs = [
@@ -126,30 +104,74 @@ async function runTasksInBatch(gradlewTasksToRun, excludeTasks, excludeTestTasks
126
104
  `--excludeTestTasks=${Array.from(excludeTestTasks).join(',')}`,
127
105
  ...(process.env.NX_VERBOSE_LOGGING === 'true' ? [] : ['--quiet']),
128
106
  ];
129
- // Use 'inherit' for stderr so Gradle output (tee'd to System.err
130
- // by TeeOutputStream) flows to the terminal in real-time.
131
- // stdout is piped to capture the JSON batch results.
132
- const batchResults = await new Promise((resolve, reject) => {
133
- const cp = (0, child_process_1.spawn)('java', spawnArgs, {
134
- cwd: devkit_1.workspaceRoot,
135
- windowsHide: true,
136
- env: process.env,
137
- stdio: ['pipe', 'pipe', 'inherit'],
138
- });
139
- const chunks = [];
140
- cp.stdout.on('data', (chunk) => chunks.push(chunk));
107
+ // stderr is inherited so Gradle output (tee'd to System.err by TeeOutputStream)
108
+ // and logger output flow to the terminal in real-time.
109
+ // stdout is piped so we can read NX_RESULT lines emitted per task.
110
+ const cp = (0, child_process_1.spawn)('java', spawnArgs, {
111
+ cwd: devkit_1.workspaceRoot,
112
+ windowsHide: true,
113
+ env: process.env,
114
+ stdio: ['pipe', 'pipe', 'inherit'],
115
+ });
116
+ const exit = new Promise((resolve, reject) => {
141
117
  cp.on('error', reject);
142
- cp.on('close', (code) => {
143
- if (code !== 0) {
144
- reject(new Error(`Gradle batch runner exited with code ${code}`));
118
+ cp.on('close', (code) => resolve(code ?? 0));
119
+ });
120
+ const rl = (0, readline_1.createInterface)({ input: cp.stdout, crlfDelay: Infinity });
121
+ // Drain stdout into a queue eagerly. Yielding inside the readline loop creates
122
+ // back-pressure: if the consumer is slow, `yield` blocks, readline pauses, the
123
+ // OS pipe between Java and Node fills, and Java's NX_RESULT println blocks on
124
+ // a full pipe — the JVM hangs even though all task work is done.
125
+ const queue = [];
126
+ let notifyAvailable = null;
127
+ let readerClosed = false;
128
+ rl.on('line', (line) => {
129
+ if (!line.startsWith('NX_RESULT:'))
130
+ return;
131
+ try {
132
+ const data = JSON.parse(line.slice('NX_RESULT:'.length));
133
+ queue.push({
134
+ task: data.task,
135
+ result: {
136
+ success: data.result.success ?? false,
137
+ status: data.result.status,
138
+ terminalOutput: data.result.terminalOutput ?? '',
139
+ startTime: data.result.startTime,
140
+ endTime: data.result.endTime,
141
+ },
142
+ });
143
+ }
144
+ catch (e) {
145
+ console.error('[Gradle Batch] Failed to parse result line:', line, e);
146
+ return;
147
+ }
148
+ notifyAvailable?.();
149
+ notifyAvailable = null;
150
+ });
151
+ rl.on('close', () => {
152
+ readerClosed = true;
153
+ notifyAvailable?.();
154
+ notifyAvailable = null;
155
+ });
156
+ try {
157
+ while (!readerClosed || queue.length > 0) {
158
+ if (queue.length > 0) {
159
+ yield queue.shift();
145
160
  }
146
161
  else {
147
- resolve(Buffer.concat(chunks).toString());
162
+ await new Promise((resolve) => {
163
+ notifyAvailable = resolve;
164
+ });
148
165
  }
149
- });
150
- });
166
+ }
167
+ }
168
+ finally {
169
+ rl.close();
170
+ }
171
+ const code = await exit;
151
172
  const gradlewBatchEnd = performance.mark(`gradlew-batch:end`);
152
173
  performance.measure(`gradlew-batch`, gradlewBatchStart.name, gradlewBatchEnd.name);
153
- const gradlewBatchResults = JSON.parse(batchResults);
154
- return gradlewBatchResults;
174
+ if (code !== 0) {
175
+ throw new Error(`Gradle batch runner exited with code ${code}`);
176
+ }
155
177
  }
@@ -1 +1 @@
1
- {"version":3,"file":"gradle.impl.d.ts","sourceRoot":"","sources":["../../../../../../packages/gradle/src/executors/gradle/gradle.impl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAiB,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAShD,wBAA8B,cAAc,CAC1C,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CA8E/B"}
1
+ {"version":3,"file":"gradle.impl.d.ts","sourceRoot":"","sources":["../../../../../../packages/gradle/src/executors/gradle/gradle.impl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAiB,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAShD,wBAA8B,cAAc,CAC1C,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAkF/B"}
@@ -44,9 +44,12 @@ async function gradleExecutor(options, context) {
44
44
  }
45
45
  }
46
46
  });
47
- if (options.excludeDependsOn) {
47
+ if (options.excludeDependsOn && context.taskGraph) {
48
+ const taskId = context.configurationName
49
+ ? `${context.projectName}:${context.targetName}:${context.configurationName}`
50
+ : `${context.projectName}:${context.targetName}`;
48
51
  const includeDependsOnTasks = new Set(options.includeDependsOnTasks ?? []);
49
- (0, get_exclude_task_1.getExcludeTasks)(new Set([{ project: context.projectName, target: context.targetName }]), context.projectGraph.nodes, new Set(), includeDependsOnTasks).forEach((task) => {
52
+ (0, get_exclude_task_1.getExcludeTasksFromTaskGraph)([taskId], new Set([taskId]), context.taskGraph, context.projectGraph.nodes, includeDependsOnTasks).forEach((task) => {
50
53
  if (task) {
51
54
  args.push('--exclude-task', task);
52
55
  }