fix(gradle): add build-ci target even if atomized=false (#31537)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->
when atomized=false, it does not generate build-ci and check-ci targets

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
- when atomized=false, it should still generate build-ci and check-ci
targets
- upgrade dev.nx.gradle.project-graph version to 0.1.2

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
This commit is contained in:
Emily Xiong 2025-06-17 13:06:24 -04:00 committed by GitHub
parent b89ca32a01
commit 3aa546ffe3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 488 additions and 140 deletions

View File

@ -2076,6 +2076,16 @@
}
},
"migrations": {
"/technologies/java/api/migrations/change-plugin-version-0-1-2": {
"description": "Change dev.nx.gradle.project-graph to version 0.1.2 in build file",
"file": "generated/packages/gradle/migrations/change-plugin-version-0-1-2.json",
"hidden": false,
"name": "change-plugin-version-0-1-2",
"version": "21.3.0-beta.0",
"originalFilePath": "/packages/gradle",
"path": "/technologies/java/api/migrations/change-plugin-version-0-1-2",
"type": "migration"
},
"/technologies/java/api/migrations/change-plugin-version-0-1-0": {
"description": "Change dev.nx.gradle.project-graph to version 0.1.0 in build file",
"file": "generated/packages/gradle/migrations/change-plugin-version-0-1-0.json",

View File

@ -2249,6 +2249,16 @@
}
],
"migrations": [
{
"description": "Change dev.nx.gradle.project-graph to version 0.1.2 in build file",
"file": "generated/packages/gradle/migrations/change-plugin-version-0-1-2.json",
"hidden": false,
"name": "change-plugin-version-0-1-2",
"version": "21.3.0-beta.0",
"originalFilePath": "/packages/gradle",
"path": "gradle/migrations/change-plugin-version-0-1-2",
"type": "migration"
},
{
"description": "Change dev.nx.gradle.project-graph to version 0.1.0 in build file",
"file": "generated/packages/gradle/migrations/change-plugin-version-0-1-0.json",

View File

@ -0,0 +1,14 @@
{
"name": "change-plugin-version-0-1-2",
"version": "21.3.0-beta.0",
"cli": "nx",
"description": "Change dev.nx.gradle.project-graph to version 0.1.2 in build file",
"factory": "./src/migrations/21-3-0/change-plugin-version-0-1-2",
"implementation": "/packages/gradle/src/migrations/21-3-0/change-plugin-version-0-1-2.ts",
"aliases": [],
"hidden": false,
"path": "/packages/gradle",
"schema": null,
"type": "migration",
"examplesFile": "#### Change dev.nx.gradle.project-graph to version 0.1.2\n\nChange dev.nx.gradle.project-graph to version 0.1.2 in build file\n\n#### Sample Code Changes\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```{% fileName=\"build.gradle\" %}\nplugins {\n\tid \"dev.nx.gradle.project-graph\" version \"0.1.0\"\n}\n```\n\n{% /tab %}\n{% tab label=\"After\" %}\n\n```{% fileName=\"build.gradle\" %}\nplugins {\n id \"dev.nx.gradle.project-graph\" version \"0.1.2\"\n}\n```\n\n{% /tab %}\n{% /tabs %}\n"
}

View File

@ -35,6 +35,12 @@
"cli": "nx",
"description": "Change dev.nx.gradle.project-graph to version 0.1.0 in build file",
"factory": "./src/migrations/21-1-2/change-plugin-version-0-1-0"
},
"change-plugin-version-0-1-2": {
"version": "21.3.0-beta.0",
"cli": "nx",
"description": "Change dev.nx.gradle.project-graph to version 0.1.2 in build file",
"factory": "./src/migrations/21-3-0/change-plugin-version-0-1-2"
}
},
"packageJsonUpdates": {}

View File

