Publishing Maven/Gradle Artifacts Via Bintray

Some time back I wrote a post regarding a tool chain for open source Java projects. I mentioned Bintray, but didn’t have much to say since I hadn’t managed to succeed in working with it. From responses to that post it appeared I’d got some things wrong in my ignorance, and I’d mentally committed to give Bintray a proper try. After a couple of half starts I finally got it done and here are my thoughts.

Getting Set Up

Bintray touts itself as “Distribution as a Service”, which is to say it does a lot more then just distribute Java artifacts. A lot more. There is probably a lot there that’s cool and useful, but if your mission is just to distribute Java artifacts, you need to wade through a fair bit of other stuff to get it set up.

Building the account was straight forward, but after that they’ve their own terminology and process, and you need to be assimilated before you’ll get anywhere. Artifacts end up as leaves on a tree whose hierarchy is Repository > Package > Version. Package and version are intuitive, but Repository wasn’t what I’d immediately expected. Repository would appear to be the classification of your distribution type, so for example the repository I used was Maven.

Before you can publish you’ll have to set up your account, make sure you’ve a Maven repository (it was one of the defaults), and create a package, which I did by linking to one in github. Lastly you’ll need your API key which you’ll need to dig around on their profile pages to generate.

With all that in place you’re ready to publish.

Publishing With Gradle – An Example

Bintray has a gradle plugin for publishing and that was what I went with and got working. It had examples, but they were very broad brush and it took some dedicated searching and experimentation to work out the specifics. Here’s the relevant bits from my build file (note I use gradle 2.3):


plugins {
    id "java"
    id "maven-publish"
    id "com.jfrog.bintray" version "1.2"
}

version="0.2.1"  // The version

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

task javadocJar(type: Jar, dependsOn: javadoc) {
    classifier = 'javadoc'
    from javadoc.destinationDir
}

publishing {
    publications {
        mavenJava(MavenPublication) {  // Artifacts to publish
            from components.java
            artifact sourceJar
            artifact javadocJar
        }
    }
}

bintray {
        user = 'bintray-user'
        key = 'bintray-api-key'

        dryRun = false 
        publish = true 
        publications = ['mavenJava']
        pkg {
            repo = 'maven'         // The repository
            name = 'jdk8-tostring' // The package
            desc = 'Utilities to generate a standard toString of a class using Jdk8 features.'
            websiteUrl = 'https://github.com/nwillc/jdk8-tostring'
            issueTrackerUrl = 'https://github.com/nwillc/jdk8-tostring/issues'
            vcsUrl = 'https://github.com/nwillc/jdk8-tostring.git'
            licenses = ['ISC']
            labels = ['tostring']
            publicDownloadNumbers = true
        }
}

Looking at the example you’ll note a few things. You need to get your source and java jars together yourself. Next, you need to use the publishing closure to inform the plugin what you want published. Finally you’ll need to complete the bintray closure. Note too, the commented values above must correspond to the values you want in the hierarchy you set up on Bintray.

With that in place, deploying is as simple as invoking the bintray task with gradle.

Summary

Now having used both Sonatype and Bintray to share java artifacts I can contrast Bintray:

Pros

  • Registration is completely automated, no waiting for a human review.
  • Deploying is a single command from your build tool.
  • The artifact is almost immediately usable from jCenter

Cons

  • There is a fair bit to wrap your head around to get things working
  • Documentation for the site and tools is very scattered and not detailed.
  • jCenter is still not as widely integrated as mavenCentral. For example javadoc.io only supports maven central. Bintray can mirror your artifacts to Maven Central, but that involves given them your pgp private key.

Overall

Bintray is absolutely usable, with a somewhat complementary set of pros and cons over Sonatype/Maven Central. The simplicity and speed of deployments are certainly a win, and I’m sure I’ll keep employing it for projects that don’t need the broader integration Maven Central affords.

Publishing a Gradle Plugin to plugins.gradle.org

In a prior post I discussed creating a plugin for gradle. The example plugin is useful and so I published it to maven central, and have used it from there.  As I upgraded some of my gradle build files this weekend, I looked into the new plugin mechanism in gradle 2.1+ and checked out what it would take to update my plugin.  It turned out to be easy, just a new publishing mechanism.  The new method to publish adds the plugin to plugins.gradle.org and jcenter, and is easier then the maven central publish for the win!

Here’s What’s Needed

First just follow the steps here to create an account and an API key. Then you update your gradle.properties and your gradle.build. The biggest challenge was incorporating the plugin-publish plugin into the build file. It’s documented here but those notes didn’t cover all I needed to do, so lets look.

First I cleared out the maven central publishing code. Then I added the support for the new plugin. It boiled down to:

// Prepare the artifacts
task sourcesJar(type: Jar, dependsOn: classes) {
    classifier = 'sources'
    from sourceSets.main.allSource
}

task groovydocJar (type: Jar, dependsOn: groovydoc) {
    classifier = 'groovydoc'
    from groovydoc.destinationDir
}

groovydocJar.dependsOn 'groovydoc'

artifacts {
    archives jar
    archives groovydocJar
    archives sourcesJar
}
// Configure the publish-plugin
pluginBundle {
    website = 'http://nwillc.github.io/vplugin/'
    vcsUrl = 'https://github.com/nwillc/vplugin'
    description = 'Gradle plugin to report newer versions of dependencies'
    tags = ['versions']

    plugins {
        versionsPlugin {
            id = 'com.github.nwillc.vplugin'
            displayName = 'Gradle versions plugin'
        }
    }
}

What the docs did not cover was getting your artifacts prepared (first section above). It’s basic stuff but wasn’t needed before. Once I got that figured out I invoked the publishPlugins task and it worked without issue.

I’ve now switched my other builds to get the versions plugin with the new mechanism and have been very happy with it. As an added perk they generate usage notes for you plugin too!

About the versions plugin.