From 4516902aaf65005479165527662b1e05fef09692 Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Tue, 2 Jul 2019 16:10:26 +0300 Subject: [PATCH] Fix metadata transformation for non-published dependencies, KT-32225 Fix dependencies that are added in non-published source sets, which were omitted from the requested dependencies since their configurations were not added to the extendsFrom set of the merged configurations. Also, don't resolve both merged configurations (compile and runtime) in GranularMetadataTransformation, as the IDE can anyway import only the compile-scoped dependencies from api & implementation. Issue #KT-32225 Fixed --- .../kotlin/gradle/HierarchicalMppIT.kt | 72 +++++++++++++++++++ .../mpp/GranularMetadataTransformation.kt | 26 +++++-- .../mpp/TransformKotlinGranularMetadata.kt | 2 +- 3 files changed, 94 insertions(+), 6 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt index b75db9af831..c0a19ab3ce8 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.gradle.internals.parseKotlinSourceSetMetadataFromXml import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinProjectStructureMetadata import org.jetbrains.kotlin.gradle.plugin.mpp.ModuleDependencyIdentifier import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet +import org.jetbrains.kotlin.gradle.util.checkedReplace import org.jetbrains.kotlin.gradle.util.modify import java.io.File import java.util.zip.ZipFile @@ -52,6 +53,77 @@ class HierarchicalMppIT : BaseGradleIT() { } } + @Test + fun testDependenciesInTests() { + publishThirdPartyLib(withGranularMetadata = true) + + Project("my-lib-foo", gradleVersion, "hierarchical-mpp-published-modules").run { + setupWorkingDir() + gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl) + + testDependencyTransformations { reports -> + val testApiTransformationReports = + reports.filter { report -> + report.groupAndModule.startsWith("com.example.thirdparty") && + report.sourceSetName.let { it == "commonTest" || it == "jvmAndJsTest" } + } + + testApiTransformationReports.forEach { + assertTrue("$it") { it.isExcluded } // should not be visible in test source sets + } + } + + // --- Move the dependency from jvmAndJsMain to commonMain, expect that it is now propagated to commonTest: + gradleBuildScript().modify { + it.checkedReplace("api(\"com.example.thirdparty:third-party-lib:1.0\")", "//") + "\n" + """ + dependencies { + "commonMainApi"("com.example.thirdparty:third-party-lib:1.0") + } + """.trimIndent() + } + + testDependencyTransformations { reports -> + val testApiTransformationReports = + reports.filter { report -> + report.groupAndModule.startsWith("com.example.thirdparty") && + report.sourceSetName.let { it == "commonTest" || it == "jvmAndJsTest" } && + report.scope == "api" + } + + testApiTransformationReports.forEach { + assertEquals(setOf("commonMain"), it.allVisibleSourceSets, "$it") + assertEquals(emptySet(), it.newVisibleSourceSets, "$it") + } + } + + // --- Remove the dependency from commonMain, add it to commonTest to check that it is correctly picked from a non-published + // source set: + gradleBuildScript().modify { + it.checkedReplace("\"commonMainApi\"(\"com.example.thirdparty:third-party-lib:1.0\")", "//") + "\n" + """ + dependencies { + "commonTestApi"("com.example.thirdparty:third-party-lib:1.0") + } + """.trimIndent() + } + + testDependencyTransformations { reports -> + reports.single { + it.sourceSetName == "commonTest" && it.scope == "api" && it.groupAndModule.startsWith("com.example.thirdparty") + }.let { + assertEquals(setOf("commonMain"), it.allVisibleSourceSets) + assertEquals(setOf("commonMain"), it.newVisibleSourceSets) + } + + reports.single { + it.sourceSetName == "jvmAndJsTest" && it.scope == "api" && it.groupAndModule.startsWith("com.example.thirdparty") + }.let { + assertEquals(setOf("commonMain"), it.allVisibleSourceSets) + assertEquals(emptySet(), it.newVisibleSourceSets) + } + } + } + } + @Test fun testProjectDependencies() { publishThirdPartyLib(withGranularMetadata = false) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt index 454b6ea125f..8ff0afef16e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt @@ -82,7 +82,7 @@ internal class GranularMetadataTransformation( /** A list of scopes that the dependencies from [kotlinSourceSet] are treated as requested dependencies. */ val sourceSetRequestedScopes: List, /** A configuration that holds the dependencies of the appropriate scope for all Kotlin source sets in the project */ - val allSourceSetsConfigurations: Iterable + val allSourceSetsConfiguration: Configuration, val parentTransformations: Lazy> ) { val metadataDependencyResolutions: Iterable by lazy { doTransform() } @@ -134,8 +134,24 @@ internal class GranularMetadataTransformation( ownDependencies + parentDependencies } - private val resolvedConfigurations: Iterable by lazy { - allSourceSetsConfigurations.map { it.resolvedConfiguration.lenientConfiguration } + private val resolvedConfiguration: LenientConfiguration by lazy { + /** If [kotlinSourceSet] is not a published source set, its dependencies are not included in [allSourceSetsConfiguration]. + * In that case, to resolve the dependencies of the source set in a way that is consistent with the published source sets, + * we need to create a new configuration with the dependencies from both [allSourceSetsConfiguration] and the + * input configuration(s) of the source set. */ + var modifiedConfiguration: Configuration? = null + + val originalDependencies = allSourceSetsConfiguration.allDependencies + + requestedDependencies.forEach { dependency -> + if (dependency !in originalDependencies) { + modifiedConfiguration = (modifiedConfiguration ?: allSourceSetsConfiguration.copyRecursive()).apply { + dependencies.add(dependency) + } + } + } + + (modifiedConfiguration ?: allSourceSetsConfiguration).resolvedConfiguration.lenientConfiguration } private fun doTransform(): Iterable { @@ -146,7 +162,7 @@ internal class GranularMetadataTransformation( val allRequestedDependencies = requestedDependencies - val allModuleDependencies = resolvedConfigurations.flatMap { it.allModuleDependencies } + val allModuleDependencies = resolvedConfiguration.allModuleDependencies val knownProjectDependencies = collectProjectDependencies( allRequestedDependencies.filterIsInstance(), @@ -157,7 +173,7 @@ internal class GranularMetadataTransformation( val requestedModules: Set = allRequestedDependencies.mapTo(mutableSetOf()) { it.moduleId } addAll( - resolvedConfigurations.flatMap { it.firstLevelModuleDependencies } + resolvedConfiguration.firstLevelModuleDependencies .filter { it.moduleId in requestedModules } .map { ResolvedDependencyWithParent(it, null) } ) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/TransformKotlinGranularMetadata.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/TransformKotlinGranularMetadata.kt index 91543e9b7d6..35ebc8a261e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/TransformKotlinGranularMetadata.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/TransformKotlinGranularMetadata.kt @@ -71,7 +71,7 @@ open class TransformKotlinGranularMetadata project, kotlinSourceSet, listOf(API_SCOPE, IMPLEMENTATION_SCOPE), - listOf(project.configurations.getByName(ALL_COMPILE_METADATA_CONFIGURATION_NAME)), + project.configurations.getByName(ALL_COMPILE_METADATA_CONFIGURATION_NAME), lazy { KotlinMetadataTargetConfigurator.dependsOnWithInterCompilationDependencies(project, kotlinSourceSet).map { project.tasks.withType(TransformKotlinGranularMetadata::class.java)