Pin AGP 'debug.keystore' in the repo.

This change adds shared 'debug.keystore' into the repository and
sets all the tests to use it.

Fixes issue when keystore was created by AGP 7+, but then consumed in
the test using lower versions of AGP.

^KT-45745 In Progress
This commit is contained in:
Yahor Berdnikau
2021-12-01 22:28:04 +01:00
committed by Space
parent 782b4f64be
commit 59ec10eb9c
26 changed files with 349 additions and 10 deletions
@@ -0,0 +1,4 @@
## Description
Contains a plugin for Gradle integration tests applying different fixes
for test that are using Android Gradle plugin.
@@ -0,0 +1,56 @@
import plugins.KotlinBuildPublishingPlugin
plugins {
id("java-gradle-plugin")
id("gradle-plugin-common-configuration")
id("com.gradle.plugin-publish")
}
repositories {
google()
}
dependencies {
compileOnly(gradleKotlinDsl())
compileOnly("com.android.tools.build:gradle:3.4.0")
compileOnly("com.android.tools.build:gradle-api:3.4.0")
compileOnly("com.android.tools.build:builder:3.4.0")
compileOnly("com.android.tools.build:builder-model:3.4.0")
}
configure<GradlePluginDevelopmentExtension> {
isAutomatedPublishing = false
}
gradlePlugin {
(plugins) {
create("android-test-fixes") {
id = "org.jetbrains.kotlin.test.fixes.android"
implementationClass = "org.jetbrains.kotlin.gradle.test.fixes.android.AndroidTestFixesPlugin"
}
}
}
pluginBundle {
(plugins) {
named("android-test-fixes") {
id = "org.jetbrains.kotlin.test.fixes.android"
displayName = "AndroidTestFixes"
}
}
}
publishPluginMarkers()
// Disable releasing for this plugin
// It is not intended to be released publicly
tasks.withType<PublishToMavenRepository>()
.configureEach {
if (name.endsWith("PublicationTo${KotlinBuildPublishingPlugin.REPOSITORY_NAME}Repository")) {
enabled = false
}
}
tasks.named("publishPlugins") {
enabled = false
}
@@ -0,0 +1,17 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.test.fixes.android
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.test.fixes.android.fixes.applyDebugKeystoreFix
class AndroidTestFixesPlugin : Plugin<Project> {
override fun apply(target: Project) {
val testFixesProperties = TestFixesProperties(target)
target.applyDebugKeystoreFix(testFixesProperties)
}
}
@@ -0,0 +1,22 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.test.fixes.android
import org.gradle.api.Project
internal class TestFixesProperties(
private val project: Project
) {
val androidDebugKeystoreLocation: String
get() = project.findProperty(ANDROID_DEBUG_KEYSTORE_LOCATION) as String? ?: throw IllegalArgumentException(
"$ANDROID_DEBUG_KEYSTORE_LOCATION property was not found in 'gradle.properties'."
)
companion object {
private const val PROP_PREFIX = "test.fixes."
private const val ANDROID_DEBUG_KEYSTORE_LOCATION = "${PROP_PREFIX}android.debugKeystore"
}
}
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.test.fixes.android.fixes
import com.android.build.gradle.AppExtension
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.TestExtension
import org.gradle.api.Action
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.jetbrains.kotlin.gradle.test.fixes.android.TestFixesProperties
/**
* AGP 7+ creates a keystore that is not compatible with lover versions of AGP,
* but could consume keystores created by them.
*
* With this fix 'debug.keystore' could be checked in into the repo and shared
* between test executions.
*/
internal fun Project.applyDebugKeystoreFix(
testFixesProperties: TestFixesProperties
) {
plugins.withId("com.android.application", fix<AppExtension>(testFixesProperties))
plugins.withId("com.android.test", fix<TestExtension>(testFixesProperties))
}
private inline fun <reified AndroidExtension : BaseExtension> Project.fix(
testFixesProperties: TestFixesProperties
): Action<Plugin<*>> = Action {
extensions.configure<AndroidExtension> {
logger.info("Reconfiguring Android debug keystore")
buildTypes.named("debug") {
it.signingConfig?.storeFile = file(testFixesProperties.androidDebugKeystoreLocation)
}
}
}
@@ -103,6 +103,43 @@ fun someTest(
}
```
##### Common test fixes
Test infrastructure adds following common fixes to all test projects:
- applies 'org.jetbrains.kotlin.test.fixes.android' [plugin](../gradle/android-test-fixes/Readme.md). If you are using custom `settings.gradle`
or `settings.gradle.kts` content in the test project, you need to add this plugin into `pluginManagement`:
<details open>
<summary>Kotlin script</summary>
```kotlin
pluginManagement {
repositories {
mavenLocal()
}
val test_fixes_version: String by settings
plugins {
id("org.jetbrains.kotlin.test.fixes.android") version test_fixes_version
}
}
```
</details>
<details>
<summary>Groovy</summary>
```groovy
pluginManagement {
repositories {
mavenLocal()
}
plugins {
id "org.jetbrains.kotlin.test.fixes.android" version $test_fixes_version
}
}
```
</details>
##### Deprecated tests setup
When you create a new test, figure out which Gradle versions it is supposed to run on. Then, when you instantiate a test project, specify one of:
@@ -288,6 +288,7 @@ tasks.withType<Test> {
dependsOn(":kotlin-gradle-plugin:validatePlugins")
dependsOnKotlinGradlePluginInstall()
dependsOn(":gradle:android-test-fixes:install")
dependsOn(":examples:annotation-processor-example:install")
systemProperty("kotlinVersion", rootProject.extra["kotlinVersion"] as String)
@@ -14,6 +14,7 @@ import org.intellij.lang.annotations.Language
import org.jetbrains.kotlin.gradle.model.ModelContainer
import org.jetbrains.kotlin.gradle.model.ModelFetcherBuildAction
import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType
import org.jetbrains.kotlin.gradle.testbase.applyAndroidTestFixes
import org.jetbrains.kotlin.gradle.testbase.enableCacheRedirector
import org.jetbrains.kotlin.gradle.testbase.extractJavaCompiledSources
import org.jetbrains.kotlin.gradle.testbase.extractKotlinCompiledSources
@@ -302,6 +303,7 @@ abstract class BaseGradleIT {
projectDir.toPath().apply {
addPluginManagementToSettings()
if (enableCacheRedirector) enableCacheRedirector()
applyAndroidTestFixes()
}
}
}
@@ -445,7 +447,7 @@ abstract class BaseGradleIT {
}
val options = defaultBuildOptions()
val arguments = mutableListOf("-Pkotlin_version=${options.kotlinVersion}")
val arguments = mutableListOf("-Pkotlin_version=${options.kotlinVersion}", "-Ptest_fixes_version=$KOTLIN_VERSION")
options.androidGradlePluginVersion?.let { arguments.add("-Pandroid_tools_version=$it") }
val env = createEnvironmentVariablesMap(options)
val wrapperVersion = chooseWrapperVersionOrFinishTest()
@@ -874,6 +876,7 @@ Finished executing task ':$taskName'|
}
add("-Pkotlin_version=" + options.kotlinVersion)
add("-Ptest_fixes_version=$KOTLIN_VERSION")
options.incremental?.let {
add("-Pkotlin.incremental=$it")
}
@@ -1551,6 +1551,7 @@ class NewMultiplatformIT : BaseGradleIT() {
.replace(": ", " = ")
.replace("def ", " val ")
.replace("new File(cacheRedirectorFile)", "File(cacheRedirectorFile)")
.replace("id \"org.jetbrains.kotlin.test.fixes.android\"", "id(\"org.jetbrains.kotlin.test.fixes.android\")")
}
renameTo(projectDir.resolve("app/build.gradle.kts"))
}
@@ -109,6 +109,7 @@ data class BuildOptions(
if (androidVersion != null) {
arguments.add("-Pandroid_tools_version=${androidVersion}")
}
arguments.add("-Ptest_fixes_version=${TestVersions.Kotlin.CURRENT}")
return arguments.toList()
}
@@ -0,0 +1,98 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.testbase
import org.jetbrains.kotlin.gradle.util.modify
import java.io.File
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.io.path.exists
internal fun Path.applyAndroidTestFixes() {
// Path relative to the current gradle module project dir
val keystoreFile = Paths.get("src/test/resources/common/debug.keystore")
assert(keystoreFile.exists()) {
"Common 'debug.keystore' file does not exists in ${keystoreFile.toAbsolutePath()} location!"
}
resolve("gradle.properties").append(
"""
|test.fixes.android.debugKeystore=${keystoreFile.toAbsolutePath().toString().normalizePath()}
|
""".trimMargin()
)
val pathFile = toFile()
pathFile.walkTopDown()
.filter { it.name == "build.gradle" || it.name == "build.gradle.kts" }
.forEach { file ->
when (file.name) {
"build.gradle" -> file.updateBuildGradle()
"build.gradle.kts" -> file.updateBuildGradleKts()
}
}
}
private fun File.updateBuildGradle() {
modify {
if (it.contains("plugins {")) {
"""
|${it.substringBefore("plugins {")}
|plugins {
| id "org.jetbrains.kotlin.test.fixes.android"
|${it.substringAfter("plugins {")}
""".trimMargin()
} else if (it.contains("apply plugin:")) {
it.modifyBuildScript().run {
"""
|${substringBefore("apply plugin:")}
|apply plugin: 'org.jetbrains.kotlin.test.fixes.android'
|apply plugin:${substringAfter("apply plugin:")}
""".trimMargin()
}
} else {
it.modifyBuildScript()
}
}
}
private fun String.modifyBuildScript(isKts: Boolean = false): String =
if (contains("buildscript {") &&
contains("classpath")
) {
val kotlinVersionStr = if (isKts) "${'$'}{property(\"test_fixes_version\")}" else "${'$'}test_fixes_version"
"""
|${substringBefore("classpath")}
|classpath("org.jetbrains.kotlin:android-test-fixes:$kotlinVersionStr")
|classpath${substringAfter("classpath")}
""".trimMargin()
} else {
this
}
private fun File.updateBuildGradleKts() {
modify {
if (it.contains("plugins {")) {
"""
|${it.substringBefore("plugins {")}
|plugins {
| id("org.jetbrains.kotlin.test.fixes.android")
|${it.substringAfter("plugins {")}
""".trimMargin()
} else if (it.contains("apply(plugin")) {
it.modifyBuildScript(true).run {
"""
|${substringBefore("apply(plugin")}
|apply(plugin = "org.jetbrains.kotlin.test.fixes.android")
|apply(plugin${substringAfter("apply(plugin")}
""".trimMargin()
}
} else {
it.modifyBuildScript(true)
}
}
}
@@ -26,7 +26,7 @@ internal val DEFAULT_GROOVY_SETTINGS_FILE =
id "org.jetbrains.kotlin.multiplatform" version "${'$'}kotlin_version"
id "org.jetbrains.kotlin.multiplatform.pm20" version "${'$'}kotlin_version"
id "org.jetbrains.kotlin.plugin.allopen" version "${'$'}kotlin_version"
id "org.jetbrains.kotlin.test.fixes.android" version "${'$'}kotlin_version"
id "org.jetbrains.kotlin.test.fixes.android" version "${'$'}test_fixes_version"
}
resolutionStrategy {
@@ -67,6 +67,7 @@ internal val DEFAULT_KOTLIN_SETTINGS_FILE =
val kotlin_version: String by settings
val android_tools_version: String by settings
val test_fixes_version: String by settings
plugins {
id("org.jetbrains.kotlin.jvm") version kotlin_version
id("org.jetbrains.kotlin.kapt") version kotlin_version
@@ -75,7 +76,7 @@ internal val DEFAULT_KOTLIN_SETTINGS_FILE =
id("org.jetbrains.kotlin.multiplatform") version kotlin_version
id("org.jetbrains.kotlin.multiplatform.pm20") version kotlin_version
id("org.jetbrains.kotlin.plugin.allopen") version kotlin_version
id("org.jetbrains.kotlin.test.fixes.android") version kotlin_version
id("org.jetbrains.kotlin.test.fixes.android") version test_fixes_version
}
resolutionStrategy {
@@ -318,6 +318,10 @@ internal fun Path.addPluginManagementToSettings() {
}
else -> settingsGradle.toFile().writeText(DEFAULT_GROOVY_SETTINGS_FILE)
}
if (Files.exists(resolve("buildSrc"))) {
resolve("buildSrc").addPluginManagementToSettings()
}
}
private fun TestProject.agreeToBuildScanService() {
@@ -365,6 +369,7 @@ internal fun Path.enableAndroidSdk() {
""".trimIndent()
)
acceptAndroidSdkLicenses(androidSdk)
applyAndroidTestFixes()
}
@OptIn(ExperimentalPathApi::class)
@@ -7,5 +7,6 @@ pluginManagement {
plugins {
id "org.jetbrains.kotlin.jvm" version "$kotlin_version"
id "org.jetbrains.kotlin.test.fixes.android" version "$test_fixes_version"
}
}
@@ -1,10 +1,14 @@
pluginManagement {
repositories {
gradlePluginPortal()
mavenLocal()
mavenCentral()
google()
gradlePluginPortal()
}
plugins {
id "org.jetbrains.kotlin.js" version "$kotlin_version"
id "org.jetbrains.kotlin.test.fixes.android" version "$test_fixes_version"
}
}
@@ -1,6 +1,11 @@
pluginManagement {
repositories {
mavenCentral()
mavenLocal()
mavenCentral()
}
val test_fixes_version: String by settings
plugins {
id("org.jetbrains.kotlin.test.fixes.android") version test_fixes_version
}
}
@@ -1,4 +1,6 @@
apply plugin: 'kotlin'
plugins {
id "org.jetbrains.kotlin.jvm"
}
repositories {
mavenLocal()
@@ -1,10 +1,12 @@
plugins {
id 'java'
}
repositories {
mavenLocal()
mavenCentral()
}
apply plugin: 'java'
dependencies {
runtimeOnly "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
@@ -0,0 +1,10 @@
pluginManagement {
repositories {
mavenLocal()
mavenCentral()
}
plugins {
id "org.jetbrains.kotlin.test.fixes.android" version "$test_fixes_version"
}
}
@@ -5,6 +5,8 @@ pluginManagement {
}
plugins {
val kotlin_version: String by settings
val test_fixes_version: String by settings
kotlin("multiplatform").version(kotlin_version)
id("org.jetbrains.kotlin.test.fixes.android") version test_fixes_version
}
}
@@ -1 +1,14 @@
pluginManagement {
repositories {
mavenLocal()
mavenCentral()
google()
gradlePluginPortal()
}
plugins {
id "org.jetbrains.kotlin.test.fixes.android" version "$test_fixes_version"
}
}
include 'projA', 'projB'
@@ -3,4 +3,8 @@ pluginManagement {
maven { url '<mavenLocalUrl>' }
gradlePluginPortal()
}
plugins {
id "org.jetbrains.kotlin.test.fixes.android" version "$test_fixes_version"
}
}
@@ -3,4 +3,8 @@ pluginManagement {
maven { url '<mavenLocalUrl>' }
gradlePluginPortal()
}
plugins {
id "org.jetbrains.kotlin.test.fixes.android" version "$test_fixes_version"
}
}
@@ -3,6 +3,10 @@ pluginManagement {
maven { url '<mavenLocalUrl>' }
gradlePluginPortal()
}
plugins {
id "org.jetbrains.kotlin.test.fixes.android" version "$test_fixes_version"
}
}
include 'subproject'
+2
View File
@@ -234,6 +234,7 @@ include ":benchmarks",
":kotlin-gradle-plugin-model",
":kotlin-gradle-plugin-test-utils-embeddable",
":kotlin-gradle-plugin-integration-tests",
":gradle:android-test-fixes",
":kotlin-tooling-metadata",
":kotlin-allopen",
":kotlin-noarg",
@@ -616,6 +617,7 @@ project(':kotlin-gradle-plugin').projectDir = "$rootDir/libraries/tools/kotlin-g
project(':kotlin-gradle-plugin-model').projectDir = "$rootDir/libraries/tools/kotlin-gradle-plugin-model" as File
project(':kotlin-gradle-plugin-test-utils-embeddable').projectDir = "$rootDir/libraries/tools/kotlin-gradle-plugin-test-utils-embeddable" as File
project(':kotlin-gradle-plugin-integration-tests').projectDir = "$rootDir/libraries/tools/kotlin-gradle-plugin-integration-tests" as File
project(':gradle:android-test-fixes').projectDir = "$rootDir/libraries/tools/gradle/android-test-fixes" as File
project(':kotlin-tooling-metadata').projectDir = "$rootDir/libraries/tools/kotlin-tooling-metadata" as File
project(':kotlin-allopen').projectDir = "$rootDir/libraries/tools/kotlin-allopen" as File
project(':kotlin-noarg').projectDir = "$rootDir/libraries/tools/kotlin-noarg" as File