Skip to content

GitLab CI template for Gradle

This project implements a generic GitLab CI template Gradle based projects.

Usage

In order to include this template in your project, add the following to your gitlab-ci.yml (replace __VERSION__ with the adequate version):

include:
  - project: 'to-be-continuous/gradle'
    ref: '1.2.1'
    file: '/templates/gitlab-ci-gradle.yml'

Global configuration

The Gradle template uses some global configuration used throughout all jobs.

Name description default value
GRADLE_IMAGE The Docker image used to run Gradle
⚠️ set the version required by your project
gradle:latest
GRADLE_CLI_OPTS Additional Gradle options used on the command line None
GRADLE_CLI_BIN The location of the gradle binary. If you prefer using a gradle wrapper you should override this (for e.g. gradlew) gradle
GRADLE_USER_HOME The gradle user home $CI_PROJECT_DIR/.gradle
GRADLE_DAEMON Whether to use or not gradle daemon false

As you can see the GRADLE_USER_HOME is set to a directory inside $CI_PROJECT_DIR. This will allow you to do some gradle caching (declared in all gradle jobs) but also to provide a custom gradle.properties file in your directory.

⚠️ You don't need to provide proxy and daemon properties in your gradle.properties as they will be set by each gradle job (they won't be overwritten if you do so).

Template supports http_proxy, https_proxy and no_proxy that will be put in gradle.properties.

For example, if you provide:

variables:
    http_proxy: "http://the-proxy:8080"
    https_proxy: "http://the-proxy:8080"
    no_proxy: "localhost,my.neighbour.service"

and if you kept default GRADLE_DAEMON variable and did not specify proxy and daemon properties, the properties added to $GRADLE_USER_HOME/gradle.properties will be:

org.gradle.daemon=false
systemProp.http.proxyHost=the-proxy
systemProp.http.proxyPort=8080
systemProp.http.nonProxyHosts=localhost|my.neighbour.service
systemProp.https.proxyHost=the-proxy
systemProp.https.proxyPort=8080
systemProp.https.nonProxyHosts=localhost|my.neighbour.service

Jobs

Build jobs

The Gradle template features a single job gradle-build that performs build (including tests) at once. This stage is performed in a single job for optimization purpose (it saves time) and also for test jobs dependency reasons.

It uses the following variable:

Name description default value
GRADLE_BUILD_ARGS Gradle arguments for the build & test job build

About Code Coverage

You can in your build.gradle file apply some code coverage such as jacoco.

For example, by doing this in your build file (more information about the jacoco plugin ):

plugins {
    //...
    id 'jacoco'
    //...
 }
//...   
jacoco {
    toolVersion = "0.8.3"
}

jacocoTestReport {
    reports {
        // mandatory as it will be read by the pipeline
        csv.enabled true
        // optional for gitlab-ci pipeline yet required if you need sonar analysis
        xml.enabled true
    }
}

By adding the plugin, the template will automatically add jacocoTestReport and jacocoTestCoverageVerification tasks to the build phase.

The jacoco coverage display in gitlab uses the following variable

Name description default value
JACOCO_CSV_REPORT Name of report jacocoTestReport.csv

Dependency-check

The Gradle template features a job gradle-dependency-check that performs a manual Dependency-Check analysis.

It is bound to the test stage and use the following variable :

Name description default value
GRADLE_DEPENDENCY_CHECK_TASK Name of the gradle task launching the analysis dependencyCheckAnalyze

A Dependency-Check is a quite long operation and therefore the job is configured to be ran manually by default (overridable).

You need to configure your build.gradle to include the Dependency-Check module, the exemples below can help you kickstart the use of the plugin

Here is a generic configuration :

buildscript {
  repositories {
    mavenCentral()
    // ...
  }
  dependencies {
    // ...
    classpath 'org.owasp.dependency-check-gradle:5.3.2.1'
  }
}
apply plugin: 'org.owasp.dependencycheck'
dependencyCheck {
  formats=['HTML', 'JSON']
  analyzers {
    assemblyEnabled=false
    retirejs {
      enabled=false
    }
  }
}

If you're using an Artifactory as a repository/mirror, you might need to add a repositories block and add an artifactory block in the job definition.

Here is an example (change the urls accordingly):

buildscript {
  // ...
  repositories {
    maven {
      url "https://artifactory.acme.host/artifactory/maven-virtual-repo"
    }
  }
}
// ...
dependencyCheck {
  // ...
  analyzers {
    artifactory {
      enabled=true
      url="https://artifactory.acme.host/artifactory"
    }
    // ...
  }
}

⚠️ The injection of systemProp.http(s).nonProxyHosts (through either custom gradle.properties file or no_proxy environment variable) into gradle.properties crashes for version 5.3.x below 5.3.2.1 (bug) and is ignored for 5.3.2.1 version of plugin (bug) so if you need to specify exceptions for your proxy for this task, you should either :

  • use the 5.2.4 version or below
  • or removing injection for the task and add a proxy block like this :
dependencyCheck {
  // ...
  proxy {
    server=my.proxy.org
    port=8080
    nonProxyHosts=["127.0.0.1", "mycorp.com"]
  }
}

More info on how you can configure the gradle Dependency-Check plugin can be found in the official documentation

Publish jobs

Currently the pipeline exposes two manual jobs of publication:

  • gradle-snapshot: launched on branches
  • gradle-release: launched on tags

Both jobs use the following variables

Name description default value
GRADLE_PUBLISH_VERSION The value is propagated as gradle properties named version. It should be used in your publish task ${CI_COMMIT_REF_SLUG}-SNAPSHOT
GRADLE_PUBLISH_ARGS The publish task that is invoked publish
GRADLE_NO_PUBLISH Set this variable if you wish to disable publish phase None

If you keep default value for GRADLE_PUBLISH_VERSION, it will have the following values

  • for a snapshot: <branch name>-SNAPSHOT
  • for a release: <tag name>

Here is an example of a build.gradle publishing on Artifactory:

plugins {
    // ...
    id 'maven-publish'
}

def snapshotsRepoUrl = "https://artifactory.acme.host/artifactory/maven-snapshot-repo/"
def releasesRepoUrl = "https://artifactory.acme.host/artifactory/maven-release-repo/"

task sourceJar(type: Jar) {
    classifier "sources"
}

task dokkaJavadoc(type: org.jetbrains.dokka.gradle.DokkaTask) {
    outputFormat = 'javadoc'
    outputDirectory = javadoc.destinationDir
    inputs.dir 'src/main/kotlin'
}

task dokkaJavadocJar(type: Jar, dependsOn: dokkaJavadoc) {
    classifier = 'javadoc'
    from javadoc.destinationDir
}


publishing {
    repositories {
        maven {
            url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
            authentication {
                basic(BasicAuthentication)
            }
            credentials(PasswordCredentials) {
                // Artifactory credentials got from environment (set it in your GitLab CI/CD variables)
                username System.getenv("ARTIFACTORY_USERNAME")
                password System.getenv("ARTIFACTORY_PASSWORD")
            }
        }
    }
    publications {
        maven(MavenPublication) {
            from components.kotlin
            artifact(sourceJar)
            artifact(dokkaJavadocJar)
        }
    }
}

GitLab compatibility

ℹ️ This template is actually tested and validated on GitLab Community Edition instance version 13.12.11