diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/VariantAwareDependenciesIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/VariantAwareDependenciesIT.kt index 8e35b424570..6c693436f54 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/VariantAwareDependenciesIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/VariantAwareDependenciesIT.kt @@ -241,6 +241,30 @@ class VariantAwareDependenciesIT : BaseGradleIT() { } } + @Test + fun testCompileAndRuntimeResolutionOfElementsConfigurations() = + with(Project("sample-app", gradleVersion, "new-mpp-lib-and-app")) { + val libProject = Project("sample-lib", gradleVersion, "new-mpp-lib-and-app") + embedProject(libProject) + gradleBuildScript().modify { + it.replace("'com.example:sample-lib:1.0'", "project('${libProject.projectName}')") + } + + listOf("jvm6" to "Classpath", "nodeJs" to "Classpath", "wasm32" to "Klibraries").forEach { (target, suffix) -> + build("dependencyInsight", "--configuration", "${target}Compile$suffix", "--dependency", "sample-lib") { + assertSuccessful() + assertContains("variant \"${target}ApiElements\" [") + } + + if (suffix == "Classpath") { + build("dependencyInsight", "--configuration", "${target}Runtime$suffix", "--dependency", "sample-lib") { + assertSuccessful() + assertContains("variant \"${target}RuntimeElements\" [") + } + } + } + } + private fun Project.embedProject(other: Project) { setupWorkingDir() other.setupWorkingDir() diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinUsages.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinUsages.kt index bd64c2ce9d2..f807c969edf 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinUsages.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinUsages.kt @@ -65,19 +65,33 @@ object KotlinUsages { override fun execute(details: MultipleCandidatesDetails) = with(details) { val candidateNames = candidateValues.map { it?.name }.toSet() + fun chooseCandidateByName(name: String?): Unit = closestMatch(candidateValues.single { it?.name == name }!!) + // if both API and runtime artifacts are chosen according to the compatibility rules, then // the consumer requested nothing specific, so provide them with the runtime variant, which is more complete: if (candidateNames.filterNotNull().toSet() == setOf(KOTLIN_RUNTIME, KOTLIN_API)) { - details.closestMatch(candidateValues.single { it?.name == KOTLIN_RUNTIME }!!) + chooseCandidateByName(KOTLIN_RUNTIME) } - if (JAVA_API in candidateNames && JAVA_RUNTIME_JARS in candidateNames && values.none { it in candidateNames }) { - details.closestMatch(candidateValues.single { it?.name == JAVA_RUNTIME_JARS }!!) - } - if (JAVA_API in candidateNames && JAVA_RUNTIME in candidateNames && values.none { it in candidateNames }) { - details.closestMatch(candidateValues.single { it?.name == JAVA_RUNTIME }!!) + + // The consumer value is available and can be used for disambiguation in Gradle 4.1+ + if (isGradleVersionAtLeast(4, 1)) { + val javaRuntimeUsages = setOf(JAVA_RUNTIME_JARS, JAVA_RUNTIME) + + if (JAVA_API in candidateNames && + javaRuntimeUsages.any { it in candidateNames } && + values.none { it in candidateNames } + ) { + when (consumerValue?.name) { + KOTLIN_API, JAVA_API -> + chooseCandidateByName(JAVA_API) + null, KOTLIN_RUNTIME, in javaRuntimeUsages -> + chooseCandidateByName(javaRuntimeUsages.first { it in candidateNames }) + } + } } + if (JAVA_RUNTIME_CLASSES in candidateNames && JAVA_RUNTIME_RESOURCES in candidateNames && KOTLIN_RUNTIME in candidateNames) { - closestMatch(candidateValues.single { it?.name == KOTLIN_RUNTIME }!!) + chooseCandidateByName(KOTLIN_RUNTIME) } } }