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
This commit is contained in:
Sergey Igushkin
2019-07-02 16:10:26 +03:00
parent dbc8007c63
commit 4516902aaf
3 changed files with 94 additions and 6 deletions
@@ -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)
@@ -82,7 +82,7 @@ internal class GranularMetadataTransformation(
/** A list of scopes that the dependencies from [kotlinSourceSet] are treated as requested dependencies. */
val sourceSetRequestedScopes: List<KotlinDependencyScope>,
/** A configuration that holds the dependencies of the appropriate scope for all Kotlin source sets in the project */
val allSourceSetsConfigurations: Iterable<Configuration>
val allSourceSetsConfiguration: Configuration,
val parentTransformations: Lazy<Iterable<GranularMetadataTransformation>>
) {
val metadataDependencyResolutions: Iterable<MetadataDependencyResolution> by lazy { doTransform() }
@@ -134,8 +134,24 @@ internal class GranularMetadataTransformation(
ownDependencies + parentDependencies
}
private val resolvedConfigurations: Iterable<LenientConfiguration> 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<MetadataDependencyResolution> {
@@ -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<ProjectDependency>(),
@@ -157,7 +173,7 @@ internal class GranularMetadataTransformation(
val requestedModules: Set<ModuleId> = allRequestedDependencies.mapTo(mutableSetOf()) { it.moduleId }
addAll(
resolvedConfigurations.flatMap { it.firstLevelModuleDependencies }
resolvedConfiguration.firstLevelModuleDependencies
.filter { it.moduleId in requestedModules }
.map { ResolvedDependencyWithParent(it, null) }
)
@@ -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)