Skip to content

GitLab CI template for Maven

This project implements a generic GitLab CI template for Maven.

It provides several features, usable in different modes (by configuration).

Usage

In order to include this template in your project, add the following to your gitlab-ci.yml:

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

Global configuration

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

Name description default value
MAVEN_IMAGE The Docker image used to run Maven
⚠ī¸ set the version required by your project
maven:latest
MAVEN_CFG_DIR The Maven configuration directory .m2
MAVEN_OPTS Global Maven options -Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=${MAVEN_CFG_DIR}/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true
MAVEN_CLI_OPTS Additional Maven options used on the command line --batch-mode --errors --fail-at-end --show-version -DinstallAtEnd=true -DdeployAtEnd=true

About $MAVEN_CFG_DIR

This variable is used to define the Maven configuration directory. It is used for 2 purposes:

  • in case a Maven settings file (settings.xml) is found, the template automatically uses it (using the -s option on command line),
  • the cache policy declares the ${MAVEN_CFG_DIR}/repository directory as cached (not to download Maven dependencies over and over again).

If you have a good reason to do differently, you'll have to override the MAVEN_CLI_OPTS variable as well as the cache policy.

Jobs

mvn-build job

The Maven template features a job mvn-build that performs build and tests at once. This stage is performed in a single job for optimization purpose (it saves time) and also for test jobs dependency reasons (some test jobs such as SONAR analysis have a dependency on test results).

It uses the following variable:

Name description default value
MAVEN_BUILD_ARGS Maven arguments for the build & test job org.jacoco:jacoco-maven-plugin:prepare-agent verify org.jacoco:jacoco-maven-plugin:report

About Code Coverage

With its default arguments, the GitLab CI template for Maven forces the use of JaCoCo Maven Plugin to compute code coverage during unit tests execution.

In addition it makes the necessary to integrate code coverage stats into your GitLab project: report badge and viewable in merge requests.

If yo want to fix the JaCoCo plugin version or tweak the default configuration, you may have to configure the JaCoCo Maven Plugin in your pom.xml, but be aware of the following:

  • do not declare JaCoCo executions for prepare-agent and report goals otherwise then would be ran twice during unit tests (not necessarily with the expected configuration). If you really need to do so anyway, you'll have to override the $MAVEN_BUILD_ARGS variable to remove explicit invocation to JaCoCo goals.
  • make sure the report goal computes a CSV report, that is used by the Maven template to compute the global coverage stat.

More info:

SonarQube analysis job

This job is disabled by default and performs a SonarQube analysis of your code.

It is bound to the test stage, and uses the following variables:

Name description default value
SONAR_URL SonarQube server url none (disabled)
🔒 SONAR_AUTH_TOKEN SonarQube authentication token (depends on your authentication method) none
🔒 SONAR_LOGIN SonarQube login (depends on your authentication method) none
🔒 SONAR_PASSWORD SonarQube password (depends on your authentication method) none
SONAR_BASE_ARGS SonarQube analysis arguments sonar:sonar -Dsonar.host.url=${SONAR_URL} -Dsonar.links.homepage=${CI_PROJECT_URL} -Dsonar.links.ci=${CI_PROJECT_URL}/-/pipelines -Dsonar.links.issue=${CI_PROJECT_URL}/-/issues
🔒 SONAR_GITLAB_TOKEN GitLab access token with api scope. When set, activates the Sonar GitLab plugin integration. none
SONAR_BRANCH_ANALYSIS_DISABLED Set to true to disable automatic Pull Request Analysis and Branch Analysis none (enabled)
SONAR_GITLAB_ARGS Extra arguments to use with Sonar GitLab plugin -Dsonar.gitlab.url=${CI_SERVER_URL} -Dsonar.gitlab.user_token=${SONAR_GITLAB_TOKEN} -Dsonar.gitlab.project_id=${CI_PROJECT_ID} -Dsonar.gitlab.commit_sha=${CI_COMMIT_SHA} -Dsonar.gitlab.ref_name=${CI_COMMIT_REF_NAME}
SONAR_AUTO_ON_DEV_DISABLED When set to true, SonarQube analysis becomes manual on development branches (automatic otherwise) none
SONAR_QUALITY_GATE_ENABLED Set to true to enables check of SonarQube Quality Gate none (disabled)

