Maven mirros and gitlab ci

30 Jul
2020

Over past couple of months I’ve been playing with gitlab ci as it brings a bit of refreshing breeze after years of struggle with Jenkins. Don’t get me wrong, I value what Jenkins did for us over past decade. I just think that maintenance of it is a bit of nightmare. Yet, I’ve reached a place where I had to adjust some more stuff for gitlab in order to get my builds straight.

Issues I’ve had are mainly related to customization of deploy phase and maven repositories. Today I’ve learned that recent version of Maven (it is 3.6.3 at the moment of writing) requires distinct mirror identifiers.
Somewhat I missed that. I always thought it was used just to lookup credentials for authorization. I was wrong or never before used multiple mirrors in one maven settings.

To let you understand my motivation, I will briefly describe a case. I was trying to get side build for openHAB project which would be under my control. In order to do such I have to take care about all openHAB dependencies which are distributed over different places. Some of them hold same contents as Maven central, while other do hold project specific releases of its dependencies – namely various OSGi wrappers, repackaging of dependencies necessary by some legacy Eclipse related modules and so on. If I would hid behind one big proxy I would never spot changes in dependency chains. Having multiple mirrors which are aimed to proxy individual repositories allows to control where new dependencies come from during the build time. Once it is cached it is extremely hard to find which build pulled it over.

This means that even if you have same proxy server instance using same credentials, you need to declare mirrors with different ID. Take a look on below example:

<?xml version="1.0" encoding="utf-8" ?>
<settings xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd"
  xmlns="http://maven.apache.org/SETTINGS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <servers>
    <server>
      <id>${env.MAVEN_SERVER_ID}</id>
      <username>${env.MAVEN_REPO_USER}</username>
      <password>${env.MAVEN_REPO_PASS}</password>
    </server>
  </servers>

  <mirrors>
    <mirror>
      <id>${env.MAVEN_SERVER_ID}</id>
      <mirrorOf>${env.CENTRAL_PROXY_MIRROR_OF}</mirrorOf>
      <url>${env.CENTRAL_PROXY_URL}</url>
    </mirror>
    <mirror>
      <id>${env.MAVEN_SERVER_ID}</id>
      <mirrorOf>${env.OPENHAB_PROXY_MIRROR_OF}</mirrorOf>
      <url>${env.OPENHAB_PROXY_URL}</url>
    </mirror>
  </mirrors>
</settings>

As you can see, there are two mirrors using same id. In effect Maven will use just one of them. You can inspect this with Maven help plugin:

MAVEN_SERVER_ID=proxy \
MAVEN_REPO_USER=test \
MAVEN_REPO_PASS=secret \
CENTRAL_PROXY_MIRROR_OF=central \
CENTRAL_PROXY_URL=http://proxy/central/ \
OPENHAB_PROXY_MIRROR_OF=openhab-mirror \
OPENHAB_PROXY_URL=http://proxy/openhab \
 mvn -s .gitlab/settings.xml help:effective-settings

The result, at least till this morning for me, is quite surprising. The openhab mirror is lost, see below output!

<?xml version="1.0" encoding="UTF-8"?>
<!-- ====================================================================== -->
<!--                                                                        -->
<!-- Generated by Maven Help Plugin on 2020-07-30T12:04:19+02:00            -->
<!-- See: http://maven.apache.org/plugins/maven-help-plugin/                -->
<!--                                                                        -->
<!-- ====================================================================== -->
<!-- ====================================================================== -->
<!--                                                                        -->
<!-- Effective Settings for 'splatch' on 'arch'                             -->
<!--                                                                        -->
<!-- ====================================================================== -->
<settings xmlns="http://maven.apache.org/SETTINGS/1.1.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="
    http://maven.apache.org/SETTINGS/1.1.0
    http://maven.apache.org/xsd/settings-1.1.0.xsd
  ">
  <localRepository>...</localRepository>
  <servers>
    <server>
      <id>proxy</id>
      <username>test</username>
      <password>secret</password>
    </server>
  </servers>

  <mirrors>
    <mirror>
      <mirrorOf>central</mirrorOf>
      <url>http://proxy/central</url>
      <id>proxy</id>
    </mirror>
  </mirrors>
  <!-- ommited -->
</settings>

In order to get whole thing working you need to declare distinct server identifiers:

<?xml version="1.0" encoding="utf-8" ?>
<settings xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd"
  xmlns="http://maven.apache.org/SETTINGS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <servers>
    <server>
      <id>${env.MAVEN_SERVER_ID}</id>
      <username>${env.MAVEN_REPO_USER}</username>
      <password>${env.MAVEN_REPO_PASS}</password>
    </server>
    <server>
      <id>${env.OPENHAB_PROXY_ID}</id>
      <username>${env.MAVEN_REPO_USER}</username>
      <password>${env.MAVEN_REPO_PASS}</password>
    </server>
    <server>
      <id>${env.CENTRAL_PROXY_ID}</id>
      <username>${env.MAVEN_REPO_USER}</username>
      <password>${env.MAVEN_REPO_PASS}</password>
    </server>
  </servers>

  <mirrors>
    <mirror>
      <id>${env.CENTRAL_PROXY_ID}</id>
      <mirrorOf>${env.CENTRAL_PROXY_MIRROR_OF}</mirrorOf>
      <url>${env.CENTRAL_PROXY_URL}</url>
    </mirror>
    <mirror>
      <id>${env.OPENHAB_PROXY_ID}</id>
      <mirrorOf>${env.OPENHAB_PROXY_MIRROR_OF}</mirrorOf>
      <url>${env.OPENHAB_PROXY_URL}</url>
    </mirror>
  </mirrors>
</settings>

Its not nicest, but it works. Also you can do an variant with suffixes added after ${env.MAVEN_SERVER_ID} . By this way you will limit number of environment variables which needs to be passed to build script.
Also keep in mind that Maven currently does not have support for “fallback” values you would expect. If environment variable is missing placeholder will be left intact. The ${env.var:-default} is not supported.

Comment Form

top