Introduction

I’m used to importing libraries that I need in gradle by simply adding them as a dependency for implementation or testing. However, I’ve always been curious about how to publish my own dependency that can easily be used by other projects. This tutorial shows how to take a Kotlin library and publish it to bintray as a dependency that can be used in gradle projects.

In this tutorial I will create the color-console library that allows console messages to be colorized using ANSI color codes. Here is the end result snippet that we are looking to enable for our color-console library.

Desired snippet for build.gradle.kts (using Kotlin DSL):

repositories {
  jcenter()
}

dependencies {
  implementation("com.developerlife:color-console:1.0")
}

Desired snippet for build.gradle (using Groovy):

repositories {
  jcenter()
}

dependencies {
  implementation 'com.developerlife:color-console:1.0'
}

Step 1: Setup a bintray account and create a new repo named “maven” of type “Maven”

Create a JFrog Bintray account and sign in w/ a GitHub account, so there is no username and password. Then create a new repository of type Maven named “maven”, with the following characteristics. Here is an example.

  • Public anyone can download
  • Name: “maven”
  • Type: Maven
  • License: Apache 2.0

💡 Note that many different libraries can be published into this repo, and color-console will just be one of them.

In this case, I want to create a color-console dependency which is a Kotlin module. So a snapshot of that module will be published under this repo named maven in bintray, and the URL is something like .../bintray.com/nazmulidris/maven/color-console.

If there is another library that I want to publish named my-library then that would be accessible under the same maven repo and accessed via .../bintray.com/nazmulidris/maven/my-library.

Make sure to get the API key from “Edit Profile” and save it to an environment variable on your machine. Create these environment variables in your terminal for this (will be used later). Here’s an example of this using fish shell.

  1. set -gx BINTRAY_USER <YOUR_USERNAME>
  2. set -gx BINTRAY_API_KEY <YOUR_API_KEY>

Step 2: Create a new GitHub repo for the actual code of the library color-console

The previous step just created a “place” or “destination” where we can publish the artifacts generated by building our library. Now we must actually write the code that comprises the library, that will be built. Here’s the GitHub repo for color-console.

Using IDEA create a Gradle + Java + Kotlin (JVM) project. Make sure it uses Kotlin and not Groovy for the Gradle build script (I only got this working w/ the Kotlin DSL and not Groovy). It’s a very simple Kotlin and Gradle that has a single source file. Add the source code there and the following steps are where things get interesting.

Edit the build.gradle.kts file to allow this library to be published to bintray. Here are the high level steps.

  1. Add some plugins so that we can publish this project to bintray.
  2. Configure the maven publishing plugin. More info.
  3. Configure the bintray plugin. More info.
  4. To publish, you have to run the gradle task named bintrayPublish. This will dump the color-console package into this maven repo here.
  5. Publish this to jcenter so that there is no need to add the custom repositories entry in build.gradle of developers who want to use this library. Instead, they must add a jcenter() entry. To publish it, simply click on the “Add to JCenter” button in this page. Here’s an issue which describes this process in detail.

💡 Note if you want to delete the module that was just uploaded, you can go into the bintray UI and delete it.

Here’s the configuration information in build.gradle.kts.

val myArtifactName = rootProject.name
val myArtifactGroup = project.group.toString()
val myArtifactVersion = project.version.toString()

val myDescription = "ANSI colored console log output"

val myGithubHttpUrl = "https://github.com/nazmulidris/color-console"
val myGithubIssueTrackerUrl = "https://github.com/nazmulidris/color-console/issues"
val myGithubRepo = "nazmulidris/color-console"
val myLicense = "Apache-2.0"
val myLicenseUrl = "http://www.apache.org/licenses/LICENSE-2.0.txt"
val myDeveloperId = "nazmulidris"
val myDeveloperName = "Nazmul Idris"

val myBintrayUser: String = System.getenv("BINTRAY_USER")
val myBintrayApiKey: String = System.getenv("BINTRAY_API_KEY")
val myBintrayRepo = "maven"
val myBintrayUserOrg = myDeveloperId

And here are the plugins that have to be added and configured in build.gradle.kts.

val sourcesJar by tasks.creating(Jar::class) {
  archiveClassifier.set("sources")
  from(sourceSets.getByName("main").allSource)
  from("LICENCE.md") {
    into("META-INF")
  }
}

val dokkaJavadocJar by tasks.creating(Jar::class) {
  dependsOn(tasks.dokkaJavadoc)
  from(tasks.dokkaJavadoc.get().outputDirectory.get())
  archiveClassifier.set("javadoc")
}

// More info: https://docs.gradle.org/current/userguide/publishing_maven.html#publishing_maven:resolved_dependencies
publishing {
  publications {
    create<MavenPublication>(myArtifactName) {
      groupId = myArtifactGroup
      artifactId = myArtifactName
      version = myArtifactVersion

      from(components["java"])

      artifact(sourcesJar)
      artifact(dokkaJavadocJar)

      pom {
        packaging = "jar"
        name.set(myArtifactName)
        description.set(myDescription)
        url.set(myGithubHttpUrl)
        scm {
          url.set(myGithubHttpUrl)
        }
        issueManagement {
          url.set(myGithubIssueTrackerUrl)
        }
        licenses {
          license {
            name.set(myLicense)
            url.set(myLicenseUrl)
          }
        }
        developers {
          developer {
            id.set(myDeveloperId)
            name.set(myDeveloperName)
          }
        }
      }

    }
  }
}

// More info: https://github.com/bintray/gradle-bintray-plugin
bintray {
  user = System.getenv("BINTRAY_USER").toString()
  key = System.getenv("BINTRAY_API_KEY").toString()

  publish = true

  println("publish: $publish")
  println("myArtifactName: $myArtifactName")
  println("myArtifactVersion: $myArtifactVersion")

  setPublications(myArtifactName)

  pkg.apply {
    repo = myBintrayRepo
    name = myArtifactName
    userOrg = myBintrayUserOrg
    githubRepo = myGithubRepo
    vcsUrl = myGithubHttpUrl
    description = myDescription
    setLicenses(myLicense)
    desc = myDescription
    websiteUrl = myGithubHttpUrl
    issueTrackerUrl = myGithubIssueTrackerUrl

    version.apply {
      name = myArtifactVersion
      desc = myDescription
      released = Date().toString()
    }
  }
}

Notes

  1. ⚠️ You can’t use SNAPSHOT in the version string of the library, otherwise, the bintray plugin does not work.
  2. ⚠️ You can’t have any spaces in the myLicense value either, otherwise, the bintray plugin does not work.

References

  • Here’s a straightforward tutorial on how to get started.
  • Here’s another great tutorial on how to get started w/ this. Here’s the build.gradle.kts file that is referenced in this tutorial.
  • I tried looking at using GitHub packages, but unfortunately, it is not possible to get these dependencies from gradle w/out providing authentication information. In other words, only private dependencies can be created using GitHub packages. Here’s a discussion about this severe limitation.

Related Posts