Using Gradle to Release a Plugin

How to use Gradle to release a commercial plugin for Jenkins to ToolSpring Update Center.

Using Gradle to Release a Plugin

This guide is based on the Gradle JPI Plugin which automates the steps to release artifacts to the ToolSpring Update Center. See article Releasing a Commercial Plugin for background information about releasing to this Update Center.

sample-jenkins-plugin-gradle is a sample Jenkins Plugin project with a Gradle configuration for releasing to ToolSpring.

You will need the following installed:

  • The Gradle Build Tool. See Install Gradle for directions.
  • Java JDK 1.8 which is required for compatibility with Jenkins.

If your Jenkins plugin project is not set up for building with Gradle, execute the command below from the project root directory.

gradle init

This should create a hierarchy of subdirectories and download/copy the Gradle Wrapper into the project root directory:

  • Create or move your project code and resource files into the appropriate subdirectories.
  • You can now execute Gradle using the Wrapper script, e.g. on Linux ./gradlew tasks will show tasks defined for the current project. The examples below show the equivalent command on Windows:
Operating systemPath
PowerShell.\gradlew tasks
Command Prompt (cmd.exe)gradlew tasks

For brevity, the command examples below use the Linux form.

To prepare for a release you may need to edit your Gradle build script and project properties, as described in the sections below.

Custom Properties

If the file gradle.properties is not in your project root directory*, create this file to store custom properties for the project.

Copy the lines below into your gradle.properties file. The properties defined here will be used to configure the build script (see below) for communicating with the ToolSpring Update Center. Set the values at toolspringUsername and toolspringPassword to your ToolSpring login credentials.

# Do not publish artifacts with SHA 256 and 512 checksums.
# These checksums are not currently supported.
systemProp.org.gradle.internal.publish.checksums.insecure=true

# ToolSpring Update Center repository name and URL.
toolspringMavenName=toolspring-licensing-service
toolspringMavenUrl=https://licensing.toolspring.com/repository/toolspring-releases/

# ToolSpring login credentials, required when pushing to ToolSpring Update Center.
toolspringUsername=my-username
toolspringPassword=my-password

* Be sure to keep the properties file secure when it contains secrets like your ToolSpring login credentials. For example, do not include the file in source control. Alternately, copy these properties to the Gradle user properties file, usually located in the .gradle subdirectory of your home directory; see the table below.

Operating systemPath
Linux~/.gradle/gradle.properties
Windows%USERPROFILE%\.gradle\gradle.properties

Build Script

The script samples below have been customized for releasing to the ToolSpring Update Center, and use the properties defined above in the gradle.properties file.

Configuration: Gradle Plugins

If your build.gradle file does not include it, add a plugins clause to the file as shown below. Your project may require additional plugins.

plugins {
    // Gradle JPI plugin
    id 'org.jenkins-ci.jpi' version '0.43.0'

    // required for publishing (releasing) to a Maven repository
    id 'maven-publish'
}

Configuration: Required Library Repositories

If your build.gradle file does not include it, add a repositories clause to the file as shown below. Your project may require additional repositories.

repositories {
    mavenLocal()
    maven {
        url = uri('https://repo.jenkins-ci.org/public/')
    }

    maven {
        url = uri('https://repo.maven.apache.org/maven2/')
    }
}

Configuration: Java Compatibility

If your build.gradle file does not include them, set the Java compatibility properties as shown below.

java.sourceCompatibility = JavaVersion.VERSION_1_8

// required for compatibility with Jenkins
java.targetCompatibility = JavaVersion.VERSION_1_8

Configuration: JPI Plugin DSL

If your build.gradle file does not include it, add a jenkinsPlugin clause to the file as below. Set each property to a suitable value for your project.

jenkinsPlugin {
    // version of Jenkins core this plugin depends on, must be 1.420 or later
    // during a build Gradle will download Jenkins libraries that correspond to the specified version 
    jenkinsVersion = '1.420'

    // ID of the plugin, defaults to the project name without trailing '-plugin'
    shortName = 'echo-static-analysis'

    // human-readable name of plugin
    displayName = 'Echo Static Analysis'

    // URL for plugin on Jenkins wiki or elsewhere
    url = 'http://wiki.andreiprozorov.com/plugins/echo-static-analysis-plugin'

    // plugin URL on GitHub, optional
    gitHubUrl = 'https://github.com/toolspring/echo-static-analysis-plugin'

    // use the plugin class loader before the core class loader, defaults to false
    pluginFirstClassLoader = false

    // optional list of package prefixes that your plugin doesn't want to see from core
    // maskClasses = 'groovy.grape org.apache.commons.codec'

    // optional version number from which this plugin release is configuration-compatible
    // compatibleSinceVersion = '1.1.0'

    // set the directory from which the development server will run, defaults to 'work'
    // workDir = file('/tmp/jenkins')

    // URL used to deploy the plugin, defaults to the value shown
    // the system property 'jpi.repoUrl' can be used to override this option
    // repoUrl = 'https://repo.jenkins-ci.org/releases'

    // URL used to deploy snapshots of the plugin, defaults to the value shown
    // the system property 'jpi.snapshotRepoUrl' can be used to override this option
    // snapshotRepoUrl = 'https://repo.jenkins-ci.org/snapshots'

    // enable injection of additional tests for checking the syntax of Jelly and other things
    disabledTestInjection = false

    // the output directory for the localizer task relative to the project root
    // defaults to the value shown
    localizerOutputDir = "${project.buildDir}/generated-src/localizer"

    // disable configuration of Maven Central, the local Maven cache and the Jenkins Maven repository
    // defaults to true
    configureRepositories = false

    // skip configuration of publications and repositories for the Maven Publishing plugin
    // defaults to true
    configurePublishing = false

    // plugin file extension, either 'jpi' or 'hpi'
    // defaults to 'hpi'
    fileExtension = 'hpi'

    // the developers section is optional, and corresponds to the POM developers section
    developers {
        developer {
            id 'aprozorov'
            name 'Andrei Prozorov'
            email 'info@andreiprozorov.com'
        }
    }

    // the licenses section is optional, and corresponds to the POM licenses section
    licenses {
        license {
            // Maven:
            name ''
            url ''
            distribution 'repo'
            comments ''
        }
    }
}

