Newer
Older
# GitLab CI template for Maven
This project implements a generic GitLab CI template for [Maven](https://maven.apache.org/).
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`:
```yaml
include:
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 <br/>:warning: **set the version required by your project** | `maven:latest` |
| `MAVEN_PROJECT_DIR` | Maven projet root directory | `.` |
| `MAVEN_CFG_DIR` | The Maven configuration directory | `.m2` |
| `MAVEN_OPTS` | [Global Maven options](http://maven.apache.org/configure.html#maven_opts-environment-variable) | `-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](https://maven.apache.org/ref/3-LATEST/maven-embedder/cli.html) used on the command line | `--batch-mode --errors --fail-at-end --show-version -DinstallAtEnd=true -DdeployAtEnd=true` |
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).
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
If you have a good reason to do differently, you'll have to override the `MAVEN_CLI_OPTS` variable as well as the [`cache`](https://docs.gitlab.com/ee/ci/yaml/README.html#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](https://www.eclemma.org/jacoco/trunk/doc/maven.html)
to compute code coverage during unit tests execution.
In addition it [makes the necessary](https://docs.gitlab.com/ee/user/project/pipelines/settings.html#test-coverage-parsing)
to integrate code coverage stats into your GitLab project: [report badge](https://docs.gitlab.com/ee/user/project/pipelines/settings.html#test-coverage-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](https://www.eclemma.org/jacoco/trunk/doc/maven.html) 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:
* [Maven Surefire Plugin](https://maven.apache.org/surefire/maven-surefire-plugin)
* [`surefire:test` parameters](https://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html)
### 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) |
| :lock: `SONAR_AUTH_TOKEN`| SonarQube authentication [token](https://docs.sonarqube.org/latest/user-guide/user-token/) (depends on your authentication method) | _none_ |
| :lock: `SONAR_LOGIN` | SonarQube login (depends on your authentication method) | _none_ |
| :lock: `SONAR_PASSWORD` | SonarQube password (depends on your authentication method) | _none_ |
| `SONAR_BASE_ARGS` | SonarQube [analysis arguments](https://docs.sonarqube.org/latest/analysis/analysis-parameters/) | `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` |
| :lock: `SONAR_GITLAB_TOKEN` | GitLab [access token](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html) with `api` scope. When set, activates the [Sonar GitLab plugin](https://github.com/gabrie-allaigre/sonar-gitlab-plugin/#plugins-properties) integration. | _none_ |
| `SONAR_BRANCH_ANALYSIS_DISABLED` | Set to `true` to disable automatic [Pull Request Analysis](https://docs.sonarqube.org/latest/analysis/pull-request/) and [Branch Analysis](https://docs.sonarqube.org/latest/branches/overview/) | _none_ (enabled) |
| `SONAR_GITLAB_ARGS` | Extra arguments to use with [Sonar GitLab plugin](https://github.com/gabrie-allaigre/sonar-gitlab-plugin/#plugins-properties) | `-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](https://docs.sonarqube.org/latest/user-guide/quality-gates/) | _none_ (disabled) |
#### Automatic Branch Analysis & Pull Request Analysis
By default, this template tries to auto-detect and use [Pull Request Analysis](https://docs.sonarqube.org/latest/analysis/pull-request/) or [Branch Analysis](https://docs.sonarqube.org/latest/branches/overview/) (depending on the context).
Those is a great SonarQube features but it assumes one of the following conditions:
* you are using a [Developer Edition](https://www.sonarqube.org/developer-edition/) version,
* or you are using Community Edition with an opensource plugin emulating those features, such as [sonarqube-community-branch-plugin](https://github.com/mc1arke/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](https://docs.sonarqube.org/latest/analysis/pull-request/) will be made.
* Otherwise, a simple [Branch Analysis](https://docs.sonarqube.org/latest/branches/overview/) is performed on the current branch.
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#### About Sonar GitLab plugin
The [Sonar GitLab plugin](https://github.com/gabrie-allaigre/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](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html).
### `mvn-dependency-check` job
This job enables a manual [Dependency-Check](https://jeremylong.github.io/DependencyCheck/dependency-check-maven/configuration.html)
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:
* [Maven Dependency-Check Plugin](https://jeremylong.github.io/DependencyCheck/dependency-check-maven/configuration.html)
### `mvn-forbid-snapshot-dependencies` job
This job checks your project has release-only dependencies (no _snapshot_), using the [Maven Enforcer](https://maven.apache.org/enforcer/enforcer-rules/requireReleaseDeps.html) 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](https://maven.apache.org/plugins/maven-deploy-plugin/) of your Java packages (jar, war or else),
* a [Maven release](http://maven.apache.org/maven-release/maven-release-plugin/index.html) 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) |
Girija Saint Ange
committed
| `MAVEN_DEPLOY_ARGS` | Maven arguments for the Snapshot job | `deploy -Dmaven.test.skip=true` |
| `MAVEN_RELEASE_ARGS` | Maven arguments for the Release job | `release:prepare release:perform -Darguments=-Dmaven.test.skip=true` |
| `MAVEN_RELEASE_SCM_COMMENT_PREFIX` | Maven release plugin [scmCommentPrefix](https://maven.apache.org/maven-release/maven-release-plugin/prepare-mojo.html#scmCommentPrefix) parameter | `[ci skip][maven-release-plugin]` |
| `MVN_SEMREL_RELEASE_DISABLED` | Set to `true` to disable [semantic-release integration](#semantic-release-integration) | _none_ (disabled) |
More info:
* [Maven Deploy Plugin](https://maven.apache.org/plugins/maven-deploy-plugin/)
* [Maven Release Plugin](http://maven.apache.org/maven-release/maven-release-plugin/index.html)
#### `semantic-release` integration
If you activate the [`semantic-release-info` job from the `semantic-release` template](https://gitlab.com/to-be-continuous/semantic-release/#semantic-release-info-job), 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
:warning: 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](https://gitlab.com/to-be-continuous/semantic-release/#variables)).
```yml
variables:
SEMREL_TAG_FORMAT: "myArtifactId-$${version}"
```
Or you can [override the maven release plugin tag format](http://maven.apache.org/maven-release/maven-release-plugin/examples/prepare-release.html#Overriding_the_default_tag_name_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.
```yml
variables:
SEMREL_RELEASE_DISABLED: "true"
```
Finally, the semantic-release integration can be disabled with the `MVN_SEMREL_RELEASE_DISABLED` variable.
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
#### 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 :lock: [project variables](https://docs.gitlab.com/ee/ci/variables/#create-a-custom-variable-in-the-ui),
2. make sure your `pom.xml` (or ancestor) [declares your `<repository>` and `<snapshotRepository>` with server **id**s in a `<distributionManagement>` section](https://maven.apache.org/pom.html#repository),
3. in your `${MAVEN_CFG_DIR}/settings.xml` file, [define the repository servers credentials in the `<servers>` section](https://maven.apache.org/settings.html#Servers)
using the `${env.VARIABLE}` pattern (will be automatically evaluated and replaced by Maven).
**Example 1** (using the [GitLab Maven Repository](https://docs.gitlab.com/ee/user/packages/maven_repository/)):
`pom.xml`:
```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`:
```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 -->
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
<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`:
```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`:
```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](https://docs.gitlab.com/ee/user/project/deploy_keys/#project-deploy-keys) with write access to your project.
The key should not have a passphrase (see [how to generate a new SSH key pair](https://docs.gitlab.com/ce/ssh/README.html#generating-a-new-ssh-key-pair)).
Specify :lock: `$GIT_PRIVATE_KEY` as protected project variable with the private part of the deploy key.
```PEM
-----BEGIN OPENSSH PRIVATE KEY-----
blablabla
-----END OPENSSH PRIVATE KEY-----
```
The template handle both classic variable and file variable.
:warning: The scm connections in your pom.xml should use the ssh protocol
```xml
<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 :lock: `$GIT_USERNAME` and :lock: `$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.
:warning: The scm connections in your pom.xml should use the https protocol
```xml
<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>
```