[Gradle] Ide Dependency Resolution: Filter 'loop' or 'self' dependencies

Those are dependencies that point back to the original project.
This can happen with two projects like

```
// project a
kotlin {
    commonMain.get().dependencies {
        api(project(":b"))
    }
}

// project b
kotlin {
    commonTest.get().dependencies {
        implementation(project(":a"))
    }
}
```

Where b(test) -> a -> b

^KT-59020 Verification Pending
This commit is contained in:
Sebastian Sellmair
2023-06-02 19:27:39 +02:00
committed by Space Team
parent 19073b96a7
commit a80d6a7b74
6 changed files with 83 additions and 33 deletions
@@ -154,7 +154,8 @@ public final class org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/Id
public fun <init> (Lkotlin/jvm/functions/Function1;)V public fun <init> (Lkotlin/jvm/functions/Function1;)V
public fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)V public fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)V
public fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)V public fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)V
public synthetic fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
public synthetic fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
} }
public final class org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeBinaryDependencyResolver$ArtifactResolutionStrategy$PlatformLikeSourceSet : org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeBinaryDependencyResolver$ArtifactResolutionStrategy { public final class org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeBinaryDependencyResolver$ArtifactResolutionStrategy$PlatformLikeSourceSet : org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeBinaryDependencyResolver$ArtifactResolutionStrategy {
@@ -162,14 +163,16 @@ public final class org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/Id
public fun <init> (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)V public fun <init> (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)V
public fun <init> (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)V public fun <init> (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)V
public fun <init> (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V public fun <init> (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
public synthetic fun <init> (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun <init> (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
public synthetic fun <init> (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
} }
public final class org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeBinaryDependencyResolver$ArtifactResolutionStrategy$ResolvableConfiguration : org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeBinaryDependencyResolver$ArtifactResolutionStrategy { public final class org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeBinaryDependencyResolver$ArtifactResolutionStrategy$ResolvableConfiguration : org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeBinaryDependencyResolver$ArtifactResolutionStrategy {
public fun <init> (Lkotlin/jvm/functions/Function1;)V public fun <init> (Lkotlin/jvm/functions/Function1;)V
public fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)V public fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)V
public fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)V public fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)V
public synthetic fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
public synthetic fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
} }
public final class org/jetbrains/kotlin/gradle/plugin/mpp/external/CreateExternalKotlinCompilationKt { public final class org/jetbrains/kotlin/gradle/plugin/mpp/external/CreateExternalKotlinCompilationKt {
@@ -5,9 +5,7 @@
package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers
import org.gradle.api.artifacts.ArtifactView import org.gradle.api.artifacts.*
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.DependencySubstitutions
import org.gradle.api.artifacts.component.* import org.gradle.api.artifacts.component.*
import org.gradle.api.attributes.AttributeContainer import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.logging.Logger import org.gradle.api.logging.Logger
@@ -24,6 +22,7 @@ import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver.Companion.gradleArtifact import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver.Companion.gradleArtifact
import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinBinaryCoordinates import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinBinaryCoordinates
import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinProjectCoordinates import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinProjectCoordinates
import org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers.IdeBinaryDependencyResolver.ArtifactResolutionStrategy
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationConfigurationsContainer import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationConfigurationsContainer
import org.jetbrains.kotlin.gradle.plugin.mpp.internal import org.jetbrains.kotlin.gradle.plugin.mpp.internal
@@ -34,7 +33,6 @@ import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.sources.InternalKotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.sources.InternalKotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.sources.internal import org.jetbrains.kotlin.gradle.plugin.sources.internal
import org.jetbrains.kotlin.gradle.utils.markResolvable import org.jetbrains.kotlin.gradle.utils.markResolvable
import org.gradle.api.artifacts.ResolutionStrategy
import org.jetbrains.kotlin.tooling.core.mutableExtrasOf import org.jetbrains.kotlin.tooling.core.mutableExtrasOf
/** /**
@@ -57,11 +55,14 @@ import org.jetbrains.kotlin.tooling.core.mutableExtrasOf
@ExternalKotlinTargetApi @ExternalKotlinTargetApi
class IdeBinaryDependencyResolver @JvmOverloads constructor( class IdeBinaryDependencyResolver @JvmOverloads constructor(
private val binaryType: String = IdeaKotlinBinaryDependency.KOTLIN_COMPILE_BINARY_TYPE, private val binaryType: String = IdeaKotlinBinaryDependency.KOTLIN_COMPILE_BINARY_TYPE,
private val artifactResolutionStrategy: ArtifactResolutionStrategy = ArtifactResolutionStrategy.Compilation() private val artifactResolutionStrategy: ArtifactResolutionStrategy = ArtifactResolutionStrategy.Compilation(),
) : IdeDependencyResolver { ) : IdeDependencyResolver {
@ExternalKotlinTargetApi @ExternalKotlinTargetApi
sealed class ArtifactResolutionStrategy { sealed class ArtifactResolutionStrategy {
internal abstract val setupArtifactViewAttributes: AttributeContainer.(sourceSet: KotlinSourceSet) -> Unit
internal abstract val componentFilter: ((ComponentIdentifier) -> Boolean)?
internal abstract val dependencyFilter: ((Dependency) -> Boolean)?
/** /**
* Resolve the artifacts from a [KotlinSourceSet] using its [KotlinCompilation.compileDependencyConfigurationName], * Resolve the artifacts from a [KotlinSourceSet] using its [KotlinCompilation.compileDependencyConfigurationName],
@@ -74,9 +75,11 @@ class IdeBinaryDependencyResolver @JvmOverloads constructor(
*/ */
@ExternalKotlinTargetApi @ExternalKotlinTargetApi
class Compilation @JvmOverloads constructor( class Compilation @JvmOverloads constructor(
internal val compilationSelector: (KotlinSourceSet) -> KotlinCompilation<*>? = { sourceSet -> sourceSet.internal.compilations.singleOrNull { it.platformType != KotlinPlatformType.common } }, internal val compilationSelector: (KotlinSourceSet) -> KotlinCompilation<*>? =
internal val setupArtifactViewAttributes: AttributeContainer.(sourceSet: KotlinSourceSet) -> Unit = {}, { sourceSet -> sourceSet.internal.compilations.singleOrNull { it.platformType != KotlinPlatformType.common } },
internal val componentFilter: ((ComponentIdentifier) -> Boolean)? = null override val setupArtifactViewAttributes: AttributeContainer.(sourceSet: KotlinSourceSet) -> Unit = {},
override val componentFilter: ((ComponentIdentifier) -> Boolean)? = null,
override val dependencyFilter: ((Dependency) -> Boolean)? = null,
) : ArtifactResolutionStrategy() ) : ArtifactResolutionStrategy()
/** /**
@@ -84,12 +87,14 @@ class IdeBinaryDependencyResolver @JvmOverloads constructor(
* @param configurationSelector Returns the configuration that shall be resolved for the given [KotlinSourceSet] * @param configurationSelector Returns the configuration that shall be resolved for the given [KotlinSourceSet]
* @param setupArtifactViewAttributes: Additional attributes that will be used to create an [ArtifactView] for resolving the dependencies. * @param setupArtifactViewAttributes: Additional attributes that will be used to create an [ArtifactView] for resolving the dependencies.
* @param componentFilter Filter added to the artifactView: Only components passing the filter will be resolved * @param componentFilter Filter added to the artifactView: Only components passing the filter will be resolved
* @param dependencyFilter Filter added to the [ResolvableDependencies]: Only dependencies passing the filter will be resolved
*/ */
@ExternalKotlinTargetApi @ExternalKotlinTargetApi
class ResolvableConfiguration @JvmOverloads constructor( class ResolvableConfiguration @JvmOverloads constructor(
internal val configurationSelector: (KotlinSourceSet) -> Configuration?, internal val configurationSelector: (KotlinSourceSet) -> Configuration?,
internal val setupArtifactViewAttributes: AttributeContainer.(sourceSet: KotlinSourceSet) -> Unit = {}, override val setupArtifactViewAttributes: AttributeContainer.(sourceSet: KotlinSourceSet) -> Unit = {},
internal val componentFilter: ((ComponentIdentifier) -> Boolean)? = null override val componentFilter: ((ComponentIdentifier) -> Boolean)? = null,
override val dependencyFilter: ((Dependency) -> Boolean)? = null,
) : ArtifactResolutionStrategy() ) : ArtifactResolutionStrategy()
/** /**
@@ -101,13 +106,15 @@ class IdeBinaryDependencyResolver @JvmOverloads constructor(
* @param componentFilter Filter added to the artifactView: Only components passing the filter will be resolved * @param componentFilter Filter added to the artifactView: Only components passing the filter will be resolved
* @param dependencySubstitution Dependency substitution added to the adhoc configuration created for this resolution. * @param dependencySubstitution Dependency substitution added to the adhoc configuration created for this resolution.
* see [ResolutionStrategy.dependencySubstitution] * see [ResolutionStrategy.dependencySubstitution]
* @param dependencyFilter Filter added to the [ResolvableDependencies]: Only dependencies passing the filter will be resolved
*/ */
@ExternalKotlinTargetApi @ExternalKotlinTargetApi
class PlatformLikeSourceSet @JvmOverloads constructor( class PlatformLikeSourceSet @JvmOverloads constructor(
internal val setupPlatformResolutionAttributes: AttributeContainer.(sourceSet: KotlinSourceSet) -> Unit, internal val setupPlatformResolutionAttributes: AttributeContainer.(sourceSet: KotlinSourceSet) -> Unit,
internal val setupArtifactViewAttributes: AttributeContainer.(sourceSet: KotlinSourceSet) -> Unit = {}, override val setupArtifactViewAttributes: AttributeContainer.(sourceSet: KotlinSourceSet) -> Unit = {},
internal val componentFilter: ((ComponentIdentifier) -> Boolean)? = null, override val componentFilter: ((ComponentIdentifier) -> Boolean)? = null,
internal val dependencySubstitution: ((DependencySubstitutions) -> Unit)? = null, internal val dependencySubstitution: ((DependencySubstitutions) -> Unit)? = null,
override val dependencyFilter: ((Dependency) -> Boolean)? = null,
) : ArtifactResolutionStrategy() ) : ArtifactResolutionStrategy()
} }
@@ -194,24 +201,12 @@ class IdeBinaryDependencyResolver @JvmOverloads constructor(
return null return null
} }
return compilation.internal.configurations.compileDependencyConfiguration.incoming.artifactView { view -> return createArtifactViewFromConfiguration(sourceSet, compilation.internal.configurations.compileDependencyConfiguration)
view.isLenient = true
view.attributes.setupArtifactViewAttributes(sourceSet)
if (componentFilter != null) {
view.componentFilter(componentFilter)
}
}
} }
private fun ArtifactResolutionStrategy.ResolvableConfiguration.createArtifactView(sourceSet: InternalKotlinSourceSet): ArtifactView? { private fun ArtifactResolutionStrategy.ResolvableConfiguration.createArtifactView(sourceSet: InternalKotlinSourceSet): ArtifactView? {
val configuration = configurationSelector(sourceSet) ?: return null val configuration = configurationSelector(sourceSet) ?: return null
return configuration.incoming.artifactView { view -> return createArtifactViewFromConfiguration(sourceSet, configuration)
view.isLenient = true
view.attributes.setupArtifactViewAttributes(sourceSet)
if (componentFilter != null) {
view.componentFilter(componentFilter)
}
}
} }
private fun ArtifactResolutionStrategy.PlatformLikeSourceSet.createArtifactView(sourceSet: InternalKotlinSourceSet): ArtifactView? { private fun ArtifactResolutionStrategy.PlatformLikeSourceSet.createArtifactView(sourceSet: InternalKotlinSourceSet): ArtifactView? {
@@ -227,14 +222,23 @@ class IdeBinaryDependencyResolver @JvmOverloads constructor(
platformLikeCompileDependenciesConfiguration.resolutionStrategy.dependencySubstitution(dependencySubstitution) platformLikeCompileDependenciesConfiguration.resolutionStrategy.dependencySubstitution(dependencySubstitution)
} }
return platformLikeCompileDependenciesConfiguration.incoming.artifactView { view -> return createArtifactViewFromConfiguration(sourceSet, platformLikeCompileDependenciesConfiguration)
}
private fun ArtifactResolutionStrategy.createArtifactViewFromConfiguration(
sourceSet: KotlinSourceSet, configuration: Configuration,
): ArtifactView = configuration.incoming
.apply {
val dependencyFilter = dependencyFilter
if (dependencyFilter != null) dependencies.removeIf { dependency -> !dependencyFilter.invoke(dependency) }
}
.artifactView { view ->
view.isLenient = true view.isLenient = true
view.attributes.setupArtifactViewAttributes(sourceSet) view.attributes.setupArtifactViewAttributes(sourceSet)
if (componentFilter != null) { if (componentFilter != null) {
view.componentFilter(componentFilter) view.componentFilter(componentFilter)
} }
} }
}
private companion object { private companion object {
val logger: Logger = Logging.getLogger(IdeBinaryDependencyResolver::class.java) val logger: Logger = Logging.getLogger(IdeBinaryDependencyResolver::class.java)
@@ -9,6 +9,7 @@ package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.DependencySubstitutions import org.gradle.api.artifacts.DependencySubstitutions
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.artifacts.component.ModuleComponentSelector import org.gradle.api.artifacts.component.ModuleComponentSelector
import org.gradle.api.artifacts.component.ProjectComponentIdentifier import org.gradle.api.artifacts.component.ProjectComponentIdentifier
import org.gradle.api.attributes.Category import org.gradle.api.attributes.Category
@@ -44,7 +45,8 @@ internal fun IdeJvmAndAndroidPlatformBinaryDependencyResolver(project: Project):
Otherwise we would match the -jvm.jar from the dependency project which will result in Otherwise we would match the -jvm.jar from the dependency project which will result in
matching the jvmMain source set as well (which is undesired) matching the jvmMain source set as well (which is undesired)
*/ */
componentFilter = { identifier -> identifier !is ProjectComponentIdentifier }, componentFilter = { identifier -> identifier !is ProjectComponentIdentifier }, // paranoia: Only dependencyFilter should be OK
dependencyFilter = { dependency -> dependency !is ProjectDependency },
dependencySubstitution = ::substituteStdlibCommonWithAndroidJvm, dependencySubstitution = ::substituteStdlibCommonWithAndroidJvm,
) )
) )
@@ -29,6 +29,10 @@ internal object IdeJvmAndAndroidSourceDependencyResolver : IdeDependencyResolver
if (!isJvmAndAndroid(sourceSet)) return emptySet() if (!isJvmAndAndroid(sourceSet)) return emptySet()
if (sourceSet !is DefaultKotlinSourceSet) return emptySet() if (sourceSet !is DefaultKotlinSourceSet) return emptySet()
return sourceSet.resolveMetadata<MetadataDependencyResolution.ChooseVisibleSourceSets>() return sourceSet.resolveMetadata<MetadataDependencyResolution.ChooseVisibleSourceSets>()
/**
* See [IdeVisibleMultiplatformSourceDependencyResolver] on why this could happen
*/
.filter { chooseVisibleSourceSets -> chooseVisibleSourceSets.projectDependency(sourceSet.project) != sourceSet.project }
.flatMap { chooseVisibleSourceSets -> .flatMap { chooseVisibleSourceSets ->
val projectDependency = chooseVisibleSourceSets.projectDependency(sourceSet.project) val projectDependency = chooseVisibleSourceSets.projectDependency(sourceSet.project)
?: return@flatMap emptyList<IdeaKotlinDependency>() ?: return@flatMap emptyList<IdeaKotlinDependency>()
@@ -13,18 +13,28 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver
import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinProjectCoordinates import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinProjectCoordinates
import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution
import org.jetbrains.kotlin.gradle.plugin.mpp.projectDependency
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet
internal object IdeVisibleMultiplatformSourceDependencyResolver : IdeDependencyResolver { internal object IdeVisibleMultiplatformSourceDependencyResolver : IdeDependencyResolver {
override fun resolve(sourceSet: KotlinSourceSet): Set<IdeaKotlinDependency> { override fun resolve(sourceSet: KotlinSourceSet): Set<IdeaKotlinDependency> {
if (sourceSet !is DefaultKotlinSourceSet) return emptySet() if (sourceSet !is DefaultKotlinSourceSet) return emptySet()
return sourceSet.resolveMetadata<MetadataDependencyResolution.ChooseVisibleSourceSets>() return sourceSet.resolveMetadata<MetadataDependencyResolution.ChooseVisibleSourceSets>()
/*
Check if resolved dependency is pointing to the project that contains the Source Set
Such 'loop' or 'self' dependencies can happen when e.g.
1) 'project A' depends on 'project B'
2) 'project B / test' depends on project A
In this case project B tests will get a project dependency pointing to project B's main variant
*/
.filter { resolution -> resolution.projectDependency(sourceSet.project) != sourceSet.project }
.flatMap { resolution -> resolveSourceDependencies(resolution) } .flatMap { resolution -> resolveSourceDependencies(resolution) }
.toSet() .toSet()
} }
private fun resolveSourceDependencies( private fun resolveSourceDependencies(
resolution: MetadataDependencyResolution.ChooseVisibleSourceSets resolution: MetadataDependencyResolution.ChooseVisibleSourceSets,
): Iterable<IdeaKotlinDependency> { ): Iterable<IdeaKotlinDependency> {
val projectComponentIdentifier = resolution.dependency.id as? ProjectComponentIdentifier ?: return emptyList() val projectComponentIdentifier = resolution.dependency.id as? ProjectComponentIdentifier ?: return emptyList()
return resolution.allVisibleSourceSetNames.map { visibleSourceSetName -> return resolution.allVisibleSourceSetNames.map { visibleSourceSetName ->
@@ -112,6 +112,33 @@ class IdeJvmAndAndroidDependencyResolutionTest {
) )
} }
@Test
fun `test - KT-59020 - transitive project dependency to self`() {
val root = buildProject { setMultiplatformAndroidSourceSetLayoutVersion(2) }
val a = buildProject({ withParent(root).withName("a") }) { configureAndroidAndMultiplatform() }
val b = buildProject({ withParent(root).withName("b") }) { configureAndroidAndMultiplatform() }
b.multiplatformExtension.commonMain.dependencies {
api(project(":a"))
}
a.multiplatformExtension.commonTest.dependencies {
api(project(":b"))
}
root.evaluate()
a.evaluate()
b.evaluate()
a.kotlinIdeMultiplatformImport.resolveDependencies("jvmAndAndroidTest").assertMatches(
friendSourceDependency(":a/commonMain"),
friendSourceDependency(":a/jvmAndAndroidMain"),
dependsOnDependency(":a/commonTest"),
regularSourceDependency(":b/commonMain"),
regularSourceDependency(":b/jvmAndAndroidMain"),
)
}
@Test @Test
fun `test - default stdlib with no other dependencies`() { fun `test - default stdlib with no other dependencies`() {
val project = buildProject { configureAndroidAndMultiplatform(enableDefaultStdlib = true) } val project = buildProject { configureAndroidAndMultiplatform(enableDefaultStdlib = true) }