[Gradle] Implement BuildToolsApiVersionInconsistency diagnostic
This diagnostic checks if the Build Tools API implementation version is consistent with KGP in the case compilation goes using the old way #KT-61449 Fixed
This commit is contained in:
committed by
Space Team
parent
271d767138
commit
501c111e36
+52
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle
|
||||
import org.gradle.testkit.runner.BuildResult
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.kotlin.gradle.internals.asFinishLogMessage
|
||||
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics
|
||||
import org.jetbrains.kotlin.gradle.testbase.*
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy
|
||||
import org.jetbrains.kotlin.gradle.tasks.USING_JVM_INCREMENTAL_COMPILATION_MESSAGE
|
||||
@@ -19,6 +20,42 @@ import org.junit.jupiter.api.DisplayName
|
||||
class BuildToolsApiJvmCompilationIT : KGPBaseTest() {
|
||||
override val defaultBuildOptions = super.defaultBuildOptions.copy(runViaBuildToolsApi = true)
|
||||
|
||||
@GradleTest
|
||||
@DisplayName("Build Tools version consistency checker works if the old way of compilation is used together with the build tools API transform")
|
||||
fun versionConsistencyDiagnosticWorks(gradleVersion: GradleVersion) {
|
||||
project(
|
||||
"simpleProject", gradleVersion, buildOptions = defaultBuildOptions.copy(
|
||||
runViaBuildToolsApi = false,
|
||||
incremental = false,
|
||||
)
|
||||
) {
|
||||
build("assemble") {
|
||||
assertNoDiagnostic(KotlinToolingDiagnostics.BuildToolsApiVersionInconsistency)
|
||||
}
|
||||
enableOtherVersionBuildToolsImpl()
|
||||
buildAndFail("assemble") {
|
||||
assertHasDiagnostic(KotlinToolingDiagnostics.BuildToolsApiVersionInconsistency)
|
||||
assertOutputContains("Expected version: ${defaultBuildOptions.kotlinVersion}")
|
||||
assertOutputContains("Actual resolved version: $OTHER_KOTLIN_VERSION")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GradleTest
|
||||
@DisplayName("Build Tools version consistency checker disabled if compilation goes via the build tools api")
|
||||
fun versionConsistencyDiagnosticDisabled(gradleVersion: GradleVersion) {
|
||||
project(
|
||||
"simpleProject", gradleVersion, buildOptions = defaultBuildOptions.copy(
|
||||
incremental = false,
|
||||
)
|
||||
) {
|
||||
enableOtherVersionBuildToolsImpl()
|
||||
build("assemble") {
|
||||
assertNoDiagnostic(KotlinToolingDiagnostics.BuildToolsApiVersionInconsistency)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GradleTest
|
||||
@DisplayName("Simple project non-incremental in-process compilation")
|
||||
fun compileJvmInProcessNonIncremental(gradleVersion: GradleVersion) = testSimpleProject(
|
||||
@@ -79,4 +116,19 @@ class BuildToolsApiJvmCompilationIT : KGPBaseTest() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val OTHER_KOTLIN_VERSION = "1.9.30-dev-460"
|
||||
|
||||
private fun TestProject.enableOtherVersionBuildToolsImpl() {
|
||||
buildGradle.append(
|
||||
"""
|
||||
repositories {
|
||||
maven { setUrl("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap") }
|
||||
}
|
||||
kotlin {
|
||||
useCompilerVersion("$OTHER_KOTLIN_VERSION")
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
+31
-2
@@ -12,6 +12,7 @@ import org.gradle.api.file.FileSystemLocation
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.Classpath
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.jetbrains.kotlin.buildtools.api.CompilationService
|
||||
import org.jetbrains.kotlin.buildtools.api.jvm.ClassSnapshotGranularity
|
||||
@@ -19,13 +20,16 @@ import org.jetbrains.kotlin.buildtools.api.jvm.ClassSnapshotGranularity.CLASS_LE
|
||||
import org.jetbrains.kotlin.buildtools.api.jvm.ClassSnapshotGranularity.CLASS_MEMBER_LEVEL
|
||||
import org.jetbrains.kotlin.compilerRunner.btapi.SharedApiClassesClassLoaderProvider
|
||||
import org.jetbrains.kotlin.gradle.internal.ClassLoadersCachingBuildService
|
||||
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics
|
||||
import org.jetbrains.kotlin.gradle.plugin.diagnostics.TransformActionUsingKotlinToolingDiagnostics
|
||||
import java.io.File
|
||||
|
||||
/** Transform to create a snapshot of a classpath entry (directory or jar). */
|
||||
@CacheableTransform
|
||||
abstract class BuildToolsApiClasspathEntrySnapshotTransform : TransformAction<BuildToolsApiClasspathEntrySnapshotTransform.Parameters> {
|
||||
abstract class BuildToolsApiClasspathEntrySnapshotTransform : TransformAction<BuildToolsApiClasspathEntrySnapshotTransform.Parameters>,
|
||||
TransformActionUsingKotlinToolingDiagnostics<BuildToolsApiClasspathEntrySnapshotTransform.Parameters> {
|
||||
|
||||
abstract class Parameters : TransformParameters {
|
||||
abstract class Parameters : TransformParameters, TransformActionUsingKotlinToolingDiagnostics.Parameters {
|
||||
@get:Internal
|
||||
abstract val gradleUserHomeDir: DirectoryProperty
|
||||
|
||||
@@ -34,13 +38,38 @@ abstract class BuildToolsApiClasspathEntrySnapshotTransform : TransformAction<Bu
|
||||
|
||||
@get:Classpath
|
||||
internal abstract val classpath: ConfigurableFileCollection
|
||||
|
||||
@get:Input
|
||||
internal abstract val compilationViaBuildToolsApi: Property<Boolean>
|
||||
|
||||
@get:Internal
|
||||
internal abstract val buildToolsImplVersion: Property<String>
|
||||
|
||||
@get:Internal
|
||||
internal abstract val kgpVersion: Property<String>
|
||||
|
||||
@get:Internal
|
||||
internal abstract val suppressVersionInconsistencyChecks: Property<Boolean>
|
||||
}
|
||||
|
||||
@get:Classpath
|
||||
@get:InputArtifact
|
||||
abstract val inputArtifact: Provider<FileSystemLocation>
|
||||
|
||||
private fun checkVersionConsistency() {
|
||||
if (parameters.suppressVersionInconsistencyChecks.get()) return
|
||||
val kgpVersion = parameters.kgpVersion.get()
|
||||
val buildToolsImplVersion = parameters.buildToolsImplVersion.orNull
|
||||
.takeIf { it != "null" } // workaround for incorrect nullability of `map`
|
||||
if (kgpVersion != buildToolsImplVersion) {
|
||||
reportDiagnostic(KotlinToolingDiagnostics.BuildToolsApiVersionInconsistency(kgpVersion, buildToolsImplVersion))
|
||||
}
|
||||
}
|
||||
|
||||
override fun transform(outputs: TransformOutputs) {
|
||||
if (!parameters.compilationViaBuildToolsApi.get()) {
|
||||
checkVersionConsistency()
|
||||
}
|
||||
val classpathEntryInputDirOrJar = inputArtifact.get().asFile
|
||||
val snapshotOutputFile = outputs.file(classpathEntryInputDirOrJar.name.replace('.', '_') + "-snapshot.bin")
|
||||
|
||||
|
||||
+8
@@ -549,6 +549,13 @@ internal class PropertiesProvider private constructor(private val project: Proje
|
||||
val konanDataDir: String?
|
||||
get() = property(PropertyNames.KONAN_DATA_DIR)
|
||||
|
||||
/**
|
||||
* Allows suppressing the diagnostic [KotlinToolingDiagnostics.BuildToolsApiVersionInconsistency].
|
||||
* Required only for Kotlin repo bootstrapping.
|
||||
*/
|
||||
val suppressBuildToolsApiVersionConsistencyChecks: Boolean
|
||||
get() = booleanProperty(PropertyNames.KOTLIN_SUPPRESS_BUILD_TOOLS_API_VERSION_CONSISTENCY_CHECKS) ?: false
|
||||
|
||||
/**
|
||||
* Retrieves a comma-separated list of browsers to use when running karma tests for [target]
|
||||
* @see KOTLIN_JS_KARMA_BROWSERS
|
||||
@@ -648,6 +655,7 @@ internal class PropertiesProvider private constructor(private val project: Proje
|
||||
val KOTLIN_NATIVE_IGNORE_DISABLED_TARGETS = property("kotlin.native.ignoreDisabledTargets")
|
||||
val KOTLIN_NATIVE_SUPPRESS_EXPERIMENTAL_ARTIFACTS_DSL_WARNING = property("kotlin.native.suppressExperimentalArtifactsDslWarning")
|
||||
val KONAN_DATA_DIR = property("konan.data.dir")
|
||||
val KOTLIN_SUPPRESS_BUILD_TOOLS_API_VERSION_CONSISTENCY_CHECKS = property("kotlin.internal.suppress.buildToolsApiVersionConsistencyChecks")
|
||||
|
||||
/**
|
||||
* Internal properties: builds get big non-suppressible warning when such properties are used
|
||||
|
||||
+13
@@ -10,6 +10,8 @@ import org.jetbrains.kotlin.gradle.InternalKotlinGradlePluginApi
|
||||
import org.jetbrains.kotlin.gradle.PRESETS_DEPRECATION_MESSAGE_SUFFIX
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinSourceSetConvention.isRegisteredByKotlinSourceSetConventionAt
|
||||
import org.jetbrains.kotlin.gradle.dsl.NativeTargetShortcutTrace
|
||||
import org.jetbrains.kotlin.gradle.internal.KOTLIN_BUILD_TOOLS_API_IMPL
|
||||
import org.jetbrains.kotlin.gradle.internal.KOTLIN_MODULE_GROUP
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||
@@ -639,6 +641,17 @@ object KotlinToolingDiagnostics {
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
|
||||
object BuildToolsApiVersionInconsistency : ToolingDiagnosticFactory(FATAL) {
|
||||
operator fun invoke(expectedVersion: String, actualVersion: String?) = build(
|
||||
"""
|
||||
Artifact $KOTLIN_MODULE_GROUP:$KOTLIN_BUILD_TOOLS_API_IMPL must have version aligned with the version of KGP when compilation via the Build Tools API is disabled.
|
||||
|
||||
Expected version: $expectedVersion
|
||||
Actual resolved version: ${actualVersion ?: "not found"}
|
||||
""".trimIndent(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.indentLines(nSpaces: Int = 4, skipFirstLine: Boolean = true): String {
|
||||
|
||||
+40
-7
@@ -6,17 +6,24 @@
|
||||
package org.jetbrains.kotlin.gradle.tasks.configuration
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
|
||||
import org.gradle.api.artifacts.result.ResolvedDependencyResult
|
||||
import org.gradle.api.artifacts.transform.TransformSpec
|
||||
import org.gradle.api.attributes.Attribute
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension
|
||||
import org.jetbrains.kotlin.gradle.internal.ClassLoadersCachingBuildService
|
||||
import org.jetbrains.kotlin.gradle.internal.KOTLIN_BUILD_TOOLS_API_IMPL
|
||||
import org.jetbrains.kotlin.gradle.internal.KOTLIN_MODULE_GROUP
|
||||
import org.jetbrains.kotlin.gradle.internal.transforms.BuildToolsApiClasspathEntrySnapshotTransform
|
||||
import org.jetbrains.kotlin.gradle.plugin.BUILD_TOOLS_API_CLASSPATH_CONFIGURATION_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationInfo
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
|
||||
import org.jetbrains.kotlin.gradle.plugin.diagnostics.setupTransformActionToolingDiagnostics
|
||||
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaCompilation
|
||||
@@ -35,7 +42,8 @@ internal open class BaseKotlinCompileConfig<TASK : KotlinCompile> : AbstractKotl
|
||||
val useClasspathSnapshot = propertiesProvider.useClasspathSnapshot
|
||||
val classpathConfiguration = if (useClasspathSnapshot) {
|
||||
val jvmToolchain = taskProvider.flatMap { it.defaultKotlinJavaToolchain }
|
||||
registerTransformsOnce(project, jvmToolchain)
|
||||
val runKotlinCompilerViaBuildToolsApi = propertiesProvider.runKotlinCompilerViaBuildToolsApi
|
||||
registerTransformsOnce(project, jvmToolchain, runKotlinCompilerViaBuildToolsApi)
|
||||
// Note: Creating configurations should be done during build configuration, not task configuration, to avoid issues with
|
||||
// composite builds (e.g., https://issuetracker.google.com/183952598).
|
||||
project.configurations.detachedConfiguration(
|
||||
@@ -117,19 +125,23 @@ internal open class BaseKotlinCompileConfig<TASK : KotlinCompile> : AbstractKotl
|
||||
private fun registerTransformsOnce(
|
||||
project: Project,
|
||||
jvmToolchain: Provider<DefaultKotlinJavaToolchain>,
|
||||
runKotlinCompilerViaBuildToolsApi: Boolean,
|
||||
) {
|
||||
if (project.extensions.extraProperties.has(TRANSFORMS_REGISTERED)) {
|
||||
return
|
||||
}
|
||||
project.extensions.extraProperties[TRANSFORMS_REGISTERED] = true
|
||||
|
||||
registerBuildToolsApiTransformations(project, jvmToolchain)
|
||||
registerBuildToolsApiTransformations(project, jvmToolchain, runKotlinCompilerViaBuildToolsApi)
|
||||
}
|
||||
|
||||
private fun TransformSpec<BuildToolsApiClasspathEntrySnapshotTransform.Parameters>.configureCommonParameters(
|
||||
kgpVersion: String,
|
||||
classLoadersCachingService: Provider<ClassLoadersCachingBuildService>,
|
||||
classpath: Provider<out FileCollection>,
|
||||
classpath: Provider<out Configuration>,
|
||||
jvmToolchain: Provider<DefaultKotlinJavaToolchain>,
|
||||
runKotlinCompilerViaBuildToolsApi: Boolean,
|
||||
suppressVersionInconsistencyChecks: Boolean,
|
||||
) {
|
||||
parameters.gradleUserHomeDir.set(project.gradle.gradleUserHomeDir)
|
||||
parameters.classLoadersCachingService.set(classLoadersCachingService)
|
||||
@@ -142,20 +154,41 @@ internal open class BaseKotlinCompileConfig<TASK : KotlinCompile> : AbstractKotl
|
||||
emptySet()
|
||||
}
|
||||
})
|
||||
parameters.compilationViaBuildToolsApi.set(runKotlinCompilerViaBuildToolsApi)
|
||||
if (!suppressVersionInconsistencyChecks) {
|
||||
parameters.buildToolsImplVersion.set(classpath.map { configuration -> configuration.findBuildToolsApiImplVersion() })
|
||||
}
|
||||
parameters.kgpVersion.set(kgpVersion)
|
||||
parameters.suppressVersionInconsistencyChecks.set(suppressVersionInconsistencyChecks)
|
||||
}
|
||||
|
||||
private fun registerBuildToolsApiTransformations(project: Project, jvmToolchain: Provider<DefaultKotlinJavaToolchain>) {
|
||||
private fun Configuration.findBuildToolsApiImplVersion() = incoming.resolutionResult.allDependencies
|
||||
.filterIsInstance<ResolvedDependencyResult>()
|
||||
.map { it.selected.id }
|
||||
.filterIsInstance<ModuleComponentIdentifier>()
|
||||
.find { it.group == KOTLIN_MODULE_GROUP && it.module == KOTLIN_BUILD_TOOLS_API_IMPL }
|
||||
?.version ?: "null" // workaround for incorrect nullability of `map`
|
||||
|
||||
private fun registerBuildToolsApiTransformations(
|
||||
project: Project,
|
||||
jvmToolchain: Provider<DefaultKotlinJavaToolchain>,
|
||||
runKotlinCompilerViaBuildToolsApi: Boolean
|
||||
) {
|
||||
val classLoadersCachingService = ClassLoadersCachingBuildService.registerIfAbsent(project)
|
||||
val classpath = project.configurations.named(BUILD_TOOLS_API_CLASSPATH_CONFIGURATION_NAME)
|
||||
val kgpVersion = project.getKotlinPluginVersion()
|
||||
val suppressVersionInconsistencyChecks = project.kotlinPropertiesProvider.suppressBuildToolsApiVersionConsistencyChecks
|
||||
project.dependencies.registerTransform(BuildToolsApiClasspathEntrySnapshotTransform::class.java) {
|
||||
it.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, JAR_ARTIFACT_TYPE)
|
||||
it.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE)
|
||||
it.configureCommonParameters(classLoadersCachingService, classpath, jvmToolchain)
|
||||
it.configureCommonParameters(kgpVersion, classLoadersCachingService, classpath, jvmToolchain, runKotlinCompilerViaBuildToolsApi, suppressVersionInconsistencyChecks)
|
||||
it.setupTransformActionToolingDiagnostics(project)
|
||||
}
|
||||
project.dependencies.registerTransform(BuildToolsApiClasspathEntrySnapshotTransform::class.java) {
|
||||
it.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, DIRECTORY_ARTIFACT_TYPE)
|
||||
it.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE)
|
||||
it.configureCommonParameters(classLoadersCachingService, classpath, jvmToolchain)
|
||||
it.configureCommonParameters(kgpVersion, classLoadersCachingService, classpath, jvmToolchain, runKotlinCompilerViaBuildToolsApi, suppressVersionInconsistencyChecks)
|
||||
it.setupTransformActionToolingDiagnostics(project)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user