Skip to content

Commit

Permalink
feat(core): add gradle plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
xiongemi committed Jan 6, 2025
1 parent 21d5bd8 commit e69e282
Show file tree
Hide file tree
Showing 39 changed files with 1,222 additions and 607 deletions.
38 changes: 31 additions & 7 deletions e2e/gradle/src/utils/create-gradle-project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
isWindows,
runCommand,
tmpProjPath,
updateFile,
} from '@nx/e2e/utils';
import { execSync } from 'child_process';
import { createFileSync, writeFileSync } from 'fs-extra';
Expand All @@ -15,14 +16,10 @@ export function createGradleProject(
packageName: string = 'gradleProject',
addProjectJsonNamePrefix: string = ''
) {
e2eConsoleLogger(
`Using java version: ${execSync('java -version')} ${execSync(
'echo $JAVA_HOME'
)}`
);
e2eConsoleLogger(`Using java version: ${execSync('java -version')}`);
const gradleCommand = isWindows()
? resolve(`${__dirname}/../../gradlew.bat`)
: resolve(`${__dirname}/../../gradlew`);
? resolve(`${__dirname}/../../../../packages/gradle/native/gradlew.bat`)
: resolve(`${__dirname}/../../../../packages/gradle/native/gradlew`);
e2eConsoleLogger(
'Using gradle version: ' +
execSync(`${gradleCommand} --version`, {
Expand Down Expand Up @@ -60,4 +57,31 @@ export function createGradleProject(
`{"name": "${addProjectJsonNamePrefix}utilities"}`
);
}

addLocalPluginManagement(`settings.gradle${type === 'kotlin' ? '.kts' : ''}`);
addLocalPluginManagement(
`buildSrc/settings.gradle${type === 'kotlin' ? '.kts' : ''}`
);

e2eConsoleLogger(
execSync(`${gradleCommand} publishToMavenLocal`, {
cwd: `${__dirname}/../../../../packages/gradle/native`,
}).toString()
);
}

function addLocalPluginManagement(file: string) {
updateFile(
file,
(content) =>
`pluginManagement {
repositories {
mavenLocal()
gradlePluginPortal()
mavenCentral()
// Add other repositories if needed
}
}
` + content
);
}
File renamed without changes.
5 changes: 5 additions & 0 deletions packages/gradle/native/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Ignore Gradle project-specific cache directory
.gradle

# Ignore Gradle build output directory
build
6 changes: 6 additions & 0 deletions packages/gradle/native/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# This file was generated by the Gradle 'init' task.
# https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties

org.gradle.parallel=true
org.gradle.caching=true
version=0.0.1
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# This file was generated by the Gradle 'init' task.
# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format

[plugins]
jvm = { id = "org.jetbrains.kotlin.jvm", version = "1.9.20" }
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
validateDistributionUrl=false
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
6 changes: 4 additions & 2 deletions e2e/gradle/gradlew → packages/gradle/native/gradlew
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#

##############################################################################
#
Expand Down Expand Up @@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
Expand Down Expand Up @@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
Expand Down
22 changes: 12 additions & 10 deletions e2e/gradle/gradlew.bat → packages/gradle/native/gradlew.bat
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem

@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
Expand Down Expand Up @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2

goto fail

Expand All @@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto execute

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2

goto fail

Expand Down
33 changes: 33 additions & 0 deletions packages/gradle/native/plugin/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Gradle plugin project to get you started.
* For more details on writing Custom Plugins, please refer to https://docs.gradle.org/8.5/userguide/custom_plugins.html in the Gradle documentation.
* This project uses @Incubating APIs which are subject to change.
*/

plugins {
// Apply the Java Gradle plugin development plugin to add support for developing Gradle plugins
`java-gradle-plugin`
`maven-publish`

// Apply the Kotlin JVM plugin to add support for Kotlin.
alias(libs.plugins.jvm)
}

repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}

gradlePlugin {
// Define the plugin
val Nodes by plugins.creating {
id = "io.nx.gradle.plugin.Nodes"
implementationClass = "io.nx.gradle.plugin.Nodes"
}
}

dependencies {
implementation("com.google.code.gson:gson:2.11.0")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
package io.nx.gradle.plugin

import org.gradle.api.DefaultTask
import org.gradle.api.Project
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 com.google.gson.Gson
import com.google.gson.GsonBuilder
import java.lang.Error
import java.nio.file.Path

data class GradleTargets(val targets: MutableMap<String, Any>, val targetGroups: MutableMap<String, MutableList<String>>)
data class Metadata(val targetGroups: MutableMap<String, MutableList<String>>, val technologies: Array<String>, val description: String?)
data class ProjectConfiguration(val targets: MutableMap<String, Any>, val metadata: Metadata, val name: String)
data class Dependency(val source: String, val target: String, val sourceFile: String)
data class Node(val project: ProjectConfiguration, val dependencies: MutableSet<Dependency>)

abstract class CreateNodesTask : DefaultTask() {
@Option(option = "outputDirectory", description = "Output directory, default to {workspaceRoot}/.nx/cache")
@Input
var outputDirectory: String = ""

@Option(option = "workspaceRoot", description = "Workspace root, default to cwd")
@Input
var workspaceRoot: String = ""

@TaskAction
fun action() {
val rootProjectDirectory = project.getProjectDir()
if (workspaceRoot == "") {
// assign the workspace root to root project's path
workspaceRoot = System.getProperty("user.dir")
}
if (outputDirectory == "") {
outputDirectory = File(workspaceRoot, ".nx/cache").getPath()
}

val projectNodes = mutableMapOf<String, Node>()
project.getAllprojects().forEach { project ->
try {
// get dependencies of project
val dependencies = getDependenciesForProject(project)

val gradleTargets = this.processTargetsForProject(project, workspaceRoot, rootProjectDirectory)
var projectRoot = project.getProjectDir().getPath()
val projectConfig = ProjectConfiguration(
gradleTargets.targets,
Metadata(gradleTargets.targetGroups, arrayOf("Gradle"), project.getDescription()),
project.getName()
)
projectNodes.put(projectRoot, Node(projectConfig, dependencies))
} catch (e: Error) {
} // ignore errors
}
val gson = Gson()
val json = gson.toJson(projectNodes)
val file = File(outputDirectory, "${project.name}.json")
file.writeText(json)
println(file)
}

fun processTargetsForProject(
project: Project,
workspaceRoot: String,
rootProjectDirectory: File
): GradleTargets {
val targets = mutableMapOf<String, Any>();
val targetGroups = mutableMapOf<String, MutableList<String>>();
val projectRoot = project.getProjectDir().getPath()

var command: String;
val operSys = System.getProperty("os.name").lowercase();
if (operSys.contains("win")) {
command = ".\\gradlew.bat "
} else {
command = "./gradlew "
}
command += project.getBuildTreePath()
if (!command.endsWith(":")) {
command += ":"
}

project.getTasks().forEach { task ->
val target = mutableMapOf<String, Any?>()
val metadata = mutableMapOf<String, Any?>()
var taskCommand = command.toString()
metadata.put("description", task.getDescription())
metadata.put("technologies", arrayOf("Gradle"))
val group: String? = task.getGroup();
if (!group.isNullOrBlank()) {
if (targetGroups.contains(group)) {
targetGroups.get(group)?.add(task.name)
} else {
targetGroups.set(group, mutableListOf<String>(task.name))
}
}

var inputs = task.getInputs().getSourceFiles()
if (!inputs.isEmpty()) {
target.put("inputs", inputs.mapNotNull { file ->
val path: String = file.getPath()
replaceRootInPath(path, projectRoot, workspaceRoot)
})
}
val outputs = task.getOutputs().getFiles()
if (!outputs.isEmpty()) {
target.put("outputs", outputs.mapNotNull { file ->
val path: String = file.getPath()
replaceRootInPath(path, projectRoot, workspaceRoot)
})
}
target.put("cache", true)

val dependsOn = task.getTaskDependencies().getDependencies(task)
if (!dependsOn.isEmpty()) {
target.put("dependsOn", dependsOn.map { depTask ->
val depProject = depTask.getProject()
if (depProject == project) {
depTask.name
}
"${depProject.name}:${depTask.name}"
})
}
target.put("metadata", metadata)

taskCommand += task.name
target.put("command", taskCommand)
target.put("options", mapOf("cwd" to rootProjectDirectory.getPath()))

targets.put(task.name, target)
}

return GradleTargets(
targets,
targetGroups
);
}
}

fun replaceRootInPath(p: String, projectRoot: String, workspaceRoot: String): String? {
var path = p
if (path.startsWith(projectRoot)) {
path = path.replace(projectRoot, "{projectRoot}")
return path
} else if (path.startsWith(workspaceRoot)) {
path = path.replace(workspaceRoot, "{workspaceRoot}")
return path
}
return null
}

fun getDependenciesForProject(project: Project): MutableSet<Dependency> {
var dependencies = mutableSetOf<Dependency>();
project.getConfigurations().filter { config ->
val configName = config.name
configName == "compileClasspath" || configName == "implementationDependenciesMetadata"
}.forEach {
it.getAllDependencies().filter {
it is ProjectDependency
}.forEach {
dependencies.add(
Dependency(
project.getProjectDir().getPath(),
it.getName(),
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
}
Loading

0 comments on commit e69e282

Please sign in to comment.