As a Java/JVM/Android developers we rely on the work of other people through frameworks and libraries. Many of them are open-source. Most of the developers are consumers of such projects. What if we would like to create our own library and distribute it to other developers? We can always create it and share a
*.aar file with others. Drawback of such solution is the fact that source of distribution may not be trusted. We also have problems with versioning. Consumers of the library have to constantly download and update their files. It’s much better to publish our library to Maven Central Repository and allow others to easily and seamlessly add it as an external dependency to
pom.xml file (in case of Maven) or
build.gradle file (in case of Gradle). In such case, dependency is managed by the appropriate build system and distributed via trusted source. This may be not easy for the first time that’s why I decided to collect information related to this topic in a single article. Let’s see how to do this.
Generating a GPG Key
Before we upload library, we need to generate GPG key.
In order to generate GPG key, we need to open the terminal and type the following command:
Then, we should see the output:
... gpg: key YOUR_KEY_ID marked as ultimately trusted ...
Read more at: https://alexcabal.com/creating-the-perfect-gpg-keypair
Distributing the public key
Next, we need to distribute public key. We can do that as follows:
gpg --keyserver hkp://pool.sks-keyservers.net --send-keys YOUR_KEY_ID
We can distribute our key to multiple servers to speed up the synchronization process (pgp.mit.edu, keyserver.ubuntu.com, etc.)
We can also list our keys as follows:
To list secret keys, we can type:
Preparing the Gradle configuration
In my case, I used Gradle as a build system, which works well for Java, Kotlin and Android projects. We can use Maven for this purpose as well. As a reference, I used a Gradle script prepared by Chris Banes. You can have a look at it in one of my projects.
In my libraries, I usually have the following structure:
/ ├── library │ ├── gradle.properties │ └── build.gradle │ ├── build.gradle ├── maven_push.gradle └── gradle.properties
maven_push.gradle I keep the mentioned release script. In the
library/gradle.properties, I keep details about artifact released from a given directory:
POM_NAME=reactivenetwork POM_ARTIFACT_ID=reactivenetwork-rx2 POM_PACKAGING=aar
It can be
jar if you’re releasing pure Java library. Here’s an example for Android library.
/gradle.properties file, I keep release configuration:
VERSION_NAME=3.0.3 VERSION_CODE=34 GROUP=com.github.pwittchen POM_DESCRIPTION=Android library listening network connection state and Internet connectivity with RxJava Observables POM_URL=https://github.com/pwittchen/ReactiveNetwork POM_SCM_URL=https://github.com/pwittchen/ReactiveNetwork POM_SCM_CONNECTION=scm:firstname.lastname@example.org:pwittchen/ReactiveNetwork.git POM_SCM_DEV_CONNECTION=scm:email@example.com:pwittchen/ReactiveNetwork.git POM_LICENCE_NAME=The Apache Software License, Version 2.0 POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt POM_LICENCE_DIST=repo POM_DEVELOPER_ID=pwittchen POM_DEVELOPER_NAME=Piotr Wittchen org.gradle.daemon=true org.gradle.jvmargs=-XX:MaxPermSize=1024m -XX:+CMSClassUnloadingEnabled -XX:+HeapDumpOnOutOfMemoryError -Xmx2048m
library/build.gradle file I need to include release Gradle script:
apply from: '../maven_push.gradle' ...
$HOME/.gradle/gradle.properties file, I keep system-wide release configuration for Sonatype:
signing.keyId=YOUR_KEY_ID signing.password=YOUR_SIGNING_PASSWORD signing.secretKeyRingFile=/home/piotr/.gnupg/secring.gpg NEXUS_USERNAME=YOUR_NEXUS_USERNAME NEXUS_PASSWORD=YOUR_NEXUS_PASSWORD
YOUR_NEXUS_PASSWORD can be defined during account creation on the http://oss.sonatype.org website.
Of course, you need to provide your own path to
secretKeyRingFile, which was created during generating key.
If you’re interested in the complete project structure prepared for library release, you can have a look at the following examples:
- Java library (compiled into
- Android library written in Java (compiled into
- Android library written in Kotlin (compiled into
Creating a Jira ticket for Sonatype
We should create a Sonatype Jira account and a new project ticket. You can have a look at my first issue. It took a bit longer in my case, because I needed to adjust package name.
To avoid my mistakes, have a look at the following guides:
Please note, this step is required for the first time only as well as generating keys. After that, we we’ll be able to release as many artifacts under the given package name as we want. These steps need to be repeated in the case of registering the new package name.
This is reasonable from the security and stability perspective because random people cannot just override widely used packages what might cause serious problems in many projects around the world.
Uploading an artifact
Once, we have everything set up, we can go to our project via terminal, and type:
and wait while artifacts are being uploaded.
Releasing an artifact
Next, we need to go to the http://oss.sonatype.org website, log in and on the left-hand side, click “Staging Repositories”. Then, we need to sort artifacts by date (Updated column), to view the recently updated items. We should find our artifact (it should be on the top) and click it. We can verify its contents to ensure that everything is ok (package name, version, etc.) and then, we should press “Release” on our artifact. Once release is done, we should press “Close” on the artifact.
Commenting the Jira ticket
When we are done with the previous steps, we should go back to our Jira ticket and provide the comment:
I have promoted my first release. Thanks.
Waiting for the Maven sync
After all of these steps, we need to wait for the acceptance from the people from Sonatype and Maven Sync. Maven Sync can take no longer than 48 hours. It’s usually faster, but it won’t happen immediately after releasing and closing an artifact like in the release of the Python packages.
We can see, that release process may be overwhelming and time consuming, but once we release the first artifact, we can skip most of these steps like generating keys and creating Jira ticket. We just need to have Gradle or Maven configuration, upload artifacts, release and close them via sonatype website and wait for the Maven Sync. Process of releasing new versions of the same artifact is the same as the first release (excluding mentioned first-time steps). During the next release, we simply need to bump library version in the Gradle configuration before uploading artifacts. In the future, I’m planning to write another article, which shows how to skip manual steps of going to Sonatype website and releasig artifacts via clicking on the page via Gradle plugins, so everything will be automated via CLI.
Links and references