From b5e36a3c1b9e3ac1046575020b53e5090b4f667c Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Fri, 24 Mar 2023 16:08:04 +0100 Subject: [PATCH] Allow to force values in kotlin-compiler-arguments-plugin Added readme how to use with external projects --- .../kotlin-compiler-args-properties/Readme.md | 48 ++++++++++++++++++- .../build.gradle.kts | 2 +- .../GradleKotlinCompilerArgumentsPlugin.kt | 42 +++++++++++++--- .../gradle/arguments/KotlinTaskProperties.kt | 45 ++++++++++------- 4 files changed, 111 insertions(+), 26 deletions(-) diff --git a/libraries/tools/gradle/kotlin-compiler-args-properties/Readme.md b/libraries/tools/gradle/kotlin-compiler-args-properties/Readme.md index bd29b7bddb4..b19af710881 100644 --- a/libraries/tools/gradle/kotlin-compiler-args-properties/Readme.md +++ b/libraries/tools/gradle/kotlin-compiler-args-properties/Readme.md @@ -1,3 +1,49 @@ ## Description -Contains a plugin for Gradle tests to set Kotlin arguments (api and language version) via 'gradle.properties' \ No newline at end of file +Contains a plugin for Gradle tests to set Kotlin arguments (api and language version) via 'gradle.properties' +or via `-P` command line flag. + +### Available properties + +- `kotlin.test.languageVersion` - sets `-language-version` to the given value +- `kotlin.test.apiVersion` - sets '-api-version' to the given value +- `kotlin.test.overrideUserValue` - make the best effort to override values set explicitly by the user in the build script + +### Plugin usage in the external projects + +Plugin is also possible to use not only in the tests, but on the external projects. +To do this follow these steps: +- Run `./gradlew :gradle:kotlin-compiler-args-properties:install` (short variant `./gradlew :gr:k-c-a-p:i`) +- In the external project modify `settings.gradle.kts` following way: +```kotlin +pluginManagement { + repositories { + mavenLocal() + // other repos defined by the project + } + + plugins { + id("org.jetbrains.kotlin.test.kotlin-compiler-args-properties") version "1.9.255-SNAPSHOT" + // other plugin declarations by the project + } +} +``` +- In the external project modify root `build.gradle.kts` following way: +```kotlin +plugins { + id("org.jetbrains.kotlin.test.kotlin-compiler-args-properties") + // Other plugin declarations by the project +} + +allprojects { + apply(plugin = "org.jetbrains.kotlin.test.kotlin-compiler-args-properties") + repositories { + mavenLocal() + } +} +``` + +This plugin should be also added similar way into any included build. + +**NOTE**: Build logic (for example `buildSrc`) and projects building Gradle plugins written in Kotlin should not apply this plugin, +as Gradle Kotlin runtime most probably will not be compatible with values under-the-test (for example language version '2.0'). \ No newline at end of file diff --git a/libraries/tools/gradle/kotlin-compiler-args-properties/build.gradle.kts b/libraries/tools/gradle/kotlin-compiler-args-properties/build.gradle.kts index 8803606c14f..482ab2565bf 100644 --- a/libraries/tools/gradle/kotlin-compiler-args-properties/build.gradle.kts +++ b/libraries/tools/gradle/kotlin-compiler-args-properties/build.gradle.kts @@ -7,7 +7,7 @@ plugins { dependencies { commonApi(project(":kotlin-gradle-plugin-api")) - commonApi(project(":kotlin-gradle-plugin")) + commonCompileOnly(project(":kotlin-gradle-plugin")) commonCompileOnly(gradleKotlinDsl()) } diff --git a/libraries/tools/gradle/kotlin-compiler-args-properties/src/common/kotlin/org/jetbrains/kotlin/gradle/arguments/GradleKotlinCompilerArgumentsPlugin.kt b/libraries/tools/gradle/kotlin-compiler-args-properties/src/common/kotlin/org/jetbrains/kotlin/gradle/arguments/GradleKotlinCompilerArgumentsPlugin.kt index 1fc39b0becc..f407487d32c 100644 --- a/libraries/tools/gradle/kotlin-compiler-args-properties/src/common/kotlin/org/jetbrains/kotlin/gradle/arguments/GradleKotlinCompilerArgumentsPlugin.kt +++ b/libraries/tools/gradle/kotlin-compiler-args-properties/src/common/kotlin/org/jetbrains/kotlin/gradle/arguments/GradleKotlinCompilerArgumentsPlugin.kt @@ -5,9 +5,9 @@ package org.jetbrains.kotlin.gradle.arguments -import org.gradle.api.Action import org.gradle.api.Project import org.gradle.api.plugins.ExtensionContainer +import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.provider.ProviderFactory import org.gradle.kotlin.dsl.withType @@ -30,12 +30,27 @@ class GradleKotlinCompilerArgumentsPlugin @Inject constructor( } private fun Project.configureKotlinVersions(properties: KotlinTaskProperties) { - plugins.withType().configureEach(configureTask(properties)) + plugins.withType().configureEach { + if (properties.kotlinOverrideUserValues.get()) { + forceConfigureTask(properties) + } else { + configureTask(properties) + } + } } - private fun Project.configureTask(properties: KotlinTaskProperties): Action = Action { + private fun Project.configureTask(properties: KotlinTaskProperties) { tasks.withType>().configureEach { - configureKotlinOption(properties, it.compilerOptions) + configureKotlinOptions(properties, it.compilerOptions) + } + } + + private fun Project.forceConfigureTask(properties: KotlinTaskProperties) { + // Wrapping into afterEvaluate to reduce amount of exception trying to modify value from the user-script + afterEvaluate { + tasks.withType>().configureEach { + configureKotlinOptions(properties, it.compilerOptions, true) + } } } @@ -51,8 +66,21 @@ class GradleKotlinCompilerArgumentsPlugin @Inject constructor( return extensions.projectCompilerOptions()?.apiVersion ?: providers.provider { null } } - private fun Project.configureKotlinOption(properties: KotlinTaskProperties, taskOptions: KotlinCommonCompilerOptions) { - taskOptions.languageVersion.convention(properties.kotlinLanguageVersion.orElse(projectLevelLanguageVersion())) - taskOptions.apiVersion.convention(properties.kotlinApiVersion.orElse(projectLevelApiVersion())) + private fun Project.configureKotlinOptions( + properties: KotlinTaskProperties, + taskOptions: KotlinCommonCompilerOptions, + shouldSetValue: Boolean = false + ) { + taskOptions.languageVersion.configureValue(properties.kotlinLanguageVersion.orElse(projectLevelLanguageVersion()), shouldSetValue) + taskOptions.apiVersion.configureValue(properties.kotlinApiVersion.orElse(projectLevelApiVersion()), shouldSetValue) + } + + private fun Property.configureValue( + source: Provider, + shouldSetValue: Boolean + ): Property = if (shouldSetValue) { + value(source) + } else { + convention(source) } } diff --git a/libraries/tools/gradle/kotlin-compiler-args-properties/src/common/kotlin/org/jetbrains/kotlin/gradle/arguments/KotlinTaskProperties.kt b/libraries/tools/gradle/kotlin-compiler-args-properties/src/common/kotlin/org/jetbrains/kotlin/gradle/arguments/KotlinTaskProperties.kt index c0fc288ee67..e09d38886d6 100644 --- a/libraries/tools/gradle/kotlin-compiler-args-properties/src/common/kotlin/org/jetbrains/kotlin/gradle/arguments/KotlinTaskProperties.kt +++ b/libraries/tools/gradle/kotlin-compiler-args-properties/src/common/kotlin/org/jetbrains/kotlin/gradle/arguments/KotlinTaskProperties.kt @@ -10,26 +10,37 @@ import org.gradle.api.provider.ProviderFactory import org.gradle.util.GradleVersion import org.jetbrains.kotlin.gradle.dsl.KotlinVersion -class KotlinTaskProperties(providerFactory: ProviderFactory) { - val kotlinLanguageVersion: Provider = readKotlinVersionProperty(KOTLIN_LANGUAGE_VERSION_PROPERTY, providerFactory) - val kotlinApiVersion: Provider = readKotlinVersionProperty(KOTLIN_API_VERSION_PROPERTY, providerFactory) +class KotlinTaskProperties( + private val providerFactory: ProviderFactory +) { + private val toKotlinVersionMapper: (String) -> KotlinVersion = { KotlinVersion.fromVersion(it) } + private val toBooleanMapper: (String) -> Boolean = { it.toBoolean() } + + val kotlinLanguageVersion: Provider = readProperty(KOTLIN_LANGUAGE_VERSION_PROPERTY, toKotlinVersionMapper) + val kotlinApiVersion: Provider = readProperty(KOTLIN_API_VERSION_PROPERTY, toKotlinVersionMapper) + val kotlinOverrideUserValues: Provider = readProperty(KOTLIN_OVERRIDE_USER_VALUES, toBooleanMapper).orElse(false) + + private fun readProperty( + propertyName: String, + mapper: (String) -> T + ): Provider { + return providerFactory.gradleProperty(propertyName) + .configurationCacheCompat() + .map(mapper) + } + + private fun Provider.configurationCacheCompat(): Provider { + return if (GradleVersion.current() < GradleVersion.version("7.4")) { + @Suppress("DEPRECATION") + this.forUseAtConfigurationTime() + } else { + this + } + } companion object { private const val KOTLIN_LANGUAGE_VERSION_PROPERTY = "kotlin.test.languageVersion" private const val KOTLIN_API_VERSION_PROPERTY = "kotlin.test.apiVersion" - - @Suppress("DEPRECATION") - private fun readKotlinVersionProperty(propertyName: String, providerFactory: ProviderFactory): Provider { - return if (GradleVersion.current() < GradleVersion.version("7.4")) { - providerFactory.gradleProperty(propertyName) - .forUseAtConfigurationTime() - .map { KotlinVersion.fromVersion(it as String) } - } else { - providerFactory.gradleProperty(propertyName) - .map { KotlinVersion.fromVersion(it as String) } - } - } + private const val KOTLIN_OVERRIDE_USER_VALUES = "kotlin.test.overrideUserValues" } - - } \ No newline at end of file