Skip to content

Commit 11fa73f

Browse files
committed
feat(gradle): excludeDependsOn based on provider relationships
1 parent 0119275 commit 11fa73f

File tree

3 files changed

+82
-14
lines changed

3 files changed

+82
-14
lines changed

packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/NxProjectReportTask.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ abstract class NxProjectReportTask @Inject constructor(private val projectLayout
5252
logger.info("${Date()} Target Name Overrides ${targetNameOverrides.get()}")
5353
logger.info("${Date()} Target Name Prefix: ${targetNamePrefix.get()}")
5454
logger.info("${Date()} Atomized: ${atomized.get()}")
55+
5556
val project = projectRef.get() // Get project reference at execution time
5657
val report =
5758
createNodeForProject(

packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/ProjectUtils.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ fun processTargetsForProject(
147147
dependencies,
148148
targetNameOverrides,
149149
gitIgnoreClassifier,
150-
targetNamePrefix)
150+
targetNamePrefix,
151+
project)
151152

152153
targets[targetName] = target
153154

packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/TaskUtils.kt

Lines changed: 79 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import dev.nx.gradle.data.Dependency
55
import dev.nx.gradle.data.ExternalDepData
66
import dev.nx.gradle.data.ExternalNode
77
import java.io.File
8+
import org.gradle.api.Project
89
import org.gradle.api.Task
910

1011
/**
@@ -24,7 +25,8 @@ fun processTask(
2425
dependencies: MutableSet<Dependency>,
2526
targetNameOverrides: Map<String, String>,
2627
gitIgnoreClassifier: GitIgnoreClassifier,
27-
targetNamePrefix: String = ""
28+
targetNamePrefix: String = "",
29+
project: Project,
2830
): MutableMap<String, Any?> {
2931
val logger = task.logger
3032
logger.info("NxProjectReportTask: process $task for $projectRoot")
@@ -77,15 +79,20 @@ fun processTask(
7779
task.description ?: "Run ${projectBuildPath}.${task.name}", projectBuildPath, task.name)
7880
target["metadata"] = metadata
7981

80-
target["options"] =
81-
if (continuous) {
82-
mapOf(
83-
"taskName" to "${projectBuildPath}:${task.name}",
84-
"continuous" to true,
85-
"excludeDependsOn" to shouldExcludeDependsOn(task))
86-
} else {
87-
mapOf("taskName" to "${projectBuildPath}:${task.name}")
88-
}
82+
if (task.name == "composedJar") {
83+
println("DEBUG location")
84+
}
85+
86+
target["options"] = buildMap {
87+
put("taskName", "${projectBuildPath}:${task.name}")
88+
if (hasProviderBasedDependencies(task, project)) {
89+
put("excludeDependsOn", false)
90+
}
91+
if (continuous) {
92+
put("continuous", true)
93+
}
94+
}
95+
8996

9097
return target
9198
}
@@ -470,8 +477,67 @@ fun isCacheable(task: Task): Boolean {
470477
return !nonCacheableTasks.contains(task.name)
471478
}
472479

473-
private val tasksWithDependsOn = setOf("bootRun", "bootJar")
480+
/**
481+
* Finds provider-based task dependencies by comparing explicit dependsOn with computed
482+
* taskDependencies after resolving configurations.
483+
*
484+
* Provider-based dependencies are lazy and only appear in taskDependencies after the underlying
485+
* providers have been evaluated. This happens when configurations are resolved.
486+
*
487+
* @param task the task to analyze
488+
* @param project the project containing the task
489+
* @return set of task paths that are provider-based dependencies
490+
*/
491+
fun findProviderBasedDependencies(task: Task, project: Project): Set<String> {
492+
val logger = task.logger
493+
494+
// Step 1: Get explicit dependsOn BEFORE resolution
495+
val explicitDependsOn: Set<String> =
496+
try {
497+
task.dependsOn.filterIsInstance<Task>().map { it.path }.toSet()
498+
} catch (e: Exception) {
499+
logger.debug("Could not get explicit dependsOn for ${task.path}: ${e.message}")
500+
emptySet()
501+
}
474502

475-
fun shouldExcludeDependsOn(task: Task): Boolean {
476-
return !tasksWithDependsOn.contains(task.name)
503+
// Step 2: Resolve all resolvable configurations to trigger provider evaluation
504+
project.configurations
505+
.matching { it.isCanBeResolved }
506+
.forEach { conf ->
507+
try {
508+
conf.resolve()
509+
} catch (e: Exception) {
510+
// Some configurations may fail to resolve, log and continue
511+
logger.debug("Could not resolve configuration ${conf.name}: ${e.message}")
512+
}
513+
}
514+
515+
// Step 3: Get computed dependencies AFTER resolution - providers have now been evaluated
516+
val computedDependencies: Set<String> =
517+
try {
518+
task.taskDependencies.getDependencies(task).map { it.path }.toSet()
519+
} catch (e: Exception) {
520+
logger.debug("Could not get computed dependencies for ${task.path}: ${e.message}")
521+
emptySet()
522+
}
523+
524+
// Step 4: Provider-based dependencies are those in computed but not in explicit
525+
val providerBasedDeps = computedDependencies - explicitDependsOn
526+
527+
if (providerBasedDeps.isNotEmpty()) {
528+
logger.info("Task ${task.path} has provider-based dependencies: $providerBasedDeps")
529+
}
530+
531+
return providerBasedDeps
532+
}
533+
534+
/**
535+
* Checks if a task has any provider-based dependencies.
536+
*
537+
* @param task the task to check
538+
* @param project the project containing the task
539+
* @return true if the task has provider-based dependencies, false otherwise
540+
*/
541+
fun hasProviderBasedDependencies(task: Task, project: Project): Boolean {
542+
return findProviderBasedDependencies(task, project).isNotEmpty()
477543
}

0 commit comments

Comments
 (0)