Automatic Branch Analysis & Pull Request Analysis

By default, this template tries to auto-detect and use Pull Request Analysis or Branch Analysis (depending on the context).

Those is a great SonarQube features but it assumes one of the following conditions:

If you're not in one of those cases, then you shall disable this feature by setting SONAR_BRANCH_ANALYSIS_DISABLED.

If you leave the feature enabled, if SONAR_AUTH_TOKEN is provided, the template will try to autodetect (using GitLab APIs) an opened merge request matching the current branch:

About Sonar GitLab plugin

The Sonar GitLab plugin uses the GitLab APIs to inline comments into your commits directly in GitLab for each new anomaly.

As explained above, this template automatically enables the Sonar GitLab plugin if SONAR_GITLAB_TOKEN is set. It will then simply append the SONAR_GITLAB_ARGS (overridable) to the SonarQube analysis arguments.

Comments added to GitLab will appear as owned by the user associated to the GitLab access token.

mvn-dependency-check job

This job enables a manual Dependency-Check analysis.

It is bound to the test stage, and uses the following variables:

Name description default value
MAVEN_DEPENDENCY_CHECK_ARGS Maven arguments for Dependency Check job org.owasp:dependency-check-maven:check -DretireJsAnalyzerEnabled=false -DassemblyAnalyzerEnabled=false

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

However, if you want to enable an automatic Dependency-Check scan, you will have to override the rules keyword for the mvn-dependency-check job.

Furthermore, if you want to upload Dependency-Check reports to SonarQube, you have to:

  • Move mvn-dependency-check to the build stage
  • Add -Dformats=html,json,xml to MAVEN_DEPENDENCY_CHECK_ARGS to output reports
    • HTML report to read the report on SonarQube UI
    • JSON report to create SonarQube issues from the report
    • XML report to import into DefectDojo security dashboard
  • Add -Dsonar.dependencyCheck.htmlReportPath and -Dsonar.dependencyCheck.jsonReportPath with the paths of the generated html and json reports to SonarQube arguments.

More info:

mvn-forbid-snapshot-dependencies job

This job checks your project has release-only dependencies (no snapshot), using the Maven Enforcer plugin.

Failure is allowed in feature branches.

It is bound to the test stage, and uses the following variables:

Name description default value
MVN_FORBID_SNAPSHOT_DEPENDENCIES_DISABLED Set to true to disable this job none

mvn-snapshot & mvn-release jobs

Those jobs are disabled by default and perform respectively:

They are bound to the publish stage, and use the following variables:

Name description default value
MAVEN_DEPLOY_ENABLED Set to true to enable a publish jobs none (disabled)
MAVEN_DEPLOY_FROM_UNPROTECTED_DISABLED Set to true to limit snapshot publication to protected branches none (disabled)
MAVEN_DEPLOY_ARGS Maven arguments for the Snapshot job deploy -DskipTests
MAVEN_RELEASE_ARGS Maven arguments for the Release job release:prepare release:perform -DskipTests
MAVEN_RELEASE_SCM_COMMENT_PREFIX Maven release plugin scmCommentPrefix parameter [ci skip][maven-release-plugin]
MVN_SEMREL_RELEASE_DISABLED Set to true to disable semantic-release integration [ci skip][maven-release-plugin]

More info:

semantic-release integration

If you activate the semantic-release-info job from the semantic-release template, the mvn-release job will rely on the generated next version info.

  • the release will only be performed if a next semantic release is present
  • the version is passed to the maven release plugin as release version argument adding -DreleaseVersion=${SEMREL_INFO_NEXT_VERSION} to the MAVEN_RELEASE_ARGS value

⚠ī¸ Both maven release plugin and semantic-release use a dedicated tag format that need to be set accordingly. By default maven release plugin uses ${artifactId}-${version} and semantic-release uses s${version} For exemple you can modify the semantic-release tag format with the SEMREL_TAG_FORMAT variable (see semantic-release template variables).

variables:
  SEMREL_TAG_FORMAT: "myArtifactId-$${version}"

Or you can override the maven release plugin tag format.

