From 50f5fadfd8a41ba72d9176883c797adb82584d9f Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Tue, 18 Apr 2023 19:49:18 +0200 Subject: [PATCH] Expose task input to control jvm target validation mode ^KT-56971 Fixed --- .../api/kotlin-gradle-plugin-api.api | 9 +++++ .../gradle/dsl/jvm/JvmTargetValidationMode.kt | 30 ++++++++++++++ .../kotlin/gradle/tasks/KotlinTaskConfigs.kt | 23 +++++++++++ .../kotlin/gradle/JvmTargetValidationTest.kt | 39 +++++++++++++++++++ .../gradle/plugin/PropertiesProvider.kt | 5 +-- .../kotlin/gradle/tasks/KotlinCompile.kt | 14 +++---- .../configuration/KotlinCompileConfig.kt | 2 +- 7 files changed, 110 insertions(+), 12 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/jvm/JvmTargetValidationMode.kt diff --git a/libraries/tools/kotlin-gradle-plugin-api/api/kotlin-gradle-plugin-api.api b/libraries/tools/kotlin-gradle-plugin-api/api/kotlin-gradle-plugin-api.api index 1eaa8b1994c..207f1ab78af 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/api/kotlin-gradle-plugin-api.api +++ b/libraries/tools/kotlin-gradle-plugin-api/api/kotlin-gradle-plugin-api.api @@ -563,6 +563,14 @@ public final class org/jetbrains/kotlin/gradle/dsl/KotlinVersion$Companion { public final fun getDEFAULT ()Lorg/jetbrains/kotlin/gradle/dsl/KotlinVersion; } +public final class org/jetbrains/kotlin/gradle/dsl/jvm/JvmTargetValidationMode : java/lang/Enum { + public static final field ERROR Lorg/jetbrains/kotlin/gradle/dsl/jvm/JvmTargetValidationMode; + public static final field IGNORE Lorg/jetbrains/kotlin/gradle/dsl/jvm/JvmTargetValidationMode; + public static final field WARNING Lorg/jetbrains/kotlin/gradle/dsl/jvm/JvmTargetValidationMode; + public static fun valueOf (Ljava/lang/String;)Lorg/jetbrains/kotlin/gradle/dsl/jvm/JvmTargetValidationMode; + public static fun values ()[Lorg/jetbrains/kotlin/gradle/dsl/jvm/JvmTargetValidationMode; +} + public abstract class org/jetbrains/kotlin/gradle/plugin/AbstractCompileWithDependenciesTracking : org/gradle/api/tasks/compile/AbstractCompile { public fun ()V public fun isDependentTaskOutOfDate (Lorg/gradle/api/Task;)Z @@ -1607,6 +1615,7 @@ public final class org/jetbrains/kotlin/gradle/tasks/KotlinJavaToolchain$JdkSett } public abstract interface class org/jetbrains/kotlin/gradle/tasks/KotlinJvmCompile : org/jetbrains/kotlin/gradle/dsl/KotlinCompile, org/jetbrains/kotlin/gradle/tasks/BaseKotlinCompile, org/jetbrains/kotlin/gradle/tasks/KotlinCompilationTask { + public abstract fun getJvmTargetValidationMode ()Lorg/gradle/api/provider/Property; public abstract fun getModuleName ()Lorg/gradle/api/provider/Property; public abstract fun getParentKotlinOptions ()Lorg/gradle/api/provider/Property; } diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/jvm/JvmTargetValidationMode.kt b/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/jvm/JvmTargetValidationMode.kt new file mode 100644 index 00000000000..4693d64af14 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/jvm/JvmTargetValidationMode.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2010-2023 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.dsl.jvm + +/** + * Controls JVM target validation mode between Kotlin JVM compilation task from this plugin and related Java compilation task from Gradle. + * + * See [org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile.jvmTargetValidationMode] for more details. + * + * @since 1.9.0 + */ +enum class JvmTargetValidationMode { + /** + * Ignores JVM target mismatches and proceeds with compilation. + */ + IGNORE, + + /** + * Produces a warning message in the console output on JVM target mismatch and proceeds with compilation. + */ + WARNING, + + /** + * Throws an exception on JVM target mismatch and stops execution. + */ + ERROR, +} diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinTaskConfigs.kt b/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinTaskConfigs.kt index 1a20755381e..ff5cb139537 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinTaskConfigs.kt +++ b/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinTaskConfigs.kt @@ -16,6 +16,7 @@ import org.gradle.api.tasks.util.PatternFilterable import org.gradle.work.Incremental import org.gradle.work.NormalizeLineEndings import org.jetbrains.kotlin.gradle.dsl.* +import org.jetbrains.kotlin.gradle.dsl.jvm.JvmTargetValidationMode import org.jetbrains.kotlin.gradle.plugin.CompilerPluginConfig interface KotlinCompileTool : PatternFilterable, Task { @@ -96,6 +97,28 @@ interface KotlinJvmCompile : BaseKotlinCompile, replaceWith = ReplaceWith("compilerOptions") ) val parentKotlinOptions: Property + + /** + * Controls JVM target validation mode between this task and the Java compilation task from Gradle for the same source set. + * + * The same JVM targets ensure that the produced jar file contains class files of the same JVM bytecode version, + * which is important to avoid compatibility issues for the code consumers. + * + * Also, Gradle Java compilation task [org.gradle.api.tasks.compile.JavaCompile.targetCompatibility] controls value + * of "org.gradle.jvm.version" [attribute](https://docs.gradle.org/current/javadoc/org/gradle/api/attributes/java/TargetJvmVersion.html) + * which itself controls the produced artifact minimal supported JVM version via + * [Gradle Module Metadata](https://docs.gradle.org/current/userguide/publishing_gradle_module_metadata.html). + * This allows Gradle to check compatibility of dependencies at dependency resolution time. + * + * To avoid problems with different targets we advise to use [JDK Toolchain](https://kotl.in/gradle/jvm/toolchain) feature. + * + * Default value for builds with Gradle <8.0 is [JvmTargetValidationMode.WARNING], + * while for builds with Gradle 8.0+ it is [JvmTargetValidationMode.ERROR]. + * + * @since 1.9.0 + */ + @get:Input + val jvmTargetValidationMode: Property } interface KaptGenerateStubs : KotlinJvmCompile { diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/JvmTargetValidationTest.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/JvmTargetValidationTest.kt index 99fa22450c0..d1dd3203708 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/JvmTargetValidationTest.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/JvmTargetValidationTest.kt @@ -51,6 +51,45 @@ class JvmTargetValidationTest : KGPBaseTest() { } } + @DisplayName("Should allow to override validation mode for specific task") + @GradleTest + internal fun overrideModeForTask(gradleVersion: GradleVersion) { + project( + projectName = "kotlinJavaProject".fullProjectName, + gradleVersion = gradleVersion, + buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.WARN) + ) { + setJavaCompilationCompatibility(JavaVersion.VERSION_1_8) + useToolchainToCompile(11) + + gradleProperties.append( + """ + kotlin.jvm.target.validation.mode = error + """.trimIndent() + ) + + buildGradle.appendText( + //language=groovy + """ + | + |tasks.named("compileKotlin", org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile.class) { + | jvmTargetValidationMode.set(org.jetbrains.kotlin.gradle.dsl.jvm.JvmTargetValidationMode.IGNORE) + |} + """.trimMargin() + ) + + build("assemble") { + assertOutputDoesNotContain( + "'compileJava' task (current target is 1.8) and 'compileKotlin' task (current target is 11) jvm target compatibility " + + "should be set to the same Java version.\n" + + "By default will become an error since Gradle 8.0+! " + + "Read more: https://kotl.in/gradle/jvm/target-validation\n" + + "Consider using JVM toolchain: https://kotl.in/gradle/jvm/toolchain" + ) + } + } + } + @DisplayName("Should warn in the build log if verification mode is 'warning' and kotlin and java targets are different") @GradleTest internal fun shouldWarnBuildIfJavaAndKotlinJvmTargetsAreDifferent(gradleVersion: GradleVersion) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt index 518eed38c1d..9ed449a1b05 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.cli.common.CompilerSystemProperties import org.jetbrains.kotlin.cli.common.toBooleanLenient import org.jetbrains.kotlin.gradle.dsl.NativeCacheKind import org.jetbrains.kotlin.gradle.dsl.NativeCacheOrchestration +import org.jetbrains.kotlin.gradle.dsl.jvm.JvmTargetValidationMode import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessageOutputStreamHandler.Companion.IGNORE_TCSM_OVERFLOW import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType.Companion.jsCompilerProperty import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_JS_STDLIB_DOM_API_INCLUDED @@ -479,10 +480,6 @@ internal class PropertiesProvider private constructor(private val project: Proje val kotlinOptionsSuppressFreeArgsModificationWarning: Boolean get() = booleanProperty(PropertyNames.KOTLIN_OPTIONS_SUPPRESS_FREEARGS_MODIFICATION_WARNING) ?: false - enum class JvmTargetValidationMode { - IGNORE, WARNING, ERROR - } - val jvmTargetValidationMode: JvmTargetValidationMode get() = enumProperty( "kotlin.jvm.target.validation.mode", diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompile.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompile.kt index 43695cf73f8..e41f0a5a8f9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompile.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompile.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptionsHelper import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions +import org.jetbrains.kotlin.gradle.dsl.jvm.JvmTargetValidationMode import org.jetbrains.kotlin.gradle.dsl.usesK2 import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles import org.jetbrains.kotlin.gradle.logging.GradleErrorMessageCollector @@ -39,7 +40,6 @@ import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.CreateCompilerArgumentsContext.Companion.create -import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion import org.jetbrains.kotlin.gradle.report.BuildReportMode import org.jetbrains.kotlin.gradle.tasks.internal.KotlinJvmOptionsCompat @@ -165,9 +165,6 @@ abstract class KotlinCompile @Inject constructor( @get:Internal internal abstract val associatedJavaCompileTaskName: Property - @get:Input - internal abstract val jvmTargetValidationMode: Property - @get:Internal internal val nagTaskModuleNameUsage: Property = objectFactory.propertyWithConvention(false) @@ -368,6 +365,9 @@ abstract class KotlinCompile @Inject constructor( private fun validateKotlinAndJavaHasSameTargetCompatibility( args: K2JVMCompilerArguments, ) { + val jvmTargetValidationMode: JvmTargetValidationMode = jvmTargetValidationMode.get() + if (jvmTargetValidationMode == JvmTargetValidationMode.IGNORE) return + associatedJavaCompileTaskTargetCompatibility.orNull?.let { targetCompatibility -> val normalizedJavaTarget = when (targetCompatibility) { "6" -> "1.6" @@ -392,9 +392,9 @@ abstract class KotlinCompile @Inject constructor( appendLine("Consider using JVM toolchain: https://kotl.in/gradle/jvm/toolchain") } - when (jvmTargetValidationMode.get()) { - PropertiesProvider.JvmTargetValidationMode.ERROR -> throw GradleException(errorMessage) - PropertiesProvider.JvmTargetValidationMode.WARNING -> logger.warn(errorMessage) + when (jvmTargetValidationMode) { + JvmTargetValidationMode.ERROR -> throw GradleException(errorMessage) + JvmTargetValidationMode.WARNING -> logger.warn(errorMessage) else -> Unit } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt index 3bef6e135ff..5c6c2ba18c5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt @@ -43,7 +43,7 @@ internal open class BaseKotlinCompileConfig : AbstractKotl taskProvider.configure { task -> task.incremental = propertiesProvider.incrementalJvm ?: true task.usePreciseJavaTracking = propertiesProvider.usePreciseJavaTracking ?: true - task.jvmTargetValidationMode.set(propertiesProvider.jvmTargetValidationMode) + task.jvmTargetValidationMode.convention(propertiesProvider.jvmTargetValidationMode).finalizeValueOnRead() task.useKotlinAbiSnapshot.value(propertiesProvider.useKotlinAbiSnapshot).disallowChanges() task.classpathSnapshotProperties.useClasspathSnapshot.value(useClasspathSnapshot).disallowChanges()