diff --git a/build.gradle.kts b/build.gradle.kts index 1b83371fa360f..2a71308cde428 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,20 +1,15 @@ -group = "dev.nx" - plugins { - // id("dev.nx.gradle.native") version("+") + id("dev.nx.gradle.native") version("+") } +group = "dev.nx.gradle" + allprojects { apply { plugin("project-report") } } -repositories { - // Use Maven Central for resolving dependencies. - mavenCentral() -} - tasks.register("projectReportAll") { // All project reports of subprojects allprojects.forEach { @@ -25,4 +20,4 @@ tasks.register("projectReportAll") { gradle.includedBuilds.forEach { dependsOn(it.task(":projectReportAll")) } -} \ No newline at end of file +} diff --git a/packages/build.gradle.kts b/packages/build.gradle.kts deleted file mode 100644 index 9aa884ac23573..0000000000000 --- a/packages/build.gradle.kts +++ /dev/null @@ -1,23 +0,0 @@ -group = "dev.nx" - -plugins { - // id("dev.nx.gradle.native") version("+") -} - -allprojects { - apply { - plugin("project-report") - } -} - -tasks.register("projectReportAll") { - // All project reports of subprojects - allprojects.forEach { - dependsOn(it.tasks.get("projectReport")) - } - - // All projectReportAll of included builds - gradle.includedBuilds.forEach { - dependsOn(it.task(":projectReportAll")) - } -} \ No newline at end of file diff --git a/packages/gradle/build.gradle.kts b/packages/gradle/build.gradle.kts deleted file mode 100644 index 9aa884ac23573..0000000000000 --- a/packages/gradle/build.gradle.kts +++ /dev/null @@ -1,23 +0,0 @@ -group = "dev.nx" - -plugins { - // id("dev.nx.gradle.native") version("+") -} - -allprojects { - apply { - plugin("project-report") - } -} - -tasks.register("projectReportAll") { - // All project reports of subprojects - allprojects.forEach { - dependsOn(it.tasks.get("projectReport")) - } - - // All projectReportAll of included builds - gradle.includedBuilds.forEach { - dependsOn(it.task(":projectReportAll")) - } -} \ No newline at end of file diff --git a/packages/gradle/native/build.gradle.kts b/packages/gradle/native/build.gradle.kts index 28d2f7f841340..71fb5b2d27ac2 100644 --- a/packages/gradle/native/build.gradle.kts +++ b/packages/gradle/native/build.gradle.kts @@ -15,7 +15,7 @@ plugins { id("com.gradle.plugin-publish") version "1.3.0" id("java-library") - id("org.jetbrains.kotlin.jvm") version "1.9.25" + id("org.jetbrains.kotlin.jvm") version "2.1.10" } repositories { @@ -52,9 +52,6 @@ publishing { dependencies { implementation("com.google.code.gson:gson:2.11.0") - compileOnly("org.jetbrains.kotlin:kotlin-gradle-plugin") - compileOnly("org.jetbrains.kotlin:kotlin-stdlib") - testImplementation(kotlin("test")) } diff --git a/packages/gradle/native/settings.gradle.kts b/packages/gradle/native/settings.gradle.kts new file mode 100644 index 0000000000000..e348c4a200689 --- /dev/null +++ b/packages/gradle/native/settings.gradle.kts @@ -0,0 +1,17 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.5/userguide/building_swift_projects.html in the Gradle documentation. + */ + + +pluginManagement { + repositories { + mavenLocal() + mavenCentral() + gradlePluginPortal() + } +} + +rootProject.name = "native" diff --git a/packages/gradle/native/settings.xml b/packages/gradle/native/settings.xml deleted file mode 100644 index 26ef9dbc88eb5..0000000000000 --- a/packages/gradle/native/settings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - ${server} - m+nR6jxh - bnbMSW8wlggq770eJvmuSG9/0aXDwz3xd8NZCBCpn4jd - diff --git a/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/CreateNodesTask.kt b/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/CreateNodesTask.kt index befefbc86f54e..d0d6b7b3fab62 100644 --- a/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/CreateNodesTask.kt +++ b/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/CreateNodesTask.kt @@ -1,19 +1,19 @@ package dev.nx.gradle.native +import com.google.gson.Gson import org.gradle.api.DefaultTask import java.io.File import org.gradle.api.tasks.options.Option import org.gradle.api.tasks.Input import org.gradle.api.tasks.TaskAction -import java.nio.file.Path -import org.gradle.api.logging.Logger import org.gradle.api.file.ProjectLayout +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Nested import javax.inject.Inject -import kotlin.io.path.Path import java.nio.file.Files /** - * This task generates nodes, depedencies and external nodes for all projects int the workspace + * This task generates nodes, dependencies and external nodes for all projects int the workspace * For each project, it will generate a json file at outputDirectory/projectName+hash.json * Inputs: * - hash: hash to in the file name @@ -22,37 +22,37 @@ import java.nio.file.Files */ abstract class CreateNodesTask @Inject constructor(private var projectLayout: ProjectLayout) : DefaultTask() { - @Option(option = "hash", description = "hash adds to output file") + @Option(option = "hash", description = "hash adds to output file name") @Input var hash: String = "" - @get:Input - abstract var json: String - @get:Input abstract var projectName: String - private var logger = getLogger() + @get:Nested + abstract val gradleNodeReport: Property @TaskAction fun action() { - logger.info("CreateNodes: using hash ${hash}") - logger.info("CreateNodes: create file for ${projectName}") + logger.info("CreateNodes: using hash $hash") + logger.info("CreateNodes: create file for $projectName") - var buildDirectory = projectLayout.getBuildDirectory() - var buildDirectoryFile: File = buildDirectory.getAsFile().get() + val buildDirectory = projectLayout.buildDirectory + val buildDirectoryFile: File = buildDirectory.asFile.get() if (!buildDirectoryFile.exists()) { Files.createDirectory(buildDirectoryFile.toPath()) } - var outputDirectory = buildDirectory.dir("nx").get() - var outputDirectoryFile = outputDirectory.getAsFile() + val outputDirectory = buildDirectory.dir("nx").get() + val outputDirectoryFile = outputDirectory.asFile if (!outputDirectoryFile.exists()) { Files.createDirectory(outputDirectoryFile.toPath()) } - val file = outputDirectory.file("${projectName}${hash}.json").getAsFile() + val file = outputDirectory.file("${projectName}${hash}.json").asFile + val gson = Gson() + val json = gson.toJson(gradleNodeReport.get()) file.writeText(json) - println(file.getPath()) + println(file.path) } } diff --git a/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/Data.kt b/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/Data.kt index 5898ce03d4472..6c8064e359f18 100644 --- a/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/Data.kt +++ b/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/Data.kt @@ -1,5 +1,7 @@ package dev.nx.gradle.native +import org.gradle.api.tasks.Input + typealias Target = MutableMap typealias Targets = MutableMap @@ -14,7 +16,7 @@ data class GradleTargets( var externalNodes: MutableMap ) -data class NodeMetadata(val targetGroups: TargetGroups, val technologies: Array, val description: String?) +data class NodeMetadata(val targetGroups: TargetGroups, val technologies: List, val description: String?) data class ProjectNode( val targets: Targets, @@ -27,4 +29,10 @@ data class ExternalDepData(val version: String?, val packageName: String, val ha data class ExternalNode(var type: String?, val name: String, var data: ExternalDepData) -data class GradleNodeReport(var nodes: MutableMap?, var dependencies: MutableSet?, var externalNodes: MutableMap?) +data class GradleNodeReport( + @Input + var nodes: MutableMap?, + @Input + var dependencies: MutableSet?, + @Input + var externalNodes: MutableMap?) diff --git a/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/NodesPlugin.kt b/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/NodesPlugin.kt index 7d3885088f85f..0e3591339df2a 100644 --- a/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/NodesPlugin.kt +++ b/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/NodesPlugin.kt @@ -1,69 +1,35 @@ package dev.nx.gradle.native -import org.gradle.api.Project import org.gradle.api.Plugin -import com.google.gson.Gson +import org.gradle.api.Project /** * A plugin to create nx nodes, dependencies and external nodes */ class NodesPlugin : Plugin { + override fun apply(project: Project) { - project.logger.info("HELLO") + val gradleNodeReport = project.objects.property(GradleNodeReport::class.java) + + // Initialize and store data in GradleNodeReport safely + project.gradle.projectsEvaluated { + val report = createNodeForProject(project) + gradleNodeReport.set(report) + } // Register a task project.tasks.register("createNodes", CreateNodesTask::class.java) { task -> - val gradleNodeReport = createNodeForProject(project) - task.projectName = project.name - val gson = Gson() - val json = gson.toJson(gradleNodeReport) - task.json = json + task.gradleNodeReport.set(gradleNodeReport) - task.setDescription("Create nodes and dependencies for Nx") - task.setGroup("Nx Custom") + task.description = "Create nodes and dependencies for Nx" + task.group = "Nx Custom" // Run task for composite builds - project.getGradle().includedBuilds.forEach { includedBuild -> + project.gradle.includedBuilds.forEach { includedBuild -> task.dependsOn(includedBuild.task(":createNodes")) } } } - - /** - * Loops through all projects and populate dependencies and nodes for each target - */ - fun createNodeForProject(rootProject: Project): GradleNodeReport { - val gradleNodeReport = GradleNodeReport(null, null, null) - val logger = rootProject.getLogger() - logger.info("createNodeForProject: get nodes and dependencies for ${rootProject}") - - try { - // get dependencies of project - val dependencies = getDependenciesForProject(rootProject, rootProject.getAllprojects()) - gradleNodeReport.dependencies = dependencies - logger.info("createNodeForProject: get dependencies for ${rootProject}") - } catch (e: Exception) { - logger.info("createNodeForProject: get dependencies error ${e.toString()}") - } - - - try { - val gradleTargets: GradleTargets = processTargetsForProject(rootProject) - var projectRoot = rootProject.getProjectDir().getPath() - val projectNode = ProjectNode( - gradleTargets.targets, - NodeMetadata(gradleTargets.targetGroups, arrayOf("gradle"), rootProject.getDescription()), - rootProject.getName() - ) - gradleNodeReport.nodes = mutableMapOf(projectRoot to projectNode) - - gradleNodeReport.externalNodes = gradleTargets.externalNodes - logger.info("CreateNodes: get nodes and external nodes for ${projectRoot}") - } catch (e: Exception) { - logger.info("${rootProject}: get nodes error ${e.toString()}") - } - return gradleNodeReport - } } diff --git a/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/NodesUtils.kt b/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/NodesUtils.kt deleted file mode 100644 index 7db12a929a768..0000000000000 --- a/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/NodesUtils.kt +++ /dev/null @@ -1,130 +0,0 @@ -package dev.nx.gradle.native - -import org.gradle.api.DefaultTask -import org.gradle.api.Project -import org.gradle.api.file.FileCollection -import java.io.File -import org.gradle.api.tasks.options.Option -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.TaskAction -import org.gradle.api.artifacts.ProjectDependency -import org.gradle.api.artifacts.ExternalModuleDependency -import com.google.gson.Gson -import com.google.gson.GsonBuilder -import java.nio.file.Path -import org.gradle.api.logging.Logger -import java.lang.Exception - - -/** - * Get depended projects for current projects - * It is going to modify the dependencies in place - */ -fun getDependenciesForProject(project: Project, allProjects: Set): MutableSet { - var dependencies = mutableSetOf() - project.getConfigurations().filter { config -> - val configName = config.name - configName == "compileClasspath" || configName == "implementationDependenciesMetadata" - }.forEach { - it.getAllDependencies().filter { - it is ProjectDependency - }.forEach { - val foundProject = allProjects.find { p -> p.getName() == it.getName() } - if (foundProject != null) { - dependencies.add( - Dependency( - project.getProjectDir().getPath(), - foundProject.getProjectDir().getPath(), - project.getBuildFile().getPath() - ) - ) - } - } - } - project.getSubprojects().forEach { childProject -> - dependencies.add( - Dependency( - project.getProjectDir().getPath(), - childProject.getProjectDir().getPath(), - project.getBuildFile().getPath() - ) - ) - } - project.getGradle().includedBuilds.forEach { includedBuild -> - dependencies.add( - Dependency( - project.getProjectDir().getPath(), - includedBuild.getProjectDir().getPath(), - project.getBuildFile().getPath() - ) - ) - } - return dependencies -} - -/** - * Process targets for project - * @return targets and targetGroups - */ -fun processTargetsForProject( - project: Project, -): GradleTargets { - val targets = mutableMapOf>() - val targetGroups = mutableMapOf>() - val externalNodes = mutableMapOf() - val projectRoot = project.getProjectDir().getPath() - val workspaceRoot = workspaceRootInner(System.getProperty("user.dir"), System.getProperty("user.dir")) - project.getLogger().info("Using workspace root ${workspaceRoot}") - - var projectBuildPath: String = project.getBuildTreePath() // get the build path of project e.g. :app, :utils:number-utils, :buildSrc - if (projectBuildPath.endsWith(":")) { // root project is ":", manually remove last : - projectBuildPath = projectBuildPath.dropLast(1) - } - - val logger = project.getLogger() - - logger.info("${project}: process targets") - - var gradleProject = project.getBuildTreePath() - if (!gradleProject.endsWith(":")) { - gradleProject += ":" - } - - project.getTasks().forEach { task -> - try { - // add task to target groups - val group: String? = task.getGroup(); - if (!group.isNullOrBlank()) { - if (targetGroups.contains(group)) { - targetGroups.get(group)?.add(task.name) - } else { - targetGroups.set(group, mutableListOf(task.name)) - } - } - - val target = processTask(task, projectBuildPath, projectRoot, workspaceRoot, externalNodes) - targets.put(task.name, target) - - if (task.name.startsWith("compileTest")) { - addTestCiTargets( - task.getInputs().getSourceFiles(), - projectBuildPath, - target, - targets, - targetGroups, - projectRoot, - workspaceRoot - ) - } - } catch (e: Exception) { - logger.info("${task}: process task error ${e.toString()}") - } - } - - return GradleTargets( - targets, - targetGroups, - externalNodes - ); -} - diff --git a/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/ProjectUtils.kt b/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/ProjectUtils.kt new file mode 100644 index 0000000000000..c87732ed2daf7 --- /dev/null +++ b/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/ProjectUtils.kt @@ -0,0 +1,152 @@ +package dev.nx.gradle.native + +import org.gradle.api.Project +import org.gradle.api.artifacts.ProjectDependency + +/** + * Loops through a project and populate dependencies and nodes for each target + */ +fun createNodeForProject(project: Project): GradleNodeReport { + val gradleNodeReport = GradleNodeReport(null, null, null) + val logger = project.logger + logger.info("createNodeForProject: get nodes and dependencies for $project") + + try { + // get dependencies of project + val dependencies = getDependenciesForProject(project, project.allprojects) + gradleNodeReport.dependencies = dependencies + logger.info("createNodeForProject: get dependencies for $project") + } catch (e: Exception) { + logger.info("createNodeForProject: get dependencies error $e") + } + + + try { + val gradleTargets: GradleTargets = processTargetsForProject(project) + val projectRoot = project.projectDir.path + val projectNode = ProjectNode( + gradleTargets.targets, + NodeMetadata(gradleTargets.targetGroups, listOf("gradle"), project.description), + project.name + ) + gradleNodeReport.nodes = mutableMapOf(projectRoot to projectNode) + + gradleNodeReport.externalNodes = gradleTargets.externalNodes + logger.info("CreateNodes: get nodes and external nodes for $projectRoot") + } catch (e: Exception) { + logger.info("${project}: get nodes error $e") + } + return gradleNodeReport +} + +/** + * Get dependent projects for current projects + * It is going to modify the dependencies in place + */ +fun getDependenciesForProject(project: Project, allProjects: Set): MutableSet { + val dependencies = mutableSetOf() + project.configurations.filter { config -> + val configName = config.name + configName == "compileClasspath" || configName == "implementationDependenciesMetadata" + }.forEach { + it.allDependencies.filterIsInstance().forEach { + val foundProject = allProjects.find { p -> p.name == it.name } + if (foundProject != null) { + dependencies.add( + Dependency( + project.projectDir.path, + foundProject.projectDir.path, + project.buildFile.path + ) + ) + } + } + } + project.subprojects.forEach { childProject -> + dependencies.add( + Dependency( + project.projectDir.path, + childProject.projectDir.path, + project.buildFile.path + ) + ) + } + project.gradle.includedBuilds.forEach { includedBuild -> + dependencies.add( + Dependency( + project.projectDir.path, + includedBuild.projectDir.path, + project.buildFile.path + ) + ) + } + return dependencies +} + +/** + * Process targets for project + * @return targets and targetGroups + */ +fun processTargetsForProject( + project: Project, +): GradleTargets { + val targets = mutableMapOf>() + val targetGroups = mutableMapOf>() + val externalNodes = mutableMapOf() + val projectRoot = project.projectDir.path + val workspaceRoot = workspaceRootInner(System.getProperty("user.dir"), System.getProperty("user.dir")) + project.logger.info("Using workspace root $workspaceRoot") + + var projectBuildPath: String = project.buildTreePath // get the build path of project e.g. :app, :utils:number-utils, :buildSrc + if (projectBuildPath.endsWith(":")) { // root project is ":", manually remove last : + projectBuildPath = projectBuildPath.dropLast(1) + } + + val logger = project.logger + + logger.info("${project}: process targets") + + var gradleProject = project.buildTreePath + if (!gradleProject.endsWith(":")) { + gradleProject += ":" + } + + project.tasks.forEach { task -> + try { + logger.info("Processing $task") + // add task to target groups + val group: String? = task.group + if (!group.isNullOrBlank()) { + if (targetGroups.contains(group)) { + targetGroups[group]?.add(task.name) + } else { + targetGroups[group] = mutableListOf(task.name) + } + } + + val target = processTask(task, projectBuildPath, projectRoot, workspaceRoot, externalNodes) + targets[task.name] = target + + if (task.name.startsWith("compileTest")) { + addTestCiTargets( + task.inputs.sourceFiles, + projectBuildPath, + target, + targets, + targetGroups, + projectRoot, + workspaceRoot + ) + } + } catch (e: Exception) { + logger.info("${task}: process task error $e") + logger.debug("Stack trace:", e) + } + } + + return GradleTargets( + targets, + targetGroups, + externalNodes + ) +} diff --git a/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/ProcessTaskUtils.kt b/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/TaskUtils.kt similarity index 61% rename from packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/ProcessTaskUtils.kt rename to packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/TaskUtils.kt index 7bdf809ef783b..d5838d258b1a8 100644 --- a/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/ProcessTaskUtils.kt +++ b/packages/gradle/native/src/main/kotlin/dev/nx/gradle/native/TaskUtils.kt @@ -1,9 +1,7 @@ package dev.nx.gradle.native import org.gradle.api.Task -import org.gradle.api.tasks.TaskProvider import org.gradle.api.file.FileCollection -import java.io.File /** * Process a task and convert it into target @@ -24,60 +22,56 @@ fun processTask( externalNodes: MutableMap ): MutableMap { val logger = task.logger - logger.info(" >> CreateNodes: process ${task} for ${projectRoot}") + logger.info("CreateNodes: process $task for $projectRoot") val target = mutableMapOf() - target.put("cache", true) // set cache to be always true - target.put("parallelism", false) // set parallelism alaway false + target["cache"] = true // set cache to be always true + target["parallelism"] = false // set parallelism always false // process inputs val inputs = getInputsForTask(task, projectRoot, workspaceRoot, externalNodes) if (inputs?.isEmpty() == false) { - logger.info("${task}: processed ${inputs?.size} inputs") - target.put("inputs", inputs) + logger.info("${task}: processed ${inputs.size} inputs") + target["inputs"] = inputs } - // process oputputs + // process outputs val outputs = getOutputsForTask(task, projectRoot, workspaceRoot) if (outputs?.isEmpty() == false) { - logger.info("${task}: processed ${outputs?.size} outputs") - target.put("outputs", outputs) + logger.info("${task}: processed ${outputs.size} outputs") + target["outputs"] = outputs } // process dependsOn val dependsOn = getDependsOnForTask(task) if (dependsOn?.isEmpty() == false) { - logger.info("${task}: processed ${dependsOn?.size} dependsOn") - target.put("dependsOn", dependsOn) + logger.info("${task}: processed ${dependsOn.size} dependsOn") + target["dependsOn"] = dependsOn } val gradlewCommand = getGradlewCommand() - target.put("command", "${gradlewCommand} ${projectBuildPath}:${task.name}") + target["command"] = "$gradlewCommand ${projectBuildPath}:${task.name}" - val metadata = getMetadata(task.getDescription() ?: "Run ${task.getName()}", projectBuildPath, task.getName()) - target.put("metadata", metadata) + val metadata = getMetadata(task.description ?: "Run ${task.name}", projectBuildPath, task.name) + target["metadata"] = metadata var cwd = System.getProperty("user.dir") if (cwd.startsWith(workspaceRoot)) { cwd = cwd.replace(workspaceRoot, ".") } - target.put("options", mapOf( + target["options"] = mapOf( "cwd" to cwd, "args" to "--configuration-cache --parallel --build-cache" // add these args to improve performance - )) + ) return target } -const val testCiTargetGroup = "verfication" +const val testCiTargetGroup = "verification" /** * Add atomized ci test targets * Going to loop through each test files and create a target for each * It is going to modify targets and targetGroups in place - * @param projectBuildPath current gradle project to add test ci targets - * @param task compileTest task to be split up - * @param targets targets to add ci test targets to, going to modify it in place - * @param targetGroups targetsGroup to add newly created ci test targets */ fun addTestCiTargets( testFiles: FileCollection, @@ -89,7 +83,7 @@ fun addTestCiTargets( workspaceRoot: String ) { if (!targetGroups.contains(testCiTargetGroup)) { // add target group if not exist - targetGroups.set(testCiTargetGroup, mutableListOf()) + targetGroups[testCiTargetGroup] = mutableListOf() } val dependsOn = mutableListOf>() val gradlewCommand = getGradlewCommand() @@ -97,19 +91,19 @@ fun addTestCiTargets( val fileName = testFile.getName().split(".").first() val regex = ".*(Test)(s)?\\d*".toRegex() // find the files that match Test(any number) regex testFile.startsWith(workspaceRoot) && regex.matches(fileName) - }?.forEach { testFile -> + }.forEach { testFile -> val fileName = testFile.getName().split(".").first() val testCiTarget = target.toMutableMap() - testCiTarget.put("command", "${gradlewCommand} ${projectBuildPath}:test --tests ${fileName}") - val metadata = getMetadata("Runs Gradle test ${fileName} in CI", projectBuildPath, "test") - testCiTarget.put("metadata", metadata) - testCiTarget.put("cache", true) - testCiTarget.put("parallelism", false) - testCiTarget.put("inputs", arrayOf(replaceRootInPath(testFile.getPath(), projectRoot, workspaceRoot))) + testCiTarget["command"] = "$gradlewCommand ${projectBuildPath}:test --tests $fileName" + val metadata = getMetadata("Runs Gradle test $fileName in CI", projectBuildPath, "test") + testCiTarget["metadata"] = metadata + testCiTarget["cache"] = true + testCiTarget["parallelism"] = false + testCiTarget["inputs"] = arrayOf(replaceRootInPath(testFile.path, projectRoot, workspaceRoot)) val targetName = "ci--${fileName}" - targets.put(targetName, testCiTarget) - targetGroups.get("verification")?.add(targetName) + targets[targetName] = testCiTarget + targetGroups["verification"]?.add(targetName) dependsOn.add( mapOf( "target" to targetName, @@ -119,26 +113,26 @@ fun addTestCiTargets( ) } - if (!dependsOn.isEmpty()) { + if (dependsOn.isNotEmpty()) { val testCiTarget = mutableMapOf() val metadata = getMetadata("Runs Gradle Tests in CI", projectBuildPath, "test") - testCiTarget.put("executor", "nx:noop") - testCiTarget.put("metadata", metadata) - testCiTarget.put("dependsOn", dependsOn) - testCiTarget.put("cache", true) - testCiTarget.put("parallelism", false) - targets.put("ci", testCiTarget) - targetGroups.get(testCiTargetGroup)?.add("ci") + testCiTarget["executor"] = "nx:noop" + testCiTarget["metadata"] = metadata + testCiTarget["dependsOn"] = dependsOn + testCiTarget["cache"] = true + testCiTarget["parallelism"] = false + targets["ci"] = testCiTarget + targetGroups[testCiTargetGroup]?.add("ci") } } fun getGradlewCommand(): String { - var gradlewCommand: String; - val operSys = System.getProperty("os.name").lowercase(); - if (operSys.contains("win")) { - gradlewCommand = ".\\gradlew.bat" + val gradlewCommand: String + val operatingSystem = System.getProperty("os.name").lowercase() + gradlewCommand = if (operatingSystem.contains("win")) { + ".\\gradlew.bat" } else { - gradlewCommand = "./gradlew" + "./gradlew" } return gradlewCommand } @@ -154,14 +148,14 @@ fun getInputsForTask( workspaceRoot: String, externalNodes: MutableMap? ): MutableList? { - try { - var mappedInputsIncludeExternal: MutableList = mutableListOf() - val inputs = task.getInputs() + return try { + val mappedInputsIncludeExternal: MutableList = mutableListOf() + val inputs = task.inputs val externalDependencies = mutableListOf() - inputs.getSourceFiles().filter { + inputs.sourceFiles.filter { it.exists() }.forEach { file -> - val path: String = file.getPath() + val path: String = file.path // replace the absolute path to contain {projectRoot} or {workspaceRoot} val pathWithReplacedRoot = replaceRootInPath(path, projectRoot, workspaceRoot) if (pathWithReplacedRoot != null) { // if the path is inside workspace @@ -171,46 +165,52 @@ fun getInputsForTask( if (pathWithReplacedRoot == null && path.endsWith(".jar") && externalNodes != null) { // add it to external dependencies try { val externalDep = getExternalDepFromInputFile(path, externalNodes) - externalDependencies.add(getExternalDepFromInputFile(path, externalNodes)) + externalDependencies.add(externalDep) } catch (e: Exception) { - task.logger.info("${task}: get external dependency error ${e.toString()}") + task.logger.info("${task}: get external dependency error $e") } } } if (externalDependencies.isNotEmpty()) { mappedInputsIncludeExternal.add(mutableMapOf("externalDependencies" to externalDependencies)) } - if (!mappedInputsIncludeExternal.isEmpty()) { + if (mappedInputsIncludeExternal.isNotEmpty()) { return mappedInputsIncludeExternal } + return null } catch (e: Exception) { - task.logger.info("${task}: get inputs error ${e.toString()}") + // Log the error but don't fail the build + task.logger.info("Error getting outputs for ${task.path}: ${e.message}") + task.logger.debug("Stack trace:", e) + null } - return null } /** * Get outputs for task * @param task task to process - * @return list of outpus file, will not include if output file is outside workspace, null if empty or an error ocurred + * @return list of outputs file, will not include if output file is outside workspace, null if empty or an error occurred */ fun getOutputsForTask( task: Task, projectRoot: String, workspaceRoot: String ): List? { - try { - val outputs = task.getOutputs().getFiles() - if (!outputs.isEmpty()) { + return try { + val outputs = task.outputs.files + if (!outputs.isEmpty) { return outputs.mapNotNull { file -> - val path: String = file.getPath() + val path: String = file.path replaceRootInPath(path, projectRoot, workspaceRoot) } } + null } catch (e: Exception) { - task.logger.info("${task}: get outputs error ${e.toString()}") + // Log the error but don't fail the build + task.logger.info("Error getting outputs for ${task.path}: ${e.message}") + task.logger.debug("Stack trace:", e) + null } - return null } /** @@ -220,34 +220,15 @@ fun getOutputsForTask( */ fun getDependsOnForTask(task: Task): List? { return try { - // Get the raw dependencies set without forcing evaluation - val rawDependencies = task.dependsOn - - // Filter and process only the resolved tasks - val resolvedDependencies = rawDependencies.mapNotNull { dep -> - when (dep) { - // Handle direct task references - is Task -> "${dep.project.name}:${dep.name}" - - // Handle task providers (lazy task references) - is TaskProvider<*> -> "${dep.get().project.name}:${dep.name}" - - // Handle string task paths - is String -> { - // For cross-project task dependencies - if (dep.contains(":")) dep - // For same-project task dependencies - else "${task.project.name}:$dep" - } - - // Ignore other dependency types - else -> null + val dependsOn = task.taskDependencies.getDependencies(null) + if (dependsOn.isNotEmpty()) { + val dependsOnTasksNames = dependsOn.map { depTask -> + val depProject = depTask.project + "${depProject.name}:${depTask.name}" } + return dependsOnTasksNames } - - // Return null if no dependencies found - resolvedDependencies.takeIf { it.isNotEmpty() } - + null } catch (e: Exception) { // Log the error but don't fail the build task.logger.info("Error getting dependencies for ${task.path}: ${e.message}") @@ -266,7 +247,7 @@ fun getMetadata(description: String?, projectBuildPath: String, taskName: String "description" to description, "technologies" to arrayOf("gradle"), "help" to mapOf( - "command" to "${gradlewCommand} help --task ${projectBuildPath}:${taskName}" + "command" to "$gradlewCommand help --task ${projectBuildPath}:${taskName}" ) ) } @@ -283,7 +264,7 @@ fun getMetadata(description: String?, projectBuildPath: String, taskName: String */ fun getExternalDepFromInputFile(inputFile: String, externalNodes: MutableMap): String { val segments: List = inputFile.split("/") - var nameKey = segments.last().replace(".jar", "") + val nameKey = segments.last().replace(".jar", "") val hash = segments[segments.size - 2] val version = segments[segments.size - 3] val packageName = segments[segments.size - 4] @@ -291,7 +272,7 @@ fun getExternalDepFromInputFile(inputFile: String, externalNodes: MutableMap