06 Aug 2014

Nexus: why you shouldn't use LATEST

In every team where I happened to work with Sonatype Nexus I’ve seen the same misunderstanding on what LATEST version of artifacts is. People didn’t always understand why they shouldn’t use it.

Every artifact has a meta file maven-metadata.xml, which looks something like this:

<?xml version="1.0" encoding="UTF-8"?>
<metadata>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-javadoc-plugin</artifactId>
  <versioning>
    <latest>2.9.1</latest>
    <release>2.9.1</release>
    <versions>
      <version>2.8.1</version>
      <version>2.9</version>
      <version>2.9.1</version>
    </versions>
    <lastUpdated>20130628064237</lastUpdated>
  </versioning>
</metadata>

Now let’s imagine you want to download the latest version of the artifact. Of course first links in google will lead you to the REST query: http://somerepo.org/service/local/artifact/maven/redirect?r=central-proxy&g=groupId&a=artifactId&v=LATEST And maybe, just maybe, it will work for some time. But later at some point Nexus will start returning old artifacts.

This is because when Nexus searches for LATEST first it checks whether maven-metadata.xml has <latest> and chooses it. If this tag is absent (which is usually true at first), then the last item in <versions> is used.

This mechanism meets your expectations for some time because at the beginning maven-metadata.xml doesn’t have <latest>. Versions are added to the end of the list as new artifacts get uploaded which means that the latest version is returned. But then one of these happens:

  • Someone/something puts <latest> to the meta file.

  • Developers work in branches and several teams independently upload artifacts with different versions. The last upload is the winner - one of artifacts will be listed in the end of <versions> and therefore it will be chosen as LATEST.

As it appears in Nexus LATEST works correctly only for plugins and this mechanism MUST NOT be used for casual artifacts.

Couple of Q/As:

Who updates maven-metadata.xml?

Albeit many think that Nexus is the one, it’s actually Maven Deploy Plugin who does the trick: it first fetches existing maven-medatadata.xml from remote repo, then it updates all the required information and uploads it back to the repo. If the file doesn’t exist in the first place, then it gets created and uploaded.

How come <latest> shows up if Maven doesn’t use it?

Maven doesn’t actually add this tag. Nexus has its utility mechanisms, one of them is Rebuild Metadata. This item can be found in the context menu of the repositories and folders. It removes existing maven-metadata.xml, then it iterates over the artifacts and creates a brand new meta file according to what it found. And this is when <latest> is added. What for? I wish I knew. I even noticed <latest> in cases no one (presumably) ran Rebuild Metadata, thus one may assume there are other events that trigger these updates. Note that during Rebuild the versions are sorted according to the internal algorithms of Maven, these algorithms are then used by Nexus:

The ordering is derived by parsing the version string and supports sematic versioning with additional semantics for specific classifiers. Further details can be found in the documentation for the implementing class GenericVersionScheme.

This means that what was LATEST before may not be latest anymore.

Why <latest> is not always up-to-date?

Even if you happened to start Rebuild Metadata, this is still a one-time action. Afterwards it’s Maven who updates meta files. And it won’t do anything with <latest> - Maven will simply copy it from the maven-metadata.xml originally obtained from Nexus.

Let’s sum up

If you need a mechanism to fetch the latest version of the artifact, you MUST implement it yourself (presumably you’ll write a script). Those out-of-box mechanisms Nexus provides will simply stop working at some point.

Also note, that if you think you need the latest versions, you’re probably moving in a wrong direction, I haven’t seen good workflows which require latests.

PS: the links on Sonatype Wiki are now broken, they probably moved their pages or removed them from public access. URLs will be updated when I find new locations.

Read more
13 Jan 2014

Nexus - почему не нужно использовать LATEST

Везде, где мне приходилось работать с Sonatype Nexus в какой-то момент возникало недопонимание о том что такое LATEST версия артефакта и почему ее нельзя использовать.

Любой артефакт обладает неким информационным файлом maven-metadata.xml, содержимое которого приблизительно такое:

<?xml version="1.0" encoding="UTF-8"?>
<metadata>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-javadoc-plugin</artifactId>
  <versioning>
    <latest>2.9.1</latest>
    <release>2.9.1</release>
    <versions>
      <version>2.8.1</version>
      <version>2.9</version>
      <version>2.9.1</version>
    </versions>
    <lastUpdated>20130628064237</lastUpdated>
  </versioning>
</metadata>

Итак, вы захотели получить последнюю версию артефакта. Вы быстро нагуглите как это можно сделать: http://somerepo.org/service/local/artifact/maven/redirect?r=central-proxy&g=groupId&a=artifactId&v=LATEST И первое время это возможно даже будет работать. Однако в какой-то момент Nexus начнет вам возвращать старые артефакты.

Это происходит из-за алгоритма, который использует Nexus для нахождения LATEST: сначала смотрит если в maven-metadata.xml есть <latest> и возвращает его. Если тега нет, то вернется последняя версия в списке <versions>.

Изначально механизм этот работает лишь потому, что в maven-metadata.xml просто нет <latest>. Версии отсортированы в порядке добавления, возвращается последняя. Но в какой-то момент происходит что-то из двух:

  • Кто-то таки проставляет <latest> в мета-файл.

  • Работа идет в ветках и две команды независимо друг от друга заливают артефакты с разными версиями. Кто залил последний - того и последняя версия. Просто-напросто в конец добавляется та версия, которая сейчас деплоится.

Как оказывается в Nexus LATEST работает правильно только для плагинов и использовать этот механизм для обычных артефактов нельзя.

Несколько ожидаемых вопросов:

Кто обновляет maven-metadata.xml?

Этот файл обновляется не Nexus’ом, а Maven Deploy Plugin’ом: сначала он забирает из репозитория существующий maven-medatadata.xml, затем обновляет информацию и заливает обратно в репозиторий. Если существующего файла нет, создается новый и заливается в Nexus.

Откуда берется <latest> если Maven его никак не использует?

Maven этот тег и не проставляет. У Nexus’a есть некие утилитарные механизмы, среди таких - Rebuild Metadata. Этот пункт можно найти в контекстном меню репозиториев и каталогов. Этот механизм удаляет существующую maven-metadata.xml, просматривает артефакты и создает новый файл. И в этот момент он создает <latest>. Для чего - хрен знает, но создает. Причем я замечал <latest> даже в том случае, когда Rebuild Metadata вроде как и не делался, поэтому есть подозрения что это происходит еще по каким-то событиям. Имейте в виду, что сортировка версий происходит исходя из механизмов зашитых в Maven, а эти механизмы уже используются Nexus’ом:

The ordering is derived by parsing the version string and supports sematic versioning with additional semantics for specific classifiers. Further details can be found in the documentation for the implementing class GenericVersionScheme.

Почему <latest> устаревает?

Даже если Rebuild Metadata и происходит, то это разовое действие. Дальше метадата-файл обновлять все равно будет Maven. А тот просто ничего не делает с <latest> - она копируется из того maven-metadata.xml, который был загружен из Nexus’a.

Подведем итоги

Если вам нужен механизм получения последней версии артефакта, этот механизм вы сами и должны будете создать (написать скрипт). Механизм, используемый Nexus’ом по умолчанию в какой-то момент просто перестанет работать.

К тому же если вы считаете вам нужна где-то последняя версия артефактов, скорей всего вы двигаетесь в неправильном направлении, мне не приходилось видеть хорошо поставленные процессы где была нужда в LATEST.

PS: ссылки на Sonatype Wiki сломались, они либо перенесли куда-то страницы, либо убрали их из открытого доступа. Я обновлю адреса как только найду новое расположение.

Read more