as of June 2024; based on material from Maven Central
This guide aims at making it as easy as possible for you to publish your first artifact.
While it's absolutely possible to deviate from this approach, this guide assumes you're in possession of:
- a GitHub account
- a Linux machine for development (this example has been created with Ubuntu)
- and a Maven-based project waiting to be published
- basic familiarity with Maven
Hop on over to the Maven Central repository, and login via GitHub. This registers the io.github.your-username namespace for you, allowing you to publish artifacts matching this namespace.
Important
If you didn't do so yet, adapt the <groupId>
of your artifact accordingly.
You might use io.github.your-username
or subgroups like io.github.your-username.foo
.
Consider renaming the package names accordingly.
For the artifact publishing, Maven needs access to your credentials.
Since you don't want to share your credentials by listing them in the project's POM,
these are put into the Maven settings, which are usually located at ~/.m2/settings.xml
.
As credentials, you'll be using a user token:
- go to your account on the Central Publisher Portal
- click the button "Generate User Token"
- copy the code snippet
- add it to your existing Maven settings, or create a new file containing
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>central</id>
<username>...</username>
<password>...</password>
</server>
</servers>
</settings>
Tip
Consider using Maven password encryption for storing these credentials.
Since you're using a Linux machine, gpg
should be available.
- create a key pair:
gpg --batch --passphrase '' --quick-gen-key "your-username@users.noreply.github.com"
- Note down the keyid (the hexadecimal code, usually the second line)
gpg -k your-username@users.noreply.github.com
- Distribute your public key
gpg --keyserver keys.openpgp.org --send-keys YOUR-KEYID
Note
When using GitHub actions to publish, you have to "hand out" both key & passphrase anyway,
thus we're using an empty passphrase to begin with.
If you'd rather want to use a passphrase, use gpg --gen-key
to create a key.
Now, your Maven project needs to be configured with a number of plugins.
We'll start with central-publishing-maven-plugin
, which will upload the artifacts to the Maven Central repository:
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.5.0</version>
<extensions>true</extensions>
<configuration>
<autoPublish>false</autoPublish>
<deploymentName>${project.artifactId}:${project.version}</deploymentName>
<waitUntil>validated</waitUntil>
</configuration>
</plugin>
With this in place, we can try out the publish process!
mvn -B -ntp deploy
This will eventually fail because we're still missing a couple of things,
yet your Deployments section in the Maven Central repository
should list our attempt to publish something.
Go ahead and hit the Drop button.
In order to publish to Maven Central, you need to sign all artifacts, and ship a Javadoc as well as the sources. Therefore, we need to configure more plugins:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
Now, let's run the deployment process again:
mvn -B -ntp deploy
Note
Chances are that generating the Javadoc fails. Fix any errors that occur.
Tip
If you happen to have multiple GPG keys, you might have to configure the correct key to use
(an indicator for that is Sonatype complaining with "Invalid signature for file").
There are several options to do this;
using -Dgpg.keyname=...
when calling Maven is suggested for now:
when automating the release later on, only one key will be available.
The Maven execution is probably still going to fail, since some information in the POM is missing. Sonatype requires you to provide (click here to see what I've added)
- a project description
- a project URL
- a license
- developers information
- an SCM URL
The only remaining thing to do is adapt the version, since SNAPSHOT
versions cannot be released.
Go ahead and adapt the version. Now if you run the Maven command again, you should have a successful build.
The Deployments section will now show a VALIDATED deployment.
Tip
If you think everything's working out, you can go ahead and publish your artifact now! π
For a more automated release process, we want the version numbering handled and have the released code tagged.
We'll use the maven-release-plugin
for this.
We pin the version of the maven-release-plugin
and overwrite some defaults:
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<arguments>-ntp</arguments>
<scmCommentPrefix />
<tagNameFormat>v@{project.version}</tagNameFormat>
</configuration>
</plugin>
</plugins>
</pluginManagement>
And, if not done so already, you need to set the SCM connection in the POM:
<scm>
<connection>scm:git:https://github.com/your-username/your-repository.git</connection>
</scm>
As an execution engine, we'll use GitHub Actions.
So let's create the file .github/workflows/release.yml
:
name: Release
on:
workflow_dispatch:
jobs:
release:
permissions:
contents: write # to manage the POM's version
runs-on: ubuntu-latest
steps:
- name: Check-out
uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
cache: maven
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
server-id: central
server-username: SONATYPE_USERNAME
server-password: SONATYPE_TOKEN
- name: Release with Maven
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
mvn -B -ntp -Dstyle.color=always release:prepare
VERSION=`cat release.properties | grep scm.tag= | cut -d'=' -f2`
mvn -B -ntp -Dstyle.color=always release:perform
echo "Released ${VERSION} π" >> $GITHUB_STEP_SUMMARY
env:
GPG_PASSPHRASE: ''
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
SONATYPE_TOKEN: ${{ secrets.SONATYPE_TOKEN }}
The script refers to 3 secrets that need to be set up before the workflow can successfully run:
the GPG private key for artifact signing, and the Sonatype credentials for publishing.
To do so,
- in your GitHub repository, navigate to Settings/Secrets and variables/Actions
- click on _New repository secret"
- put
SONATYPE_USERNAME
into the Name field - put your username into the Value field
- store the secret by hitting Add secret
- put
- now create a secret for
SONATYPE_TOKEN
following the same steps - now create a secret for
GPG_PRIVATE_KEY
- for the Value field, paste the data returned by
gpg --export-secret-keys --armor YOUR-KEYID
- for the Value field, paste the data returned by
Tip
If your GPG key requires a pass phrase, simply add that as a secret as well, and adapt the release.yml
accordingly.
We're all set to release!
In your GitHub repository,
go to Actions,
click on Release in the left panel,
select Run workflow on the right,
and finally click Run workflow in the pop up.
It'll take a few seconds, then the workflow run will appear.
You may drill into the details, or just wait until the process has finished.
Once again, Maven Central repository's Deployments section will show a VALIDATED deployment.
For a fully automated release, set the autoPublish
parameter to true
. πͺ
Now you're all set - go ahead, release your stuff, change the world!