Skip to content

Commit

Permalink
Support AGP's built-in Kotlin compilation
Browse files Browse the repository at this point in the history
Previously, the sourceSet-specific KSP configurations (e.g., kspTest)
weren't being created when AGP's built-in Kotlin compilation was
enabled.

This change also increases the AGP version to 8.7.0 in order to test
against a version of AGP with the built-in Kotlin support.

Bug: b/362279380
Test: GradleCompilationTest
  • Loading branch information
scott-pollom committed Oct 7, 2024
1 parent 69060b2 commit 3331de1
Show file tree
Hide file tree
Showing 15 changed files with 110 additions and 35 deletions.
11 changes: 8 additions & 3 deletions .github/workflows/auto-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,15 @@ jobs:
# Check API compatibility
- name: API compatibility check
run: ./gradlew :api:checkApi

# Run ksp generated tests

# Run old AGP compatibility tests
# Run these before other tests to avoid XML parsing issues from old AGP when using SDKs downloaded by new AGP
- name: test with old AGP versions
run: ./gradlew --stacktrace --info :integration-tests:test --tests=com.google.devtools.ksp.test.compatibility.*

# Run other tests
- name: test
run: ./gradlew --stacktrace --info test
run: ./gradlew --stacktrace --info test -PexcludeAgpCompatibilityTests

- name: push to release branch
if: success()
Expand Down
11 changes: 9 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,17 @@ jobs:
if: matrix.os == 'ubuntu-latest'
run: ./gradlew :api:checkApi

# Run tests
# Run old AGP compatibility tests
# Run these before other tests to avoid XML parsing issues from old AGP when using SDKs downloaded by new AGP
- name: test with old AGP versions
shell: bash
run: ./gradlew --stacktrace --info :integration-tests:test --tests=com.google.devtools.ksp.test.compatibility.*

# Run other tests
- name: test
shell: bash
run: ./gradlew --stacktrace --info test
run: ./gradlew --stacktrace --info test -PexcludeAgpCompatibilityTests

- name: Upload test results
if: always()
uses: actions/upload-artifact@v3
Expand Down
11 changes: 9 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,17 @@ jobs:
path: ~/.gradle/wrapper
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}

# Run tests
# Run old AGP compatibility tests
# Run these before other tests to avoid XML parsing issues from old AGP when using SDKs downloaded by new AGP
- name: test with old AGP versions
shell: bash
run: ./gradlew --stacktrace --info :integration-tests:test --tests=com.google.devtools.ksp.test.compatibility.*

# Run other tests
- name: test
shell: bash
run: ./gradlew --stacktrace --info test
run: ./gradlew --stacktrace --info test -PexcludeAgpCompatibilityTests

- name: Upload test results
if: always()
uses: actions/upload-artifact@v3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 ->
Expand Down Expand Up @@ -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)"
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}

Expand All @@ -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")
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions integration-tests/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ tasks.withType<Test> {
rootProject.layout.buildDirectory.dir("repos/test").get().asFile
)
)
filter {
if (project.hasProperty("excludeAgpCompatibilityTests")) {
excludeTestsMatching("com.google.devtools.ksp.test.compatibility.*")
}
}
dependsOn(":api:publishAllPublicationsToTestRepository")
dependsOn(":gradle-plugin:publishAllPublicationsToTestRepository")
dependsOn(":common-deps:publishAllPublicationsToTestRepository")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
* limitations under the License.
*/

package com.google.devtools.ksp.test
package com.google.devtools.ksp.test.compatibility

import com.google.devtools.ksp.test.TemporaryTestProject
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome
import org.junit.Assert
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
* limitations under the License.
*/

package com.google.devtools.ksp.test
package com.google.devtools.ksp.test.compatibility

import com.google.devtools.ksp.test.TemporaryTestProject
import org.gradle.testkit.runner.GradleRunner
import org.junit.Assert
import org.junit.Rule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ dependencies {
android {
namespace = "com.example.kspandroidtestapp"
defaultConfig {
minSdkVersion(24)
minSdk = 24
}
compileSdk = 34
buildFeatures {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ dependencies {

android {
namespace = "com.example.mylibrary"
compileSdkVersion(34)
compileSdk = 34
defaultConfig {
minSdkVersion(34)
targetSdkVersion(34)
minSdk = 34
targetSdk = 34
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down

0 comments on commit 3331de1

Please sign in to comment.