[kotlin] Gradle: Add reliable 'kotlinGradlePluginVersion'

Previously, there were just some heuristics available to infer the
current Kotlin Gradle Plugin version used for a given Module.

The Kotlin Gradle Plugin version is exactly known during the
Gradle sync and now stored in the Project Data.

^KTIJ-23814 Verification Pending
^KTIJ-31125 Verification Pending

GitOrigin-RevId: 8f10ef728a89485d9aeeaebb0ee0780686f8dbdd
This commit is contained in:
Sebastian Sellmair
2024-09-16 16:11:05 +00:00
committed by intellij-monorepo-bot
parent a8681e4566
commit 5cf2c1c66b
8 changed files with 153 additions and 1 deletions
@@ -126,6 +126,7 @@ class KotlinGradleProjectResolverExtension : AbstractProjectResolverExtension()
pureKotlinSourceFolders.addAll(
gradleModel.kotlinTaskProperties.flatMap { it.value.pureKotlinSourceFolders ?: emptyList() }.map { it.absolutePath }
)
kotlinGradlePluginVersion = gradleModel.kotlinGradlePluginVersion
mainModuleNode.createChild(KotlinGradleProjectData.KEY, this)
}
if (gradleModel.hasKotlinPlugin) {
@@ -223,6 +223,7 @@ private fun KotlinMppGradleProjectResolver.Context.initializeModuleData() {
}
}
KotlinGradleProjectData().apply {
kotlinGradlePluginVersion = mppModel.kotlinGradlePluginVersion
kotlinNativeHome = mppModel.kotlinNativeHome
coroutines = mppModel.extraFeatures.coroutinesState
isHmpp = mppModel.extraFeatures.isHMPPEnabled
@@ -0,0 +1,48 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.gradleJava
import com.intellij.openapi.module.Module
import org.jetbrains.kotlin.idea.gradleJava.configuration.kotlinGradleProjectDataNodeOrNull
import org.jetbrains.kotlin.idea.gradleTooling.KotlinGradlePluginVersion
import org.jetbrains.plugins.gradle.execution.build.CachedModuleDataFinder
/**
* Returns the Kotlin Gradle Plugin version reported directly by the Kotlin Gradle Sync.
* e.g.
* ```kotlin
* //build.gradle.kts
*
* plugins {
* kotlin("jvm") version "2.0.20-Beta01"
* }
* ```
* Will return "2.0.20-Beta01" as
* major: 2
* minor: 0
* patch: 20
* versionString: ""2.0.20-Beta01"
*
* See [KotlinGradlePluginVersion].
*
*
* Example Usage
* ```kotlin
* fun example(module: Module) {
* val version = module.kotlinGradlePluginVersion ?: return
* if(version >= "1.9.20-Beta01") {
* // Code
* }
*
* if(version >= KotlinToolingVersion(1, 9, 20, "Beta01")) {
* // Code
* }
* }
* ```
*
*/
val Module.kotlinGradlePluginVersion: KotlinGradlePluginVersion?
get() {
val dataNode = CachedModuleDataFinder.findMainModuleData(this) ?: return null
val projectDataNode = dataNode.kotlinGradleProjectDataNodeOrNull ?: return null
return projectDataNode.data.kotlinGradlePluginVersion
}
@@ -0,0 +1,86 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.gradle
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.vfs.writeText
import org.jetbrains.kotlin.idea.codeInsight.gradle.MultiplePluginVersionGradleImportingTestCase
import org.jetbrains.kotlin.idea.gradleJava.kotlinGradlePluginVersion
import org.jetbrains.kotlin.idea.gradleTooling.toKotlinToolingVersion
import org.jetbrains.plugins.gradle.tooling.annotation.TargetVersions
import org.junit.Test
class KotlinGradlePluginVersionImportTest : MultiplePluginVersionGradleImportingTestCase() {
@Test
@TargetVersions("7.6+")
fun testJvm() {
ApplicationManager.getApplication().runWriteAction {
createProjectSubFile("settings.gradle.kts").writeText(
"""
pluginManagement {
repositories {
${repositories(true)}
}
}
""".trimIndent()
)
createProjectSubFile("build.gradle.kts").writeText(
"""
plugins {
kotlin("jvm") version "$kotlinPluginVersion"
}
repositories {
${repositories(true)}
}
""".trimIndent()
)
}
importProject(true)
assertEquals(kotlinPluginVersion, getModule("project.main").kotlinGradlePluginVersion?.toKotlinToolingVersion())
}
@Test
@TargetVersions("7.6+")
fun testKmp() {
ApplicationManager.getApplication().runWriteAction {
createProjectSubFile("settings.gradle.kts").writeText(
"""
pluginManagement {
repositories {
${repositories(true)}
}
}
""".trimIndent()
)
createProjectSubFile("build.gradle.kts").writeText(
"""
plugins {
kotlin("multiplatform") version "$kotlinPluginVersion"
}
repositories {
${repositories(true)}
}
kotlin {
jvm()
linuxX64()
}
""".trimIndent()
)
}
importProject(true)
listOf("project", "project.jvmMain", "project.jvmTest", "project.linuxX64Main", "project.linuxX64Test").forEach { moduleName ->
assertEquals(
"Expected $kotlinPluginVersion for module $moduleName, got ${getModule(moduleName).kotlinGradlePluginVersion}",
kotlinPluginVersion, getModule(moduleName).kotlinGradlePluginVersion?.toKotlinToolingVersion())
}
}
}
@@ -13,8 +13,8 @@ import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.provider.Property
import org.gradle.tooling.BuildController
import org.gradle.tooling.model.gradle.BasicGradleProject
import org.gradle.tooling.model.gradle.GradleBuild
import org.jetbrains.kotlin.idea.gradleTooling.reflect.KotlinExtensionReflection
import org.jetbrains.kotlin.idea.projectModel.KotlinTaskProperties
import org.jetbrains.kotlin.tooling.core.Interner
import org.jetbrains.plugins.gradle.model.ProjectImportModelProvider
@@ -41,6 +41,7 @@ interface KotlinGradleModel : Serializable {
val kotlinTarget: String?
val kotlinTaskProperties: KotlinTaskPropertiesBySourceSet
val gradleUserHome: String
val kotlinGradlePluginVersion: KotlinGradlePluginVersion?
}
data class KotlinGradleModelImpl(
@@ -53,6 +54,7 @@ data class KotlinGradleModelImpl(
override val kotlinTarget: String? = null,
override val kotlinTaskProperties: KotlinTaskPropertiesBySourceSet,
override val gradleUserHome: String,
override val kotlinGradlePluginVersion: KotlinGradlePluginVersion?
) : KotlinGradleModel
abstract class AbstractKotlinGradleModelBuilder : ModelBuilderService {
@@ -252,6 +254,7 @@ class KotlinGradleModelBuilder : AbstractKotlinGradleModelBuilder(), ModelBuilde
kotlinTarget = platform ?: kotlinPluginId,
kotlinTaskProperties = extraProperties,
gradleUserHome = project.gradle.gradleUserHomeDir.absolutePath,
kotlinGradlePluginVersion = project.kotlinGradlePluginVersion()
)
}
@@ -291,4 +294,10 @@ class KotlinGradleModelBuilder : AbstractKotlinGradleModelBuilder(), ModelBuilde
}
}
}
private fun Project.kotlinGradlePluginVersion(): KotlinGradlePluginVersion? {
val extension = project.extensions.findByName("kotlin") ?: return null
val kotlinGradlePluginVersionString = KotlinExtensionReflection(project, extension).kotlinGradlePluginVersion ?: return null
return KotlinGradlePluginVersion.parse(kotlinGradlePluginVersionString)
}
}
@@ -7,6 +7,10 @@ import org.jetbrains.kotlin.tooling.core.KotlinToolingVersion
import org.jetbrains.kotlin.tooling.core.KotlinToolingVersionOrNull
import java.io.Serializable
/**
* Wrapper around the [KotlinToolingVersion].
* Comparisons (e.g. [compareTo] are expected to work fine granular and will respect maturity classifiers (e.g. "beta01, "RC", ...)
*/
sealed interface KotlinGradlePluginVersion : Serializable {
val versionString: String
val major: Int
@@ -13,6 +13,7 @@ import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.util.IntellijInternalApi
import com.intellij.serialization.PropertyMapping
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.idea.gradleTooling.KotlinGradlePluginVersion
import org.jetbrains.kotlin.idea.gradleTooling.KotlinImportingDiagnostic
import org.jetbrains.plugins.gradle.util.GradleConstants
import java.io.Serializable
@@ -22,6 +23,7 @@ interface ImplementedModulesAware : Serializable {
}
class KotlinGradleProjectData : AbstractExternalEntityData(GradleConstants.SYSTEM_ID), ImplementedModulesAware {
var kotlinGradlePluginVersion: KotlinGradlePluginVersion? = null
var isResolved: Boolean = false
var kotlinTarget: String? = null
var hasKotlinPlugin: Boolean = false
@@ -467,6 +467,7 @@ private const val GROUP_WITH_KOTLIN_VERSION = 2
typealias ModulesNamesAndFirstSourceRootModules = Map<String, Module>
typealias KotlinVersionsAndModules = Map<String, ModulesNamesAndFirstSourceRootModules>
@Deprecated("Use org.jetbrains.kotlin.idea.gradleJava.kotlinGradlePluginVersion instead")
fun Module.getGradleKotlinVersion(): String? {
return getKotlinCompilerArguments(this)?.pluginClasspaths?.let { pluginsClasspaths ->
pluginsClasspaths.firstOrNull { it.contains(ARTIFACT_NAME) }?.let {