diff --git a/libraries/tools/kotlin-gradle-plugin/api/kotlin-gradle-plugin.api b/libraries/tools/kotlin-gradle-plugin/api/kotlin-gradle-plugin.api index d6ef1b8f7aa..2f5ded0cfaa 100644 --- a/libraries/tools/kotlin-gradle-plugin/api/kotlin-gradle-plugin.api +++ b/libraries/tools/kotlin-gradle-plugin/api/kotlin-gradle-plugin.api @@ -720,7 +720,9 @@ public class org/jetbrains/kotlin/gradle/plugin/mpp/external/DecoratedExternalKo public final fun getRuntimeElementsConfiguration ()Lorg/gradle/api/artifacts/Configuration; public fun getRuntimeElementsConfigurationName ()Ljava/lang/String; public final fun getRuntimeElementsPublishedConfiguration ()Lorg/gradle/api/artifacts/Configuration; + public final fun getSourcesElementsConfiguration ()Lorg/gradle/api/artifacts/Configuration; public fun getSourcesElementsConfigurationName ()Ljava/lang/String; + public final fun getSourcesElementsPublishedConfiguration ()Lorg/gradle/api/artifacts/Configuration; public fun getTargetName ()Ljava/lang/String; public fun getUseDisambiguationClassifierAsSourceSetNamePrefix ()Z public fun isSourcesPublishable ()Z @@ -799,6 +801,7 @@ public abstract interface class org/jetbrains/kotlin/gradle/plugin/mpp/external/ public abstract fun getRuntimeElements ()Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetConfigurationDescriptor; public abstract fun getRuntimeElementsPublished ()Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetConfigurationDescriptor; public abstract fun getSourcesElements ()Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetConfigurationDescriptor; + public abstract fun getSourcesElementsPublished ()Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetConfigurationDescriptor; public abstract fun getTargetFactory ()Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetDescriptor$TargetFactory; public abstract fun getTargetName ()Ljava/lang/String; } @@ -816,6 +819,7 @@ public final class org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotli public final fun getRuntimeElements ()Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetConfigurationDescriptorBuilder; public final fun getRuntimeElementsPublished ()Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetConfigurationDescriptorBuilder; public final fun getSourcesElements ()Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetConfigurationDescriptorBuilder; + public final fun getSourcesElementsPublished ()Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetConfigurationDescriptorBuilder; public final fun getTargetFactory ()Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetDescriptor$TargetFactory; public final fun getTargetName ()Ljava/lang/String; public final fun setPlatformType (Lorg/jetbrains/kotlin/gradle/plugin/KotlinPlatformType;)V diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/DecoratedExternalKotlinTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/DecoratedExternalKotlinTarget.kt index f44c4f1b9da..6485232751f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/DecoratedExternalKotlinTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/DecoratedExternalKotlinTarget.kt @@ -40,7 +40,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.InternalKotlinTarget */ @ExternalKotlinTargetApi open class DecoratedExternalKotlinTarget internal constructor( - internal val delegate: ExternalKotlinTargetImpl + internal val delegate: ExternalKotlinTargetImpl, ) : InternalKotlinTarget by delegate { constructor(delegate: Delegate) : this(delegate.impl) @@ -50,10 +50,20 @@ open class DecoratedExternalKotlinTarget internal constructor( val runtimeElementsConfiguration: Configuration = delegate.runtimeElementsConfiguration + /** + * @since 1.9.20 + */ + val sourcesElementsConfiguration: Configuration = delegate.sourcesElementsConfiguration + val apiElementsPublishedConfiguration: Configuration = delegate.apiElementsPublishedConfiguration val runtimeElementsPublishedConfiguration: Configuration = delegate.runtimeElementsPublishedConfiguration + /** + * @since 1.9.20 + */ + val sourcesElementsPublishedConfiguration: Configuration = delegate.sourcesElementsPublishedConfiguration + internal val logger: Logger = delegate.logger } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetDescriptor.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetDescriptor.kt index a2c33ad6a6e..3bc224732c6 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetDescriptor.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetDescriptor.kt @@ -37,6 +37,11 @@ interface ExternalKotlinTargetDescriptor { val apiElementsPublished: ExternalKotlinTargetConfigurationDescriptor val runtimeElementsPublished: ExternalKotlinTargetConfigurationDescriptor + /** + * @since 1.9.20 + */ + val sourcesElementsPublished: ExternalKotlinTargetConfigurationDescriptor + val configure: ((T) -> Unit)? val configureIdeImport: (IdeMultiplatformImport.() -> Unit)? } @@ -91,6 +96,12 @@ class ExternalKotlinTargetDescriptorBuilder i val runtimeElementsPublished: ExternalKotlinTargetConfigurationDescriptorBuilder = ExternalKotlinTargetConfigurationDescriptorBuilder() + /** + * @since 1.9.20 + */ + val sourcesElementsPublished: ExternalKotlinTargetConfigurationDescriptorBuilder = + ExternalKotlinTargetConfigurationDescriptorBuilder() + private var configure: ((T) -> Unit)? = null /** @@ -128,6 +139,7 @@ class ExternalKotlinTargetDescriptorBuilder i sourcesElements = sourcesElements.build(), apiElementsPublished = apiElementsPublished.build(), runtimeElementsPublished = runtimeElementsPublished.build(), + sourcesElementsPublished = sourcesElementsPublished.build(), configure = configure, configureIdeImport = configureIdeImport ) @@ -142,6 +154,7 @@ private data class ExternalKotlinTargetDescriptorImpl, override val apiElementsPublished: ExternalKotlinTargetConfigurationDescriptor, override val runtimeElementsPublished: ExternalKotlinTargetConfigurationDescriptor, + override val sourcesElementsPublished: ExternalKotlinTargetConfigurationDescriptor, override val configure: ((T) -> Unit)?, override val configureIdeImport: (IdeMultiplatformImport.() -> Unit)?, ) : ExternalKotlinTargetDescriptor diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetImpl.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetImpl.kt index 87496987b8f..97778504849 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetImpl.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetImpl.kt @@ -32,6 +32,7 @@ internal class ExternalKotlinTargetImpl internal constructor( val sourcesElementsConfiguration: Configuration, val apiElementsPublishedConfiguration: Configuration, val runtimeElementsPublishedConfiguration: Configuration, + val sourcesElementsPublishedConfiguration: Configuration, val kotlinTargetComponent: ExternalKotlinTargetComponent, private val artifactsTaskLocator: ArtifactsTaskLocator, ) : InternalKotlinTarget { @@ -78,7 +79,7 @@ internal class ExternalKotlinTargetImpl internal constructor( @InternalKotlinGradlePluginApi override val kotlinComponents: Set = setOf(kotlinTargetComponent) - override val components: Set by lazy { + override val components: Set by lazy { logger.debug("Creating SoftwareComponent") setOf(ExternalKotlinTargetSoftwareComponent(this)) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetSoftwareComponent.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetSoftwareComponent.kt index b16c785c075..fdbd2cf9f4b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetSoftwareComponent.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetSoftwareComponent.kt @@ -31,6 +31,10 @@ internal fun ExternalKotlinTargetSoftwareComponent( details.mapToMavenScope("runtime") } + if (target.isSourcesPublishable) { + adhocSoftwareComponent.addVariantsFromConfiguration(target.sourcesElementsPublishedConfiguration) { _ -> } + } + @OptIn(UnsafeApi::class) return ExternalKotlinTargetSoftwareComponent( target.project.multiplatformExtension, @@ -42,7 +46,7 @@ internal fun ExternalKotlinTargetSoftwareComponent( internal class ExternalKotlinTargetSoftwareComponent @UnsafeApi constructor( private val multiplatformExtension: KotlinMultiplatformExtension, private val adhocSoftwareComponent: SoftwareComponentInternal, - private val kotlinTargetComponent: ExternalKotlinTargetComponent + private val kotlinTargetComponent: ExternalKotlinTargetComponent, ) : ComponentWithCoordinates, ComponentWithVariants, SoftwareComponentInternal { override fun getName(): String = adhocSoftwareComponent.name override fun getUsages(): Set = adhocSoftwareComponent.usages diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/createExternalKotlinTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/createExternalKotlinTarget.kt index 0baa6459f42..e0d1eb8aaf5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/createExternalKotlinTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/createExternalKotlinTarget.kt @@ -32,7 +32,7 @@ import org.jetbrains.kotlin.gradle.utils.named */ @ExternalKotlinTargetApi fun KotlinMultiplatformExtension.createExternalKotlinTarget( - descriptor: ExternalKotlinTargetDescriptor + descriptor: ExternalKotlinTargetDescriptor, ): T { val apiElementsConfiguration = project.configurations.maybeCreate(lowerCamelCaseName(descriptor.targetName, "apiElements")) val runtimeElementsConfiguration = project.configurations.maybeCreate(lowerCamelCaseName(descriptor.targetName, "runtimeElements")) @@ -44,6 +44,9 @@ fun KotlinMultiplatformExtension.createExter val runtimeElementsPublishedConfiguration = project.configurations.maybeCreate(lowerCamelCaseName(descriptor.targetName, "runtimeElements-published")) + val sourcesElementsPublishedConfiguration = + project.configurations.maybeCreate(lowerCamelCaseName(descriptor.targetName, "sourcesElements-published")) + val kotlinTargetComponent = ExternalKotlinTargetComponent( ExternalKotlinTargetComponent.TargetProvider.byTargetName(this, descriptor.targetName) ) @@ -62,6 +65,7 @@ fun KotlinMultiplatformExtension.createExter sourcesElementsConfiguration = sourcesElementsConfiguration, apiElementsPublishedConfiguration = apiElementsPublishedConfiguration, runtimeElementsPublishedConfiguration = runtimeElementsPublishedConfiguration, + sourcesElementsPublishedConfiguration = sourcesElementsPublishedConfiguration, kotlinTargetComponent = kotlinTargetComponent, artifactsTaskLocator = artifactsTaskLocator ) @@ -71,6 +75,7 @@ fun KotlinMultiplatformExtension.createExter target.setupRuntimeElements(runtimeElementsConfiguration) target.setupRuntimeElements(runtimeElementsPublishedConfiguration) target.setupSourcesElements(sourcesElementsConfiguration) + target.setupSourcesElements(sourcesElementsPublishedConfiguration) apiElementsConfiguration.markConsumable() runtimeElementsConfiguration.markConsumable() sourcesElementsConfiguration.markConsumable() @@ -80,6 +85,8 @@ fun KotlinMultiplatformExtension.createExter apiElementsPublishedConfiguration.isCanBeResolved = false runtimeElementsPublishedConfiguration.isCanBeResolved = false runtimeElementsPublishedConfiguration.isCanBeConsumed = false + sourcesElementsPublishedConfiguration.isCanBeConsumed = false + sourcesElementsPublishedConfiguration.isCanBeResolved = false val decorated = descriptor.targetFactory.create(DecoratedExternalKotlinTarget.Delegate(target)) target.onCreated() @@ -90,6 +97,7 @@ fun KotlinMultiplatformExtension.createExter descriptor.sourcesElements.configure?.invoke(decorated, sourcesElementsConfiguration) descriptor.apiElementsPublished.configure?.invoke(decorated, apiElementsPublishedConfiguration) descriptor.runtimeElementsPublished.configure?.invoke(decorated, runtimeElementsPublishedConfiguration) + descriptor.sourcesElementsPublished.configure?.invoke(decorated, sourcesElementsPublishedConfiguration) descriptor.configureIdeImport?.invoke(project.kotlinIdeMultiplatformImport) targets.add(decorated) @@ -102,7 +110,7 @@ fun KotlinMultiplatformExtension.createExter */ @ExternalKotlinTargetApi fun KotlinMultiplatformExtension.createExternalKotlinTarget( - descriptor: ExternalKotlinTargetDescriptorBuilder.() -> Unit + descriptor: ExternalKotlinTargetDescriptorBuilder.() -> Unit, ): T { return createExternalKotlinTarget(ExternalKotlinTargetDescriptor(descriptor)) } @@ -121,4 +129,4 @@ private fun ExternalKotlinTargetImpl.setupRuntimeElements(configuration: Configu private fun ExternalKotlinTargetImpl.setupSourcesElements(configuration: Configuration) { configuration.configureSourcesPublicationAttributes(this) -} \ No newline at end of file +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetApiTests.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetApiTests.kt index c83b064349f..bb341a9d052 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetApiTests.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetApiTests.kt @@ -7,6 +7,9 @@ package org.jetbrains.kotlin.gradle.unitTests +import org.gradle.api.attributes.Attribute +import org.gradle.api.attributes.Category +import org.gradle.api.attributes.DocsType import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle @@ -20,9 +23,8 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.external.ExternalKotlinTargetDescr import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP import org.jetbrains.kotlin.gradle.util.runLifecycleAwareTest import org.jetbrains.kotlin.gradle.utils.property -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNull +import org.jetbrains.kotlin.gradle.utils.toMap +import kotlin.test.* class ExternalKotlinTargetApiTests { @@ -89,4 +91,79 @@ class ExternalKotlinTargetApiTests { assertEquals(KotlinSourceSetTree.main, KotlinSourceSetTree.orNull(mainCompilation)) assertNull(KotlinSourceSetTree.orNull(auxCompilation)) } + + @Test + fun `test - sourcesElements - default configuration`() = buildProjectWithMPP().runLifecycleAwareTest { + val target = kotlin.createExternalKotlinTarget { defaults() } + + assertNotEquals(target.sourcesElementsConfiguration, target.sourcesElementsPublishedConfiguration) + + assertEquals( + target.sourcesElementsConfigurationName, + target.sourcesElementsConfiguration.name + ) + + assertEquals( + target.sourcesElementsConfiguration.attributes.toMap(), + target.sourcesElementsPublishedConfiguration.attributes.toMap(), + "Expected sourcesElements and sourcesElementsPublished to contain the same attributes" + ) + + assertEquals( + KotlinPlatformType.jvm, target.sourcesElementsPublishedConfiguration.attributes.getAttribute(KotlinPlatformType.attribute), + "Expected KotlinPlatformType attribute to be present" + ) + + assertEquals( + Category.DOCUMENTATION, target.sourcesElementsPublishedConfiguration.attributes.getAttribute(Category.CATEGORY_ATTRIBUTE)?.name, + "Expected 'Category.DOCUMENTATION' as category attribute" + ) + + assertEquals( + DocsType.SOURCES, target.sourcesElementsPublishedConfiguration.attributes.getAttribute(DocsType.DOCS_TYPE_ATTRIBUTE)?.name, + "Expected 'DocsType.SOURCES' attribute" + ) + } + + @Test + fun `test - sourcesElements - configure`() = buildProjectWithMPP().runLifecycleAwareTest { + val testAttribute = Attribute.of("for.test", String::class.java) + + val target = kotlin.createExternalKotlinTarget { + defaults() + sourcesElements.configure { target, configuration -> + assertEquals(target.sourcesElementsConfiguration, configuration) + configuration.attributes.attribute(testAttribute, "sourcesElements") + } + + sourcesElementsPublished.configure { target, configuration -> + assertEquals(target.sourcesElementsPublishedConfiguration, configuration) + configuration.attributes.attribute(testAttribute, "sourcesElements-published") + } + } + + /* Check traces left before */ + assertEquals("sourcesElements", target.sourcesElementsConfiguration.attributes.getAttribute(testAttribute)) + assertEquals("sourcesElements-published", target.sourcesElementsPublishedConfiguration.attributes.getAttribute(testAttribute)) + } + + @Test + fun `test - sourcesElements - publication`() = buildProjectWithMPP().runLifecycleAwareTest { + val target = kotlin.createExternalKotlinTarget { defaults() } + val component = target.delegate.components.singleOrNull() ?: fail("Expected single 'component' for external target") + + component.usages.find { it.name == target.sourcesElementsPublishedConfiguration.name } + ?: fail("Missing sourcesElements usage") + } + + @Test + fun `test - sourcesElements - publication - withSourcesJar set to false`() = buildProjectWithMPP().runLifecycleAwareTest { + val target = kotlin.createExternalKotlinTarget { defaults() } + target.withSourcesJar(false) + val component = target.delegate.components.singleOrNull() ?: fail("Expected single 'component' for external target") + val sourcesUsage = component.usages.find { it.name.contains("sources", true) } + if (sourcesUsage != null) { + fail("Unexpected usage '${sourcesUsage.name} in target publication") + } + } }