This page looks best with JavaScript enabled

Unified Gradle projects releasing to Maven Central in 2021 + migration guide

As a counterbalance to an imminent JCenter shutdown, get know the unified (and united) power of releasing to Maven Central with a brand new Gradle Nexus Publish Plugin. A migration guide from the old plugins is included.



2 big things in Q1 2021

The beginning of 2021 electrified the JVM ecosystem by an unexpected decision of the fast upcoming shutdown of JCenter , a quite popular place to keep FOSS projects’ binary artifacts. Business is for making money, not for supporting the community that helped the company got to the successful IPO a few months earlier, so the need “to streamline the productivity of the JFrog Platform” has to be understood.

As a (positive) side effect, I and Marc Phillip streamlined our focus to release a stable version of our unified Gradle plugin for publishing projects to Maven Central. 1.0.0 hit the repository soon after. That version provides an initial set of functionality which should allow the majority of the Gradle projects to publish artifacts to Maven Central (aka The Central Repository).

A story of three plugins

In 2015, I created gradle-nexus-staging-plugin which was providing - not available earlier for the Gradle users - an ability to close and release staging repositories in Nexus repository manager without touching Nexus UI. It opened an opportunity to manage releasing Gradle projects to Maven Central completely from code (also using a CI server). Over the years, it has been adopted by the various projects and companies across the globe , however there was a small problem. Due to technical limitations in the publishing process in Gradle, it was required to use heuristics to track implicitly created staging repositories, what often failed for multiple repositories in a given state. The situation became even worse when Travis changed its network architecture in late 2019 and the majority of releases started to fail.
Here, Marc Philipp entered the stage who created Nexus Publish Plugin which was enriching the publishing mechanism in Gradle to explicitly create staging repositories and publish (upload) artifacts directly to it.

Those two plugins nicely worked together, providing a reliable way to handle publishing artifacts to Maven Central (and to other Nexus instances in general). However, the need of using two plugins was very often confusing for users. As a result, an idea to create one plugin mixing the aforementioned capabilities emerged. It took us some time, but sunsetting JCenter motivated us to intensify work and Gradle Nexus Publish Plugin 1.0.0 has been released in February 2021 as joint effort.

Migration guide

The new plugin was intended as a natural successor of the aforementioned two plugins. We tried to keep the syntax unchanged where feasible. As a result a migration guide - in the majority of cases - is straightforward.

Plugins

Let’s start with the plugins declaration.

plugins {   //old
    id "io.codearte.nexus-staging" version "0.22.0"
    id "de.marcphilipp.nexus-publish" version "0.4.0"
}

The old two has to be replaced with the new one:

1
2
3
plugins {
    id "io.github.gradle-nexus.publish-plugin" version "1.0.0"
}

Configuration - simple case

If only default plugins settings were used:

nexusStaging {   //old
    packageGroup = "com.example.mycompany.myproject"
    stagingProfileId = "yourStagingProfileId"
}

nexusPublishing {
    repositories {
        sonatype()
    }
}

packageGroup and stagingProfileId have to be moved to the nexusPublishing section:

1
2
3
4
5
6
7
8
9
nexusPublishing {
    packageGroup = "com.example.mycompany.myproject"  //defaults to 'project.group'
    repositories {
        sonatype {   //custom repository name - 'sonatype' is pre-configured
                     //for Sonatype Nexus (OSSRH) which is used for The Central Repository
            stagingProfileId = "yourStagingProfileId" //can reduce execution time by even 10 seconds
        }
    }
}

Due to the improved support for releasing to multiple Nexus instances in one project, the credentials configuration has changed in non-backward compatible way. gradle-nexus-staging-plugin by default was using nexusUsername and nexusPassword project properties which could be reused by nexus-publish-plugin. With the new plugin it has been unified to sonatypeUsername and sonatypePassword, where a suffix reflects a name of a configured repository (here sonatype).

Configuration - more customizations

Having more customizations in place:

//majority of the properties is optional, you might just don't have them in your project       //old
nexusStaging {
    packageGroup = "com.example.mycompany.myproject"
    stagingProfileId = "yourStagingProfileId"

    //by default project properties 'nexusUsername' and 'nexusPassword' are used
    username = project.findProperty("...")   
    password = project.findProperty("...")
    numberOfRetries = 40
    delayBetweenRetriesInMillis = 3000
}

nexusPublishing {
    repositories {
        sonatype {
            //by default value from above 'nexusStaging' closure is used (alternative project properties 'sonatypeUsername' and 'sonatypePassword')
            username = project.findProperty("...")  
            password = project.findProperty("...")
        }
    }

    clientTimeout = Duration.ofSeconds(300)
    connectTimeout = Duration.ofSeconds(60)

}

they also have to be moved to the nexusPublishing closure:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
nexusPublishing {
    packageGroup = "com.example.mycompany.myproject"  //defaults to 'project.group'

    repositories {
        sonatype {   //or custom repository name
            stagingProfileId = "yourStagingProfileId" //can reduce execution time by even 10 seconds

            //defaults to project properties 'sonatypeUsername' and 'sonatypePassword', where 'sonatype' is name of configured repository
            username = project.findProperty("...")  
            password = project.findProperty("...")
        }
    }

    clientTimeout = Duration.ofSeconds(300)
    connectTimeout = Duration.ofSeconds(60)

    transitionCheckOptions {
        maxRetries.set(40)
        delayBetween.set(java.time.Duration.ofMillis(3000))
    }
}

It is worth to mention - in addition to changed default project properties to read credentials from - that the configuration of retries during the close and release attempts has been renamed to transitionCheckOptions with more modern duration types.

Tasks - simple case

At the task level - due to support for multiple repositories - the following common execution:

./gradlew publish closeAndReleaseRepository        //old

has to be enhanced with a repository name:

./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository

To short the second task name slightly, there is still a simplified variant closeAndReleaseStagingRepository which closes and releases the staging repositories in all configured Nexus instances (one by default).

Summary

For the new projects, using gradle-nexus-publish-plugin is the only logical choice. The main authors’ effort will be put in its development. The whole process of onboarding to Soantype Nexus (together with a sample project) is nicely described by Rob Winch .

For the projects migrating from releasing from JCenter to Maven Central - I plan to cover it in a separate blog post - it also holds.

I hope this short blog post clearly showed that migration - in the majority of cases - from the old due-solution should be trouble-free. All the projects should - eventually - migrate to the new plugin.

For existing projects, temporary staying with the already working (old) duo-solution also is an acceptable choice. The migration might wait for the next big configuration change in the project (e.g. a migration to Gradle 7). The new plugin is less mature and there might be some features missing. In that case, however, please let us know !

Lead photo by TheDigitalArtist, published in Pixabay, Pixabay License.
Share on

Marcin Zajączkowski
WRITTEN BY
Marcin Zajączkowski
Software Craftsman & Solution Architect
An experienced architect aiming for high quality solutions. Very engaged in evangelising Software Craftsmanship, Clean Code and Test-Driven Development as a conference speaker and a trainer. A specialist in Continuous Delivery and Continuous Inspection of Code Quality. An enthusiast of Reactive Systems and broadly defined concurrency.

Besides, open source author and contributor, a proud Linux user.


Don't want to use the Utterance bot? Comments can be also placed directly on GitHub.
What's on this Page