diff --git a/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/configuration/KotlinGradleProjectResolverExtension.kt b/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/configuration/KotlinGradleProjectResolverExtension.kt index 20f84e876498..130aaa318af0 100644 --- a/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/configuration/KotlinGradleProjectResolverExtension.kt +++ b/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/configuration/KotlinGradleProjectResolverExtension.kt @@ -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) { diff --git a/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/configuration/mpp/populateMppModuleDataNode.kt b/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/configuration/mpp/populateMppModuleDataNode.kt index 52300607247b..c2f0a6ba8662 100644 --- a/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/configuration/mpp/populateMppModuleDataNode.kt +++ b/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/configuration/mpp/populateMppModuleDataNode.kt @@ -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 diff --git a/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/kotlinGradlePluginVersion.kt b/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/kotlinGradlePluginVersion.kt new file mode 100644 index 000000000000..1729ea44dfd1 --- /dev/null +++ b/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/kotlinGradlePluginVersion.kt @@ -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 + } diff --git a/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/gradle/KotlinGradlePluginVersionImportTest.kt b/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/gradle/KotlinGradlePluginVersionImportTest.kt new file mode 100644 index 000000000000..7790bb00ef4c --- /dev/null +++ b/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/gradle/KotlinGradlePluginVersionImportTest.kt @@ -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()) + } + } +} \ No newline at end of file diff --git a/plugins/kotlin/gradle/gradle-tooling/impl/src/org/jetbrains/kotlin/idea/gradleTooling/KotlinGradleModelBuilder.kt b/plugins/kotlin/gradle/gradle-tooling/impl/src/org/jetbrains/kotlin/idea/gradleTooling/KotlinGradleModelBuilder.kt index 16d7d20abd22..b258375bb27a 100644 --- a/plugins/kotlin/gradle/gradle-tooling/impl/src/org/jetbrains/kotlin/idea/gradleTooling/KotlinGradleModelBuilder.kt +++ b/plugins/kotlin/gradle/gradle-tooling/impl/src/org/jetbrains/kotlin/idea/gradleTooling/KotlinGradleModelBuilder.kt @@ -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) + } } diff --git a/plugins/kotlin/gradle/gradle-tooling/impl/src/org/jetbrains/kotlin/idea/gradleTooling/KotlinGradlePluginVersion.kt b/plugins/kotlin/gradle/gradle-tooling/impl/src/org/jetbrains/kotlin/idea/gradleTooling/KotlinGradlePluginVersion.kt index 793a8fb2b6ae..c5d57b8471bd 100644 --- a/plugins/kotlin/gradle/gradle-tooling/impl/src/org/jetbrains/kotlin/idea/gradleTooling/KotlinGradlePluginVersion.kt +++ b/plugins/kotlin/gradle/gradle-tooling/impl/src/org/jetbrains/kotlin/idea/gradleTooling/KotlinGradlePluginVersion.kt @@ -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 diff --git a/plugins/kotlin/gradle/gradle/src/org/jetbrains/kotlin/idea/gradle/configuration/KotlinDataNodes.kt b/plugins/kotlin/gradle/gradle/src/org/jetbrains/kotlin/idea/gradle/configuration/KotlinDataNodes.kt index 62b15759630d..588821603374 100644 --- a/plugins/kotlin/gradle/gradle/src/org/jetbrains/kotlin/idea/gradle/configuration/KotlinDataNodes.kt +++ b/plugins/kotlin/gradle/gradle/src/org/jetbrains/kotlin/idea/gradle/configuration/KotlinDataNodes.kt @@ -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 diff --git a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt index b08e86c02754..4436cc736aab 100644 --- a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt +++ b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt @@ -467,6 +467,7 @@ private const val GROUP_WITH_KOTLIN_VERSION = 2 typealias ModulesNamesAndFirstSourceRootModules = Map typealias KotlinVersionsAndModules = Map +@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 {