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.0.0'
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 | 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 -s ${MAVEN_CFG_DIR}/settings.xml |
As you can see, your local Maven settings file is supposed to be located in ${MAVEN_CFG_DIR}/settings.xml
.
The cache policy also 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
andreport
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:
- you are using a Developer Edition version,
- or you are using Community Edition with an opensource plugin emulating those features, such as sonarqube-community-branch-plugin.
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:
- If one is found, a SonarQube Pull Request Analysis will be made.
- Otherwise, a simple Branch Analysis is performed on 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 thebuild
stage - Add
-Dformats=html,json,xml
toMAVEN_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:
- a Maven deploy of your Java packages (jar, war or else),
- a Maven release of your current branch.
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 theMAVEN_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:
- define all required credentials as 🔒 project variables,
- make sure your
pom.xml
(or ancestor) declares your<repository>
and<snapshotRepository>
with server ids in a<distributionManagement>
section, - 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>