Maven Central Publishing using Gradle and gpg signing

D C
4 min readApr 19, 2020

Being new to Maven Central publishing it is difficult to get straight steps to get publishing to work on first try. This article is a step by step guide on how to publish your java project using gradle.

Let’s get started, below are the steps that will guide you and help understand how to publish and which information is needed and for what purpose.

  1. Sonatype account

You need a repository on Nexus Sonatype to publish your project. The account can be created here. If you are using your company account then your Jira account id and password is what you need for publishing.

2. Gradle plugins and Repositories

You’ll need the following plugins in your build.gradle:

apply plugin: 'maven'
apply plugin: 'signing'

You’ll need the mavenCentral repository:

repositories{
mavenCentral()
}

3. Jars

For a java project we need JavaDocJar and SourcesJar. The javaDocJar contains the static html which is extracted form the jar itself and sourcesJar contain the compiled jar.

task javadocJar(type: Jar) {    
classifier = 'javadoc'
from javadoc
}
task sourcesJar(type: Jar) {
classifier = 'sources'
from sourceSets.main.allSource
}

Then we need to hook them to artifact collection so that they are archived and sent to repository along with the jar.

artifacts {
archives jar, javadocJar, sourcesJar
}

At this point it is highly advised to check your javadocJar and sourceJar tasks. You can do that by simply running those tasks either from IDE or by using gradlew

You might get error while running javadocJar most probably when you are using symbols like: < or > or @ etc inside the code as a part of comment, you get this error because the javadocJar task mistakes those symbols as wrongly used HTML elements.

The simplest way to resolve them is by using @literal for example: if you have used < in one of your comments then replace it with {@literal <}

4. Signing

This is the part for which we used sigining plugin. Maven Central requires all your files to be signed using the gpg key. The process to create that is pretty straight forward.

  • Creating a gpg key:

For this you have to install gnupg first. I have used homebrew to do that. To install gnupg just type: brew install gnupg on your terminal. If you do not have home brew and want to install then you can just do this in your terminal: ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Finally create your gpg key:

gpg — gen-key 

Once you hit enter it will ask for Real Name, email. Confirm by typing O and press return. After which it should ask you for a passphrase. Enter and re-enter your passphrase when prompted.

Once you are done with above step you can see your gpg key file inside your .gnupg folder. You’ll be able to see the following files:

Files inside your .gnupg folder

You can navigate to your gnupg folder by typing cd ~/.gnupg in terminal. We are not done yet.

Now, here is the catch the latest version of gnupg does not create public file straight away. You need to extract it by using:

gpg — output yourchoice.gpg — export

This will create a the public key file for you.

Finally sign you artifact using the following task:

signing {
sign configurations.archives
}

5. Uploading Archives

This part is pretty straight forward and is described here.

First you need to define the following at the top level of your build. gradle.

group = "com.example.applications"
archivesBaseName = "example-application"
version = "1.4.7"

Then you’ll need the following task:

uploadArchives {
repositories {
mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }

repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication(userName: ossrhUsername, password: ossrhPassword)
}

snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
authentication(userName: ossrhUsername, password: ossrhPassword)
}

pom.project {
name 'Example Application'
packaging 'jar'
group 'com.example.lib'
artifactId 'artifact-id'
description 'A application used as an example on how to set up
pushing its components to the Central Repository.'
url 'http://www.example.com/example-application'

scm {
connection 'scm:svn:http://foo.googlecode.com/svn/trunk/'
developerConnection 'scm:svn:https://foo.googlecode.com/svn/trunk/'
url 'http://foo.googlecode.com/svn/trunk/'
}

licenses {
license {
name 'The Apache License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}

developers {
developer {
id 'sampleId'
name 'Sample Name'
email 'sample@samplecompany.com'
}
}
}
}
}
}

We are almost done here, the last step is to define the variables we have used in the above code and the signing credentials, we need to put the following in your local gradle.properties

signing.keyId=YourKeyId
signing.password=YourPublicKeyPassword
signing.secretKeyRingFile=PathToYourKeyRingFile

ossrhUsername=your-jira-id
ossrhPassword=your-jira-password

The keyId, publicKeyPassword are the ones which we created our gpg key with step 4. PathToYourKeyRingFile is the extracted gpg file.

That’s it.

Now you just have to run uploadArchives task. Once the task successfully uploads the archives to the repository it will be available in staging repo. You can publish it manually after you confirm the file structure.

--

--