From 099dba1a5a53edb0ef73da81a05359696f705775 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Thu, 30 Oct 2025 22:18:29 +0100 Subject: [PATCH] Fix Gradle 9 compatibility by using explicit Gradle 6.1.1 dependencies Gradle 9 embeds Groovy 4.0.28, while RewriteGradleProject.groovy is compiled against Gradle 6.1.1 (Groovy 3.x). The Groovy version mismatch prevented proper type attribution during parsing. **Solution:** 1. Replace `localGroovy()` with explicit `groovy-all:3.0.25` to maintain Groovy 3.x consistency 2. Replace `gradleApi()` with explicit Gradle 6.1.1 module dependencies to avoid pulling in Gradle 9's API 3. Add `gradle-tooling-api:6.1.1` for GradleConnector support without Gradle 9's full API 4. Change `rewrite-gradle-tooling-model/model` to use `compileOnly(gradleApi())` to prevent leaking Gradle 9 API --- .../model/build.gradle.kts | 4 ++- rewrite-gradle/build.gradle.kts | 34 ++++++++++++++++--- .../openrewrite/gradle/GradleParserTest.java | 26 ++++++++++++++ 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/rewrite-gradle-tooling-model/model/build.gradle.kts b/rewrite-gradle-tooling-model/model/build.gradle.kts index 49913559ef..4a104fb684 100644 --- a/rewrite-gradle-tooling-model/model/build.gradle.kts +++ b/rewrite-gradle-tooling-model/model/build.gradle.kts @@ -13,7 +13,9 @@ dependencies { // last version which supports java 8, which testGradle4 runs on testImplementation("org.assertj:assertj-core:3.27.4!!") } - implementation(gradleApi()) + // Use compileOnly instead of implementation to avoid leaking gradleApi() to consumers + // This prevents Gradle 9's API from polluting rewrite-gradle's test classpath + compileOnly(gradleApi()) // NOTE: this is latest.integration because we need to be able to release // rewrite-gradle-tooling-model BEFORE rewrite but also need to depend on diff --git a/rewrite-gradle/build.gradle.kts b/rewrite-gradle/build.gradle.kts index f1a359732e..c660fbeb7b 100644 --- a/rewrite-gradle/build.gradle.kts +++ b/rewrite-gradle/build.gradle.kts @@ -42,7 +42,29 @@ val latest = if (project.hasProperty("releasing")) { } else { "latest.integration" } + val pluginLocalTestClasspath = configurations.create("pluginLocalTestClasspath") + +// Helper function to add Gradle 6.1.1 API modules as a bundle +fun DependencyHandler.gradle611Api(configurationName: String) { + listOf( + "gradle-base-services", + "gradle-core-api", + "gradle-language-groovy", + "gradle-language-java", + "gradle-logging", + "gradle-messaging", + "gradle-native", + "gradle-process-services", + "gradle-resources", + "gradle-testing-base", + "gradle-testing-jvm", + "gradle-tooling-api" + ).forEach { module -> + add(configurationName, "org.gradle:$module:6.1.1") + } +} + dependencies { api(project(":rewrite-core")) api(project(":rewrite-groovy")) { @@ -56,7 +78,9 @@ dependencies { implementation(project(":rewrite-toml")) compileOnly("org.codehaus.groovy:groovy:latest.release") - compileOnly(gradleApi()) + // Use explicit Gradle 6.1.1 dependencies instead of gradleApi() to avoid compilation against Gradle 9 + // gradleApi() always resolves to the wrapper version (9.1.0), which removed classes like JavaPluginConvention + gradle611Api("compileOnly") // No particular reason to hold back upgrading this beyond 3.x, but it takes some effort: https://github.com/openrewrite/rewrite/issues/5270 compileOnly("com.gradle:develocity-gradle-plugin:3.+") @@ -69,10 +93,10 @@ dependencies { testImplementation(project(":rewrite-gradle-tooling-model:model")) "pluginLocalTestClasspath"(project(mapOf("path" to ":rewrite-gradle-tooling-model:model", "configuration" to "pluginLocalTestClasspath"))) testImplementation("com.squareup.okhttp3:mockwebserver:4.+") - testImplementation(localGroovy()) - - testRuntimeOnly("org.gradle:gradle-base-services:latest.release") - testRuntimeOnly(gradleApi()) + // Use explicit Groovy 3.x with all modules instead of localGroovy() which would bring in Gradle 9's Groovy 4.x + testImplementation("org.codehaus.groovy:groovy-all:3.0.25") + // Use Gradle 6.1.1 API bundle for test dependencies + gradle611Api("testImplementation") testRuntimeOnly("com.google.guava:guava:latest.release") testRuntimeOnly(project(":rewrite-java-21")) testRuntimeOnly("org.projectlombok:lombok:latest.release") diff --git a/rewrite-gradle/src/test/java/org/openrewrite/gradle/GradleParserTest.java b/rewrite-gradle/src/test/java/org/openrewrite/gradle/GradleParserTest.java index 828ac22994..5385e3dfc1 100644 --- a/rewrite-gradle/src/test/java/org/openrewrite/gradle/GradleParserTest.java +++ b/rewrite-gradle/src/test/java/org/openrewrite/gradle/GradleParserTest.java @@ -21,6 +21,8 @@ import org.openrewrite.Parser; import org.openrewrite.SourceFile; import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.TypeUtils; import org.openrewrite.test.RewriteTest; import org.openrewrite.tree.ParseError; @@ -29,6 +31,7 @@ import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.openrewrite.gradle.Assertions.*; class GradleParserTest implements RewriteTest { @@ -383,4 +386,27 @@ implementation platform("commons-lang:commons-lang3:3.0",) ) ); } + + @Issue("https://github.com/openrewrite/rewrite-testing-frameworks/pull/836") + @Test + void typeAttributionOnTasks() { + rewriteRun( + //language=groovy + buildGradle( + """ + plugins { + id 'java' + } + tasks.withType(Test) { + } + """, + spec -> spec.beforeRecipe(cu -> { + JavaType tasksType = ((J.MethodInvocation) cu.getStatements().getLast()).getSelect().getType(); + assertThat(TypeUtils.asFullyQualified(tasksType).getFullyQualifiedName()).isNotEqualTo("java.lang.Object"); + assertTrue(TypeUtils.isAssignableTo("org.gradle.api.tasks.TaskContainer", tasksType), tasksType.toString()); + }) + ) + ); + } + }