[Gradle] KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck: Use AndroidGradlePluginVersion tool

^KT-54033 WIP
This commit is contained in:
Sebastian Sellmair
2022-09-19 11:34:47 +02:00
committed by Space
parent 32f86d4672
commit 7d5b3d3628
2 changed files with 65 additions and 121 deletions
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.gradle.plugin
import com.android.Version
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ANDROID_GRADLE_PLUGIN_COMPATIBILITY_NO_WARN
@@ -18,8 +17,8 @@ import java.util.concurrent.atomic.AtomicBoolean
internal object KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck {
val compatibleAndroidGradlePluginVersionRange = AndroidGradlePluginVersionRange(
minSupportedVersion = AndroidGradlePluginVersion(4, 0),
maxSupportedVersion = AndroidGradlePluginVersion(7, 3)
minSupportedVersion = AndroidGradlePluginVersionRange.Version(4, 0),
maxSupportedVersion = AndroidGradlePluginVersionRange.Version(7, 3)
)
/**
@@ -32,81 +31,47 @@ internal object KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck {
*/
const val PROPERTY_KEY_EXECUTED_PROJECT_PATHS = "KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck.executedProjects"
data class AndroidGradlePluginVersion(val major: Int, val minor: Int) : Comparable<AndroidGradlePluginVersion> {
override fun compareTo(other: AndroidGradlePluginVersion): Int {
if (this.major != other.major) return this.major.compareTo(other.major)
return this.minor.compareTo(other.minor)
}
override fun toString(): String {
return "$major.$minor"
}
}
data class AndroidGradlePluginVersionRange(
val minSupportedVersion: AndroidGradlePluginVersion,
val maxSupportedVersionMajor: Int,
val maxSupportedVersionMinor: Int?
val minSupportedVersion: Version,
val maxSupportedVersion: Version
) {
constructor(
minSupportedVersionMajor: Int,
minSupportedVersionMinor: Int,
maxSupportedVersionMajor: Int,
maxSupportedVersionMinor: Int? = null
) : this(
minSupportedVersion = AndroidGradlePluginVersion(minSupportedVersionMajor, minSupportedVersionMinor),
maxSupportedVersionMajor = maxSupportedVersionMajor,
maxSupportedVersionMinor = maxSupportedVersionMinor
)
constructor(
minSupportedVersion: AndroidGradlePluginVersion,
maxSupportedVersion: AndroidGradlePluginVersion
minSupportedVersionMajor: Int, minSupportedVersionMinor: Int = 0,
maxSupportedVersionMajor: Int, maxSupportedVersionMinor: Int = 0
) : this(
minSupportedVersion = minSupportedVersion,
maxSupportedVersionMajor = maxSupportedVersion.major,
maxSupportedVersionMinor = maxSupportedVersion.minor
minSupportedVersion = Version(minSupportedVersionMajor, minSupportedVersionMinor),
maxSupportedVersion = Version(maxSupportedVersionMajor, maxSupportedVersionMinor)
)
data class Version(val major: Int, val minor: Int)
fun isTooHigh(version: AndroidGradlePluginVersion): Boolean {
return if (maxSupportedVersionMinor != null)
version > AndroidGradlePluginVersion(maxSupportedVersionMajor, maxSupportedVersionMinor)
else version.major > maxSupportedVersionMajor
if (version.major > this.maxSupportedVersion.major) return true
if (version.major < this.maxSupportedVersion.major) return false
return version.minor > this.maxSupportedVersion.minor
}
fun isTooLow(version: AndroidGradlePluginVersion): Boolean {
return version < minSupportedVersion
if (version.major < this.minSupportedVersion.major) return true
if (version.major > this.minSupportedVersion.major) return false
return version.minor < this.minSupportedVersion.minor
}
}
interface AndroidGradlePluginStringProvider {
fun getAndroidGradlePluginString(): String?
interface AndroidGradlePluginVersionProvider {
fun getAndroidGradlePluginVersion(): AndroidGradlePluginVersion?
object Default : AndroidGradlePluginStringProvider {
override fun getAndroidGradlePluginString(): String? =
runCatching { Version.ANDROID_GRADLE_PLUGIN_VERSION }.getOrElse { return null }
}
}
interface AndroidGradlePluginVersionParser {
fun parseVersionString(version: String): AndroidGradlePluginVersion?
object Default : AndroidGradlePluginVersionParser {
private val versionRegex = Regex("""(\d+)\.(\d+)(\.\d+)?(.*)""")
override fun parseVersionString(version: String): AndroidGradlePluginVersion? {
val matchResult = versionRegex.matchEntire(version) ?: return null
val major = matchResult.groups[1]?.value?.toIntOrNull() ?: return null
val minor = matchResult.groups[2]?.value?.toIntOrNull() ?: return null
return AndroidGradlePluginVersion(major, minor)
object Default : AndroidGradlePluginVersionProvider {
override fun getAndroidGradlePluginVersion(): AndroidGradlePluginVersion? {
return AndroidGradlePluginVersion.current
}
}
}
fun Project.runMultiplatformAndroidGradlePluginCompatibilityHealthCheckWhenAndroidIsApplied(
warningLogger: (warningMessage: String) -> Unit = project.logger::warn,
androidGradlePluginStringProvider: AndroidGradlePluginStringProvider = AndroidGradlePluginStringProvider.Default,
androidGradlePluginVersionParser: AndroidGradlePluginVersionParser = AndroidGradlePluginVersionParser.Default
androidGradlePluginVersionProvider: AndroidGradlePluginVersionProvider = AndroidGradlePluginVersionProvider.Default
) {
val emittedMessages = project.getOrPutRootProjectProperty(PROPERTY_KEY_EMITTED_MESSAGES) { mutableSetOf<String>() }
@@ -121,7 +86,7 @@ internal object KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck {
plugins.withId(id) {
if (!executed.getAndSet(true)) {
runMultiplatformAndroidGradlePluginCompatibilityHealthCheck(
deduplicateWarningMessageLogger, androidGradlePluginStringProvider, androidGradlePluginVersionParser
deduplicateWarningMessageLogger, androidGradlePluginVersionProvider
)
}
}
@@ -130,8 +95,7 @@ internal object KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck {
fun Project.runMultiplatformAndroidGradlePluginCompatibilityHealthCheck(
warningLogger: (warningMessage: String) -> Unit = project.logger::warn,
androidGradlePluginStringProvider: AndroidGradlePluginStringProvider = AndroidGradlePluginStringProvider.Default,
androidGradlePluginVersionParser: AndroidGradlePluginVersionParser = AndroidGradlePluginVersionParser.Default,
androidGradlePluginVersionProvider: AndroidGradlePluginVersionProvider = AndroidGradlePluginVersionProvider.Default,
compatibleAndroidGradlePluginVersionRange: AndroidGradlePluginVersionRange =
KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck.compatibleAndroidGradlePluginVersionRange
) = runProjectConfigurationHealthCheck check@{
@@ -141,26 +105,22 @@ internal object KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck {
/* Return when no android plugin is applied */
findAppliedAndroidPluginIdOrNull() ?: return@check
val androidGradlePluginVersionString = androidGradlePluginStringProvider.getAndroidGradlePluginString()
?: return warningLogger(Messages.FAILED_GETTING_ANDROID_GRADLE_PLUGIN_VERSION_STRING)
val androidGradlePluginVersion = androidGradlePluginVersionParser.parseVersionString(androidGradlePluginVersionString)
?: return warningLogger(Messages.failedParsingAndroidGradlePluginVersion(androidGradlePluginVersionString))
val androidGradlePluginVersion = androidGradlePluginVersionProvider.getAndroidGradlePluginVersion()
?: return warningLogger(Messages.failedGettingAndroidGradlePluginVersion())
if (compatibleAndroidGradlePluginVersionRange.isTooLow(androidGradlePluginVersion)) {
warningLogger(Messages.androidGradlePluginVersionTooLow(androidGradlePluginVersionString))
warningLogger(Messages.androidGradlePluginVersionTooLow(androidGradlePluginVersion.toString()))
}
if (compatibleAndroidGradlePluginVersionRange.isTooHigh(androidGradlePluginVersion)) {
warningLogger(Messages.androidGradlePluginVersionTooHigh(androidGradlePluginVersionString))
warningLogger(Messages.androidGradlePluginVersionTooHigh(androidGradlePluginVersion.toString()))
}
}
object Messages {
const val FAILED_GETTING_ANDROID_GRADLE_PLUGIN_VERSION_STRING = "Failed to get the version of the applied Android Gradle Plugin"
fun failedParsingAndroidGradlePluginVersion(androidGradlePluginVersionString: String) =
"w: Failed to parse the version of the applied Android Gradle Plugin: $androidGradlePluginVersionString"
fun failedGettingAndroidGradlePluginVersion() =
"w: Failed to get AndroidGradlePluginVersion"
fun androidGradlePluginVersionTooLow(androidGradlePluginVersionString: String) = createCompatibilityWarningMessage(
"The applied Android Gradle Plugin version ($androidGradlePluginVersionString) is lower than the minimum supported"
@@ -181,8 +141,8 @@ internal object KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck {
)
appendLine(
"Maximum tested Android Gradle Plugin version: " +
"${compatibleAndroidGradlePluginVersionRange.maxSupportedVersionMajor}." +
"${compatibleAndroidGradlePluginVersionRange.maxSupportedVersionMinor ?: "*"}"
"${compatibleAndroidGradlePluginVersionRange.maxSupportedVersion.major}." +
"${compatibleAndroidGradlePluginVersionRange.maxSupportedVersion.minor}"
)
appendLine("To suppress this message add $KOTLIN_MPP_ANDROID_GRADLE_PLUGIN_COMPATIBILITY_NO_WARN=true to your gradle.properties")
}
@@ -9,9 +9,8 @@ package org.jetbrains.kotlin.gradle
import com.android.build.gradle.LibraryPlugin
import org.gradle.testfixtures.ProjectBuilder
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck.AndroidGradlePluginStringProvider
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck.AndroidGradlePluginVersion
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck.AndroidGradlePluginVersionParser
import org.jetbrains.kotlin.gradle.plugin.AndroidGradlePluginVersion
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck.AndroidGradlePluginVersionProvider
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck.AndroidGradlePluginVersionRange
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck.Messages
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck.PROPERTY_KEY_EXECUTED_PROJECT_PATHS
@@ -42,8 +41,11 @@ class KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheckTest {
}
}
class FixedAndroidGradlePluginVersionProvider(private val version: String?) : AndroidGradlePluginStringProvider {
override fun getAndroidGradlePluginString(): String? = version
internal class FixedAndroidGradlePluginVersionProvider(private val version: String?) : AndroidGradlePluginVersionProvider {
override fun getAndroidGradlePluginVersion(): AndroidGradlePluginVersion? {
if (version == null) return null
return AndroidGradlePluginVersion(version)
}
}
@Test
@@ -80,8 +82,8 @@ class KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheckTest {
@Test
fun `test - version too high - major`() {
val androidGradlePluginVersion = AndroidGradlePluginVersion(
major = compatibleAndroidGradlePluginVersionRange.maxSupportedVersionMajor + 1,
minor = compatibleAndroidGradlePluginVersionRange.maxSupportedVersionMinor ?: 0
major = compatibleAndroidGradlePluginVersionRange.maxSupportedVersion.major + 1,
minor = compatibleAndroidGradlePluginVersionRange.maxSupportedVersion.minor
)
project.runMultiplatformAndroidGradlePluginCompatibilityHealthCheck(
@@ -98,8 +100,8 @@ class KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheckTest {
val androidGradlePluginVersion = AndroidGradlePluginVersion(2, 1)
val compatibleAndroidGradlePluginVersionRange = AndroidGradlePluginVersionRange(
minSupportedVersion = AndroidGradlePluginVersion(1, 0),
maxSupportedVersion = AndroidGradlePluginVersion(2, 0)
minSupportedVersion = AndroidGradlePluginVersionRange.Version(1, 0),
maxSupportedVersion = AndroidGradlePluginVersionRange.Version(2, 0)
)
project.runMultiplatformAndroidGradlePluginCompatibilityHealthCheck(
@@ -120,27 +122,10 @@ class KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheckTest {
)
assertEquals(
Messages.FAILED_GETTING_ANDROID_GRADLE_PLUGIN_VERSION_STRING, assertSingleWarningMessage()
Messages.failedGettingAndroidGradlePluginVersion(), assertSingleWarningMessage()
)
}
@Test
fun `test - failed parsing Android Gradle Plugin version`() {
val androidGradlePluginVersion = compatibleAndroidGradlePluginVersionRange.minSupportedVersion.toString()
val failingParser = object : AndroidGradlePluginVersionParser {
override fun parseVersionString(version: String): AndroidGradlePluginVersion? {
return null
}
}
project.runMultiplatformAndroidGradlePluginCompatibilityHealthCheck(
testLogger, FixedAndroidGradlePluginVersionProvider(androidGradlePluginVersion), failingParser
)
assertEquals(Messages.failedParsingAndroidGradlePluginVersion(androidGradlePluginVersion), assertSingleWarningMessage())
}
@Test
fun `test - nowarn property`() {
project.propertiesExtension.set(PropertiesProvider.PropertyNames.KOTLIN_MPP_ANDROID_GRADLE_PLUGIN_COMPATIBILITY_NO_WARN, "true")
@@ -158,14 +143,14 @@ class KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheckTest {
/* Test with too high AGP version */
project.runMultiplatformAndroidGradlePluginCompatibilityHealthCheck(
testLogger,
FixedAndroidGradlePluginVersionProvider("${compatibleAndroidGradlePluginVersionRange.maxSupportedVersionMajor + 1}.0")
FixedAndroidGradlePluginVersionProvider("${compatibleAndroidGradlePluginVersionRange.maxSupportedVersion.major + 1}.0")
)
assertNoWarningMessage()
/* Re-enable the check and test with missing AGP version */
project.propertiesExtension.set(PropertiesProvider.PropertyNames.KOTLIN_MPP_ANDROID_GRADLE_PLUGIN_COMPATIBILITY_NO_WARN, "false")
project.runMultiplatformAndroidGradlePluginCompatibilityHealthCheck(testLogger, FixedAndroidGradlePluginVersionProvider(null))
assertEquals(Messages.FAILED_GETTING_ANDROID_GRADLE_PLUGIN_VERSION_STRING, assertSingleWarningMessage())
assertEquals(Messages.failedGettingAndroidGradlePluginVersion(), assertSingleWarningMessage())
}
@Test
@@ -177,35 +162,34 @@ class KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheckTest {
assertNoWarningMessage()
}
val minSupportedVersion = compatibleAndroidGradlePluginVersionRange.minSupportedVersion
val minSupportedVersion = compatibleAndroidGradlePluginVersionRange.minSupportedVersion.run {
AndroidGradlePluginVersion(major, minor)
}
val midSupportedVersion = minSupportedVersion.copy(minor = minSupportedVersion.minor + 1)
val maxSupportedVersion = AndroidGradlePluginVersion(
compatibleAndroidGradlePluginVersionRange.maxSupportedVersionMajor,
compatibleAndroidGradlePluginVersionRange.maxSupportedVersionMinor ?: 0
compatibleAndroidGradlePluginVersionRange.maxSupportedVersion.major,
compatibleAndroidGradlePluginVersionRange.maxSupportedVersion.minor
)
assertNoWarnings("$minSupportedVersion")
assertNoWarnings("$minSupportedVersion.0")
assertNoWarnings("$minSupportedVersion.0-alpha01")
assertNoWarnings("$minSupportedVersion.0-m-281")
assertNoWarnings("${minSupportedVersion.copy(classifier = "alpha01")}")
assertNoWarnings("${minSupportedVersion.copy(classifier = "m281")}")
assertNoWarnings("$midSupportedVersion")
assertNoWarnings("$midSupportedVersion.0")
assertNoWarnings("$midSupportedVersion.0-alpha01")
assertNoWarnings("$midSupportedVersion.0-m-281")
assertNoWarnings("${midSupportedVersion.copy(classifier = "alpha01")})")
assertNoWarnings("${midSupportedVersion.copy(classifier = "m281")}")
assertNoWarnings("$minSupportedVersion.1")
assertNoWarnings("$minSupportedVersion.1-alpha01")
assertNoWarnings("${minSupportedVersion.copy(patch = 1)}")
assertNoWarnings("${minSupportedVersion.copy(patch = 1, classifier = "alpha01")}")
assertNoWarnings("$maxSupportedVersion")
assertNoWarnings("$maxSupportedVersion.0")
assertNoWarnings("$maxSupportedVersion.0-alpha01")
assertNoWarnings("$maxSupportedVersion.0-m-281")
assertNoWarnings("${maxSupportedVersion.copy(classifier = "alpha01")}")
assertNoWarnings("${maxSupportedVersion.copy(classifier = "m281")}")
assertNoWarnings("$maxSupportedVersion.1")
assertNoWarnings("$maxSupportedVersion.1-alpha01")
assertNoWarnings("${maxSupportedVersion.copy(patch = 1)}")
assertNoWarnings("${maxSupportedVersion.copy(patch = 1, classifier = "alpha01")}")
}
@Test
@@ -221,7 +205,7 @@ class KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheckTest {
addBuildEventsListenerRegistryMock(project)
project.plugins.apply(LibraryPlugin::class.java)
assertEquals(Messages.FAILED_GETTING_ANDROID_GRADLE_PLUGIN_VERSION_STRING, assertSingleWarningMessage())
assertEquals(Messages.failedGettingAndroidGradlePluginVersion(), assertSingleWarningMessage())
}
@Test
@@ -234,7 +218,7 @@ class KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheckTest {
testLogger, FixedAndroidGradlePluginVersionProvider(null)
)
assertEquals(Messages.FAILED_GETTING_ANDROID_GRADLE_PLUGIN_VERSION_STRING, assertSingleWarningMessage())
assertEquals(Messages.failedGettingAndroidGradlePluginVersion(), assertSingleWarningMessage())
}
@Test
@@ -249,7 +233,7 @@ class KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheckTest {
)
}
assertEquals(Messages.FAILED_GETTING_ANDROID_GRADLE_PLUGIN_VERSION_STRING, assertSingleWarningMessage())
assertEquals(Messages.failedGettingAndroidGradlePluginVersion(), assertSingleWarningMessage())
}
@Test
@@ -334,7 +318,7 @@ class KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheckTest {
assertFalse(isTooHigh(AndroidGradlePluginVersion(3, 0)))
assertFalse(isTooLow(AndroidGradlePluginVersion(4, 3)))
assertFalse(isTooHigh(AndroidGradlePluginVersion(4, 3)))
assertTrue(isTooHigh(AndroidGradlePluginVersion(4, 3)))
assertFalse(isTooLow(AndroidGradlePluginVersion(5, 0)))
}