Using a Private GitHub Repository as Maven Repository, with Gradle
All we’ve wanted was a quick, easy & cheap way to make our nice internal Java library (written in Kotlin) available to other internal Gradle-based projects.
Update: GitHub Packages has launched by now. It allows you to set up public and private Maven repositories and is included in your existing GitHub plan.
For public libraries it’s easy — just publish the library to your public Maven repository on Bintray, add the repository URL to your build.gradle.kts
and you’re ready. But having to spend $150/month in order to create a private repository on Bintray seems a bit too much for just a single library in a small company.
Because Maven repositories are basically just hosted files which you can download using simple URLs and we’re already paying GitHub for private repositories the idea is as simple: let’s just publish the artifacts to a local project folder and push them along the code in our repository. Other projects can then use that GitHub repository as a Maven repository to download library releases.
Publishing
That’s the easiest part and there’s enough documentation out there. I’ll assume that you’ve set up your Maven Publication already and just need to publish it to somewhere:
// build.gradle.ktspublishing {
repositories {
maven("${project.rootDir}/releases")
}
}
Now running ./gradlew publish
will publish your artifacts to the folder releases
in your project’s root directly and you can simply commit & push it to your private GitHub repository. So far so easy.
Consuming
So your repository is now on GitHub in the form of a folder in a private repository, similar to the one from Layer for example, although theirs is public.
GitHub is so kind to make all files downloadable directly using raw.githubusercontent.com, for example git-repo-plugin-1.0.0.pom. That allows us to use the such a URL as a Maven repository in our Gradle configuration:
// build.gradle.ktsrepositories {
maven("https://raw.githubusercontent.com/USERNAME/REPOSITORY/BRANCH/releases")
}
Works great for public repositories but fails for private ones because obviously some authentication is needed.
For the authentication you need an OAuth access token. The easiest way to get one is by creating a Personal access token with the repo scope. It looks something like this: 4774b9b4af1bef7dd8924793ba2962a679e0df47
.
The last step is to tell Gradle to actually use that access token when accessing your private repository:
// build.gradle.ktsrepositories {
maven("https://raw.githubusercontent.com/USERNAME/REPOSITORY/BRANCH/releases") {
credentials(HttpHeaderCredentials::class.java) {
name = "Authorization"
value = "Bearer 4774b9b4af1bef7dd8924793ba2962a679e0df47"
}
authentication {
register("header", HttpHeaderAuthentication::class)
}
}
}
Yup, it looks a bit weird, because Gradle Kotlin DSL doesn’t support the syntax properly yet. Nonetheless it will add an Authorization
header to every request Gradle makes to your private repository and thus ensure proper authentication. Gradle will be able to resolve your artifacts now and download them directly from the GitHub repository.
Security
A word of warning: Having access to the Personal access token also grants read and write access to all public and private repositories of the account for which the token was created. Keep that in mind when checking in the build scripts to Git and sharing the code and thus the token with others.
For that reason the access token should be handled with care just like a password. Ideally you create a special GitHub account just for this matter which has only read access to the GitHub repository where your Maven repository is located and to no other repositories. That way damage is limited should the access token get in the wrong hands.
Gradle Kotlin DSL
Note that the examples mention build.gradle.kts
which is Gradle build scripts written in Gradle Kotlin DSL. For Groovy-based build.gradle
files the code will look quite similar and I’m sure you’ll figure it out :)
🛠 Happy coding!