Skip to content

fix(gradle): use object format for dependsOn instead of shorthand strings#34715

Merged
FrozenPandaz merged 12 commits intomasterfrom
fix/gradle-dependson-object-format
Mar 6, 2026
Merged

fix(gradle): use object format for dependsOn instead of shorthand strings#34715
FrozenPandaz merged 12 commits intomasterfrom
fix/gradle-dependson-object-format

Conversation

@FrozenPandaz
Copy link
Collaborator

Current Behavior

The Gradle plugin generates dependsOn entries using the shorthand string format (e.g., "projectName:taskName"). This doesn't leverage the full object syntax that Nx supports.

Expected Behavior

dependsOn entries now use the object format:

  • Same-project dependencies: { "target": "taskName" }
  • Cross-project dependencies: { "target": "taskName", "projects": ["proj1", "proj2"] } with projects grouped by target name

This is more explicit, consistent with the CI targets code (which already used object format), and enables the projects array for grouping multiple project dependencies under a single target.

Related Issue(s)

N/A - internal improvement

@netlify
Copy link

netlify bot commented Mar 5, 2026

Deploy Preview for nx-dev ready!

Name Link
🔨 Latest commit 945693f
🔍 Latest deploy log https://app.netlify.com/projects/nx-dev/deploys/69ab5260c8f11000082bbe4d
😎 Deploy Preview https://deploy-preview-34715--nx-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Mar 5, 2026

Deploy Preview for nx-docs ready!

Name Link
🔨 Latest commit 945693f
🔍 Latest deploy log https://app.netlify.com/projects/nx-docs/deploys/69ab5260e68bc00008d5679e
😎 Deploy Preview https://deploy-preview-34715--nx-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@nx-cloud
Copy link
Contributor

nx-cloud bot commented Mar 5, 2026

View your CI Pipeline Execution ↗ for commit 945693f

Command Status Duration Result
nx affected --targets=lint,test,build,e2e,e2e-c... ✅ Succeeded 14m 41s View ↗
nx run-many -t check-imports check-lock-files c... ✅ Succeeded 3m 21s View ↗
nx-cloud record -- nx-cloud conformance:check ✅ Succeeded 8s View ↗
nx-cloud record -- nx format:check ✅ Succeeded 1s View ↗
nx-cloud record -- nx sync:check ✅ Succeeded <1s View ↗

☁️ Nx Cloud last updated this comment at 2026-03-06 22:36:51 UTC

@FrozenPandaz FrozenPandaz force-pushed the fix/gradle-dependson-object-format branch from 69fa893 to ee7bc98 Compare March 5, 2026 03:52
@FrozenPandaz FrozenPandaz marked this pull request as draft March 5, 2026 03:52
@FrozenPandaz FrozenPandaz force-pushed the fix/gradle-dependson-object-format branch 3 times, most recently from 3713b54 to bc16580 Compare March 5, 2026 04:05
nx-cloud[bot]

This comment was marked as outdated.

@FrozenPandaz FrozenPandaz force-pushed the fix/gradle-dependson-object-format branch from bc16580 to 9b5dd8c Compare March 5, 2026 04:24
nx-cloud[bot]

This comment was marked as outdated.

nx-cloud[bot]

This comment was marked as outdated.

@FrozenPandaz FrozenPandaz force-pushed the fix/gradle-dependson-object-format branch from a7e652b to 3aff1d4 Compare March 6, 2026 02:56
…-not-found errors

Same-project dependencies are now excluded from the Nx target's dependsOn
since Gradle handles internal task ordering automatically. Including them
caused Nx to schedule them as separate tasks via the batch executor, which
failed when tasks like compileGroovy didn't exist at execution time.

CI targets (check-ci, build-ci) now compute same-project dependencies
directly from Gradle's task graph instead of reading from the target's
dependsOn.
@FrozenPandaz FrozenPandaz force-pushed the fix/gradle-dependson-object-format branch from 3aff1d4 to 2730c96 Compare March 6, 2026 02:59
nx-cloud[bot]

This comment was marked as outdated.

