diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt
index e15ac44f6a8..e701bb22b49 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt
@@ -774,4 +774,59 @@ class NewMultiplatformIT : BaseGradleIT() {
}
}
}
+
+ @Test
+ fun testPublishMultimoduleProjectWithNoMetadata() {
+ val libProject = Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")
+ val appProject = Project("sample-app", gradleVersion, "new-mpp-lib-and-app")
+
+ with(libProject) {
+ setupWorkingDir()
+ appProject.setupWorkingDir()
+ appProject.projectDir.copyRecursively(projectDir.resolve("sample-app"))
+
+ projectDir.resolve("settings.gradle").writeText("include 'sample-app'") // also disables feature preview 'GRADLE_METADATA'
+ gradleBuildScript("sample-app").modify {
+ it.replace("'com.example:sample-lib:1.0'", "project(':')") + "\n" + """
+ apply plugin: 'maven-publish'
+ group = "com.exampleapp"
+ version = "1.0"
+ publishing {
+ repositories {
+ maven { url "file://${'$'}{rootProject.projectDir.absolutePath.replace('\\', '/')}/repo" }
+ }
+ }
+ """.trimIndent()
+ }
+
+ gradleBuildScript().appendText("\n" + """
+ publishing {
+ publications {
+ jvm6 {
+ groupId = "foo"
+ artifactId = "bar"
+ version = "42"
+ }
+ }
+ }
+ """.trimIndent())
+
+ build("publish") {
+ assertSuccessful()
+ assertFileContains(
+ "repo/com/exampleapp/sample-app-nodejs/1.0/sample-app-nodejs-1.0.pom",
+ "com.example",
+ "sample-lib-nodejs",
+ "1.0"
+ )
+ assertFileContains(
+ "repo/com/exampleapp/sample-app-jvm8/1.0/sample-app-jvm8-1.0.pom",
+ "foo",
+ "bar",
+ "42"
+ )
+ assertFileExists("repo/foo/bar/42/bar-42.jar")
+ }
+ }
+ }
}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt
index 31e0a35d77b..6e37c98cd25 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt
@@ -135,7 +135,7 @@ class KotlinMultiplatformPlugin(
}
}
(this as MavenPublicationInternal).publishWithOriginalFileName()
- artifactId = "${project.name}-${variant.target.name.toLowerCase()}"
+ artifactId = variant.target.defaultArtifactId
groupId = project.group.toString()
version = project.version.toString()
}
@@ -234,4 +234,6 @@ class KotlinMultiplatformPlugin(
companion object {
const val METADATA_TARGET_NAME = "metadata"
}
-}
\ No newline at end of file
+}
+
+internal val KotlinTarget.defaultArtifactId get() = "${project.name}-${name.toLowerCase()}"
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt
index d7fd89719c4..43ff703f9ff 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt
@@ -6,26 +6,25 @@
package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.Project
-import org.gradle.api.artifacts.Configuration
-import org.gradle.api.artifacts.DependencyConstraint
-import org.gradle.api.artifacts.ModuleDependency
-import org.gradle.api.artifacts.PublishArtifact
+import org.gradle.api.artifacts.*
import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.attributes.Usage
import org.gradle.api.capabilities.Capability
import org.gradle.api.component.ComponentWithVariants
import org.gradle.api.internal.component.SoftwareComponentInternal
import org.gradle.api.internal.component.UsageContext
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationToRunnableFiles
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetComponent
-import org.jetbrains.kotlin.gradle.plugin.usageByName
+import org.jetbrains.kotlin.utils.ifEmpty
class KotlinSoftwareComponent(
private val project: Project,
private val name: String,
private val kotlinTargets: Iterable
) : SoftwareComponentInternal, ComponentWithVariants {
-
+
override fun getUsages(): Set = emptySet()
override fun getVariants(): Set =
@@ -60,7 +59,10 @@ internal class KotlinPlatformUsageContext(
get() = project.configurations.getByName(dependencyConfigurationName)
override fun getDependencies(): MutableSet =
- configuration.incoming.dependencies.withType(ModuleDependency::class.java)
+ if (publishWithGradleMetadata)
+ configuration.incoming.dependencies.withType(ModuleDependency::class.java)
+ else
+ rewriteMppDependenciesToTargetModuleDependencies(this, configuration).toMutableSet()
override fun getDependencyConstraints(): MutableSet =
configuration.incoming.dependencyConstraints
@@ -77,3 +79,66 @@ internal class KotlinPlatformUsageContext(
// FIXME this is a stub for a function that is not present in the Gradle API that we compile against
fun getGlobalExcludes(): Set = emptySet()
}
+
+private fun rewriteMppDependenciesToTargetModuleDependencies(
+ context: KotlinPlatformUsageContext,
+ configuration: Configuration
+): Set = with(context.kotlinTarget.project) {
+ val target = context.kotlinTarget
+ val moduleDependencies = configuration.incoming.dependencies.withType(ModuleDependency::class.java).ifEmpty { return emptySet() }
+
+ val targetMainCompilation = target.compilations.findByName(KotlinCompilation.MAIN_COMPILATION_NAME)
+ ?: return moduleDependencies // Android is not yet supported
+
+ val targetCompileDependenciesConfiguration = project.configurations.getByName(
+ when (context.dependencyConfigurationName) {
+ target.apiElementsConfigurationName -> targetMainCompilation.compileDependencyConfigurationName
+ target.runtimeElementsConfigurationName ->
+ (targetMainCompilation as KotlinCompilationToRunnableFiles).runtimeDependencyConfigurationName
+ else -> error("unexpected configuration")
+ }
+ )
+
+ val resolvedCompileDependencies by lazy { // don't resolve if no project dependencies on MPP projects are found
+ targetCompileDependenciesConfiguration.resolvedConfiguration.lenientConfiguration.allModuleDependencies.associateBy {
+ Triple(it.moduleGroup, it.moduleName, it.moduleVersion)
+ }
+ }
+
+ moduleDependencies.map { dependency ->
+ when (dependency) {
+ !is ProjectDependency -> dependency
+ else -> {
+ val dependencyProject = dependency.dependencyProject
+ val dependencyProjectKotlinExtension = dependencyProject.multiplatformExtension
+ ?: return@map dependency
+
+ if (dependencyProjectKotlinExtension.isGradleMetadataAvailable)
+ return@map dependency
+
+ val resolved = resolvedCompileDependencies[Triple(dependency.group, dependency.name, dependency.version)]
+ ?: return@map dependency
+
+ val resolvedToConfiguration = resolved.configuration
+
+ val dependencyTarget = dependencyProjectKotlinExtension.targets.singleOrNull {
+ resolvedToConfiguration in setOf(
+ it.apiElementsConfigurationName,
+ it.runtimeElementsConfigurationName,
+ it.defaultConfigurationName
+ )
+ } ?: return@map dependency
+
+ val publicationDelegate = (dependencyTarget.component as KotlinVariant).publicationDelegate
+
+ dependencies.module(
+ listOf(
+ publicationDelegate?.groupId ?: dependency.group,
+ publicationDelegate?.artifactId ?: dependencyTarget.defaultArtifactId,
+ publicationDelegate?.version ?: dependency.version
+ ).joinToString(":")
+ ) as ModuleDependency
+ }
+ }
+ }.toSet()
+}