Warning for Kotlin plugins loaded multiple times (KT-30276)
Print a warning with an instruction on how to fix this. Don't warn about different versions and duplicate plugins in composite build. Issue #KT-30276 Fixed
This commit is contained in:
+68
@@ -17,6 +17,8 @@
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.jetbrains.kotlin.gradle.plugin.MULTIPLE_KOTLIN_PLUGINS_LOADED_WARNING
|
||||
import org.jetbrains.kotlin.gradle.plugin.MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_WARNING
|
||||
import org.jetbrains.kotlin.gradle.tasks.USING_JVM_INCREMENTAL_COMPILATION_MESSAGE
|
||||
import org.jetbrains.kotlin.gradle.util.*
|
||||
import org.junit.Test
|
||||
@@ -823,4 +825,70 @@ class KotlinGradleIT : BaseGradleIT() {
|
||||
assertTasksExecuted(":jvm-app:compileKotlin")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDetectingDifferentClassLoaders() = with(Project("kt-27059-pom-rewriting", GradleVersionRequired.AtLeast("4.10.2"))) {
|
||||
setupWorkingDir()
|
||||
|
||||
val originalRootBuildScript = gradleBuildScript().readText()
|
||||
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
|
||||
|
||||
build("publish", "-PmppProjectDependency=true") {
|
||||
assertSuccessful()
|
||||
assertNotContains(MULTIPLE_KOTLIN_PLUGINS_LOADED_WARNING)
|
||||
assertNotContains(MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_WARNING)
|
||||
}
|
||||
|
||||
// Specify the plugin versions in the subprojects with different plugin sets – this will make Gradle use separate class loaders
|
||||
gradleBuildScript().modify {
|
||||
originalRootBuildScript.checkedReplace("id \"org.jetbrains.kotlin.multiplatform\"", "//")
|
||||
}
|
||||
gradleBuildScript("mpp-lib").modify {
|
||||
it.checkedReplace(
|
||||
"id \"org.jetbrains.kotlin.multiplatform\"",
|
||||
"id \"org.jetbrains.kotlin.multiplatform\" version \"<pluginMarkerVersion>\""
|
||||
).let(::transformBuildScriptWithPluginsDsl)
|
||||
}
|
||||
gradleBuildScript("jvm-app").modify {
|
||||
it.checkedReplace(
|
||||
"id \"org.jetbrains.kotlin.jvm\"",
|
||||
"id \"org.jetbrains.kotlin.jvm\" version \"<pluginMarkerVersion>\""
|
||||
).let(::transformBuildScriptWithPluginsDsl)
|
||||
}
|
||||
gradleBuildScript("js-app").modify {
|
||||
it.checkedReplace(
|
||||
"id \"kotlin2js\"",
|
||||
"id \"kotlin2js\" version \"<pluginMarkerVersion>\""
|
||||
).let(::transformBuildScriptWithPluginsDsl)
|
||||
}
|
||||
|
||||
// Also include another project via a composite build:
|
||||
transformProjectWithPluginsDsl("allopenPluginsDsl", directoryPrefix = "pluginsDsl").let { other ->
|
||||
val result = other.projectName
|
||||
other.setupWorkingDir()
|
||||
other.projectDir.copyRecursively(projectDir.resolve(result))
|
||||
gradleSettingsScript().appendText("\nincludeBuild(\"${result}\")")
|
||||
gradleBuildScript().appendText(
|
||||
"\ntasks.create(\"publish\").dependsOn(gradle.includedBuild(\"${result}\").task(\":assemble\"))"
|
||||
)
|
||||
result
|
||||
}
|
||||
|
||||
build("publish", "-PmppProjectDependency=true") {
|
||||
assertSuccessful()
|
||||
assertContains(MULTIPLE_KOTLIN_PLUGINS_LOADED_WARNING)
|
||||
|
||||
val specificProjectsReported = Regex("$MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_WARNING((?:'.*'(?:, )?)+)")
|
||||
.find(output)!!.groupValues[1].split(", ").map { it.removeSurrounding("'") }.toSet()
|
||||
|
||||
assertEquals(setOf(":mpp-lib", ":jvm-app", ":js-app"), specificProjectsReported)
|
||||
}
|
||||
|
||||
// Test the flag that turns off the warnings
|
||||
build("publish", "-PmppProjectDependency=true", "-Pkotlin.pluginLoadedInMultipleProjects.ignore=true") {
|
||||
assertSuccessful()
|
||||
assertNotContains(MULTIPLE_KOTLIN_PLUGINS_LOADED_WARNING)
|
||||
assertNotContains(MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_WARNING)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+56
-7
@@ -18,23 +18,19 @@ package org.jetbrains.kotlin.gradle.plugin
|
||||
|
||||
import org.gradle.BuildAdapter
|
||||
import org.gradle.BuildResult
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.invocation.Gradle
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.gradle.api.plugins.ExtraPropertiesExtension
|
||||
import org.jetbrains.kotlin.compilerRunner.DELETED_SESSION_FILE_PREFIX
|
||||
import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner
|
||||
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskLoggers
|
||||
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
||||
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults
|
||||
import org.jetbrains.kotlin.gradle.report.KotlinBuildReporter
|
||||
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskLoggers
|
||||
import org.jetbrains.kotlin.gradle.report.configureBuildReporter
|
||||
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.utils.relativeToRoot
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.sumByLong
|
||||
import java.io.File
|
||||
import java.lang.management.ManagementFactory
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
internal class KotlinGradleBuildServices private constructor(
|
||||
private val gradle: Gradle
|
||||
@@ -137,5 +133,58 @@ internal class KotlinGradleBuildServices private constructor(
|
||||
|
||||
private fun getGcCount(): Long =
|
||||
ManagementFactory.getGarbageCollectorMXBeans().sumByLong { Math.max(0, it.collectionCount) }
|
||||
|
||||
private var loadedInProjectPath: String? = null
|
||||
|
||||
@Synchronized
|
||||
internal fun detectKotlinPluginLoadedInMultipleProjects(project: Project, kotlinPluginVersion: String) {
|
||||
val projectPath = project.path
|
||||
|
||||
val loadedInProjectsPropertyName = "kotlin.plugin.loaded.in.projects.${kotlinPluginVersion}"
|
||||
|
||||
if (loadedInProjectPath == null) {
|
||||
loadedInProjectPath = projectPath
|
||||
|
||||
val ext = project.rootProject.extensions.getByType(ExtraPropertiesExtension::class.java)
|
||||
|
||||
if (!ext.has(loadedInProjectsPropertyName)) {
|
||||
ext.set(loadedInProjectsPropertyName, projectPath)
|
||||
|
||||
gradle.taskGraph.whenReady {
|
||||
val loadedInProjects = (ext.get(loadedInProjectsPropertyName) as String).split(";")
|
||||
if (loadedInProjects.size > 1) {
|
||||
if (PropertiesProvider(project).ignorePluginLoadedInMultipleProjects != true) {
|
||||
project.logger.warn(MULTIPLE_KOTLIN_PLUGINS_LOADED_WARNING)
|
||||
project.logger.warn(
|
||||
MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_WARNING + loadedInProjects.joinToString(limit = 4) { "'$it'" }
|
||||
)
|
||||
}
|
||||
project.logger.info(
|
||||
"$MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_INFO: " +
|
||||
loadedInProjects.joinToString { "'$it'" }
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ext.set(loadedInProjectsPropertyName, (ext.get(loadedInProjectsPropertyName) as String) + ";" + loadedInProjectPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const val MULTIPLE_KOTLIN_PLUGINS_LOADED_WARNING: String =
|
||||
"\nThe Kotlin Gradle plugin was loaded multiple times in different subprojects, which is not supported and may break the build. \n" +
|
||||
|
||||
"This might happen in subprojects that apply the Kotlin plugins with the Gradle 'plugins { ... }' DSL if they specify " +
|
||||
"explicit versions, even if the versions are equal.\n" +
|
||||
|
||||
"Please add the Kotlin plugin to the common parent project or the root project, then remove the versions in the subprojects.\n" +
|
||||
|
||||
"If the parent project does not need the plugin, add 'apply false' to the plugin line.\n" +
|
||||
|
||||
"See: https://docs.gradle.org/current/userguide/plugins.html#sec:subprojects_plugins_dsl"
|
||||
|
||||
const val MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_WARNING: String =
|
||||
"The Kotlin plugin was loaded in the following projects: "
|
||||
|
||||
const val MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_INFO: String = "The full list of projects that loaded the Kotlin plugin is: "
|
||||
|
||||
+2
@@ -67,6 +67,8 @@ abstract class KotlinBasePluginWrapper(
|
||||
System.setProperty(org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY, "true")
|
||||
val kotlinGradleBuildServices = KotlinGradleBuildServices.getInstance(project.gradle)
|
||||
|
||||
kotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, kotlinPluginVersion)
|
||||
|
||||
project.createKotlinExtension(projectExtensionClass).apply {
|
||||
fun kotlinSourceSetContainer(factory: NamedDomainObjectFactory<KotlinSourceSet>) =
|
||||
project.container(KotlinSourceSet::class.java, factory)
|
||||
|
||||
+3
@@ -82,6 +82,9 @@ internal class PropertiesProvider(private val project: Project) {
|
||||
val keepMppDependenciesIntactInPoms: Boolean?
|
||||
get() = booleanProperty("kotlin.mpp.keepMppDependenciesIntactInPoms")
|
||||
|
||||
val ignorePluginLoadedInMultipleProjects: Boolean?
|
||||
get() = booleanProperty("kotlin.pluginLoadedInMultipleProjects.ignore")
|
||||
|
||||
/**
|
||||
* Enables parallel tasks execution within a project with Workers API.
|
||||
* Does not enable using actual worker proccesses
|
||||
|
||||
Reference in New Issue
Block a user