We can digitally sign artifacts in Gradle with the signing plugin. The plugin supports generating Pretty Good Privacy (PGP) signatures. This signature format is also required for publication to Maven Central Repository. To create a PGP signature, we must install a few PGP tools on our computer. Installation of the tools is different for each operating system. On Unix-like systems, the software is probably available via a package manager. With the PGP software, we need to create a key pair that we can use to sign artifacts.
To sign artifacts, we must apply the signing plugin to our project. Then we must configure the plugin using a signing
configuration block. We need to at least add information about our PGP key pair. We need the hexadecimal representation of the public key, the path to the secret key ring file with our private key, and the passphrase used to protect the private key. We assign this information to the keyId
, secretKeyRingFile
, and password
properties of the signing plugin configuration. These values shouldn't be part of the Gradle build file because they are secret, so it is better to store them in a gradle.properties
file and apply secure file permissions to the file. Also, we do not add this file to our version control system.
In the following example gradle.properties
file, we set the properties. The values are sample values and are different for each user:
signing.keyId = 8B00165A signing.secretKeyRingFile = /Users/current/.gnupg/secring.gpg signing.password = secret
We are ready to sign our artifacts. We need to configure which artifacts we want to be signed using the signing
configuration block. We must specify the name of the artifact configuration that contains the artifacts to be signed.
When we apply the Java plugin to our project, we get the archives
artifact configuration. We want to sign the artifacts assigned to this configuration. In the next example build file, we apply both the Java and signing plugins. In the signing
configuration block, we define that we want to sign the artifacts belonging to the archives
configuration:
apply plugin: 'java' apply plugin: 'signing' group = 'com.mrhaki.sample' version = '2.1' archivesBaseName = 'sample' // Configure signing plugin. signing { // Define that we want to // sign the artifacts belonging // to the archives configuration. sign configurations.archives } uploadArchives { repositories { flatDir( name: 'local-repo', dirs: "${projectDir}/repo") } }
The signing plugin also adds a new task rule to our project—sign<ConfigurationName>
. The name of the configuration is what we define in the signing
configuration block. We defined the archives
configuration so, in our project, we can now execute the
signArchives
task. The task is also added as a task dependency to the assemble task; thus, every time we invoke the assemble
task, Gradle makes sure the signArchives
task is invoked as well.
Here, we run the uploadArchives
task to see which files are put in the repository directory:
$ gradle uploadArchives :compileJava :processResources :classes :jar :signArchives :uploadArchives BUILD SUCCESSFUL Total time: 4.305 secs $ ls -1 repo ivy-2.1.xml ivy-2.1.xml.sha1 sample-2.1.asc sample-2.1.asc.sha1 sample-2.1.jar sample-2.1.jar.sha1 $
We notice that a signature file, sample-2.1.asc
, is created together with the sample-2.1.asc.sha1
checksum file for the signature file.
To sign an artifact that is not part of an artifact configuration, we must configure the signing plugin differently. In the signing
configuration block, we assigned a configuration in the previous section, but we can also use an archive task. The output of this archive task will be signed when we invoke the sign<TaskName>
task rule.
In the next example build file, we will create a ZIP file with the manualZip
task. We will configure the signing plugin for the manualZip
task so that this ZIP file is signed:
apply plugin: 'signing' version = '1.0' // New archive task to create // a ZIP file from some files. task manualZip(type: Zip) { archivesBaseName = 'manual' from 'src/docroot' } // Configure signing plugin to // sign the output of the // manualZip task. signing { sign manualZip } // Create new configuration for // ZIP and signed ZIP artifacts. configurations { manualDistribution } // Set artifacts to manualDistribution // configuration. artifacts { manualDistribution( manualZip, signManualZip.singleSignature.file) } // Configure upload task for // manualDistribution configuration. uploadManualDistribution { repositories { flatDir { dirs "${projectDir}/repo" } } } // Add task dependency so signing of // ZIP file is done before upload. uploadManualDistribution.dependsOn signManualZip
All sign<TaskName>
tasks automatically have a task dependency on the archive task identifier by <TaskName>
. So, we can now simply invoke the uploadManualDistribution
task, and the ZIP file is created, signed, and uploaded to the repo
directory. The following code shows this:
$ gradle uploadManualDistribution :manualZip :signManualZip :uploadManualDistribution BUILD SUCCESSFUL Total time: 1.695 secs $ ls -1 repo ivy-1.0.xml ivy-1.0.xml.sha1 manual-1.0.zip manual-1.0.zip-1.0.asc manual-1.0.zip-1.0.asc.sha1 manual-1.0.zip.sha1 $
18.119.133.160