The following article teaches how to publish a Kotlin library to JitPack or GitHub Packages, using Gradle build tool.
https://developerlife.com/2021/02/06/publish-kotlin-library-as-gradle-dep/
There are only two categories of software: open-source software and proprietary software. Any software that’s not open-source is proprietary, regardless of whether its source code is available on GitHub.
Introduction
I’m used to importing libraries that I need in gradle by simply adding them as a dependency for implementation or testing in build.gradle
or build.gradle.kts
.
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 the GitHub Package Registry and JitPack, as a dependency that can be used in gradle projects. I used to use JFrog Bintray but both Bintray and JCenter are going to be shut down in May 2021.
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.
Using JitPack 👍
✨ This is much simpler than GPR and the way to go for public dependencies.
This could not be any easier. It’s really a 2 step process, once you have your library built with gradle and its git repo pushed into GitHub. Let’s use the following Kotlin library that’s published via JitPack as an example for this article: color-console
.
Publish a dependency to JitPack
maven-publish plugin
Ensure that the maven-publish
plugin is imported in build.gradle.kts
.
plugins {
java
kotlin("jvm") version "1.6.0"
`maven-publish`
}
repositories {
mavenCentral()
}
dependencies {
implementation(kotlin("stdlib-jdk8"))
testImplementation("junit", "junit", "4.12")
}
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
}
publishing {
publications {
create<MavenPublication>("maven") {
groupId = "com.developerlife"
artifactId = "color-console"
version = "1.0.1"
from(components["java"])
}
}
}
publishing, groupId, artifactId, version
Without the publishing
rule of build.gradle.kts
you will get an error from JitPack even though the ./gradlew build publishToMavenLocal
will work. This error will say ERROR: No build artifacts found
. Check out this tutorial for more info on this.
Even though the groupId
, artifactId
, version
are specified inside the publishing
rule above it doesn’t really get applied to the final artifact served up by JitPack. JitPack renames these artifacts to something that reflects that they originated from github.com
and the user nazmulidris
.
So the dependencies
statement you find in a project’s Gradle build file that depends on this library doesn’t match the identifiers specified in this rule: dependencies { implementation 'com.github.nazmulidris:color-console:Tag' }
. The following is sanitized snippet from the build log that JitPack generates that shows this happening.
------------------------------------------------------------
Gradle 7.0
------------------------------------------------------------
Build time: 2021-04-09 22:27:31 UTC
Revision: d5661e3f0e07a8caff705f1badf79fb5df8022c4
Kotlin: 1.4.31
Groovy: 3.0.7
Ant: Apache Ant(TM) version 1.10.9 compiled on September 27 2020
JVM: 1.8.0_252 (Private Build 25.252-b09)
OS: Linux 4.18.0-25-generic amd64
Getting tasks: ./gradlew tasks --all
> Task :clean UP-TO-DATE
> Task :compileKotlin
> Task :compileJava NO-SOURCE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :inspectClassesForKotlinIC
> Task :jar
> Task :assemble
> Task :check
> Task :build
> Task :generateMetadataFileForMavenPublication
> Task :generatePomFileForMavenPublication
> Task :publishMavenPublicationToMavenLocal
> Task :publishToMavenLocal
BUILD SUCCESSFUL in 7s
7 actionable tasks: 6 executed, 1 up-to-date
Looking for artifacts...
Looking for pom.xml in build directory and ~/.m2
Found artifact: com.developerlife:color-console:1.0.1
Build artifacts:
com.github.nazmulidris:color-console:1.0.1
Files:
com/github/nazmulidris/color-console/1.0.1
com/github/nazmulidris/color-console/1.0.1/build.log
com/github/nazmulidris/color-console/1.0.1/color-console-1.0.1-sources.jar
com/github/nazmulidris/color-console/1.0.1/color-console-1.0.1.jar
com/github/nazmulidris/color-console/1.0.1/color-console-1.0.1.module
com/github/nazmulidris/color-console/1.0.1/color-console-1.0.1.pom
com/github/nazmulidris/color-console/1.0.1/color-console-1.0.1.pom.md5
com/github/nazmulidris/color-console/1.0.1/color-console-1.0.1.pom.sha1
Build & publish locally first
Before you can publish this library, make sure that you can run the following commands, that ensure that JitPack can build this repo using gradle.
./gradlew clean
./gradlew build
./gradlew build publishToMavenLocal
Prepare a release & publish
In order to publish this repo to JitPack you have to do the following things.
- Make the changes that you want the repo, and commit and push it. Also, make sure that the library can be built by JitPack using the command shown above.
- Update the
version
value inbuild.gradle.kts
, this affects the JAR file that is built by JitPack. For consistency, the value here should match the release and tag value as well. - Get all the tags for this repo from GitHub using
git pull origin
. Then you can list the available tags usinggit tag -l
. - Create a new tag. To create a new tag run this command
git tag <TAG_NAME>
, where<TAG_NAME>
could be something like1.0.1
. Just make sure not to clobber any existing tag name. - Publish the tag to GitHub using the following command
git push --tags
. - Finally create a new Release for this tag using GitHub web interface.
⚡ Note, to delete a tag from GitHub you can run this command
git push --delete origin <TAG_NAME> ; git pull origin
. You can delete a tag from your local repo usinggit tag -d <TAG_NAME>; git push origin --tags
. You can’t manage releases though, which require the use of the GitHub web UI. Here’s more info on git tagging.
Import and use it
Then, in the project where you want to add this library as a dependency, eg: idea-plugin-example
you have to do the following. You can import this dependency into your gradle projects by making the following changes to your build.gradle
or build.gradle.kts
file.
Add this at the end of your
repositories
section.For
build.gradle
:repositories { repositories {maven { url 'https://jitpack.io' }} }
For
build.gradle.kts
:repositories { maven{ url = uri("https://jitpack.io") } }
Add the dependency.
For
build.gradle
:dependencies { implementation 'com.github.nazmulidris:color-console:1.0.0' }
For
build.gradle.kts
:dependencies { implementation ("com.github.nazmulidris:color-console:1.0.0") }
Information about this dependency on JitPack:
Using GitHub Package Registry (GPR) 👎
⚠ GPR is complex and has authentication issues for public dependencies. People are really unhappy about this.
Desired snippet for build.gradle.kts
(using Kotlin DSL):
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/nazmulidris/color-console")
credentials {
username = System.getenv("GITHUB_PACKAGES_USERID") ?: "nazmulidris"
// Safe to share the password since it is a `read:package` scoped token.
password = System.getenv("GITHUB_PACKAGES_IMPORT_TOKEN") ?: "22e9ba0d47c3e9116a2f1023867a1985beebfb60"
}
}
}
dependencies {
implementation("com.developerlife:color-console:1.0")
}
Desired snippet for build.gradle
(using Groovy):
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/OWNER/REPOSITORY")
credentials {
username = System.getenv("GITHUB_PACKAGES_USERID") ?: "nazmulidris"
// Safe to share the password since it is a `read:package` scoped token.
password = System.getenv("GITHUB_PACKAGES_IMPORT_TOKEN") ?: "22e9ba0d47c3e9116a2f1023867a1985beebfb60"
}
}
}
dependencies {
implementation 'com.developerlife:color-console:1.0'
}
Create a new GitHub repo for the actual code of the library
The code that comprises the library, that will be built is in this 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.
Generate the personal access tokens that will be needed to publish and import
The first step is to create some GitHub personal access tokens that will do 2 things. You might consider saving them to global environment variables using whatever shell you use.
GITHUB_PACKAGES_PUBLISH_TOKEN
- this token hasrepo, write:packages
scope. Do NOT share this!GITHUB_PACKAGES_IMPORT_TOKEN
- this token hasread:packages
scope. This is ok to share.
You might also consider saving the following environment variable too.
GITHUB_PACKAGES_USERID
- this is the GitHub username for the token. This is ok to share.
Add GitHub Package Registry support to the build script so that the package can be published
Edit the build.gradle.kts
file to allow this library to be published to GitHub Packages. Here are the high level steps.
- Add some plugins so that we can publish this project to GitHub Packages.
- Configure the maven publishing plugin. More info.
- To publish, you have to run the gradle task named
publish
. This will generate a release package forcolor-console
. - Before publishing you might want to test that this works locally by using the
publishToMavenLocal
task which will generate the artifacts locally and save them to the$HOME/.m2/repository/com/developerlife/color-console/
folder.
Here is what you need to add to your build.gradle.kts
:
publishing {
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/${myGithubUsername}/${myArtifactId}")
credentials {
username = System.getenv("GITHUB_PACKAGES_USERID")
password = System.getenv("GITHUB_PACKAGES_PUBLISH_TOKEN")
}
}
}
}
publishing {
publications {
register("gprRelease", MavenPublication::class) {
groupId = myArtifactGroup
artifactId = myArtifactId
version = myArtifactVersion
from(components["java"])
artifact(sourcesJar)
artifact(dokkaJavadocJar)
pom {
packaging = "jar"
name.set(myArtifactId)
description.set(myGithubDescription)
url.set(myGithubHttpUrl)
scm {
url.set(myGithubHttpUrl)
}
issueManagement {
url.set(myGithubIssueTrackerUrl)
}
licenses {
license {
name.set(myLicense)
url.set(myLicenseUrl)
}
}
developers {
developer {
id.set(myGithubUsername)
name.set(myDeveloperName)
}
}
}
}
}
}
Here is a link to the entire source file so that you can see where these variables are defined and what the other functions are that generate the docs and the JAR files using the pom
function.
Import this dependency into another gradle project
In order to load the package for the library from GitHub Packages Registry, the official docs provide some detailed examples of the provider side of things. And you can extrapolate what the consumer side of things might look like. The biggest thing to keep in mind is that a read:packages
scoped GitHub personal access token will be required by the consumer of the package (and has to be accessible their build.gradle
or build.gradle.kts
file).
Make sure to provide the following environment variables before you import this package.
GITHUB_PACKAGES_IMPORT_TOKEN
- this token hasread:packages
scope. This is ok to share.GITHUB_PACKAGES_USERID
- this is the GitHub username for the token. This is ok to share.
Here is more information on how to declare your own maven repositories using gradle.
To import this library into your Gradle project, please add the following lines in your build.gradle
file in order to use this library (in Groovy).
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/nazmulidris/color-console")
credentials {
username = System.getenv("GITHUB_PACKAGES_USERID") ?: "nazmulidris"
// Safe to share the password since it is a `read:package` scoped token.
password = System.getenv("GITHUB_PACKAGES_IMPORT_TOKEN") ?: "22e9ba0d47c3e9116a2f1023867a1985beebfb60"
}
}
}
dependencies {
implementation 'com.developerlife:color-console:1.0'
}
Here’s the Kotlin DSL version for build.gradle.kts
:
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/nazmulidris/color-console")
credentials {
username = System.getenv("GITHUB_PACKAGES_USERID") ?: "nazmulidris"
// Safe to share the password since it is a `read:package` scoped token.
password = System.getenv("GITHUB_PACKAGES_IMPORT_TOKEN") ?: "22e9ba0d47c3e9116a2f1023867a1985beebfb60"
}
}
}
dependencies {
implementation("com.developerlife:color-console:1.0")
}
References
- Tutorial on using GitHub Package Registry to publish and import Android Kotlin library
- Tutorial on using GitHub Package Registry to import something from GitHub Package Registry
- Full
build.gradle.kts
example for tutorial above - Discussion about why it is bad to need a token to import packages
- [Discussion about Kotlin versions and the DSL to publish packages](https://github.community/t/how-to-configure-gradle-github-package-registry-maven/14247/9
#reads #nazmul idris #kotlin #open source #gradle #jitpack #github packages