如何将 Kotlin 工件发布到 Maven Central?

mcr*_*eau 3 gradle kotlin

我正在努力将 Kotlin 工件发布到 Maven Central。我该怎么做呢?这是我的 build.gradle.kts。似乎我必须运行发布命令两次。一次用于发布,另一个用于快照存储库。这是正确的还是我做错了什么?

还有模块......我能够看到一些发布到 Nexus 的东西,但它是模块类型而不是 jar 类型。有什么想法吗?我将下面的打包定义为jar,构建目录有一个jar,发布时上传一个jar。我不确定是什么原因造成的。

构建.gradle.kts

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    id("org.jetbrains.kotlin.jvm") version "1.6.10"
    id("org.jetbrains.dokka") version "1.6.10"
    id("maven-publish")
    id("signing")
    id("jacoco")
    application
}

repositories {
    mavenCentral()
}

group = "foo.bar"
version = "0.001"

val dokkaOutputDir = "$buildDir/dokka"

application{
    mainClass.set("example.MainKt")
}

tasks.dokkaHtml {
    outputDirectory.set(file(dokkaOutputDir))
}

val deleteDokkaOutputDir by tasks.register<Delete>("deleteDokkaOutputDirectory") {
    delete(dokkaOutputDir)
}

val javadocJar = tasks.register<Jar>("javadocJar") {
    dependsOn(deleteDokkaOutputDir, tasks.dokkaHtml)
    archiveClassifier.set("javadoc")
    from(dokkaOutputDir)
}

tasks.test {
    useJUnitPlatform()
    testLogging.showStandardStreams = true
}

tasks.test {
    extensions.configure(JacocoTaskExtension::class) {
        destinationFile = file("$buildDir/jacoco/jacoco.exec")
    }
    finalizedBy("jacocoTestReport")
}

jacoco {
    toolVersion = "0.8.7"
}

tasks.jacocoTestReport {
    reports {
        xml.isEnabled = false
        csv.isEnabled = false
        html.isEnabled = true
        html.destination = file("$buildDir/reports/coverage")
    }
}

val coverage by tasks.registering {
    group = ""
    description = "Runs the unit tests with coverage"
    dependsOn(":test", ":jacocoTestReport")
    tasks["jacocoTestReport"].mustRunAfter(tasks["test"])
    tasks["jacocoTestCoverageVerification"].mustRunAfter(tasks["jacocoTestReport"])
}

dependencies {
    implementation("com.h2database:h2:2.1.210")
    implementation("org.jetbrains.kotlin:kotlin-stdlib")
    implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.10")
    implementation("org.jacoco:org.jacoco.core:0.8.7")
    testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
    testImplementation("org.junit.jupiter:junit-jupiter-engine:5.8.2")
}

publishing {
    repositories {
        maven {
            name = "Snapshot"
            val releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
            val snapshotRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
            setUrl { snapshotRepoUrl }
            credentials {
                username = ""
                password = ""
            }
        }
    }

    publications {
        create<MavenPublication>("Maven") {
            groupId = "foo.bar"
            artifactId = "foo"
            version = "0.001-SNAPSHOT"
            from(components["kotlin"])
        }
        withType<MavenPublication> {
            pom {
                packaging = "jar"
                name.set("foo")
                description.set("Project Foo")
                url.set("fooyee.com")
                licenses {
                    license {
                        name.set("MIT license")
                        url.set("https://opensource.org/licenses/MIT")
                    }
                }
                issueManagement {
                    system.set("Github")
                    url.set("https://github.com/mcroteau/foo/issues")
                }
                scm {
                    connection.set("scm:git:git://github.com/mcroteau/foo.git")
                    developerConnection.set("scm:git:git@github.com:mcroteau/foo.git")
                    url.set("https://github.com/mcroteau/foo")
                }
                developers {
                    developer {
                        name.set("Mike Croteau")
                        email.set("croteau.mike@gmail.com")
                    }
                }
            }
        }
    }
}

signing {
    useInMemoryPgpKeys(
        "",
        ""
    )
    sign(publishing.publications)
}

val compileKotlin: KotlinCompile by tasks
compileKotlin.kotlinOptions {
    jvmTarget = "1.8"
}
Run Code Online (Sandbox Code Playgroud)

感谢您的任何帮助!

aSe*_*emy 6

长话短说:

  • 查看完整示例,并根据版本标签选择快照/发布存储库
      repositories {
          maven {
              // change URLs to point to your repos, e.g. http://my.org/repo
              val releasesRepoUrl = uri(layout.buildDirectory.dir("repos/releases"))
              val snapshotsRepoUrl = uri(layout.buildDirectory.dir("repos/snapshots"))
              url = if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl
          }
      }
    
    Run Code Online (Sandbox Code Playgroud)
  • 改成from(components["kotlin"])from(components["java"])
  • 删除 Dokka 配置,使用默认值

发布到快照/发布

似乎我必须运行发布命令两次。一次用于发布,另一个用于快照存储库

