How to enable maven artifact caching for GitLab CI runner?

We use GitLab CI with shared runners to do our continuous integration. For each build, the runner downloads tons of maven artifacts.

Is there a way to configure GitLab CI to cache those artifacts so we can speed up the building process by preventing downloading the same artifact over and over again?


Gitlab CI allows you to define certain paths, which contain data that should be cached between builds, on a per job or build basis (see here for more details). In combination with khmarbaise's recommendation, this can be used to cache dependencies between multiple builds.

An example that caches all job dependencies in your build:

cache:
  paths:
    - .m2/repository

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"

maven_job:
  script:
    - mvn clean install

According to the conversation over on GitLab's issue tracker, I managed to change the Maven local repository path and put it into ./.m2/repository/ directory, which is we will then persist between runs by adding this global block to the CI config:

cache:
  paths:
    - ./.m2/repository
  # keep cache across branch
  key: "$CI_BUILD_REF_NAME"

Unfortunately, according to this StackOverflow answer the maven local repository path can only be set on every run with -Dmaven.repo.local or by editing your settings.xml, which is a tedious task to do in a gitlab-ci configuration script. An option would be to set a variable with the default Maven options and pass it to every run.

Also, it is crucial that the local Maven repository is a child of the current directory. For some reason, putting it in /cache or /builds didn't work for me, even though someone from GitLab claimed it should.

Example of a working gitlab-ci.yml configuration file for Maven + Java:

image: maven:3-jdk-8

variables:
  MAVEN_OPTS: "-Djava.awt.headless=true -Dmaven.repo.local=./.m2/repository"
  MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version"

cache:
  paths:
    - ./.m2/repository
  # keep cache across branch
  key: "$CI_BUILD_REF_NAME"

stages:
  - build
  - test
  - deploy

build-job:
  stage: build
  script:
    - "mvn clean compile $MAVEN_CLI_OPTS"
  artifacts:
    paths:
      - target/

unittest-job:
  stage: test
  dependencies:
    - build-job
  script:
    - "mvn package $MAVEN_CLI_OPTS"
  artifacts:
    paths:
      - target/

integrationtest-job:
  stage: test
  dependencies:
    - build-job
  script:
    - "mvn verify $MAVEN_CLI_OPTS"
  artifacts:
    paths:
      - target/

deploy-job:
  stage: deploy
  artifacts:
    paths:
      - "target/*.jar"

The accepted answer didn't do it for me.

As zlobster mentioned, the guys at GitLab have this amazing repository where you can find a proper example of the .gitlab-ci.yml file used for Maven projects.

Basically, what you need are these lines:

cache:
  paths:
    - .m2/repository

Keep in mind that if you decide to a add a local cache for a certain job, the global one added above will be replaced. More on this here.


You can add cache folder to gitlab-ci runner configuration and pass it to maven.

/etc/gitlab-runner/config.toml

[[runners]]
...
  [runners.docker]
  ...
   volumes = ["/cache", "/.m2"]
  ...

.gitlab-ci.yml

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=/.m2"

build:
  script:
    - mvn package