将 kotlin 多平台库发布到 Maven Central(InvalidMavenPublicationException 多个具有相同的工件...)

Ole*_*bul 6 maven-central kotlin kotlin-multiplatform

由于 Jcenter 即将关闭,我\xe2\x80\x99m 尝试将我的库迁移到 Maven Central。我进行了很多搜索以找到任何可用的脚本,但没有运气。有官方文档,但这就像一个笑话,只是告诉将maven-publish插件添加到 gradle 脚本中,瞧,\xe2\x80\x99s 它。

\n

目前我收到错误:

\n
Caused by: org.gradle.api.publish.maven.InvalidMavenPublicationException: Invalid publication \'js\': multiple artifacts with the identical extension and classifier (\'jar\', \'sources\').\n
Run Code Online (Sandbox Code Playgroud)\n

我的脚本如下所示:

\n
plugins {\n    id("kotlin-multiplatform")\n    id("org.jetbrains.dokka") version "1.4.0-rc"\n    `maven-publish`\n    signing\n}\n\nkotlin {\n    sourceSets {\n        jvm()\n        js() {\n            nodejs()\n            browser()\n        }\n        linuxX64()\n        linuxArm64()\n        mingwX64()\n        macosX64()\n        iosArm64()\n        iosX64()\n\n        val commonMain by getting {\n            dependencies {\n            }\n        }\n        val commonTest by getting {\n            dependencies {\n                implementation(kotlin("test-common"))\n                implementation(kotlin("test-annotations-common"))\n            }\n        }\n\n        val jsMain by getting {\n            dependencies {\n            }\n        }\n        val jsTest by getting {\n            dependencies {\n                implementation(kotlin("test-js"))\n            }\n        }\n\n        val jvmMain by getting {\n            dependencies {\n            }\n        }\n        val jvmTest by getting {\n            dependencies {\n                implementation(kotlin("test"))\n                implementation(kotlin("test-junit"))\n            }\n        }\n\n        val nativeMain by creating {\n            dependsOn(commonMain)\n            dependencies {\n            }\n        }\n\n        val linuxX64Main by getting {\n            dependsOn(nativeMain)\n        }\n        val linuxArm64Main by getting {\n            dependsOn(nativeMain)\n        }\n        val mingwX64Main by getting {\n            dependsOn(nativeMain)\n        }\n        val macosX64Main by getting {\n            dependsOn(nativeMain)\n        }\n        val iosArm64Main by getting {\n            dependsOn(nativeMain)\n        }\n        val iosX64Main by getting {\n            dependsOn(nativeMain)\n        }\n    }\n}\n\ntasks {\n    create<Jar>("javadocJar") {\n        dependsOn(dokkaJavadoc)\n        archiveClassifier.set("javadoc")\n        from(dokkaJavadoc.get().outputDirectory)\n    }\n\n    dokkaJavadoc {\n        println("Dokka !")\n        dokkaSourceSets {\n            create("commonMain") {\n                displayName = "common"\n                platform = "common"\n            }\n        }\n    }\n}\n\n//  Publishing\n\nval fis = FileInputStream("local.properties")\nval properties = Properties().apply {\n    load(fis)\n}\nval ossUser = properties.getProperty("oss.user")\nval ossPassword = properties.getProperty("oss.password")\nextra["signing.keyId"] = properties.getProperty("signing.keyId")\nextra["signing.password"] = properties.getProperty("signing.password")\nextra["signing.secretKeyRingFile"] = properties.getProperty("signing.secretKeyRingFile")\n\nval libraryVersion: String by project\nval publishedGroupId: String by project\nval artifactName: String by project\nval libraryName: String by project\nval libraryDescription: String by project\nval siteUrl: String by project\nval gitUrl: String by project\nval licenseName: String by project\nval licenseUrl: String by project\nval developerOrg: String by project\nval developerName: String by project\nval developerEmail: String by project\nval developerId: String by project\n\nproject.group = publishedGroupId\nproject.version = libraryVersion\n\nsigning {\n    sign(publishing.publications)\n}\n\npublishing {\n    publications.withType(MavenPublication::class) {\n        groupId = publishedGroupId\n        artifactId = artifactName\n        version = libraryVersion\n\n        artifact(tasks["javadocJar"])\n        artifact(tasks["sourcesJar"])\n\n        pom {\n            name.set(libraryName)\n            description.set(libraryDescription)\n            url.set(siteUrl)\n\n            licenses {\n                license {\n                    name.set(licenseName)\n                    url.set(licenseUrl)\n                }\n            }\n            developers {\n                developer {\n                    id.set(developerId)\n                    name.set(developerName)\n                    email.set(developerEmail)\n                }\n            }\n            organization {\n                name.set(developerOrg)\n            }\n            scm {\n                connection.set(gitUrl)\n                developerConnection.set(gitUrl)\n                url.set(siteUrl)\n            }\n        }\n    }\n\n    repositories {\n        maven("https://oss.sonatype.org/service/local/staging/deploy/maven2/") {\n            name = "sonatype"\n            credentials {\n                username = ossUser\n                password = ossPassword\n            }\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我还发现这个reddit 主题没有解决方案,这篇文章不起作用,还有很多其他的。如何发布到 bintray 有很多资料,但现在都无关紧要了

\n

Ole*_*bul 8

问题似乎出在这一行,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
}
Run Code Online (Sandbox Code Playgroud)

在以下位置提供所需的库详细信息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
Run Code Online (Sandbox Code Playgroud)

这里需要在子项目中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

Run Code Online (Sandbox Code Playgroud)

现在在项目目录中发布打开终端:

./gradlew build
./gradlew publish
./gradlew closeAndReleaseRepository
Run Code Online (Sandbox Code Playgroud)
  • 您可以跳过最后一个命令,并从Nexus 存储库管理器关闭并发布暂存包。nexus-staging只需要从命令行执行该插件即可。
  • 我尝试将脚本的发布部分移至单独的文件,并将其包含在 中apply(from = "publish.gradle.kts"),但它不起作用,因为它在单独的文件中丢失了上下文
  • 我使用旧版本的 dokka 库 (1.4.0-rc),因为新版本无法为所有平台生成 javadoc。存储库需要此 javadocs 才能发布。正如作者提到的,我们可以为此目的生成空的 javadoc.jar 文件。