Configuration: Publishing

If your build.gradle file does not include it, add a publishing clause to the file as below. Set version, groupId, and artifactId to suitable values for your project. Note the references to custom properties defined in the gradle.properties file, e.g. project.toolspringUserName.

publishing {
    publications {
        maven(MavenPublication) {
            version = '1.0'

            groupId = 'com.andreiprozorov.plugins'

            // Override artifactId because the default will be based on the
            // directory structure, for example:
            //
            //     com.andreiprozorov.plugins.lib.0.1
            //
            // whereas we want this:
            //
            //     com.andreiprozorov.plugins.echo-static-analysis.1.0
            artifactId = jenkinsPlugin.shortName

            from components.java
        }
    }

    repositories {
        maven {
            name project.toolspringMavenName
            url  project.toolspringMavenUrl
    
            authentication {
                basic(BasicAuthentication)
            }
    
            credentials {
                username project.toolspringUsername
                password project.toolspringPassword
            }
        }
    }
}

Using Gradle JPI Plugin

There are two main tasks involved in using the JPI Plugin:

  • jpi builds the artifacts required for a Jenkins plugin.
  • publish publishes (releases) these artifacts to the repository specified in the publishing.repositories.maven clause of the build script.

The command below sets the log level to 'info' and executes both tasks:

./gradlew --info jpi publish

If both tasks succeed then the execution log should end with lines similar to the example below:

...
Publishing to repository 'toolspring-licensing-service' (https://licensing.toolspring.com/repository/toolspring-releases/)
Uploading echo-static-analysis-1.3.pom to /repository/toolspring-releases/com/andreiprozorov/plugins/echo-static-analysis/1.3/echo-static-analysis-1.3.pom
Uploading echo-static-analysis-1.3.jar to /repository/toolspring-releases/com/andreiprozorov/plugins/echo-static-analysis/1.3/echo-static-analysis-1.3.jar
Uploading echo-static-analysis-1.3.module to /repository/toolspring-releases/com/andreiprozorov/plugins/echo-static-analysis/1.3/echo-static-analysis-1.3.module
Uploading echo-static-analysis-1.3.hpi to /repository/toolspring-releases/com/andreiprozorov/plugins/echo-static-analysis/1.3/echo-static-analysis-1.3.hpi
Uploading maven-metadata.xml to /repository/toolspring-releases/com/andreiprozorov/plugins/echo-static-analysis/maven-metadata.xml
:publishMavenPublicationToToolspring-licensing-serviceRepository (Thread[Daemon worker Thread 6,5,main]) completed. Took 2.769 secs.

> Task :publish
Skipping task ':publish' as it has no actions.
:publish (Thread[Daemon worker Thread 6,5,main]) completed. Took 0.0 secs.

BUILD SUCCESSFUL in 4s
14 actionable tasks: 14 executed
Watching 48 directories to track changes

The sections below describe common errors and possible causes.

Error: Update Center Definition

The publish command may log output similar to this:

...
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':publishMavenPublicationToToolspring-licensing-serviceRepository'.
> Failed to publish publication 'maven' to repository 'toolspring-licensing-service'
   > Could not PUT 'https://licensing.toolspring.com/repository/toolspring-release/com/andreiprozorov/plugins/echo-static-analysis/1.2/echo-static-analysis-1.2.pom'. Received status code 500 from server:

The server returned status code 500. In this case the likely cause is that the build script's clause publishing.repositories.maven specifies an incorrect URL. The sample clause above refers to property toolspringMavenUrl in the gradle.properties file - check that this property value is correct.

Error: Update Center Authentication

The publish command may log output similar to this:

...
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':publishMavenPublicationToToolspring-licensing-serviceRepository'.
> Failed to publish publication 'maven' to repository 'toolspring-licensing-service'
   > Could not PUT 'https://licensing.toolspring.com/repository/toolspring-releases/com/andreiprozorov/plugins/echo-static-analysis/1.2/echo-static-analysis-1.2.pom'. Received status code 401 from server:

The server returned status code 401. In this case the likely cause is that your ToolSpring login credentials are missing or incorrect:

  • Your gradle.properties file should have the correct values defined for toolspringUsername and toolspringPassword.
  • Your build script's clause publishing.repositories.maven.credentials should refer to the above properties.

Error: Previously Released Version

The publish command may log output similar to this:

...
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':publishMavenPublicationToToolspring-licensing-serviceRepository'.
> Failed to publish publication 'maven' to repository 'toolspring-licensing-service'
   > Could not PUT 'https://licensing.toolspring.com/repository/toolspring-releases/com/andreiprozorov/plugins/echo-static-analysis/1.2/echo-static-analysis-1.2.pom'. Received status code 400 from server:

The server returned status code 400. In this case the likely cause is that the specified version was released previously. The Update Center does not allow releases to be replaced.