diff --git a/.kotlin/sessions/kotlin-compiler-14569499311435360095.salive b/.kotlin/sessions/kotlin-compiler-14569499311435360095.salive new file mode 100644 index 0000000000..e69de29bb2 diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/AndroidPluginIntegration.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/AndroidPluginIntegration.kt index 8c7a006c53..9647ce6eaa 100644 --- a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/AndroidPluginIntegration.kt +++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/AndroidPluginIntegration.kt @@ -53,7 +53,7 @@ object AndroidPluginIntegration { private fun decorateAndroidExtension(project: Project, onSourceSet: (String) -> Unit) { val sourceSets = when (val androidExt = project.extensions.getByName("android")) { is BaseExtension -> androidExt.sourceSets - is CommonExtension<*, *, *, *> -> androidExt.sourceSets + is CommonExtension<*, *, *, *, *, *> -> androidExt.sourceSets else -> throw RuntimeException("Unsupported Android Gradle plugin version.") } sourceSets.all { diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspConfigurations.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspConfigurations.kt index 2d437af511..9deeb82d3e 100644 --- a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspConfigurations.kt +++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspConfigurations.kt @@ -35,11 +35,13 @@ class KspConfigurations(private val project: Project) { }.replaceFirstChar { it.lowercase() } } + /** + * Returns a new or existing [Configuration] with the given [name], with applied properties. + */ private fun createConfiguration( name: String, readableSetName: String, ): Configuration { - // maybeCreate to be future-proof, but we should never have a duplicate with current logic return project.configurations.maybeCreate(name).apply { description = "KSP dependencies for the '$readableSetName' source set." isCanBeResolved = false // we'll resolve the processor classpath config @@ -48,14 +50,19 @@ class KspConfigurations(private val project: Project) { } } - private fun getAndroidConfigurationName(target: KotlinTarget, sourceSet: String): String { + /** + * Returns the Android sourceSet-specific KSP configuration name given a [kotlinTarget] and [sourceSet]. + * + * For single-platform, [kotlinTarget] can be null. + */ + private fun getAndroidConfigurationName(kotlinTarget: KotlinTarget?, sourceSet: String): String { val isMain = sourceSet.endsWith("main", ignoreCase = true) val nameWithoutMain = when { isMain -> sourceSet.substring(0, sourceSet.length - 4) else -> sourceSet } // Note: on single-platform, target name is conveniently set to "". - return configurationNameOf(PREFIX, target.name, nameWithoutMain) + return configurationNameOf(PREFIX, kotlinTarget?.name ?: "", nameWithoutMain) } private fun getKotlinConfigurationName(compilation: KotlinCompilation<*>, sourceSet: KotlinSourceSet): String { @@ -86,6 +93,13 @@ class KspConfigurations(private val project: Project) { // 1.6.0: decorateKotlinProject(project.kotlinExtension)? decorateKotlinProject(project.extensions.getByName("kotlin") as KotlinProjectExtension, project) } + // Create sourceSet-specific KSP configurations for the case when the KotlinBaseApiPlugin is applied instead + // of the KotlinBasePluginWrapper (e.g., when AGP's built-in Kotlin support is enabled). + project.plugins.withType(KotlinBaseApiPlugin::class.java) { + // FIXME: After KT-70897 is fixed and AGP's built-in Kotlin support adds a `kotlin` extension, call + // decorateKotlinProject here instead. + createAndroidSourceSetConfigurations(project, kotlinTarget = null) + } } private fun decorateKotlinProject(kotlin: KotlinProjectExtension, project: Project) { @@ -125,12 +139,7 @@ class KspConfigurations(private val project: Project) { */ private fun decorateKotlinTarget(target: KotlinTarget) { if (target.platformType == KotlinPlatformType.androidJvm) { - AndroidPluginIntegration.forEachAndroidSourceSet(target.project) { sourceSet -> - createConfiguration( - name = getAndroidConfigurationName(target, sourceSet), - readableSetName = "$sourceSet (Android)" - ) - } + createAndroidSourceSetConfigurations(target.project, target) } else { target.compilations.configureEach { compilation -> compilation.kotlinSourceSetsObservable.forAll { sourceSet -> @@ -177,4 +186,18 @@ class KspConfigurations(private val project: Project) { compilation.target.project.configurations.findByName(it) }.toSet() } + + /** + * Creates the Android sourceSet-specific KSP configurations for the given [project] and [kotlinTarget] + * + * For single-platform, [kotlinTarget] can be null. + */ + private fun createAndroidSourceSetConfigurations(project: Project, kotlinTarget: KotlinTarget?) { + AndroidPluginIntegration.forEachAndroidSourceSet(project) { sourceSet -> + createConfiguration( + name = getAndroidConfigurationName(kotlinTarget, sourceSet), + readableSetName = "$sourceSet (Android)" + ) + } + } } diff --git a/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/GradleCompilationTest.kt b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/GradleCompilationTest.kt index acb7f411ce..63d63b9e0b 100644 --- a/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/GradleCompilationTest.kt +++ b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/GradleCompilationTest.kt @@ -399,4 +399,19 @@ class GradleCompilationTest { testRule.runner().withArguments().build() } + + /** + * Regression test for b/362279380 + */ + @Test + fun androidGradlePluginBuiltInKotlin() { + testRule.setupAppAsAndroidApp(enableAgpBuiltInKotlinSupport = true) + testRule.appModule.dependencies.addAll( + listOf( + artifact(configuration = "ksp", "androidx.room:room-compiler:2.4.2"), + artifact(configuration = "kspTest", "androidx.room:room-compiler:2.4.2") + ) + ) + testRule.runner().withArguments(":app:assembleDebug").build() + } } diff --git a/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/KspIntegrationTestRule.kt b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/KspIntegrationTestRule.kt index 2407eade0d..f4fff4c835 100644 --- a/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/KspIntegrationTestRule.kt +++ b/gradle-plugin/src/test/kotlin/com/google/devtools/ksp/gradle/testing/KspIntegrationTestRule.kt @@ -92,16 +92,23 @@ class KspIntegrationTestRule( /** * Sets up the app module as an android app, adding necessary plugin dependencies, a manifest - * file and necessary gradle configuration. + * file and necessary gradle configuration. If [enableAgpBuiltInKotlinSupport] is true, enable AGP's built-in Kotlin + * support instead of applying the Kotlin Android Gradle plugin. */ - fun setupAppAsAndroidApp() { + fun setupAppAsAndroidApp(enableAgpBuiltInKotlinSupport: Boolean = false) { testProject.appModule.plugins.addAll( listOf( PluginDeclaration.id("com.android.application", testConfig.androidBaseVersion), - PluginDeclaration.kotlin("android", testConfig.kotlinBaseVersion), PluginDeclaration.id("com.google.devtools.ksp", testConfig.kspVersion) ) ) + if (enableAgpBuiltInKotlinSupport) { + testProject.appModule + .plugins + .add(PluginDeclaration.id("com.android.experimental.built-in-kotlin", testConfig.androidBaseVersion)) + } else { + testProject.appModule.plugins.add(PluginDeclaration.kotlin("android", testConfig.kotlinBaseVersion)) + } addAndroidBoilerplate() } @@ -126,11 +133,15 @@ class KspIntegrationTestRule( """ android { namespace = "com.example.kspandroidtestapp" - compileSdkVersion(31) + compileSdk = 31 defaultConfig { - minSdkVersion(24) + minSdk = 24 } } + + dependencies { + implementation("org.jetbrains.kotlin:kotlin-stdlib:${testConfig.kotlinBaseVersion}") + } """.trimIndent() ) testProject.appModule.moduleRoot.resolve("src/main/AndroidManifest.xml") diff --git a/gradle.properties b/gradle.properties index d9c787f097..5708037571 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Duser.country=US -Dkotlin.daemon.jvm.options=-Xmx4096m -Dfile.encoding=UTF-8 kotlinBaseVersion=2.1.0-dev-5441 -agpBaseVersion=8.0.2 +agpBaseVersion=8.7.0 intellijVersion=233.13135.103 junitVersion=4.13.1 junit5Version=5.8.2 diff --git a/integration-tests/build.gradle.kts b/integration-tests/build.gradle.kts index 9160be47b6..3d238281d0 100644 --- a/integration-tests/build.gradle.kts +++ b/integration-tests/build.gradle.kts @@ -20,8 +20,7 @@ dependencies { testImplementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3") } -tasks.withType { - maxParallelForks = max(1, Runtime.getRuntime().availableProcessors() / 2) +fun Test.configureCommonSettings() { systemProperty("kotlinVersion", kotlinBaseVersion) systemProperty("kspVersion", version) systemProperty("agpVersion", agpBaseVersion) @@ -38,3 +37,33 @@ tasks.withType { dependsOn(":symbol-processing-cmdline:publishAllPublicationsToTestRepository") dependsOn(":symbol-processing-aa-embeddable:publishAllPublicationsToTestRepository") } + +val agpCompatibilityTestClasses = listOf("**/AGP731IT.class", "**/AGP741IT.class") + +// Create a new test task for the AGP compatibility tests +val agpCompatibilityTest by tasks.registering(Test::class) { + description = "Runs AGP compatibility tests with maxParallelForks = 1" + group = "verification" + + // Include only the AGP compatibility tests + include(agpCompatibilityTestClasses) + + // Set maxParallelForks to 1 to avoid race conditions when downloading SDKs with old AGPs + maxParallelForks = 1 + + // Apply common settings + configureCommonSettings() +} + +tasks.named("test") { + maxParallelForks = max(1, Runtime.getRuntime().availableProcessors() / 2) + + // Exclude test classes from agpCompatibilityTest + exclude(agpCompatibilityTestClasses) + + // Apply common settings + configureCommonSettings() + + // Ensure that 'test' depends on 'compatibilityTest' + dependsOn(agpCompatibilityTest) +} diff --git a/integration-tests/src/test/resources/android-view-binding/app/build.gradle.kts b/integration-tests/src/test/resources/android-view-binding/app/build.gradle.kts index 51b0630bd5..c3c6cd4f35 100644 --- a/integration-tests/src/test/resources/android-view-binding/app/build.gradle.kts +++ b/integration-tests/src/test/resources/android-view-binding/app/build.gradle.kts @@ -12,7 +12,7 @@ dependencies { android { namespace = "com.example.kspandroidtestapp" defaultConfig { - minSdkVersion(24) + minSdk = 24 } compileSdk = 34 buildFeatures { diff --git a/integration-tests/src/test/resources/playground-android-multi/application/build.gradle.kts b/integration-tests/src/test/resources/playground-android-multi/application/build.gradle.kts index 0616367a80..3db13abd95 100644 --- a/integration-tests/src/test/resources/playground-android-multi/application/build.gradle.kts +++ b/integration-tests/src/test/resources/playground-android-multi/application/build.gradle.kts @@ -20,11 +20,11 @@ dependencies { android { namespace = "com.example.myapplication" - compileSdkVersion(34) + compileSdk = 34 defaultConfig { applicationId = "org.gradle.kotlin.dsl.samples.androidstudio" - minSdkVersion(34) - targetSdkVersion(34) + minSdk = 34 + targetSdk = 34 versionCode = 1 versionName = "1.0" } diff --git a/integration-tests/src/test/resources/playground-android-multi/workload/build.gradle.kts b/integration-tests/src/test/resources/playground-android-multi/workload/build.gradle.kts index c57146de1a..b24b869c71 100644 --- a/integration-tests/src/test/resources/playground-android-multi/workload/build.gradle.kts +++ b/integration-tests/src/test/resources/playground-android-multi/workload/build.gradle.kts @@ -23,10 +23,10 @@ dependencies { android { namespace = "com.example.mylibrary" - compileSdkVersion(34) + compileSdk = 34 defaultConfig { - minSdkVersion(34) - targetSdkVersion(34) + minSdk = 34 + targetSdk = 34 } } diff --git a/integration-tests/src/test/resources/playground-android/workload/build.gradle.kts b/integration-tests/src/test/resources/playground-android/workload/build.gradle.kts index 076e0f5816..f6874ac1e3 100644 --- a/integration-tests/src/test/resources/playground-android/workload/build.gradle.kts +++ b/integration-tests/src/test/resources/playground-android/workload/build.gradle.kts @@ -23,11 +23,11 @@ dependencies { android { namespace = "com.example.myapplication" - compileSdkVersion(34) + compileSdk = 34 defaultConfig { applicationId = "org.gradle.kotlin.dsl.samples.androidstudio" - minSdkVersion(34) - targetSdkVersion(34) + minSdk = 34 + targetSdk = 34 versionCode = 1 versionName = "1.0" }