Publishing to the Maven Central using Gradle

Publishing in Maven Central repository has gotten simpler and simpler, especially when using Gradle.

The official documentation is complete enough but I wanted to put things together in order to allow for a quick start.

The two first steps, Registration and GPG key, must be done only once for all the projects you own.

Registration

First of all, you'll have to register your group for publication in the Maven Central repository.

You can follow the step in the OSSRH documentation.

For my different projects, I register the net.nemerosa group. All the group IDs of my projects will have to begin with this group. If I would need another group, I'd have to register again.

You'll receive an account to access the OSSRH repository. Edit or create the file at ~/.gradle/gradle.properties and add those credentials.

ossrhUser = <OSSRH user>  
ossrhPassword = <OSSRH password>  

WARNING Do not ever put such information in Git or in any public location! This must stay local to your build environment and correctly protected.

GPG key

Then, you'll need a GPG key in order to sign all your artifacts. It makes things harder when it comes to publish artifacts in the Maven Central than let's say in JCenter but I like the fact that more controls are enforced upon the quality of your uploads (see later with the minimum amount of required meta information).

In order to create this key, follow the OSSRH documentation.

You'll have to note three properties for this key:

  • its short ID
  • the path to its key ring file
  • the associated passphrase

You can retrieve those elements by running:

gpg -K  

The key ring file is contained in the first line of the output; the short ID is following the / on the sec line. The passphrase is known only by you.

Edit the file at ~/.gradle/gradle.properties which contains the key information, where ~ is the home directory for your build environment:

signing.keyId=<short ID of your key>  
signing.password=<passphrase for your key>  
signing.secretKeyRingFile=<path to your key ring>  

WARNING As mentioned above, do not ever put such information in Git or in any public location! This must stay local to your build environment and correctly protected.

Gradle configuration

You're now ready to configure your Gradle build:

buildscript {  
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.5.3"
    }
}
apply plugin: 'io.codearte.nexus-staging'


if (project.hasProperty('release')) {

    subprojects {

        task javadocJar(type: Jar) {
            classifier = 'javadoc'
            from javadoc
        }

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

        artifacts {
            archives javadocJar, sourcesJar
        }
    }

    allprojects {
        apply plugin: 'signing'
        apply plugin: 'maven'

        // Signature of artifacts
        signing {
            sign configurations.archives
        }

        // OSSRH publication
        uploadArchives {
            repositories {
                mavenDeployer {
                    // POM signature
                    beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
                    // Target repository
                    repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
                        authentication(userName: ossrhUser, password: ossrhPassword)
                    }
                    pom.project {
                        name project.name
                        description project.description
                        packaging 'jar'
                        url 'https://github.com/your/project'

                        scm {
                            connection 'scm:git:https://github.com/your/project.git'
                            developerConnection 'scm:git:git@github.com:your/project.git'
                            url 'https://github.com/your/project.git'
                        }

                        licenses {
                            license {
                                name 'The MIT License (MIT)'
                                url 'http://opensource.org/licenses/MIT'
                                distribution 'repo'
                            }
                        }

                        developers {
                            developer {
                                id = 'youraccount'
                                name = 'Your Name'
                                email = 'your.account@mail.com'
                            }
                        }
                    }
                }
            }
        }

    }
}

nexusStaging {  
    username = ossrhUser
    password = ossrhPassword
}
  • We'll be using the gradle-nexus-staging-plugin plugin for the promotion of the release toward the Maven Central repository. See below.
  • I'm using a release property in order to enable or not all publication tasks. This is of course optional, according to the nature of your project.
  • Javadoc and sources are required for publication in the Maven Central repository.
  • All archives must be signed, using the GPG key configured before.
  • Before the actual publication, all generated POM files will also be signed.
  • Your OSSRH credentials configured above are used for the upload of the artifacts.
  • The POM is also configured with some required meta information:
    • name and description
    • SCM information
    • license information
    • developer information
  • The gradle-nexus-staging-plugin plugin is configured with the OSSRH credentials for the promotion (see below).

Running the publication

With configuration above, it comes down to run:

./gradlew ... -Prelease uploadArchives closeAndPromoteRepository

That's it!

Upon upload in a staging repository in the OSSH repository, the gradle-nexus-staging-plugin plugin will then close and release it.

If some information is missing in the POM files, or the signature is not OK, or if some artifacts are missing, the close operation will fail.

The actual synchronisation with the Maven Central will take less than one hour, but some mirrors might be much slower.

maven vs maven-publish

In a first version, I wanted to use the maven-publish plugin instead of the old maven one, but signing the generated POM files proved to be almost impossible. There is a bit of workarounds on the subject, but they are very complex. In the end, I prefered to work with an older but much simpler solution.