Automated Gradle Publish with GitHub Actions (To Maven Central)

In my previous article, “Complete Guide: Publish with Gradle to Maven Central (native)”, I’ve explained how to publish artefacts to Maven Central manually. Now it’s time to show the automated way with GitHub Actions 🤩

If you need to remind yourself on how to build the workflow, here you go with my workflow file (yaml):

https://gist.github.com/botscripter/2ef8c34885ba4e7c120829a7113ca373

Idea

The idea behind our following automation is to get automatically triggered with GitHub Actions in the event of a release. And to build and publish our artefact with human approval on Maven Central.

Process of the automated publishing to Maven Central

Initially, I aimed for a fully-automated pipeline to publish on Maven Central. During this practice, I figured out that it comes with technical challenges and concerns about unwanted publications. The following points made my decision to aim for automation with human approval:

  • Technical challenges can be overcome, but there is a price to pay. To get it automatically published, you would need to know the id of the staging repository. The use of custom code interacting with Sonatype’s REST API or a Gradle plugin would become necessary.
  • Technically, I would love to see it fully automated, but to mitigate security and compliance concerns, I recommend the approval workflow. It brings the benefit that we leave the final decision to a human if an artefact is going to be stored on the internet for “eternity”.

Check out the “References, Useful links” section, and there, you will find a script and a Gradle plugin, which may help you if you decide differently than I did, and you head to a fully automated solution.

Preconditions

Before we can launch, we’ve to make sure our base is ready for that. And I assume that if you found this guide, you do

*I’m no advocate, nor I’m paid to list these links here. I don't even earn anything if you click on them. I googled them or had them in my bookmarks. So it is truly here to assist you and chosen by my personal bias as a developer. Feel free to get the required know-how anywhere else, as you desire — disclaimer end.

Let’s get started! 🥳

Implementation

The implementation will consist of three tasks to execute. Afterwards, we should successfully have implemented our fully automated Pipeline.

Our first target is to provide all necessary data for our Gradle build. The following image should make you remember what you’ve defined and, therefore, what’s the mentioned needed data.

Extract from the build.gradle file regarding the publishing configuration

The only thing not visible above is that we also need the GPG private key and his passphrase for the signing task. If we build “real” non-SNAPSHOT versions.

1) GitHub secrets

You may remember my statement: we’re never allowed to store sensitive data, such as our credentials or private key, in Git? It remains still the case! Therefore we have to make use of encrypted secrets. You will have to create the following secrets:

  • OSSRH_USERNAME
    Your username for the Sonatype Jira login.
  • OSSRH_PASSWORD
    Your password for the Sonatype Jira login.
  • OSSRH_GPG_SECRET_KEY_ID
    Your ID of the GPG certificate.
  • OSSRH_GPG_SECRET_KEY
    Your gpg private key base64 encoded.
  • OSSRH_GPG_SECRET_KEY_PASSWORD
    Your GPG passphrase, if you have set any. Otherwise, you don’t need to set this secret.

If you don’t know how to do that, visit the following step-by-step guide from GitHub:

Choose between storing on the repository or global level. And keep in mind that you can’t review a secret set in GitHub.

⚠️ GitHub will mask any detected secrets and not print them in the log. But don’t think that the placed values there is a secret, it’s not! There are still ways to access this sensitive data. Therefore, read your logs and verify that you don’t expose any sensitive data.

Exporting the private key

You need to store your private key as a secret on GitHub. You have to export it in a format suitable for that purpose. For our goal, this would be a base64 encoded string. To do so, execute the following command after you have replaced the string user@email.xyz with your corresponding e-mail address used for your GPG key.

gpg --output private.pgp --armor --export-secret-key user@email.xyz

2) Workflow file

I’ve created eight steps to automate our publishing process fully. First, please create the publish.yml file at the corresponding place in your Git repository.

// .github/workflows/publish.yml

Copy and paste the content of the following complete example into your newly created publish.yml file. Feel free to delete the comments as soon as you have read them and if they annoy you too. Or maybe only I have issues with comments in my production files 😅.

Complete Example

3) GitHub releases

As the idea is first to create a release, we have to do so to trigger the pipeline. If you need help, visit the following documentation:

For development reasons, you can think about adding the following configuration to enable manual workflow triggering.

To manually trigger a workflow, use the workflow_dispatch event. You can manually start a workflow run using the GitHub API, GitHub CLI, or GitHub browser interface. For more information, see "Manually running a workflow."

on: workflow_dispatch

By now, you are finally done with your whole automation! Congrats 🎉 Let’s continue with releasing it.

As an example, this is how it looked for my release:

Example of releasing a version on GitHub

4) Releasing to Maven Central

First of all, login into the Nexus Repository Manager:

Legacy: https://oss.sonatype.org/
New:
https://s01.oss.sonatype.org/

If you aren’t sure which one you are using, look into your build.gradle file and verify which releaseRepo you have specified in the publishing/repositories definition block.

You are four clicks away from publishing to Maven Central. What you have to do is to verify what the GitHub Action Workflow has uploaded, and if you agree, then to

  • close the staging repository
  • release the staging repository

Following is how this looked for my recent release as reference:

Closing staging repository
Confirming to close the staging repository
Releasing the staging repository
Confirming to release the staging repository

If you would like to understand what’s happening under the hood here, have a look at my previous guide, and read section “3 Publishing to Maven Central”

That’s it; we’re done 😎

Details, Explanations, Further Topics, Common Errors

What is an armored GPG key export?

PGP (including GPG) ‘armoring’ is not encryption. Encryption prevents unauthorised use of data (formally, it provides confidentiality) by making it unreadable in a way that can only be reversed by someone who has the secret key. Armoring is a simple process (mostly base64, although not the same base64 used by uuencode) that can be easily reversed by anybody who reads the specification. Armoring looks like text, while unarmored (binary) data looks like garbage to a person who uses inappropriate tools like cat or a text editor, but they are equally readable by someone competent.

Copied from: https://unix.stackexchange.com/questions/623375/what-is-the-armored-option-for-in-gnupg

Sonatype’s Nexus Login issues

First of all, it happens to me too often that I open the Legacy Sonatype instead of the new one. You don’t see a difference on the web app itself. Only the URL differs. So double-check if you are on the right site when you receive an invalid username/password message.

If you have lost or forgotten your password, you have to open Sonatype’s Issue Tracker = Jira to reset the password. It’s not apparent but actually how it works. Unfortunately, there is no option on the Nexus itself to reset.

Here is the direct link to request a password reset: https://issues.sonatype.org/secure/ForgotLoginDetails.jspa

Closing words

I’m always trying to live from the earnings I make by doing stuff I sincerely love ❤️. Writing tech articles 📝 become one of those things I’m passionate about. If my article supported you, I would be honoured to receive a tip ☕. This would enable me to spend even more time writing such articles and boost my motivation. Follow me here on medium for more tech articles and bonus material 😃.

This is the link to support me or to say thanks by buying me a coffee: https://ko-fi.com/botscripter

References, Useful links

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Nikola Stanković

Nikola Stanković

Introducing software ideas to the real world. And keeping them running …