• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download

<lambda>null1 import groovy.util.*
2 import org.gradle.jvm.tasks.Jar
3 import org.gradle.kotlin.dsl.*
4 import org.gradle.plugins.signing.*
5 import org.jetbrains.kotlin.gradle.dsl.*
6 import org.jetbrains.kotlin.gradle.tasks.*
7 import java.net.*
8 
9 /*
10  * Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
11  */
12 
13 // Configures publishing of Maven artifacts to MavenCentral
14 plugins {
15     `maven-publish`
16     signing
17 }
18 
19 val isMultiplatform = name in listOf(
20     "kotlinx-serialization-core",
21     "kotlinx-serialization-json",
22     "kotlinx-serialization-json-okio",
23     "kotlinx-serialization-json-io",
24     "kotlinx-serialization-json-tests",
25     "kotlinx-serialization-protobuf",
26     "kotlinx-serialization-cbor",
27     "kotlinx-serialization-properties"
28 )
29 
30 val isBom = name == "kotlinx-serialization-bom"
31 
32 if (!isBom) {
<lambda>null33     tasks.register<Jar>("stubJavadoc") {
34         archiveClassifier = "javadoc"
35     }
36 }
37 
38 tasks.register<Jar>("emptyJar")
39 
<lambda>null40 afterEvaluate {
41     val mainSourcesJar = tasks.register<Jar>("mainSourcesJar") {
42         archiveClassifier = "sources"
43         if (isMultiplatform) {
44             from(kotlinExtension.sourceSets.getByName("commonMain").kotlin)
45         } else if (isBom) {
46             // no-op: sourceSets is [] for BOM, as it does not have sources.
47         } else {
48             from(sourceSets.named("main").get().allSource)
49         }
50     }
51 
52     publishing {
53         if (!isMultiplatform && !isBom) {
54             publications.register<MavenPublication>("maven") {
55                 artifactId = project.name
56                 from(components["java"])
57                 artifact(mainSourcesJar)
58                 artifact(tasks.named("stubJavadoc"))
59             }
60         } else {
61             // Rename artifacts for backward compatibility
62             publications.withType<MavenPublication>().configureEach {
63                 val type = name
64                 logger.info("Configuring $type")
65                 when (type) {
66                     "kotlinMultiplatform" -> {
67                         // With Kotlin 1.4.0, the root module ID has no suffix, but for compatibility with
68                         // the consumers who can't read Gradle module metadata, we publish the JVM artifacts in it
69                         artifactId = project.name
70                         reconfigureMultiplatformPublication(publications.getByName("jvm") as MavenPublication)
71                     }
72                     "metadata", "jvm", "js", "native" -> artifactId = "${project.name}-$type"
73                 }
74                 logger.info("Artifact id = $artifactId")
75 
76                 // The 'root' module publishes the JVM module's Javadoc JAR as per reconfigureMultiplatformPublication, and
77                 // every other module should publish an empty Javadoc JAR. TODO: provide proper documentation artifacts?
78                 if (name != "kotlinMultiplatform" && !isBom) {
79                     artifact(tasks.named("stubJavadoc"))
80                 }
81             }
82         }
83 
84         publications.withType<MavenPublication>().configureEach {
85             pom.configureMavenCentralMetadata()
86             signPublicationIfKeyPresent()
87         }
88     }
89 }
90 
91 val testRepositoryDir = project.layout.buildDirectory.dir("testRepository")
92 
<lambda>null93 publishing {
94     repositories {
95         addSonatypeRepository()
96 
97         /**
98          * Maven repository in build directory to check published artifacts.
99          */
100         maven {
101             setUrl(testRepositoryDir)
102             name = "test"
103         }
104     }
105 }
106 
107 interface LocalArtifactAttr : Named {
108     companion object {
109         val ATTRIBUTE = Attribute.of(
110             "kotlinx.kover.gradle-plugin",
111             LocalArtifactAttr::class.java
112         )
113     }
114 }
115 
namenull116 val testPublicationTask: TaskCollection<*> = tasks.named { name -> name == "publishAllPublicationsToTestRepository" }
<lambda>null117 configurations.register("testPublication") {
118     isVisible = false
119     isCanBeResolved = false
120     // this configuration produces modules that can be consumed by other projects
121     isCanBeConsumed = true
122     attributes {
123         attribute(Attribute.of("kotlinx.serialization.repository", String::class.java), "test")
124     }
125     outgoing.artifact(testRepositoryDir) {
126         builtBy(testPublicationTask)
127     }
128 }
129 
<lambda>null130 tasks.withType<AbstractPublishToMaven>().configureEach {
131     dependsOn(tasks.withType<Sign>())
132 }
133 
134 // NOTE: This is a temporary WA, see KT-61313.
135 // Task ':compileTestKotlin<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency
<lambda>null136 tasks.withType<KotlinNativeCompile>().matching { it.name.startsWith("compileTestKotlin") }.configureEach {
137     val targetName = name.substringAfter("compileTestKotlin")
<lambda>null138     mustRunAfter(tasks.withType<Sign>().named { it == "sign${targetName}Publication" })
139 }
140 
141 // NOTE: This is a temporary WA, see KT-61313.
142 // Task ':linkDebugTest<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency
<lambda>null143 tasks.withType<KotlinNativeLink>() {
144     val targetName = name.substringAfter("linkDebugTest")
145     mustRunAfter(tasks.withType<Sign>().named { it == "sign${targetName}Publication" })
146 }
147 
configureMavenCentralMetadatanull148 fun MavenPom.configureMavenCentralMetadata() {
149     name = project.name
150     description = "Kotlin multiplatform serialization runtime library"
151     url = "https://github.com/Kotlin/kotlinx.serialization"
152 
153     licenses {
154         license {
155             name = "The Apache Software License, Version 2.0"
156             url = "https://www.apache.org/licenses/LICENSE-2.0.txt"
157             distribution = "repo"
158         }
159     }
160 
161     developers {
162         developer {
163             id = "JetBrains"
164             name = "JetBrains Team"
165             organization = "JetBrains"
166             organizationUrl = "https://www.jetbrains.com"
167         }
168     }
169 
170     scm {
171         url = "https://github.com/Kotlin/kotlinx.serialization"
172     }
173 }
174 
175 // utility functions
176 
177 /**
178  * Re-configure common publication to depend on JVM artifact only in pom.xml.
179  *
180  *  Publish the platform JAR and POM so that consumers who depend on this module and can't read Gradle module
181  *  metadata can still get the platform artifact and transitive dependencies from the POM.
182  *
183  *  Taken from https://github.com/Kotlin/kotlinx.coroutines
184  */
reconfigureMultiplatformPublicationnull185 public fun Project.reconfigureMultiplatformPublication(jvmPublication: MavenPublication) {
186     val mavenPublications =
187         extensions.getByType<PublishingExtension>().publications.withType<MavenPublication>()
188     val kmpPublication = mavenPublications.getByName("kotlinMultiplatform")
189 
190     var jvmPublicationXml: XmlProvider? = null
191     jvmPublication.pom.withXml { jvmPublicationXml = this }
192 
193     kmpPublication.pom.withXml {
194         val root = asNode()
195         // Remove the original content and add the content from the platform POM:
196         root.children().toList().forEach { root.remove(it as Node) }
197         jvmPublicationXml!!.asNode().children().forEach { root.append(it as Node) }
198 
199         // Adjust the self artifact ID, as it should match the root module's coordinates:
200         ((root["artifactId"] as NodeList).first() as Node).setValue(kmpPublication.artifactId)
201 
202         // Set packaging to POM to indicate that there's no artifact:
203         root.appendNode("packaging", "pom")
204 
205         // Remove the original platform dependencies and add a single dependency on the platform module:
206         val dependencies = (root["dependencies"] as NodeList).first() as Node
207         dependencies.children().toList().forEach { dependencies.remove(it as Node) }
208         dependencies.appendNode("dependency").apply {
209             appendNode("groupId", jvmPublication.groupId)
210             appendNode("artifactId", jvmPublication.artifactId)
211             appendNode("version", jvmPublication.version)
212             appendNode("scope", "compile")
213         }
214     }
215 
216     // TODO verify if this is still relevant
217     tasks.matching { it.name == "generatePomFileForKotlinMultiplatformPublication" }.configureEach {
218         @Suppress("DEPRECATION")
219         dependsOn("generatePomFileFor${jvmPublication.name.capitalize()}Publication")
220     }
221 }
222 
signPublicationIfKeyPresentnull223 fun MavenPublication.signPublicationIfKeyPresent() {
224     val keyId = getSensitiveProperty("libs.sign.key.id")
225     val signingKey = getSensitiveProperty("libs.sign.key.private")
226     val signingKeyPassphrase = getSensitiveProperty("libs.sign.passphrase")
227     if (!signingKey.isNullOrBlank()) {
228         extensions.configure<SigningExtension>("signing") {
229             useInMemoryPgpKeys(keyId, signingKey, signingKeyPassphrase)
230             sign(this@signPublicationIfKeyPresent)
231         }
232     }
233 }
234 
RepositoryHandlernull235 fun RepositoryHandler.addSonatypeRepository() {
236     maven {
237         url = mavenRepositoryUri()
238         credentials {
239             username = getSensitiveProperty("libs.sonatype.user")
240             password = getSensitiveProperty("libs.sonatype.password")
241         }
242     }
243 }
244 
mavenRepositoryUrinull245 fun mavenRepositoryUri(): URI {
246     // TODO -SNAPSHOT detection can be made here as well
247     val repositoryId: String? = System.getenv("libs.repository.id")
248     return if (repositoryId == null) {
249         URI("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
250     } else {
251         URI("https://oss.sonatype.org/service/local/staging/deployByRepositoryId/$repositoryId")
252     }
253 }
254 
getSensitivePropertynull255 fun getSensitiveProperty(name: String): String? {
256     return findProperty(name) as? String ?: System.getenv(name)
257 }
258