Note: You can disable the semantic-release job (as it's the mvn-release job that will perform the release and so we only need the semantic-release-info job) with the SEMREL_RELEASE_DISABLED variable.

variables:
  SEMREL_RELEASE_DISABLED: "true"

Finally, the semantic-release integration can be disable with the MVN_SEMREL_RELEASE_DISABLED variable.

Maven repository authentication

Your Maven repository may require authentication credentials to publish artifacts.

You shall handle them in the following way:

  1. define all required credentials as 🔒 project variables,
  2. make sure your pom.xml (or ancestor) declares your <repository> and <snapshotRepository> with server ids in a <distributionManagement> section,
  3. in your ${MAVEN_CFG_DIR}/settings.xml file, define the repository servers credentials in the <servers> section using the ${env.VARIABLE} pattern (will be automatically evaluated and replaced by Maven).

Example 1 (using the GitLab Maven Repository):

pom.xml:

<!-- ... -->
<distributionManagement>
  <snapshotRepository>
      <id>gitlab-maven</id>
      <url>${env.CI_API_V4_URL}/projects/${env.CI_PROJECT_ID}/packages/maven</url>
  </snapshotRepository>
  <repository>
      <id>gitlab-maven</id>
      <url>${env.CI_API_V4_URL}/projects/${env.CI_PROJECT_ID}/packages/maven</url>
  </repository>
</distributionManagement>
<!-- ... -->

${MAVEN_CFG_DIR}/settings.xml:

<settings>
  <servers>
    <!-- required when using GitLab's package registry to deploy -->
    <!-- see: https://docs.gitlab.com/ee/user/packages/maven_repository/index.html#use-the-gitlab-endpoint-for-maven-packages -->
    <server>
        <id>gitlab-maven</id>
        <configuration>
            <httpHeaders>
                <property>
                    <name>Job-Token</name>
                    <value>${env.CI_JOB_TOKEN}</value>
                </property>
            </httpHeaders>
        </configuration>
    </server>
  </servers>
</settings>

Example 2 (using an Artifactory repository with same credentials for snapshot & release):

pom.xml:

<!--... -->
<distributionManagement>
  <snapshotRepository>
    <id>artifactory</id>
    <url>https://artifactory.acme.host/artifactory/maven-snapshot-repo</url>
  </snapshotRepository>
  <repository>
    <id>artifactory</id>
    <url>https://artifactory.acme.host/artifactory/maven-release-repo</url>
  </repository>
</distributionManagement>
<!--...-->

${MAVEN_CFG_DIR}/settings.xml:

<settings>
  <servers>
    <server>
      <id>artifactory</id>
      <username>${env.ARTIFACTORY_USER}</username>
      <password>${env.ARTIFACTORY_PASSWORD}</password>
    </server>
  </servers>
  <mirrors>
    <mirror>
      <id>artifactory.mirror</id>
      <mirrorOf>central</mirrorOf>
      <name>Artifactory Maven 2 central repository mirror</name>
      <url>https://artifactory.acme.host/artifactory/maven-virtual-repo/</url>
    </mirror>
  </mirrors>
</settings>

SCM authentication

A Maven release involves some Git push operations.

You can either use a ssh key or an authenticated and authorized Git user.

Using a SSH key

We recommend you to use a project deploy key with write access to your project.

The key should not have a passphrase (see how to generate a new SSH key pair).

Specify 🔒 $GIT_PRIVATE_KEY as protected project variable with the private part of the deploy key.

-----BEGIN OPENSSH PRIVATE KEY-----
blablabla
-----END OPENSSH PRIVATE KEY-----

The template handle both classic variable and file variable.

⚠ī¸ The scm connections in your pom.xml should use the ssh protocol

  <scm>
    <connection>scm:git:git@gitlab-host/path/to/my/project.git</connection>
    <developerConnection>scm:git:git@gitlab-host/path/to/my/project.git</developerConnection>
    ...
  </scm>
Using Git user authentication

Simply specify 🔒 $GIT_USERNAME and 🔒 $GIT_PASSWORD as protected project variables : they will be dynamically evaluated and appended to the Maven release arguments.

Note that the password should be an access token with read_repository and write_repository scopes.

⚠ī¸ The scm connections in your pom.xml should use the https protocol

  <scm>
    <connection>scm:git:https://gitlab-host/path/to/my/project.git</connection>
    <developerConnection>scm:git:https://gitlab-host/path/to/my/project.git</developerConnection>
    ...
  </scm>

GitLab compatibility

ℹī¸ This template is actually tested and validated on GitLab Community Edition instance version 13.12.11