nx-cloud bot and others added 2 commits March 6, 2026 15:03
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
Cross-project dependencies now resolve correctly in object format,
which causes bootJar to run in batch mode with its dependencies.
Instead of checking for Gradle-specific output text (:app:bootJar)
which is not captured in batch mode, check for the Nx success message
which works regardless of execution mode.
@FrozenPandaz FrozenPandaz force-pushed the fix/gradle-dependson-object-format branch from 3c34bb2 to ca21b82 Compare March 6, 2026 15:34
Same-project dependencies are now included as { "target": "taskName" }
(without a "projects" field). Cross-project dependencies remain grouped
as { "target": "taskName", "projects": [...] }.
…or dependsOn

Replace raw Map<String, Any> with typed DependsOnEntry data class for dependsOn
entries. Add DependsOnParams enum (FORWARD, IGNORE) for the params field.
Rename internal DepEntry to ResolvedTaskDep. Build CI replacement maps as named
variables for clarity.
@FrozenPandaz FrozenPandaz marked this pull request as ready for review March 6, 2026 17:23
…data class

Remove ResolvedTaskDep by building sameProjectDependsOn and
crossProjectByTarget inline during the loop.
nx-cloud[bot]

This comment was marked as outdated.

nx-cloud[bot]

This comment was marked as outdated.

The executor's get-exclude-task.ts assumed dependsOn entries were always
strings like "project:target". With the new object format
({ target: "name", projects?: [...] }), same-project deps need the
owning project prepended to form a valid Nx task ID.
Comment on lines +23 to +30
if (dep.projects) {
const projectList = Array.isArray(dep.projects)
? dep.projects
: [dep.projects];
// For cross-project deps, use the first project
return projectList[0] !== 'self'
? `${projectList[0]}:${target}`
: `${owningProject}:${target}`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical Bug: Only first project is resolved from multi-project dependencies

When a DependsOnEntry contains multiple projects (e.g., { target: "jar", projects: [": lib1", ":lib2"] }), this function only returns the first project's task ID (:lib1:jar), completely ignoring the remaining projects (:lib2:jar).

This breaks the core feature of the PR - grouping multiple project dependencies. The Kotlin code in TaskUtils.kt lines 329-332 explicitly groups multiple projects into a single entry, but this TypeScript function discards all but the first.

Fix: The function needs to return an array of task IDs, and calling code must iterate over all results:

function resolveDepToTaskIds(
  dep: string | { target?: string; projects?: string | string[] },
  owningProject: string
): string[] {
  if (typeof dep === 'string') {
    return [dep];
  }
  const target = dep?.target;
  if (!target) {
    return [];
  }
  if (dep.projects) {
    const projectList = Array.isArray(dep.projects)
      ? dep.projects
      : [dep.projects];
    return projectList.map(proj => 
      proj !== 'self' ? `${proj}:${target}` : `${owningProject}:${target}`
    );
  }
  return [`${owningProject}:${target}`];
}

Then update callers to iterate: for (const taskId of resolveDepToTaskIds(dep, project)) { ... }

Suggested change
if (dep.projects) {
const projectList = Array.isArray(dep.projects)
? dep.projects
: [dep.projects];
// For cross-project deps, use the first project
return projectList[0] !== 'self'
? `${projectList[0]}:${target}`
: `${owningProject}:${target}`;
if (dep.projects) {
const projectList = Array.isArray(dep.projects)
? dep.projects
: [dep.projects];
// For cross-project deps, map all projects to task IDs
return projectList.map(proj =>
proj !== 'self'
? `${proj}:${target}`
: `${owningProject}:${target}`
);
}

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Copy link
Contributor

@nx-cloud nx-cloud bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

At least one additional CI pipeline execution has run since the conclusion below was written and it may no longer be applicable.

Nx Cloud is proposing a fix for your failed CI:

We've fixed the issue by skipping same-project dependencies (object-format entries without a projects field) in the task exclusion logic. This prevents the Nx batch executor from attempting to schedule same-project tasks that Gradle manages internally, resolving the "task not found" errors that occurred when building Gradle projects with object-format dependsOn entries.

Warning

We could not verify this fix.

Suggested Fix changes
diff --git a/packages/gradle/src/executors/gradle/get-exclude-task.spec.ts b/packages/gradle/src/executors/gradle/get-exclude-task.spec.ts
index d712f94326..ad0068bcac 100644
--- a/packages/gradle/src/executors/gradle/get-exclude-task.spec.ts
+++ b/packages/gradle/src/executors/gradle/get-exclude-task.spec.ts
@@ -148,7 +148,8 @@ describe('getExcludeTasks', () => {
     const targets = new Set<string>(['app1:build']);
     const runningTaskIds = new Set<string>(['app1:build']);
     const excludes = getExcludeTasks(targets, objectNodes, runningTaskIds);
-    expect(excludes).toEqual(new Set([':app1:compileJava', ':app2:build']));
+    // Same-project deps (without 'projects' field) are skipped, only cross-project deps are excluded
+    expect(excludes).toEqual(new Set([':app2:build']));
   });
 });
 
