Deploying artifacts to Maven using Gradle
Sometimes more is just confusing.
Artifacts are files such as an executable or a compressed archive that are produced by a build process. When it comes time to store them somewhere, a good place to do so is a Maven artifact repository.
This can be done a number of ways — but my current favorite is to use Gradle as an interface into Maven. Gradle is a powerful build automation tool that is well documented and easy to learn. See my installation post to install it.
Within Gradle itself, there are a few ways to deploy artifacts to a Maven; some offer finer control at the cost of boiler plate, while others will suffice for small projects. This can be overwhelming when looking at Gradle’s documentation, which describes several ways to deploy to Maven. In this post we will look at Gradle’s publish
and upload
tasks, and try to de-mystify them.
Note: This post is based on Gradle 3.3, which at the time of writing is the current release version.
The ‘publish’ task
I have found the ‘publish’ task very useful for uploading a single artifact, or uploading several artifacts all at once (which will be discussed later in this post). This task is provided by the maven-publish
plugin.
Advantages:
- Small code footprint
- Easy to read and understand at a glance
Disadvantages:
- Gets tricky to manage and interact with as you add more artifacts
Single artifact upload using ‘publish’
In the following example, pretend we have a file named ‘some-artifact.tar.gz’, and that we want to deploy it to a Maven repository. You will need to create the following files:
build.gradle
apply plugin: 'maven-publish'
group 'com.group.binaries'
version = externalVersion
publishing {
publications {
maven(MavenPublication) {
artifact('some-artifact.tar.gz') {
extension 'tar.gz'
}
}
}
repositories {
maven {
name 'deploy'
url deployRepoUrl
credentials {
username = deployRepoUsername
password = deployRepoPassword
}
}
}
}
gradle.properties
externalVersion=1.0-SNAPSHOT
deployRepoUrl=https://my-repo.com/maven-snapshots
deployRepoUsername=your-username
deployRepoPassword=your-password
settings.gradle
rootProject.name = 'some-project'
To deploy ‘some-artifact.tar.gz’, run the following command on the command line:
gradle publish
… or if you want to override settings in gradle.properties
at build time:
gradle publish -PdeployRepoUsername=flying -PdeployRepoPassword=pig
Multiple artifacts using ‘publish’
Unfortunately, depending on what you want to do, this is where publish can get pretty clunky. If you want to deploy several artifacts at once, then that is not too bad. However, deploying several artifacts at different times requires a fair amount of code.
In the following example, assume we want to deploy ‘centos-app-x64.rpm’, ‘macos-app-x64.dmg’, and, ‘windows-app-x64.exe’. You can re-use the gradle-properties
and settings.gradle
files from above. But, make sure to overwrite build.gradle
with the following:
apply plugin: 'maven-publish'
group 'com.group.binaries'
version = externalVersion
publishing {
publications {
maven(MavenPublication) {
artifact('centos-app-x64.rpm') {
classifier 'centos-x64'
extension 'rpm'
}
artifact('macos-app-x64.dmg') {
classifier 'macos-x64'
extension 'dmg'
}
artifact('windows-app-x64.exe') {
classifier 'windows-x64'
extension 'exe'
}
}
}
repositories {
maven {
name "deploy"
url deployRepoUrl
credentials {
username = deployRepoUsername
password = deployRepoPassword
}
}
}
}
Now, when you execute gradle publish
, all three artifacts will be uploaded at the same time. For most projects, this will suffice just fine. However, there might be times where you only want to deploy a single artifact at a time. While it is possible to accomplish that using ‘publish’, I find the ‘upload’ task to be better suited to managing multiple artifacts.
The ‘upload’ task
The ‘upload’ task is quirky. It is also a bit overkill if you only need to work with a single artifact. That said, it will give you more control down the road if you decide to deploy multiple artifacts. This task is provided by the maven
plugin.
Advantages:
- Great for managing multiple artifacts
- Easy to interact with on the command line
Disadvantages:
- A lot of boiler plate if you only have one artifact
- Big code footprint
- Strange configuration (if you are not familiar with it)
Single artifact using ‘upload’
Assume we have a single artifact named ‘some-artifact.tar.gz’. You will need to create the following files:
build.gradle
apply plugin: 'maven'
group 'com.group.binaries'
version = externalVersion
configurations {
someArtifact
}
artifacts {
someArtifact file: file('some-artifact.tar.gz'), name: 'some-artifact', type: 'tar.gz'
}
uploadSomeArtifact {
description 'Uploads some artifact.'
group 'publishing'
repositories {
mavenDeployer {
repository(url: deployRepoUrl) {
authentication(userName: deployRepoUsername, password: deployRepoPassword)
}
}
}
}
gradle.properties
externalVersion=1.0-SNAPSHOT
deployRepoUrl=https://my-repo.com/maven-snapshots
deployRepoUsername=your-username
deployRepoPassword=your-password
settings.gradle
rootProject.name = 'some-project'
Yeah… If you have not seen this before, you are probably wondering why there is so much boiler plate in ‘build.gradle’. First off, the name of the ‘upload’ task is very important. The task name must be called upload + NameOfTheTargetConfiguration
. This is how Gradle figures out which configuration to apply to the upload task. A configuration
is an object Gradle provides us to define artifacts and their attributes. In this example, we created one called someArtifact
. Once a configuration is created in the configurations
closure, we can then define the artifact for someArtifact
using the artifacts
closure.
Now, to deploy ‘some-artifact.tar.gz’, execute:
gradle uploadSomeArtifact
… or if you want to override settings in gradle.properties
at build time:
gradle uploadSomeArtifact -PdeployRepoUsername=flying -PdeployRepoPassword=pig
Multiple artifacts using ‘upload’
Assume we want to upload ‘centos-app-x64.rpm’, ‘macos-app-x64.dmg’, and, ‘windows-app-x64.exe’. You can re-use the gradle-properties
and settings.gradle
files from above. But, make sure to overwrite build.gradle
with the following:
apply plugin: 'maven'
group 'com.group.binaries'
version = externalVersion
configurations {
centos_x64
macos_x64
windows_x64
}
artifacts {
centos_x64 file: file('centos-app-x64.rpm'), name: 'my-app', type: 'rpm', classifier: 'x64'
macos_x64 file: file('macos-app-x64.rpm'), name: 'my-app', type: 'dmg', classifier: 'x64'
windows_x64 file: file('windows-app-x64.rpm'), name: 'my-app', type: 'exe', classifier: 'x64'
}
uploadCentos_x64 {
description 'Uploads the CentOS 64-bit application.'
group 'publishing'
repositories {
mavenDeployer {
repository(url: deployRepoUrl) {
authentication(userName: deployRepoUsername, password: deployRepoPassword)
}
}
}
}uploadMacos_x64 {
description 'Uploads the macOS 64-bit application.'
group 'publishing'
repositories {
mavenDeployer {
repository(url: deployRepoUrl) {
authentication(userName: deployRepoUsername, password: deployRepoPassword)
}
}
}
}uploadWindows_x64 {
description 'Uploads the Windows 64-bit application.'
group 'publishing'
repositories {
mavenDeployer {
repository(url: deployRepoUrl) {
authentication(userName: deployRepoUsername, password: deployRepoPassword)
}
}
}
}
Yes, this is a lot more code than ‘publish’. But, the key difference is that we can now deploy our artifacts independently of one another. In other words, if I want to only deploy the Windows application, I can do so by running:
gradle uploadWindows_x64
Uploading multiple artifacts at the same time is still possible, just run:
gradle uploadCentos_x64 uploadMacos_x64 uploadWindows_x64