diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinSpecificDependenciesIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinSpecificDependenciesIT.kt index b2cfa6a6936..bf543a1c4a8 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinSpecificDependenciesIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinSpecificDependenciesIT.kt @@ -1,11 +1,10 @@ /* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2021 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 -import org.jetbrains.kotlin.gradle.internals.KOTLIN_TEST_MULTIPLATFORM_MODULE_NAME import org.jetbrains.kotlin.gradle.util.AGPVersion import org.jetbrains.kotlin.gradle.util.modify import org.jetbrains.kotlin.test.util.KtTestUtil @@ -111,7 +110,7 @@ class KotlinSpecificDependenciesIT : BaseGradleIT() { ) } - private val kotlinTestMultiplatformDependency = "org.jetbrains.kotlin:$KOTLIN_TEST_MULTIPLATFORM_MODULE_NAME" + private val kotlinTestMultiplatformDependency = "org.jetbrains.kotlin:kotlin-test" @Test fun testKotlinTestSingleDependency() { @@ -222,7 +221,7 @@ class KotlinSpecificDependenciesIT : BaseGradleIT() { gradleBuildScript().appendText( "\n" + """ dependencies { testImplementation("$kotlinTestMultiplatformDependency") } - configurations.getByName("testImplementation").dependencies.removeAll { it.name == "$KOTLIN_TEST_MULTIPLATFORM_MODULE_NAME" } + configurations.getByName("testImplementation").dependencies.removeAll { it.name == "kotlin-test" } """.trimIndent() ) checkTaskCompileClasspath("compileTestKotlin", checkModulesNotInClasspath = listOf("kotlin-test")) @@ -244,14 +243,14 @@ class KotlinSpecificDependenciesIT : BaseGradleIT() { kotlin.coreLibrariesVersion = "$customVersion" dependencies { testImplementation("org.jetbrains.kotlin:kotlin-reflect") - testImplementation("org.jetbrains.kotlin:kotlin-test-multiplatform") + testImplementation("org.jetbrains.kotlin:kotlin-test") } test.useJUnit() """.trimIndent() ) checkTaskCompileClasspath( "compileTestKotlin", - listOf("kotlin-stdlib-", "kotlin-reflect-", "kotlin-test-junit-").map { it + customVersion } + listOf("kotlin-stdlib-", "kotlin-reflect-", "kotlin-test-").map { it + customVersion } ) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KotlinDependenciesManagement.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KotlinDependenciesManagement.kt index ee514ddd019..a7c111b0b05 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KotlinDependenciesManagement.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KotlinDependenciesManagement.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2021 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. */ @@ -36,11 +36,13 @@ import org.jetbrains.kotlin.gradle.targets.jvm.JvmCompilationsTestRunSource import org.jetbrains.kotlin.gradle.tasks.KOTLIN_MODULE_GROUP import org.jetbrains.kotlin.gradle.tasks.locateTask import org.jetbrains.kotlin.gradle.testing.KotlinTaskTestRun +import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName internal fun customizeKotlinDependencies(project: Project) { configureStdlibDefaultDependency(project) configureKotlinTestDependencies(project) + configureKotlinTestDependency(project) configureDefaultVersionsResolutionStrategy(project) } @@ -179,6 +181,113 @@ private fun stdlibModuleForJvmCompilations(compilations: Iterable 1 || c1 == 1 && c2 >= 5 + } ?: false + + KotlinDependencyScope.values().forEach { scope -> + val versionOrNullBySourceSet = mutableMapOf() + + project.kotlinExtension.sourceSets.all { kotlinSourceSet -> + val configuration = project.sourceSetDependencyConfigurationByScope(kotlinSourceSet, scope) + var finalizingDependencies = false + + configuration.dependencies.matching(::isKotlinTestRootDependency).apply { + firstOrNull()?.let { versionOrNullBySourceSet[kotlinSourceSet] = it.version } + whenObjectRemoved { + if (!finalizingDependencies && !any()) + versionOrNullBySourceSet.remove(kotlinSourceSet) + } + whenObjectAdded { item -> + versionOrNullBySourceSet[kotlinSourceSet] = item.version + } + } + + project.tryWithDependenciesIfUnresolved(configuration) { dependencies -> + val parentOrOwnVersions: List = + kotlinSourceSet.getSourceSetHierarchy().filter(versionOrNullBySourceSet::contains).map(versionOrNullBySourceSet::get) + + finalizingDependencies = true + + for (version in parentOrOwnVersions.distinct()) { // add dependencies with each version and let Gradle disambiguate them + val effectiveVersion = version ?: project.kotlinExtension.coreLibrariesVersion + if (!isAtLeast1_5(effectiveVersion)) continue + val clarifyCapability = kotlinTestCapabilityForJvmSourceSet(project, kotlinSourceSet) ?: continue + val clarifiedDependency = + (project.kotlinDependency(KOTLIN_TEST_ROOT_MODULE_NAME, version) as ExternalDependency).apply { + if (version == null) { + version { constraint -> constraint.require(project.kotlinExtension.coreLibrariesVersion) } + } + capabilities { + it.requireCapability(clarifyCapability) + } + } + dependencies.add(clarifiedDependency) + } + } + } + } +} + +private fun kotlinTestCapabilityForJvmSourceSet(project: Project, kotlinSourceSet: KotlinSourceSet): String? { + val compilations = CompilationSourceSetUtil.compilationsBySourceSets(project).getValue(kotlinSourceSet) + .filter { it.target !is KotlinMetadataTarget } + + val platformTypes = compilations.map { it.platformType } + // TODO: Extract jvmPlatformTypes to public constant? + val jvmPlatforms = setOf(KotlinPlatformType.jvm, KotlinPlatformType.androidJvm) + if (!jvmPlatforms.containsAll(platformTypes)) return null + + val testTaskLists: List?> = compilations.map { compilation -> + val target = compilation.target + when { + target is KotlinTargetWithTests<*, *> -> + target.findTestRunsByCompilation(compilation)?.filterIsInstance>()?.map { it.executionTask.get() } + target is KotlinWithJavaTarget<*> -> + if (compilation.name == KotlinCompilation.TEST_COMPILATION_NAME) + project.locateTask(target.testTaskName)?.get()?.let(::listOf) + else null + compilation is KotlinJvmAndroidCompilation -> when (compilation.androidVariant) { + is UnitTestVariant -> + project.locateTask(lowerCamelCaseName("test", compilation.androidVariant.name))?.get()?.let(::listOf) + is TestVariant -> (compilation.androidVariant as TestVariant).connectedInstrumentTest?.let(::listOf) + else -> null + } + else -> null + } + } + if (null in testTaskLists) { + return null + } + val testTasks = testTaskLists.flatMap { checkNotNull(it) } + val frameworks = testTasks.mapTo(mutableSetOf()) { testTask -> + when (testTask) { + is Test -> testFrameworkOf(testTask) + else -> // Android connected test tasks don't inherit from Test, but we use JUnit for them + KotlinTestJvmFramework.junit + } + } + return when { + frameworks.size > 1 -> null + else -> "$KOTLIN_MODULE_GROUP:$KOTLIN_TEST_ROOT_MODULE_NAME-framework-${frameworks.single()}" + } +} + +internal const val KOTLIN_TEST_ROOT_MODULE_NAME = "kotlin-test" + + internal fun configureKotlinTestDependencies(project: Project) { fun isKotlinTestMultiplatformDependency(dependency: Dependency) = dependency.group == KOTLIN_MODULE_GROUP && dependency.name == KOTLIN_TEST_MULTIPLATFORM_MODULE_NAME diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt index d0fabeb4812..4b0c5b44264 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2021 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. */ @@ -253,6 +253,9 @@ internal class PropertiesProvider private constructor(private val project: Proje val stdlibDefaultDependency: Boolean get() = booleanProperty("kotlin.stdlib.default.dependency") ?: true + val kotlinTestInferJvmVariant: Boolean + get() = booleanProperty("kotlin.test.infer.jvm.variant") ?: true + private fun propertyWithDeprecatedVariant(propName: String, deprecatedPropName: String): String? { val deprecatedProperty = property(deprecatedPropName) if (deprecatedProperty != null) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt index 0c02d9fc57a..ac223b63d86 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2021 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. */ @@ -26,4 +26,3 @@ const val NO_NATIVE_STDLIB_PROPERTY_WARNING = NO_NATIVE_STDLIB_PROPERTY_WARNING val KOTLIN_12X_MPP_DEPRECATION_WARNING = KOTLIN_12X_MPP_DEPRECATION_WARNING -const val KOTLIN_TEST_MULTIPLATFORM_MODULE_NAME = org.jetbrains.kotlin.gradle.internal.KOTLIN_TEST_MULTIPLATFORM_MODULE_NAME \ No newline at end of file