@@ -239,6 +240,7 @@ describe('getAllDependsOn', () => {
       },
     };
     const dependencies = getAllDependsOn(objectNodes, 'app', 'build');
-    expect(dependencies).toEqual(new Set(['app:compileJava', 'lib:jar']));
+    // Same-project deps (without 'projects' field) are skipped, only cross-project deps are included
+    expect(dependencies).toEqual(new Set(['lib:jar']));
   });
 });
diff --git a/packages/gradle/src/executors/gradle/get-exclude-task.ts b/packages/gradle/src/executors/gradle/get-exclude-task.ts
index 9624b67639..fa06996e03 100644
--- a/packages/gradle/src/executors/gradle/get-exclude-task.ts
+++ b/packages/gradle/src/executors/gradle/get-exclude-task.ts
@@ -59,6 +59,12 @@ export function getExcludeTasks(
     const taskDeps = nodes[project]?.data?.targets?.[target]?.dependsOn ?? [];
 
     for (const dep of taskDeps) {
+      // Skip same-project dependencies (object format without 'projects' field)
+      // Gradle handles same-project task ordering automatically
+      if (typeof dep === 'object' && !dep.projects) {
+        continue;
+      }
+
       const depTaskId = resolveDepToTaskId(dep, project);
       if (depTaskId && !runningTaskIds.has(depTaskId)) {
         const gradleTaskName = getGradleTaskNameWithNxTaskId(depTaskId, nodes);
@@ -101,6 +107,12 @@ export function getAllDependsOn(
           ?.dependsOn ?? [];
 
       for (const dep of directDependencies) {
+        // Skip same-project dependencies (object format without 'projects' field)
+        // Gradle handles same-project task ordering automatically
+        if (typeof dep === 'object' && !dep.projects) {
+          continue;
+        }
+
         const depTaskId = resolveDepToTaskId(dep, currentProjectName);
         if (depTaskId && !allDependsOn.has(depTaskId)) {
           stack.push(depTaskId);

🔔 Heads up, your workspace has pending recommendations ↗ to auto-apply fixes for similar failures.

Apply fix via Nx Cloud  Reject fix via Nx Cloud


Or Apply changes locally with:

npx nx-cloud apply-locally CfkM-4C44

Apply fix locally with your editor ↗   View interactive diff ↗



🎓 Learn more about Self-Healing CI on nx.dev

Each test now creates its own workspace to avoid name collisions
between kotlin and groovy gradle subprojects that share the same
buildTreePath (e.g., :list, :app, :utilities).
@FrozenPandaz FrozenPandaz enabled auto-merge (squash) March 6, 2026 22:21
@FrozenPandaz FrozenPandaz merged commit 6f9bfbd into master Mar 6, 2026
24 checks passed
@FrozenPandaz FrozenPandaz deleted the fix/gradle-dependson-object-format branch March 6, 2026 22:36
@github-actions
Copy link
Contributor

This pull request has already been merged/closed. If you experience issues related to these changes, please open a new issue referencing this pull request.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 12, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants