This post will detail how to setup a private Maven repository in order to easily share Java, Scala, Clojure, and Android libraries with internal teams. Our example will use Jenkins CI to push an example library that will be used by an internal using Maven and an external team using Gradle.
As microservice architectures become increasingly prevalent in our industry, the number of internal libraries needed by applications to function properly has exploded. Without a proper Maven repository manager, hosting these internal libraries yourself is tedious at best (or practically insecure, at worst).
The example detailed in this post is designed to look familiar to most Java based organizations: A core frameworks team maintains a common library used by developers in two separate teams, both of them which using their own preferred build tool.
You can follow along with this post by cloning our example-framework project on Github.
Create packagecloud Maven repository
If you don’t have a packagecloud.io account already, click the button below to sign up and create your private Maven repository.
Easy to use Maven repositories, free.
Deploying to your private Maven Repository
We’re going to be deploying our
example-framework library using Jenkins CI and our private Maven repository on packagecloud.io.
Maven Setup for Jenkins CI
Before we begin, we need to make sure our Maven project is ready for use on Jenkins CI.
.jenkins.settings.xml file to your Maven project
We need to add a custom Maven
settings.xml file that instructs Maven to use an environment variable for the
password for any repositories with the
Add your repository to your Maven project
<distributionManagement/> section of your
pom.xml, we’ll need to tell Maven to deploy to our newly created private Maven repository, as demonstrated below.
Note that the
id is set to
packagecloud-examplecorp, which is what we used in our
.jenkins.settings.xml file above.
Add the packagecloud plugin to your Maven project
Lastly, you’ll need to add the plugin that lets Maven natively deploy artifacts to packagecloud.io repositories. Note: this plugin is only needed to upload artifacts, no plugin is required for downloading artifacts. Any Maven-compatible build tool can use your private Maven repository.
Add the following to the
<build/> section of your project
Now we are ready to set up our Jenkins CI job.
Jenkins CI Setup
Setting up a Jenkins CI instance is out of the scope of this post, so we’ll assume you have access to one already.
In this section, we’ll be adding our API token to the credentials system in Jenkins CI, then creating a job that uses that API token as an environment variable to invoke the
mvn deploy goal on our Maven project, using the
.jenkins.settings.xml file we added above.
Let’s get started!
Add packagecloud credentials to Jenkins CI
In order to authenticate Maven artifact uploads, Jenkins CI will need to know your packagecloud.io API token. An API token allows Jenkins CI to upload to any repository that user has access to. You can create as many “deploy tokens” or “write tokens” as you need by creating separate users on packagecloud.io and adding them as collaborators to the desired repositories. Their individual API tokens will be limited to upload only to those repositories.
Add your packagecloud.io API token to the “Global credentials” as a “Secret Text” item, as shown below.
To learn more about how Jenkins CI stores and uses credentials, refer to the Credentials Plugin page.
Create Jenkins CI Job
Our example job is a Free-form project that pulls down a Git repository and executes a single Maven goal when triggered.
Source Code Management
Set your Git repository URL and Branch Specifier under “Source Code Management”, we’re using our example-framework Github project here.
Under Build Environment, make sure that “Use secret text(s) or file(s)” is checked.
Environment Variable Bindings
Then, under “Bindings”, click “Add”, then “Secret text”.
This is where we bind the packagecloud.io API token we stored above to the environment variable Maven is configured to use for authentication.
Set the variable name to match the one used in
.jenkins.settings.xml and select your desired credentials from the dropdown.
Add build step
Add an “Invoke top-level Maven targets” build step from the dropdown in the “Build” section.
example-framework project, we are using a [SNAPSHOT version](https://github.com/computology/example-framework/blob/master/pom.xml#L7, so we can just run
mvn deploy every time the job runs without having to worry about incrementing the version number.
When writing Maven goals in Jenkins CI, the
mvn part is implied, so simply write
deploy as the goal.
Then, click on the “Advanced…” button.
This is where we tell Jenkins CI to use the custom Maven settings file we added to our project at the beginning of this post. The path is relative to the project workspace, so we can just set this to
.jenkins.settings.xml since it lives in the root of our project. Also, make sure that ‘Use private Maven repository’ is checked.
Trigger Jenkins CI build
Normally, your Jenkins CI job would be triggered externally, either via a Github Pull request, or when new source code is added to the repository. But for our example, we’ll keep it simple and just trigger it manually by clicking “Build now” on the job page.
Once the job finishes, you should see your artifact on your packagecloud.io repository page.
Sharing your private Maven repository
Now that our library is deployed to our private Maven repository, we’ll need to configure the Maven and Gradle projects to access it.
Access to your private Maven repository is controlled via a sophisticated token authentication system. These tokens are generated independently of user accounts. This means that employees do not need a packagecloud.io account in order to use your private Maven repository.
Read Tokens are created as children of Master Tokens. The sole purpose of Master Tokens is to create Read Tokens. Once a Master Token is revoked, all of its Read Tokens are also revoked.
You can manage your repository tokens by visiting the “Tokens” page of your repository or using our API
For our example, we’ll create two custom Master Tokens for both of our separate teams:
Generating Read Tokens
Read tokens are generated by making an HTTP request to your private repository using a Master Token and a
name value. The same request for the same
name value will return the same Read Token. So, you could either store the Read Token value itself, or just the
name and Master Token and generate it on demand.
For example, to generate a token for
internal-team which is the name of the custom Master Token value of
7ec609b666604a7ba2bc6e39602ac0b145fe28d2b06a134f, the request looks like this:
Alternatively, you can create Read Tokens using the “Tokens” page on the packagecloud.io repository page.
For more details about our token system, refer to the Token Auth documentation.
Setup for Developers
Similar to our Jenkins CI Setup, we’re going to use an environment variable to hold our developer’s Read token. This can be accomplished any number of ways, either distributed to each developer individually, or set from LDAP via some automatic mechanism.
For our example, we’ll just set it manually inside of our
Similar to our
.jenkins.settings.xml file, we’ll add this to the
pom.xml of any project that wants to use our
example-framework. This is using the
PACKAGECLOUD_READ_TOKEN that was set above for authenticating against our private Maven repository.
Like Maven, we tell Gradle to use the
PACKAGECLOUD_READ_TOKEN environment variable to authenticate against our private Maven repository.
Publishing and using libraries doesn’t have to be difficult or tedious. Having a private Maven repository manager that the whole team can easily use is crucial for increasing developer collaboration and reducing duplicated effort.