Tuesday, September 17, 2024

Release and publish Maven artifacts on Github (2024)

In 2024 the mechanism of publishing Maven artifacts has changed, in this short article we'll discuss how we can release and publish a new Maven package from GitHub.

https://central.sonatype.com will be our starting point, let's open it in the browser:



Let's click on "Sign in" button!

If you are new here, press on Signup, otherwise enter your username and credential:

Important note: If you already have a user from the old Maven central (oss.sonatype.org), then you might not able to log in, then read the following websites:

Once you've logged in, you'll see a similar page that I've pasted as first attachment, with only one difference on the top right corner:



Create a namespace


Open "View namespaces" to add a new namespace, then press "Add namespace".

If you have a GitHub user called "johndoe123", then you have to define

io.github.johndoe123

Once you pressed Submit, you have to verify that you own the given domain.

You can see a Verification key on the bottom left side of the panel. In order to proove that you are the owner of that GitHub account, create a repository with that name:

After the repository created, press "Verify namespace" and "Confirm":

Verification takes a few minutes to complete:


After the verification completed, you will see

HINT: After the verification don't forget to remove the repository!

GPG configuration

Create the key


In order to sign your Maven package you'll need a keypair generated by GPG. Run

gpg --gen-key

Once you generated the key, run


and you will see something like this:
$ gpg --list-keys /home/mylocaluser/.gnupg/pubring.kbx --------------------------------- pub rsa3072 2021-06-23 [SC] [expires: 2023-06-23] CA925CD6C9E8D064FF05B4728190C4130ABA0F98 uid [ultimate] Central Repo Test <central@example.com> sub rsa3072 2021-06-23 [E] [expires: 2023-06-23]

You need to copy the highlighted value, we will use it later.

Save the public key

Next we have to export the public key. It will be used by Sonatype portal, so we'll publish it on Ubuntu keyserver:

gpg --armor --export <Copied_highlighted_ID>

Save the private key

We need the exported private key in order to use it in our GitHub Action step to sign the Maven artifacts:

gpg --armor --export-secret-keys <Copied_highlighted_ID>



Upload the public key

Let's open https://keyserver.ubuntu.com/ and press "Submit key" and paste the recently exported public key into the input field:



With that all required steps completed that is necessary on Sonatype side, let's move on to our side!

Maven configuration

Resources: 

Configuration options


Before you add the necessary plugins to your pom.xml, please check this website:


If you want to release a public (open source) Maven package, you have to set all mandatory parameters!

Plugin setup

I recommend to define a new Maven profile in order to separate release functionality from other Maven features.
4 Maven plugins required:
  • maven-source-plugin
  • maven-javadoc-plugin
  • maven-gpg-plugin
  • central-publishing-maven-plugin

<profile>
<id>release</id>
<distributionManagement>
<repository>
<id>central</id>
<url>https://central.sonatype.com</url>
</repository>
</distributionManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<doclint>all,-missing</doclint>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.5.0</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
</configuration>
</plugin>
</plugins>
</build>
</profile>

Now let's discuss the most important parts of this setup!

Distribution setup

<distributionManagement>
<repository>
<id>central</id>
<url>https://central.sonatype.com</url>
</repository>
</distributionManagement>
In this configuration setup you defined that your artifact will be distributed to the Central Sonatype website, and the ID will be "central". You will see why this ID is important to remember.

Central Sonatype plugin

This plugin is essential to upload and release your Maven package. There are several ways to customize this plugin, you can find further info here: 
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.5.0</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
</configuration>
</plugin>

For instance, if you prefer automatic publishing, you need to set "autoPublish" configuration property to true.

GitHub repository setup

GitHub Action

We have to create a new GitHub workflow by pressing "New workflow", then press "setup a workflow yourself".

Let's add the following code:

name: Release Java client library

on:
  workflow_dispatch:
    inputs:
      releaseVersion:
        description: "Default version to use when preparing a release."
        required: true
        default: "X.Y.Z"
      developmentVersion:
        description: "Default version to use for new local working copy."
        required: true
        default: "X.Y.Z-SNAPSHOT"
permissions:
  contents: write
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          token: ${{ secrets.PAT }}
          ref: main
        env:
          branch: main
      - id: install-secret-key 
        name: Install gpg secret key 
        run: | 
          # Install gpg secret key 
          cat <(echo -e "${{ secrets.GPG_SIGNING_KEY }}") | gpg --batch --import 
          # Verify gpg secret key 
          gpg --list-secret-keys --keyid-format LONG
      - name: Set up Maven Central Repository
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'
          server-id: central
          server-username: MAVEN_USERNAME
          server-password: MAVEN_PASSWORD
      - name: Update pom.xml to releaseVersion
        run: mvn -B versions:set -DnewVersion=${{ github.event.inputs.releaseVersion }} -DgenerateBackupPoms=false -f ./pom.xml
      - name: Commit version change
        run: |
          git config --global user.name ${{ secrets.GH_USERNAME }}
          git config --global user.email ${{ secrets.GH_EMAIL }}
          git commit -am "[ci-skip] Version updated to ${{ github.event.inputs.releaseVersion }}"
      - name: Publish package
        run: mvn -Prelease --batch-mode -Dgpg.keyname=${{ secrets.GPG_KEY }} -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }} deploy -f ./pom.xml
        env:
          MAVEN_USERNAME:  ${{ secrets.SONATYPE_USERNAME }}
          MAVEN_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
          MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
      - name: Update pom.xml to developmentVersion
        run: mvn -B versions:set -DnewVersion=${{ github.event.inputs.developmentVersion }} -DgenerateBackupPoms=false -f ./pom.xml
      - name: Commit version change to next SNAPSHOT version
        run: |
          git config --global user.name ${{ secrets.GH_USERNAME }}
          git config --global user.email ${{ secrets.GH_EMAIL }}
          git commit -am "[ci-skip] Version updated to ${{ github.event.inputs.developmentVersion }}"
          git push

Secrets

We will need a bunch of secrets for our Maven artifact release.
  • PAT*: GitHub Personal Access Token,
  • GPG_SIGNING_KEY: Set your exported private GPG key into this secret,
  • GH_USERNAME: This should be your GitHub username (email),
  • GH_EMAIL: Your email address,
  • GPG_KEY: GPG key ID ("<Copied_highlighted_ID>"),
  • GPG_PASSPHRASE: The password that you've defined for the GPG key,
  • SONATYPE_USERNAME*: Sonatype token username,
  • SONATYPE_PASSWORD*: Sonatype token password
Some of these secrets requires some clarification, let's go one by one!

PAT

To create a new GitHub Personal Access Token, go to: https://github.com/settings/apps 

and select "Fine-grained tokens(beta)", then press "Generate new token" button. Add all mandatory parameters like:
  • token name,
  • resource owner,
  • expiration date,
  • repository access: If you want to create a PAT for only a specific repository, choose "Only select repositories" menu, otherwise you can choose "All repositories".
  • Permissions: I'd say the following permissions are enough:


Sonatype settings

The username and password names can be misleading, because these are generated user tokens. To generate a new user token name and password, go to https://central.sonatype.com/account and press "Generate new user token", then copy the provided username and password into
  • SONATYPE_USERNAME and
  • SONATYPE_PASSWORD
GitHub Actions secrets.


Check the deployed artifact

Run your GitHub Action manually, and if everything goes fine, you'll see something like that on Maven Central:

After a few minutes the status will change to deployed:




No comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Configure and use VSCode for Java web development

Embarking on Java web development often starts with choosing the right tools that streamline the coding process while enhancing productivity...