@ -10,7 +10,7 @@ plugins {
group = "dev.nx.gradle"
version = "0.0.1-alpha.6"
version = "0.1.2"
repositories { mavenCentral() }

View File

@ -12,10 +12,13 @@ private val testFileNameRegex =
Regex("^(?!(abstract|fake)).*?(Test)(s)?\\d*", RegexOption.IGNORE_CASE)
private val packageDeclarationRegex =
Regex("""package\s+([a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*)""")
Regex(
"""^\s*package\s+([a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*)""",
RegexOption.MULTILINE)
private val classDeclarationRegex =
Regex("""^\s*(?:@[\w]+)?\s*(class|object)\s+([A-Za-z_][A-Za-z0-9_]*)""")
private val privateClassRegex = Regex("""\bprivate\s+(class|object)\s+([A-Za-z_][A-Za-z0-9_]*)""")
Regex(
"""^\s*(?:@[\w]+\s*)*(?:public|protected|internal|open|sealed|final|data|enum|annotation)?\s*(class)\s+([A-Za-z_][A-Za-z0-9_]*)""")
private val privateClassRegex = Regex("""\bprivate\s+class\s+([A-Za-z_][A-Za-z0-9_]*)""")
// Essential annotations (most common subset)
private val essentialTestAnnotations =

View File

@ -84,8 +84,8 @@ fun processTargetsForProject(
val testTasks = project.getTasksByName("test", false)
val intTestTasks = project.getTasksByName("intTest", false)
val hasCiTestTarget = ciTestTargetName != null && testTasks.isNotEmpty()
val hasCiIntTestTarget = ciIntTestTargetName != null && intTestTasks.isNotEmpty()
val hasCiTestTarget = ciTestTargetName != null && testTasks.isNotEmpty() && atomized
val hasCiIntTestTarget = ciIntTestTargetName != null && intTestTasks.isNotEmpty() && atomized
project.tasks.forEach { task ->
try {
@ -111,7 +111,7 @@ fun processTargetsForProject(
targets[taskName] = target
if (hasCiTestTarget && task.name.startsWith("compileTest") && atomized) {
if (hasCiTestTarget && task.name.startsWith("compileTest")) {
addTestCiTargets(
task.inputs.sourceFiles,
projectBuildPath,
@ -124,7 +124,7 @@ fun processTargetsForProject(
ciTestTargetName!!)
}
if (hasCiIntTestTarget && task.name.startsWith("compileIntTest") && atomized) {
if (hasCiIntTestTarget && task.name.startsWith("compileIntTest")) {
addTestCiTargets(
task.inputs.sourceFiles,
projectBuildPath,
@ -137,23 +137,22 @@ fun processTargetsForProject(
ciIntTestTargetName!!)
}
if (ciTestTargetName != null || ciIntTestTargetName != null) {
val ciCheckTargetName = targetNameOverrides.getOrDefault("ciCheckTargetName", "check-ci")
if (task.name == "check") {
val replacedDependencies =
(target["dependsOn"] as? List<*>)?.map { dep ->
val dependsOn = dep.toString()
if (hasCiTestTarget && dependsOn == "${project.name}:$testTargetName" && atomized) {
if (hasCiTestTarget && dependsOn == "${project.name}:$testTargetName") {
"${project.name}:$ciTestTargetName"
} else if (hasCiIntTestTarget &&
dependsOn == "${project.name}:$intTestTargetName" &&
atomized) {
dependsOn == "${project.name}:$intTestTargetName") {
"${project.name}:$ciIntTestTargetName"
} else {
dep
}
} ?: emptyList()
if (atomized) {
val newTarget: MutableMap<String, Any?> =
mutableMapOf(
"dependsOn" to replacedDependencies,
@ -165,21 +164,19 @@ fun processTargetsForProject(
ensureTargetGroupExists(targetGroups, testCiTargetGroup)
targetGroups[testCiTargetGroup]?.add(ciCheckTargetName)
}
}
if (task.name == "build") {
val ciBuildTargetName = targetNameOverrides.getOrDefault("ciBuildTargetName", "build-ci")
val replacedDependencies =
(target["dependsOn"] as? List<*>)?.map { dep ->
val dependsOn = dep.toString()
if (dependsOn == "${project.name}:check" && atomized) {
if (dependsOn == "${project.name}:check") {
"${project.name}:$ciCheckTargetName"
} else {
dep
}
} ?: emptyList()
if (atomized) {
val newTarget: MutableMap<String, Any?> =
mutableMapOf(
"dependsOn" to replacedDependencies,
@ -199,5 +196,6 @@ fun processTargetsForProject(
}
}
logger.info("Final targets in processTargetsForProject: $targets")
return GradleTargets(targets, targetGroups, externalNodes)
}

View File

@ -9,6 +9,10 @@ class ClassDetectionTest {
fun `detects top-level and annotated nested classes only`() {
val kotlinSource =
"""
import some.package
package real.package
class ClassA {
@Nested
class ClassB
@ -18,6 +22,10 @@ class ClassDetectionTest {
private class ClassD
}
internal class ClassU
public abstract class ClassV
@Nested
class ClassX // not nested — should be ignored
@ -36,7 +44,11 @@ class ClassDetectionTest {
val result = getAllVisibleClassesWithNestedAnnotation(tempFile)
// Expected output
val expected = mapOf("ClassAClassB" to "ClassA\$ClassB", "ClassZ" to "ClassZ")
val expected =
mapOf(
"ClassAClassB" to "real.package.ClassA\$ClassB",
"ClassU" to "real.package.ClassU",
"ClassZ" to "real.package.ClassZ")
assertEquals(expected, result)
}

View File

@ -1,6 +1,5 @@
package dev.nx.gradle.utils
import dev.nx.gradle.data.*
import java.io.File
import kotlin.test.*
import org.gradle.testfixtures.ProjectBuilder
@ -11,7 +10,7 @@ class CreateNodeForProjectTest {
fun `should return GradleNodeReport with targets and metadata`() {
// Arrange
val workspaceRoot = createTempDir("workspace").absolutePath
val projectDir = createTempDir("project")
val projectDir = File(workspaceRoot, "project-a").apply { mkdirs() }
val project = ProjectBuilder.builder().withProjectDir(projectDir).build()
// Create a couple of dummy tasks
@ -51,104 +50,4 @@ class CreateNodeForProjectTest {
assertTrue(result.dependencies.isEmpty(), "Expected no dependencies")
assertTrue(result.externalNodes.isEmpty(), "Expected no external nodes")
}
@Test
fun `should not generate atomized targets when atomized is false`() {
// Arrange
val workspaceRoot = createTempDir("workspace").absolutePath
val projectDir = createTempDir("project")
val project = ProjectBuilder.builder().withProjectDir(projectDir).build()
// Create tasks that would normally trigger atomized targets
val testFile1 =
File(projectDir, "src/test/kotlin/MyFirstTest.kt").apply {
parentFile.mkdirs()
writeText("@Test class MyFirstTest")
}
val testTask =
project.task("test").apply {
group = "verification"
description = "Runs the tests"
inputs.files(project.files(testFile1))
}
project
.task("compileTestKotlin")
.dependsOn(testTask) // This task name triggers ci test target logic
val checkTask =
project.task("check").apply {
group = "verification"
description = "Runs all checks"
dependsOn(testTask)
}
project.task("build").apply {
group = "build"
description = "Assembles and tests"
dependsOn(checkTask)
}
val targetNameOverrides =
mapOf(
"ciTestTargetName" to "ci-test",
"ciCheckTargetName" to "ci-check",
"ciBuildTargetName" to "ci-build")
// Act
val result =
createNodeForProject(
project = project,
targetNameOverrides = targetNameOverrides,
workspaceRoot = workspaceRoot,
atomized = false) // Test with atomized = false
// Assert
val projectRoot = project.projectDir.absolutePath
val projectNode = result.nodes[projectRoot]
assertNotNull(projectNode, "ProjectNode should not be null")
// Verify that individual atomized targets are NOT created
assertFalse(
projectNode.targets.containsKey("ci--MyFirstTest"),
"Expected ci--MyFirstTest target NOT to be present")
// Verify 'test' and 'check' targets are present but not their 'ci' counterparts if atomized is
// false
assertNotNull(projectNode.targets["test"], "Expected 'test' target to be present")
assertNotNull(projectNode.targets["check"], "Expected 'check' target to be present")
assertNotNull(projectNode.targets["build"], "Expected 'build' target to be present")
// Verify that 'ci-test', 'ci-check', 'ci-build' are not created as main targets if atomized is
// false
assertFalse(
projectNode.targets.containsKey("ci-test"),
"Expected ci-test target NOT to be present as a main target")
assertFalse(
projectNode.targets.containsKey("ci-check"),
"Expected ci-check target NOT to be present as a main target")
assertFalse(
projectNode.targets.containsKey("ci-build"),
"Expected ci-build target NOT to be present as a main target")
// Verify dependencies are NOT rewritten for 'check' and 'build' tasks
val checkTarget = projectNode.targets["check"]
assertNotNull(checkTarget, "Check target should exist")
val checkDependsOn = checkTarget["dependsOn"] as? List<*>
assertNotNull(checkDependsOn, "Check dependsOn should not be null")
assertTrue(
checkDependsOn.contains("${project.name}:test"), "Expected 'check' to depend on 'test'")
assertFalse(
checkDependsOn.contains("${project.name}:ci-test"),
"Expected 'check' NOT to depend on 'ci-test'")
val buildTarget = projectNode.targets["build"]
assertNotNull(buildTarget, "Build target should exist")
val buildDependsOn = buildTarget["dependsOn"] as? List<*>
assertNotNull(buildDependsOn, "Build dependsOn should not be null")
assertTrue(
buildDependsOn.contains("${project.name}:check"), "Expected 'build' to depend on 'check'")
assertFalse(
buildDependsOn.contains("${project.name}:ci-check"),
"Expected 'build' NOT to depend on 'ci-check'")
}
}

View File

@ -0,0 +1,226 @@
package dev.nx.gradle.utils
import dev.nx.gradle.data.*
import java.io.File
import kotlin.test.*
import org.gradle.testfixtures.ProjectBuilder
class ProcessTargetsForProjectTest {
@Test
fun `should process targets correctly when atomized is true`() {
// Arrange
val workspaceRoot = createTempDir("workspace").absolutePath
val projectDir = File(workspaceRoot, "project-a").apply { mkdirs() }
val project = ProjectBuilder.builder().withProjectDir(projectDir).build()
// Create tasks that would normally trigger atomized targets
val testFile1 =
File(projectDir, "src/test/kotlin/MyFirstTest.kt").apply {
parentFile.mkdirs()
writeText("@Test class MyFirstTest")
}
val testTask =
project.task("test").apply {
group = "verification"
description = "Runs the tests"
inputs.files(project.files(testFile1))
}
project.task("compileTestKotlin").apply { inputs.files(project.files(testFile1)) }
val checkTask =
project.task("check").apply {
group = "verification"
description = "Runs all checks"
dependsOn(testTask)
}
project.task("build").apply {
group = "build"
description = "Assembles and tests"
dependsOn(checkTask)
}
val targetNameOverrides =
mapOf(
"ciTestTargetName" to "ci-test",
"ciCheckTargetName" to "ci-check",
"ciBuildTargetName" to "ci-build")
val dependencies = mutableSetOf<Dependency>() // Empty for this test's scope
// Act
val gradleTargets =
processTargetsForProject(
project = project,
dependencies = dependencies,
targetNameOverrides = targetNameOverrides,
workspaceRoot = workspaceRoot,
atomized = true)
// Assert
// Verify 'ci-test' should not be presented
// But 'ci-check' and 'ci-build' targets should be present in the returned targets
assertNull(
gradleTargets.targets["ci-test"],
"Expected ci-test target to NOT be present in processed targets")
assertNotNull(
gradleTargets.targets["ci-check"],
"Expected ci-check target to be present in processed targets")
assertNotNull(
gradleTargets.targets["ci-build"],
"Expected ci-build target to be present in processed targets")
// Verify dependencies are rewritten for 'check' and 'build' tasks in the returned targets
val checkTarget = gradleTargets.targets["check"]
assertNotNull(checkTarget, "Check target should exist in processed targets")
val checkDependsOn = checkTarget["dependsOn"] as? List<*>
assertNotNull(checkDependsOn, "Check dependsOn should not be null in processed targets")
assertTrue(
checkDependsOn.contains("${project.name}:test"),
"Expected 'check' to depend on 'test' in processed targets")
val checkCiTarget = gradleTargets.targets["ci-check"]
assertNotNull(checkCiTarget, "Check CI target should exist in processed targets")
val checkCiDependsOn = checkCiTarget["dependsOn"] as? List<*>
assertNotNull(checkCiDependsOn, "Check CI dependsOn should not be null in processed targets")
assertTrue(
checkCiDependsOn.contains("${project.name}:ci-test"),
"Expected 'ci-check' to depend on 'ci-test' in processed targets")
val buildTarget = gradleTargets.targets["build"]
assertNotNull(buildTarget, "Build target should exist in processed targets")
val buildDependsOn = buildTarget["dependsOn"] as? List<*>
assertNotNull(buildDependsOn, "Build dependsOn should not be null in processed targets")
assertTrue(
buildDependsOn.contains("${project.name}:check"),
"Expected 'build' to depend on 'check' in processed targets")
val buildCiTarget = gradleTargets.targets["ci-build"]
assertNotNull(buildCiTarget, "Build CI target should exist in processed targets")
val buildCiDependsOn = buildCiTarget["dependsOn"] as? List<*>
assertNotNull(buildCiDependsOn, "Build CI dependsOn should not be null in processed targets")
assertTrue(
buildCiDependsOn.contains("${project.name}:ci-check"),
"Expected 'ci-build' to depend on 'ci-check' in processed targets")
}
@Test
fun `should process targets correctly when atomized is false`() {
// Arrange
val workspaceRoot = createTempDir("workspace").absolutePath
val projectDir = File(workspaceRoot, "project-a").apply { mkdirs() }
val project = ProjectBuilder.builder().withProjectDir(projectDir).build()
// Create tasks that would normally trigger atomized targets
val testFile1 =
File(projectDir, "src/test/kotlin/MyFirstTest.kt").apply {
parentFile.mkdirs()
writeText("@Test class MyFirstTest")
}
val testTask =
project.task("test").apply {
group = "verification"
description = "Runs the tests"
inputs.files(project.files(testFile1))
}
project
.task("compileTestKotlin")
.dependsOn(testTask) // This task name triggers ci test target logic
val checkTask =
project.task("check").apply {
group = "verification"
description = "Runs all checks"
dependsOn(testTask)
}
project.task("build").apply {
group = "build"
description = "Assembles and tests"
dependsOn(checkTask)
}
val targetNameOverrides =
mapOf(
"ciTestTargetName" to "ci-test",
"ciCheckTargetName" to "ci-check",
"ciBuildTargetName" to "ci-build")
val dependencies = mutableSetOf<Dependency>() // Empty for this test's scope
// Act
val gradleTargets =
processTargetsForProject(
project = project,
dependencies = dependencies,
targetNameOverrides = targetNameOverrides,
workspaceRoot = workspaceRoot,
atomized = false) // Test with atomized = false
// Assert
// Verify that individual atomized targets are NOT created
assertFalse(
gradleTargets.targets.containsKey("ci--MyFirstTest"),
"Expected ci--MyFirstTest target NOT to be present in processed targets")
// Verify 'test' and 'check' targets are present but not their 'ci' counterparts if atomized is
// false
assertNotNull(gradleTargets.targets["test"], "Expected 'test' target to be present")
assertNotNull(gradleTargets.targets["check"], "Expected 'check' target to be present")
assertNotNull(gradleTargets.targets["build"], "Expected 'build' target to be present")
// Verify that 'ci-test' is not created as main targets if atomized is false
// 'ci-check' and 'ci-build should still be presented if ciTestTargetName is presented
// regardless of atomized value
assertFalse(
gradleTargets.targets.containsKey("ci-test"),
"Expected ci-test target NOT to be present as a main target")
assertTrue(
gradleTargets.targets.containsKey("ci-check"),
"Expected ci-check target to be present as a main target")
assertTrue(
gradleTargets.targets.containsKey("ci-build"),
"Expected ci-build target to be present as a main target")
// Verify dependencies are NOT rewritten for 'check' and 'build' tasks
val checkTarget = gradleTargets.targets["check"]
assertNotNull(checkTarget, "Check target should exist")
val checkDependsOn = checkTarget["dependsOn"] as? List<*>
assertNotNull(checkDependsOn, "Check dependsOn should not be null")
assertTrue(
checkDependsOn.contains("${project.name}:test"), "Expected 'check' to depend on 'test'")
assertFalse(
checkDependsOn.contains("${project.name}:ci-test"),
"Expected 'check' NOT to depend on 'ci-test'")
val checkCiTarget = gradleTargets.targets["ci-check"]
assertNotNull(checkCiTarget, "Check CI target should exist in processed targets")
val checkCiDependsOn = checkCiTarget["dependsOn"] as? List<*>
assertNotNull(checkCiDependsOn, "Check CI dependsOn should not be null in processed targets")
assertFalse(
checkCiDependsOn.contains("${project.name}:ci-test"),
"Expected 'ci-check' to NOT depend on 'ci-test' in processed targets")
assertTrue(
checkCiDependsOn.contains("${project.name}:test"),
"Expected 'ci-check' to depend on 'test' in processed targets")
val buildTarget = gradleTargets.targets["build"]
assertNotNull(buildTarget, "Build target should exist")
val buildDependsOn = buildTarget["dependsOn"] as? List<*>
assertNotNull(buildDependsOn, "Build dependsOn should not be null")
assertTrue(
buildDependsOn.contains("${project.name}:check"), "Expected 'build' to depend on 'check'")
assertFalse(
buildDependsOn.contains("${project.name}:ci-check"),
"Expected 'build' NOT to depend on 'ci-check'")
val buildCiTarget = gradleTargets.targets["ci-build"]
assertNotNull(buildCiTarget, "Build CI target should exist in processed targets")
val buildCiDependsOn = buildCiTarget["dependsOn"] as? List<*>
assertNotNull(buildCiDependsOn, "Build CI dependsOn should not be null in processed targets")
assertTrue(
buildCiDependsOn.contains("${project.name}:ci-check"),
"Expected 'ci-build' to depend on 'ci-check' in processed targets")
}
}

View File

@ -0,0 +1,26 @@
#### Change dev.nx.gradle.project-graph to version 0.1.2
Change dev.nx.gradle.project-graph to version 0.1.2 in build file
#### Sample Code Changes
{% tabs %}
{% tab label="Before" %}
```{% fileName="build.gradle" %}
plugins {
id "dev.nx.gradle.project-graph" version "0.1.0"
}
```
{% /tab %}
{% tab label="After" %}
```{% fileName="build.gradle" %}
plugins {
id "dev.nx.gradle.project-graph" version "0.1.2"
}
```
{% /tab %}
{% /tabs %}

View File

@ -0,0 +1,128 @@
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';
import { Tree } from '@nx/devkit';
import { FsTree } from 'nx/src/generators/tree';
import update from './change-plugin-version-0-1-2';
import { gradleProjectGraphPluginName } from '../../utils/versions';
describe('change-plugin-version-0-1-2 migration', () => {
let tempFs: TempFs;
let cwd: string;
let tree: Tree;
beforeEach(async () => {
tempFs = new TempFs('test');
cwd = process.cwd();
process.chdir(tempFs.tempDir);
tree = new FsTree(tempFs.tempDir, false);
});
afterEach(() => {
jest.resetModules();
process.chdir(cwd);
});
it('should update plugin version to 0.1.2 in Groovy DSL', async () => {
await tempFs.createFiles({
'nx.json': JSON.stringify({
plugins: ['@nx/gradle'],
}),
'proj/settings.gradle': '',
'proj/build.gradle': `plugins {
id 'java'
id "${gradleProjectGraphPluginName}" version "0.0.1"
}`,
});
await update(tree);
const content = tree.read('proj/build.gradle', 'utf-8');
expect(content).toContain(
`id "${gradleProjectGraphPluginName}" version "0.1.2"`
);
expect(content).not.toContain('version "0.0.1"');
});
it('should update plugin version to 0.1.2 in Kotlin DSL', async () => {
await tempFs.createFiles({
'nx.json': JSON.stringify({
plugins: ['@nx/gradle'],
}),
'proj/settings.gradle.kts': '',
'proj/build.gradle.kts': `plugins {
id("java")
id("${gradleProjectGraphPluginName}") version("0.0.1")
}`,
});
await update(tree);
const content = tree.read('proj/build.gradle.kts', 'utf-8');
expect(content).toContain(
`id("${gradleProjectGraphPluginName}") version("0.1.2")`
);
expect(content).not.toContain('version("0.0.1")');
});
it('should not update if nx.json is missing', async () => {
await tempFs.createFiles({
'proj/settings.gradle': '',
'proj/build.gradle': `plugins {
id 'java'
id "${gradleProjectGraphPluginName}" version "0.0.1"
}`,
});
await update(tree);
const content = tree.read('proj/build.gradle', 'utf-8');
expect(content).toContain('version "0.0.1"');
expect(content).not.toContain('version "0.1.2"');
});
it('should not update if Gradle plugin is not present', async () => {
await tempFs.createFiles({
'nx.json': JSON.stringify({}),
'proj/settings.gradle': '',
'proj/build.gradle': `plugins {
id 'java'
}`,
});
await update(tree);
const content = tree.read('proj/build.gradle', 'utf-8');
expect(content).not.toContain(gradleProjectGraphPluginName);
});
it('should handle multiple build.gradle files', async () => {
await tempFs.createFiles({
'nx.json': JSON.stringify({
plugins: ['@nx/gradle'],
}),
'proj1/settings.gradle': '',
'proj1/build.gradle': `plugins {
id 'java'
id "${gradleProjectGraphPluginName}" version "0.0.1"
}`,
'proj2/settings.gradle': '',
'proj2/build.gradle': `plugins {
id 'java'
id "${gradleProjectGraphPluginName}" version "0.0.1"
}`,
});
await update(tree);
const proj1Content = tree.read('proj1/build.gradle', 'utf-8');
const proj2Content = tree.read('proj2/build.gradle', 'utf-8');
expect(proj1Content).toContain(
`id "${gradleProjectGraphPluginName}" version "0.1.2"`
);
expect(proj2Content).toContain(
`id "${gradleProjectGraphPluginName}" version "0.1.2"`
);
expect(proj1Content).not.toContain('version "0.0.1"');
expect(proj2Content).not.toContain('version "0.0.1"');
});
});

View File

@ -0,0 +1,16 @@
import { Tree, readNxJson } from '@nx/devkit';
import { hasGradlePlugin } from '../../utils/has-gradle-plugin';
import { addNxProjectGraphPlugin } from '../../generators/init/gradle-project-graph-plugin-utils';
/* Change the plugin version to 0.1.2
*/
export default async function update(tree: Tree) {
const nxJson = readNxJson(tree);
if (!nxJson) {
return;
}
if (!hasGradlePlugin(tree)) {
return;
}
await addNxProjectGraphPlugin(tree, '0.1.2');
}