From 318feb07b1ec3581eaa4122294b203d302ca6013 Mon Sep 17 00:00:00 2001 From: Sebastien Rouif Date: Tue, 13 Jun 2023 23:45:54 +0100 Subject: [PATCH] Add possibility to check flavoured android modules --- README.md | 10 +++ .../validation/test/AndroidLibraryTest.kt | 73 ++++++++++++++++++- .../examples/classes/FlavourGreen.kt | 13 ++++ .../resources/examples/classes/FlavourRed.kt | 13 ++++ .../examples/classes/KotlinFlavour.kt | 13 ++++ .../examples/classes/KotlinFlavouredLib.dump | 23 ++++++ .../androidFlavouredKotlinLibrary.gradle.kts | 53 ++++++++++++++ .../base/androidKotlinLibrary.gradle.kts | 1 - src/main/kotlin/ApiValidationExtension.kt | 6 ++ .../BinaryCompatibilityValidatorPlugin.kt | 33 +++++++-- 10 files changed, 228 insertions(+), 10 deletions(-) create mode 100644 src/functionalTest/resources/examples/classes/FlavourGreen.kt create mode 100644 src/functionalTest/resources/examples/classes/FlavourRed.kt create mode 100644 src/functionalTest/resources/examples/classes/KotlinFlavour.kt create mode 100644 src/functionalTest/resources/examples/classes/KotlinFlavouredLib.dump create mode 100644 src/functionalTest/resources/examples/gradle/base/androidFlavouredKotlinLibrary.gradle.kts diff --git a/README.md b/README.md index 4cf37479..ade50f41 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,11 @@ apiValidation { * Flag to programmatically disable compatibility validator */ validationDisabled = true + + /** + * flavour to be tested in flavoured Android modules + */ + testedFlavourName = "blue" } ``` @@ -122,6 +127,11 @@ apiValidation { * Flag to programmatically disable compatibility validator */ validationDisabled = false + + /** + * flavour to be tested in flavoured Android modules + */ + testedFlavourName = "blue" } ``` diff --git a/src/functionalTest/kotlin/kotlinx/validation/test/AndroidLibraryTest.kt b/src/functionalTest/kotlin/kotlinx/validation/test/AndroidLibraryTest.kt index 736649e6..7dce8888 100644 --- a/src/functionalTest/kotlin/kotlinx/validation/test/AndroidLibraryTest.kt +++ b/src/functionalTest/kotlin/kotlinx/validation/test/AndroidLibraryTest.kt @@ -11,7 +11,6 @@ import org.junit.Ignore import org.junit.Test import java.io.File -@Ignore // Leftovers after revert of #94 internal class AndroidLibraryTest : BaseKotlinGradleTest() { // region Kotlin Android Library @@ -47,8 +46,42 @@ internal class AndroidLibraryTest : BaseKotlinGradleTest() { //endregion + // region Kotlin Flavoured Android Library + + @Test + fun `Given a Kotlin Flavoured Android Library, when api is dumped, then task should be successful`() { + assumeHasAndroid() + val runner = test { + createProjectWithSubModulesAndFlavour() + runner { + arguments.add(":kotlin-library:apiDump") + arguments.add("--full-stacktrace") + } + } + + runner.build().apply { + assertTaskSuccess(":kotlin-library:apiDump") + } + } + + @Test + fun `Given a Kotlin Flavoured Android Library, when api is checked, then it should match the expected`() { + assumeHasAndroid() + test { + createProjectWithSubModulesAndFlavour() + runner { + arguments.add(":kotlin-library:apiCheck") + } + }.build().apply { + assertTaskSuccess(":kotlin-library:apiCheck") + } + } + + //endregion + //region Java Android Library + @Ignore // Leftovers after revert of #94 @Test fun `Given a Java Android Library, when api is dumped, then task should be successful`() { assumeHasAndroid() @@ -65,6 +98,7 @@ internal class AndroidLibraryTest : BaseKotlinGradleTest() { } } + @Ignore // Leftovers after revert of #94 @Test fun `Given a Java Android Library, when api is checked, then it should match the expected`() { assumeHasAndroid() @@ -117,6 +151,43 @@ internal class AndroidLibraryTest : BaseKotlinGradleTest() { } } + private fun BaseKotlinScope.createProjectWithSubModulesAndFlavour() { + settingsGradleKts { + resolve("examples/gradle/settings/settings-android-project.gradle.kts") + } + buildGradleKts { + resolve("examples/gradle/base/androidProjectRoot.gradle.kts") + } + initLocalProperties() + + dir("kotlin-library") { + buildGradleKts { + resolve("examples/gradle/base/androidFlavouredKotlinLibrary.gradle.kts") + } + kotlin("KotlinLib.kt") { + resolve("examples/classes/KotlinLib.kt") + } + // different files in different folder only selected flavour should be picked + // unfortunately files in flavour folder are not picked up + kotlin("FlavourGreen.kt", sourceSet = "green") { + resolve("examples/classes/FlavourGreen.kt") + } + kotlin("FlavourRed.kt", sourceSet = "red") { + resolve("examples/classes/FlavourRed.kt") + } + // same file in different folder should not create problems + kotlin("KotlinLib2.kt", sourceSet = "green") { + resolve("examples/classes/KotlinFlavour.kt") + } + kotlin("KotlinLib2.kt", sourceSet = "red") { + resolve("examples/classes/KotlinFlavour.kt") + } + apiFile(projectName = "kotlin-library") { + resolve("examples/classes/KotlinFlavouredLib.dump") + } + } + } + private fun initLocalProperties() { val home = System.getenv("ANDROID_HOME") ?: System.getenv("HOME") File(rootProjectDir, "local.properties").apply { diff --git a/src/functionalTest/resources/examples/classes/FlavourGreen.kt b/src/functionalTest/resources/examples/classes/FlavourGreen.kt new file mode 100644 index 00000000..65ce1215 --- /dev/null +++ b/src/functionalTest/resources/examples/classes/FlavourGreen.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2016-2022 JetBrains s.r.o. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package examples.classes + +class FlavourGreen { + + fun foo(): String = "foo" + internal fun bar(): String = "bar" + +} diff --git a/src/functionalTest/resources/examples/classes/FlavourRed.kt b/src/functionalTest/resources/examples/classes/FlavourRed.kt new file mode 100644 index 00000000..3df3caed --- /dev/null +++ b/src/functionalTest/resources/examples/classes/FlavourRed.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2016-2022 JetBrains s.r.o. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package examples.classes + +class FlavourRed { + + fun foo(): String = "foo" + internal fun bar(): String = "bar" + +} diff --git a/src/functionalTest/resources/examples/classes/KotlinFlavour.kt b/src/functionalTest/resources/examples/classes/KotlinFlavour.kt new file mode 100644 index 00000000..5606ba26 --- /dev/null +++ b/src/functionalTest/resources/examples/classes/KotlinFlavour.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2016-2022 JetBrains s.r.o. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package examples.classes + +class KotlinFlavour { + + fun foo(): String = "foo" + internal fun bar(): String = "bar" + +} diff --git a/src/functionalTest/resources/examples/classes/KotlinFlavouredLib.dump b/src/functionalTest/resources/examples/classes/KotlinFlavouredLib.dump new file mode 100644 index 00000000..80eb21d6 --- /dev/null +++ b/src/functionalTest/resources/examples/classes/KotlinFlavouredLib.dump @@ -0,0 +1,23 @@ +public final class examples/classes/FlavourGreen { + public fun ()V + public final fun foo ()Ljava/lang/String; +} + +public final class examples/classes/KotlinFlavour { + public fun ()V + public final fun foo ()Ljava/lang/String; +} + +public final class examples/classes/KotlinLib { + public fun ()V + public final fun foo ()Ljava/lang/String; +} + +public final class org/jetbrains/kotlinx/android/kotlin/library/BuildConfig { + public static final field BUILD_TYPE Ljava/lang/String; + public static final field DEBUG Z + public static final field FLAVOR Ljava/lang/String; + public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String; + public fun ()V +} + diff --git a/src/functionalTest/resources/examples/gradle/base/androidFlavouredKotlinLibrary.gradle.kts b/src/functionalTest/resources/examples/gradle/base/androidFlavouredKotlinLibrary.gradle.kts new file mode 100644 index 00000000..2429f108 --- /dev/null +++ b/src/functionalTest/resources/examples/gradle/base/androidFlavouredKotlinLibrary.gradle.kts @@ -0,0 +1,53 @@ +/* + * Copyright 2016-2022 JetBrains s.r.o. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ +import org.jetbrains.kotlin.gradle.plugin.* +plugins { + id("com.android.library") + id("kotlin-android") + id("org.jetbrains.kotlinx.binary-compatibility-validator") +} + +android { + + namespace = "org.jetbrains.kotlinx.android.kotlin.library" + + compileSdk = 32 + + defaultConfig { + minSdk = 31 + targetSdk = 32 + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + + flavorDimensions += "brand" + productFlavors { + create("green") { + dimension = "brand" + } + create("red") { + dimension = "brand" + } + } +} + +apiValidation { + testedFlavourName = "green" + additionalSourceSets.add("green") +} +dependencies { + // no dependencies required +} diff --git a/src/functionalTest/resources/examples/gradle/base/androidKotlinLibrary.gradle.kts b/src/functionalTest/resources/examples/gradle/base/androidKotlinLibrary.gradle.kts index f7b99ed4..b324b04d 100644 --- a/src/functionalTest/resources/examples/gradle/base/androidKotlinLibrary.gradle.kts +++ b/src/functionalTest/resources/examples/gradle/base/androidKotlinLibrary.gradle.kts @@ -2,7 +2,6 @@ * Copyright 2016-2022 JetBrains s.r.o. * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. */ - plugins { id("com.android.library") id("kotlin-android") diff --git a/src/main/kotlin/ApiValidationExtension.kt b/src/main/kotlin/ApiValidationExtension.kt index deb85435..92f57c59 100644 --- a/src/main/kotlin/ApiValidationExtension.kt +++ b/src/main/kotlin/ApiValidationExtension.kt @@ -64,4 +64,10 @@ open class ApiValidationExtension { * By default, only the `main` source set is checked. */ public var additionalSourceSets: MutableSet = HashSet() + + /** + * In Android projects with multiple flavour, + * it specifies the flavour you want to test (assuming projects have same API) + */ + public var testedFlavourName: String? = null } diff --git a/src/main/kotlin/BinaryCompatibilityValidatorPlugin.kt b/src/main/kotlin/BinaryCompatibilityValidatorPlugin.kt index c0217ae4..44f5201f 100644 --- a/src/main/kotlin/BinaryCompatibilityValidatorPlugin.kt +++ b/src/main/kotlin/BinaryCompatibilityValidatorPlugin.kt @@ -5,13 +5,22 @@ package kotlinx.validation -import org.gradle.api.* -import org.gradle.api.plugins.* -import org.gradle.api.provider.* -import org.gradle.api.tasks.* -import org.jetbrains.kotlin.gradle.dsl.* -import org.jetbrains.kotlin.gradle.plugin.* -import java.io.* +import java.io.File +import org.gradle.api.Action +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.plugins.AppliedPlugin +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.SourceSetContainer +import org.gradle.api.tasks.Sync +import org.gradle.api.tasks.TaskProvider +import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension +import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType const val API_DIR = "api" @@ -120,7 +129,15 @@ class BinaryCompatibilityValidatorPlugin : Plugin { val androidExtension = project.extensions .getByName("kotlin") as KotlinAndroidProjectExtension androidExtension.target.compilations.matching { - it.compilationName == "release" + val testedFlavourName = extension.testedFlavourName + if (testedFlavourName == null) { + it.compilationName == "release" + } else { + it.compilationName.contains("release", ignoreCase = true) + && it.compilationName.contains("test", ignoreCase = true).not() + && it.compilationName.contains(testedFlavourName, ignoreCase = true) + } + }.all { project.configureKotlinCompilation(it, extension, useOutput = true) }