In this blog post, we will guide you through the process of automatically publishing your Kotlin package to the Maven Central Repository. Follow the steps below to ensure a seamless setup.

1. Obtain a Sonatype OSSRH Account

To start, you need a Sonatype OSSRH (OSS Repository Hosting) account. Sign up for one by following this publish guide.

2. Meet Maven Central Publishing Requirements

Before you can publish a package to Maven Central, you must satisfy certain requirements. Find the complete list here. In summary, you need to:

  • Adhere to semantic versioning
  • Provide source code
  • Provide Java documentation
  • Sign publications with GPG

3. Configure Signing in Gradle

To sign your publications with GPG, configure the signing process in Gradle. You can reference this example of a build.gradle.kts file.

I used in-memory ascii-armored OpenPGP subkeys which let me store a signing only key to Github signingPassword of screte key.

Comparing to store configurations in a property file, this method is greate for CI.

signingKeyId: last 8 digits of subkey ID signingKey: ascii-armored with ECC algorithm signingPassword: same to secrete key’s

You can create a subkey by following 5.1.2

signing {
    val signingKeyId: String? by project
    val signingKey: String? by project
    val signingPassword: String? by project

    useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword)
    sign(publishing.publications["mavenKotlin"])
}

4. Set Up Publishing

To set up publishing, use the Gradle Nexus Publish Plugin.

This is a new plugin which make publishing easier than before with two different plugins.

nexusPublishing {
    repositories {
        create("myNexus") {
            nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
            snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
            username.set(System.getenv("OSSRH_USERNAME")) // defaults to project.properties["myNexusUsername"]
            password.set(System.getenv("OSSRH_PASSWORD")) // defaults to project.properties["myNexusPassword"]
        }
    }
}

5. Configure GitHub Workflow

5.1. Add Secrets

Securely store sensitive information, such as your Nexus credentials and GPG keys, in your GitHub repository using GitHub Secrets.

5.1.1. Nexus Token

Create a Nexus token to authenticate with the Sonatype OSSRH. Follow these steps:

  1. Log in to the Sonatype Nexus Repository Manager.
  2. Click on your username in the top-right corner and select “Profile.”
  3. Navigate to the “User Token” tab and click “Access User Token.”
  4. Enter your account password and click “Authenticate.”
  5. Click “Show User Token” to reveal your token. Make sure to copy both the “Username” and “Password” for the token.

Now, store the Nexus token in your GitHub repository as secrets:

  1. Go to your repository’s main page on GitHub.
  2. Click on the “Settings” tab.
  3. Navigate to the “Secrets” section in the left sidebar.
  4. Click the “New repository secret” button.
  5. Create two new secrets: OSSRH_USERNAME and OSSRH_PASSWORD. Use the “Username” and “Password” from the Nexus token, respectively.

5.1.2. GPG Subkey

Generate a GPG subkey for signing your Kotlin package. Follow these steps:

  1. Install GnuPG, if you haven’t already, by following the instructions on the official website.
  2. Open the command line (terminal on macOS/Linux or Command Prompt on Windows) and run gpg --list-secret-keys to list your existing secret keys.
  3. If you don’t have any secret keys, create one by running gpg --gen-key. Follow the prompts to generate a new key pair.
  4. Run gpg --edit-key [KEY_ID] to start the key-editing mode, replacing [KEY_ID] with the ID of the key you want to create a subkey for.
  5. Enter the command addkey to create a new subkey. Follow the prompts and choose the “ECC (sign only)” key type.
  6. Set the expiration date and key length, then confirm the subkey creation. Finally, enter the passphrase to unlock the master key.
  7. Run the save command to save the changes and exit the key-editing mode.
  8. Export the subkey by running gpg --armor --export-secret-subkeys [SUBKEY_ID] > subkey.gpg, replacing [SUBKEY_ID] with the ID of the subkey you just created.

Now, store the GPG subkey and related information in your GitHub repository as secrets:

  1. Open the subkey.gpg file and copy its contents.
  2. Retrieve the passphrase you used when creating your GPG key pair.
  3. Run gpg --list-secret-keys to list your secret keys and find the ID of the key you want to use for signing. Copy the key ID.
  4. Go to your repository’s main page on GitHub.
  5. Click on the “Settings” tab.
  6. Navigate to the “Secrets” section in the left sidebar.
  7. Click the “New repository secret” button.
  8. Create the following secrets:
    • GPG_SIGNING_KEY: Paste the contents of the subkey.gpg file.
    • GPG_PASSPHRASE: Enter the passphrase you used when creating your GPG key pair.
    • GPG_SIGNING_KEY_ID: Enter the key ID you found using gpg --list-secret-keys.

5.2 Configure Workflow

Create a yml file under .github/workflows with content below, then test it by manually trigger.

name: Publish package to the Maven Central Repository
on:
  release:
    types: [created]
  workflow_dispatch:
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up Java
        uses: actions/setup-java@v3
        with:
          java-version: '11'
          distribution: 'corretto'
      - name: Publish package
        uses: gradle/gradle-build-action@v2
        with:
          arguments: publishToMyNexus closeAndReleaseMyNexusStagingRepository
        env:
          OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
          OSSRH_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
          ORG_GRADLE_PROJECT_signingKey: ${{ secrets.GPG_SIGNING_KEY  }}
          ORG_GRADLE_PROJECT_signingKeyId: ${{ secrets.GPG_SINGING_KEY_ID }}
          ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.GPG_PASSPHASE }}