kotlin - 将 kotlin 多平台库发布到 Maven Central(InvalidMavenPublicationException 多个工件具有相同的......)
问题描述
由于 Jcenter 即将关闭,我正在尝试将我的库迁移到 Maven Central。我进行了很多搜索以找到任何工作脚本,但没有运气。有官方文档,但这就像一个笑话,只是告诉将maven-publish
插件放入 gradle 脚本,瞧就是这样。
目前我收到错误:
Caused by: org.gradle.api.publish.maven.InvalidMavenPublicationException: Invalid publication 'js': multiple artifacts with the identical extension and classifier ('jar', 'sources').
我的脚本如下所示:
plugins {
id("kotlin-multiplatform")
id("org.jetbrains.dokka") version "1.4.0-rc"
`maven-publish`
signing
}
kotlin {
sourceSets {
jvm()
js() {
nodejs()
browser()
}
linuxX64()
linuxArm64()
mingwX64()
macosX64()
iosArm64()
iosX64()
val commonMain by getting {
dependencies {
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val jsMain by getting {
dependencies {
}
}
val jsTest by getting {
dependencies {
implementation(kotlin("test-js"))
}
}
val jvmMain by getting {
dependencies {
}
}
val jvmTest by getting {
dependencies {
implementation(kotlin("test"))
implementation(kotlin("test-junit"))
}
}
val nativeMain by creating {
dependsOn(commonMain)
dependencies {
}
}
val linuxX64Main by getting {
dependsOn(nativeMain)
}
val linuxArm64Main by getting {
dependsOn(nativeMain)
}
val mingwX64Main by getting {
dependsOn(nativeMain)
}
val macosX64Main by getting {
dependsOn(nativeMain)
}
val iosArm64Main by getting {
dependsOn(nativeMain)
}
val iosX64Main by getting {
dependsOn(nativeMain)
}
}
}
tasks {
create<Jar>("javadocJar") {
dependsOn(dokkaJavadoc)
archiveClassifier.set("javadoc")
from(dokkaJavadoc.get().outputDirectory)
}
dokkaJavadoc {
println("Dokka !")
dokkaSourceSets {
create("commonMain") {
displayName = "common"
platform = "common"
}
}
}
}
// Publishing
val fis = FileInputStream("local.properties")
val properties = Properties().apply {
load(fis)
}
val ossUser = properties.getProperty("oss.user")
val ossPassword = properties.getProperty("oss.password")
extra["signing.keyId"] = properties.getProperty("signing.keyId")
extra["signing.password"] = properties.getProperty("signing.password")
extra["signing.secretKeyRingFile"] = properties.getProperty("signing.secretKeyRingFile")
val libraryVersion: String by project
val publishedGroupId: String by project
val artifactName: String by project
val libraryName: String by project
val libraryDescription: String by project
val siteUrl: String by project
val gitUrl: String by project
val licenseName: String by project
val licenseUrl: String by project
val developerOrg: String by project
val developerName: String by project
val developerEmail: String by project
val developerId: String by project
project.group = publishedGroupId
project.version = libraryVersion
signing {
sign(publishing.publications)
}
publishing {
publications.withType(MavenPublication::class) {
groupId = publishedGroupId
artifactId = artifactName
version = libraryVersion
artifact(tasks["javadocJar"])
artifact(tasks["sourcesJar"])
pom {
name.set(libraryName)
description.set(libraryDescription)
url.set(siteUrl)
licenses {
license {
name.set(licenseName)
url.set(licenseUrl)
}
}
developers {
developer {
id.set(developerId)
name.set(developerName)
email.set(developerEmail)
}
}
organization {
name.set(developerOrg)
}
scm {
connection.set(gitUrl)
developerConnection.set(gitUrl)
url.set(siteUrl)
}
}
}
repositories {
maven("https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
name = "sonatype"
credentials {
username = ossUser
password = ossPassword
}
}
}
}
我还发现这个reddit 主题没有解决方案,这篇文章不起作用,还有很多其他的。有大量材料如何发布到 bintray,但它们现在无关紧要
解决方案
似乎问题出在这一行artifact(tasks["sourcesJar"])
,因为该任务已经包括在内。
在这里,我想将我的工作脚本用于将 kotlin 多平台库上传到 Maven Central。
首先,我们需要注册 Sonatype 账户,验证我们的域名等,这里有一篇新鲜的文章,里面有详细的步骤。
那么您的项目脚本build.gradle.kts
可能如下所示:
import java.io.FileInputStream
import java.util.Properties
import org.gradle.api.publish.PublishingExtension
plugins {
id("kotlin-multiplatform")
id("org.jetbrains.dokka") version "1.4.0-rc"
id("io.codearte.nexus-staging") version "0.22.0"
`maven-publish`
signing
}
enum class OS {
LINUX, WINDOWS, MAC
}
fun getHostOsName(): OS =
System.getProperty("os.name").let { osName ->
when {
osName == "Linux" -> OS.LINUX
osName.startsWith("Windows") -> OS.WINDOWS
osName.startsWith("Mac") -> OS.MAC
else -> throw GradleException("Unknown OS: $osName")
}
}
kotlin {
sourceSets {
jvm()
js() {
browser()
nodejs()
}
when (getHostOsName()) {
OS.LINUX -> {
linuxX64()
linuxArm64()
}
OS.WINDOWS -> {
mingwX64()
}
OS.MAC -> {
macosX64()
iosArm64()
iosX64()
}
}
val commonMain by getting {
dependencies {
implementation(kotlin("stdlib-common"))
implementation(Libs.olekdia.common)
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val jvmMain by getting {
dependencies {
}
}
val jvmTest by getting {
dependencies {
implementation(kotlin("test"))
implementation(kotlin("test-junit"))
}
}
val jsMain by getting {
dependencies {
}
}
val nativeMain by creating {
dependsOn(commonMain)
}
when (getHostOsName()) {
OS.LINUX -> {
val linuxX64Main by getting {
dependsOn(nativeMain)
}
val linuxArm64Main by getting {
dependsOn(nativeMain)
}
}
OS.WINDOWS -> {
val mingwX64Main by getting {
dependsOn(nativeMain)
}
}
OS.MAC -> {
val macosX64Main by getting {
dependsOn(nativeMain)
}
val iosArm64Main by getting {
dependsOn(nativeMain)
}
val iosX64Main by getting {
dependsOn(nativeMain)
}
}
}
}
}
tasks {
create<Jar>("javadocJar") {
dependsOn(dokkaJavadoc)
archiveClassifier.set("javadoc")
from(dokkaJavadoc.get().outputDirectory)
}
dokkaJavadoc {
dokkaSourceSets {
create("commonMain") {
displayName = "common"
platform = "common"
}
}
}
}
//--------------------------------------------------------------------------------------------------
// Publishing
//--------------------------------------------------------------------------------------------------
val fis = FileInputStream("local.properties")
val properties = Properties().apply {
load(fis)
}
val ossUser = properties.getProperty("oss.user")
val ossPassword = properties.getProperty("oss.password")
extra["signing.keyId"] = properties.getProperty("signing.keyId")
extra["signing.password"] = properties.getProperty("signing.password")
extra["signing.secretKeyRingFile"] = properties.getProperty("signing.secretKeyRingFile")
val libraryVersion: String by project
val publishedGroupId: String by project
val artifactName: String by project
val libraryName: String by project
val libraryDescription: String by project
val siteUrl: String by project
val gitUrl: String by project
val licenseName: String by project
val licenseUrl: String by project
val developerOrg: String by project
val developerName: String by project
val developerEmail: String by project
val developerId: String by project
project.group = publishedGroupId
project.version = libraryVersion
signing {
sign(publishing.publications)
}
afterEvaluate {
configure<PublishingExtension> {
publications.all {
val mavenPublication = this as? MavenPublication
mavenPublication?.artifactId =
"${project.name}${"-$name".takeUnless { "kotlinMultiplatform" in name }.orEmpty()}"
}
}
}
publishing {
publications.withType(MavenPublication::class) {
groupId = publishedGroupId
artifactId = artifactName
version = libraryVersion
artifact(tasks["javadocJar"])
pom {
name.set(libraryName)
description.set(libraryDescription)
url.set(siteUrl)
licenses {
license {
name.set(licenseName)
url.set(licenseUrl)
}
}
developers {
developer {
id.set(developerId)
name.set(developerName)
email.set(developerEmail)
}
}
organization {
name.set(developerOrg)
}
scm {
connection.set(gitUrl)
developerConnection.set(gitUrl)
url.set(siteUrl)
}
}
}
repositories {
maven("https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
name = "sonatype"
credentials {
username = ossUser
password = ossPassword
}
}
}
}
nexusStaging {
username = ossUser
password = ossPassword
packageGroup = publishedGroupId
}
在以下位置提供所需的库详细信息gradle.properties
:
libraryVersion = 0.1.1
libraryName = Your library name
libraryDescription = Your library description
publishedGroupId = com.yourdomain
artifactName = your-cool-librayr
siteUrl = https://gitlab.com/yourlibrayr
gitUrl = https://gitlab.com/yourlibrayr.git
developerId = ...
developerOrg = ...
developerName = Your Name
developerEmail = yourmail@mail.com
licenseName = The Apache Software License, Version 2.0
licenseUrl = http://www.apache.org/licenses/LICENSE-2.0.txt
allLicenses = ["Apache-2.0"]
kotlin.mpp.enableGranularSourceSetsMetadata = true
gnsp.disableApplyOnlyOnRootProjectEnforcement = true
这里gnsp.disableApplyOnlyOnRootProjectEnforcement = true
需要nexusStaging
在子项目中声明的属性。
最后把你的学分放在local.properties
:
oss.user=your_user_name
oss.password=your_pass
signing.keyId=last_8_numbers_of_key
signing.password=your_pass
signing.secretKeyRingFile=/path/to/keystorage.gpg
现在在项目目录中发布打开的终端:
./gradlew build
./gradlew publish
./gradlew closeAndReleaseRepository
- 您可以跳过最后一个命令,并从Nexus 存储库管理器关闭和发布暂存包。
nexus-staging
只需要从命令行执行该插件即可。 - 我试图将脚本的发布部分移动到单独的文件中,并将其包含在 中
apply(from = "publish.gradle.kts")
,但它不起作用,因为它在单独的文件中丢失了上下文 - 我使用旧版本的 dokka 库(1.4.0-rc),因为新版本无法为所有平台生成 javadocs。存储库需要此 javadocs 才能发布。正如作者所提到的,我们可以为此目的生成空的 javadoc.jar 文件。