通常,只有版本以 结尾的工件-SNAPSHOT才会发布到快照存储库,并且只有非快照版本才会发布到发布存储库,因此您必须运行该命令两次是有意义的。

您可以配置 Gradle,以便它将根据标签发布到版本或快照存储库。Gradle 网站上有一个很好的示例: https://docs.gradle.org/current/userguide/publishing_maven.html#publishing_maven :complete_example

这就是它的样子,适合您的情况

// select the repo based on the version
publishing {
    repositories {
        name = "sonatypeRepository"
        maven {
            val releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
            val snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
            url = if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,每个存储库的用户名和密码可能都不同。$GRADLE_HOME/gradle.propertiesGradle 有一种很好的方法来从环境变量/基于存储库名称获取凭证https://docs.gradle.org/current/samples/sample_publishing_credentials.html

这对你来说是这样的:

// select the repo based on the version, and get the credentials from Gradle properties
publishing {
  repositories {

    if (version.toString().endsWith("SNAPSHOT")) {
      maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") {
        name = "sonatypeReleaseRepository"
        credentials(PasswordCredentials::class)
      }
    } else {
      maven("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") {
        name = "sonatypeSnapshotRepository"
        credentials(PasswordCredentials::class)
      }
    }

  }
}
Run Code Online (Sandbox Code Playgroud)

最后将凭据设置环境变量

ORG_GRADLE_PROJECT_sonatypeSnapshotRepositoryUsername=my-sonaytype-SNAPSHOT-username
ORG_GRADLE_PROJECT_sonatypeSnapshotRepositoryPassowrd=Tr0ub4dor
Run Code Online (Sandbox Code Playgroud)

或者在$GRADLE_HOME/gradle.properties

sonatypeReleaseRepositoryUsername=my-sonaytype-RELEASE-username
sonatypeReleaseRepositoryPassowrd=CorrectHorseBatteryStaple
Run Code Online (Sandbox Code Playgroud)

要释放,

  1. 将版本更新build.gradle.kts-SNAPSHOT版本
  2. git commit和git tag(版本相同)
  3. ./gradlew publish
  4. 用非-SNAPSHOT版本重复...

这也可以通过在 Gradle 中编写更多逻辑来改进(或者参阅本答案的末尾以获取有关 JitPack 和“Gradle Git 版本控制插件”的信息)。

制作一个模块,而不是一个 JAR

我能够看到某些内容发布到 Nexus,但它是模块类型而不是 jar 类型。

我不确定,但我怀疑这是由于以下配置造成的:

ORG_GRADLE_PROJECT_sonatypeSnapshotRepositoryUsername=my-sonaytype-SNAPSHOT-username
ORG_GRADLE_PROJECT_sonatypeSnapshotRepositoryPassowrd=Tr0ub4dor
Run Code Online (Sandbox Code Playgroud)

我认为将版本设置为与项目版本不同可能容易出错。我将其省略,因为它将默认为 Gradle 项目版本。组 ID 和工件 ID 也是如此。

写作from(components["kotlin"])很诱人,但是,简而言之,它应该是from(components["java"])(因为它正在生成一个 JAR)。

所以我认为这更接近一个可行的解决方案:

sonatypeReleaseRepositoryUsername=my-sonaytype-RELEASE-username
sonatypeReleaseRepositoryPassowrd=CorrectHorseBatteryStaple
Run Code Online (Sandbox Code Playgroud)

多卡

您创建的 Dokka 任务对我来说看起来不正确(尽管它们可能不会给您带来发布问题)。

我怀疑默认设置可以正常工作,因此您可以删除所有 Dokka 任务和配置,并且可以按如下方式请求 Javadoc JAR:

        create<MavenPublication>("Maven") {
            groupId = "foo.bar"
            artifactId = "foo"
            version = "0.001-SNAPSHOT"
            from(components["kotlin"])
        }
Run Code Online (Sandbox Code Playgroud)

这些应该自动包含在您制作的任何出版物中。


推荐的附加工具

这里有一些我喜欢使用的工具,可以让发布变得更容易。

这些不一定有助于直接发布到 Maven,但它们可以是一个很好的替代方案或支持。我将它们包括在内,以防其他人在发布时遇到问题并需要解决方法。

Git 标签版本控制

发布过程可能涉及编辑build.gradle.kts(或其他一些文件),我个人不喜欢这样做。我建议查看Gradle Git 版本控制插件。一旦这样设置...

publishing {
  publications {
    create<MavenPublication>("Maven") {
      from(components["java"])
    }
 }
}
Run Code Online (Sandbox Code Playgroud)

现在版本号完全由git标签控制。释放变成

  1. 合并到主分支
  2. 以“release”格式创建标签,例如v1.2.3
  3. 跑步./gradlew publish

即时包装

如果您有一个开源项目,那么比 Sonatype 和 Maven 中心更容易设置的东西是JitPack。该项目将自动获取您的代码并发布新的工件。消费者只需添加一个额外的 Maven 存储库作为依赖提供者:

java {
  withJavadocJar()
  // withSourcesJar() // if you want sources?
}
Run Code Online (Sandbox Code Playgroud)