Опыт использования flatten-maven-plugin для упрощения версионирования в maven-проектах

О нас


В 1С мы разрабатываем не только платформу 1С: Предприятие на С++ и JavaScript, но и приложения на Java — в частности новую среду разработки Enterprise Development Tools на базе Eclipse и сервер глубоко интегрированного с платформой мессенджера — Системы Взаимодействия.

Вступление


В качестве системы сборки Java-приложений чаще всего мы используем maven, и в этой небольшой статье хотели бы рассказать об одной из проблем, с которой пришлось столкнуться в процессе организации разработки, и о подходе, позволившем эту проблему преодолеть.

Предпосылки и рабочий процесс


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

image

Казалось бы: ничего страшного, один раз создали и забыли. Если надо что-то поменять или добавить во всех файлах сразу, существует масса удобных инструментов в редакторах и IDE. А какое самое распространённое регулярное изменение pom.xml? Полагаем, что изменение версий проекта и зависимостей. Возможно, кто-то захочет с этим поспорить, но у нас дело обстоит именно так. Причина кроется в том, что наряду с ядром мы параллельно разрабатываем много собственных библиотек, и для постоянной воспроизводимости результатов сборки и тестирования использование снэпшотов не представляется нам удобным подходом. По этой причине и приходится поднимать номер версии в проектах при каждой сборке.

Также у разработчика время от времени возникает необходимость собрать свою ветку какой-либо библиотеки и проверить ее работоспособность по всем зависимостям, для чего в них всех приходится вручную менять версию.

Первоначальное решение


С такими частыми и множественными изменениями версий процесс в рамках CI хочется упростить и автоматизировать. Тут на помощь приходит удобный общеизвестный плагин versions-maven-plugin — подключаем его и запускаем

mvn -N versions: set -DnewVersion=2.0.1

и мавен все как надо сделает: пробежит по иерархии сверху донизу, все версии подменит — красота! Теперь осталось поднять pull-request, коллеги изменения отсмотрят, и можно быстренько вливаться в trunk. Быстренько? Как бы не так. Пара-тройка сотен pom.xml на ревью, и это не считая кода. Вдобавок и от merge-конфликтов никто не застрахован при таком большом числе изменённых файлов. Здесь надо заметить, что в процессе CI изменения версий происходят автоматически вместе с изменением функциональности, а не как-то отдельно.

Новые возможности


На некоторое время мы успокоились и, смирившись, так и жили, пока парни из Maven Apache Project не включили в maven, начиная с версии 3.5.0-beta-1, поддержку так называемых «заменителей» версий (placeholders). Суть этих заменителей в том, что в pom.xml вместо конкретного указания версии проекта используются переменные ${revision}, ${sha1} и ${changelist}. Сами значения этих свойств задаются либо в элементе properties>, либо их можно определить через системное свойство

mvn -Drevision=2.0.0 clean package

Значения системных свойств имеют преимущество перед значениями, определёнными в <properties>.

Родитель

  4.0.0
  
    org.apache
    apache
    18
  

  org.apache.maven.ci
  ci-parent
  First CI Friendly
  ${revision}${sha1}${changelist}
  …
  
    1.3.1
    -SNAPSHOT
    
  



Потомок

  4.0.0
  
    org.apache.maven.ci
    ci-parent
    ${revision}${sha1}${changelist}
  

  org.apache.maven.ci
  ci-child
   …

Если хочется собрать версию 2.0.0-SNAPSHOT, то просто используем

    mvn -Drevision=2.0.0 clean package

Если хочется сделать релиз, то просто обнуляем SNAPSHOT

    mvn -Dchangelist= clean package

*Примеры выше взяты из статьи на сайте Maven Apache Project

Суровая реальность


Всё хорошо и здорово, пора испытать чувство удовлетворения, но нет. Оказывается, что для install и deploy этот способ не подойдет, поскольку в описаниях публикующихся в репозиторий артефактов не будет подменяться ${revision} на её значение и maven дальше не поймет о чём вообще речь.


    org.apache
    apache
    ${revision}

Свет в конце тоннеля


Надо искать решение проблемы. Ситуацию мог бы спасти flatten-maven-plugin. Этот плагин разрешает все переменные в pom, но заодно вырезает массу другой информации, которая нужна только при сборке и не нужна при импорте опубликованных артефактов в другие проекты. Также плагин «выпрямляет» все parent-child зависимости, и в итоге получаются плоские pom, включающие в себя всё, что нужно. Неудобство заключалось в том, что вырезает «лишнего» он слишком много, что нас совсем не устраивало. После изучения информации по разработке этого плагина, выяснилось, что мы не одни такие во вселенной, и ещё в августе 2018 на гитхабе в репозитории плагина был создан pull-request с пожеланием сделать возможность определять самостоятельно как нужно «портить» pom.xml. Разработчики прислушались к голосам страждущих, и уже в декабре с выходом новой версии 1.1.0 во flatten-maven-plugin появился новый режим resolveCiFriendliesOnly, который как никогда пришёлся впору — он оставляет pom.xml как есть, кроме элемента и разрешает ${revision}, ${sha1} и ${changelist}.

Добавляем плагин в проект


  
    org.codehaus.mojo
    flatten-maven-plugin
    1.1.0
    
      true
      resolveCiFriendliesOnly
    

    
      
        flatten
        process-resources
        
          flatten
        

      

      
        flatten.clean
        clean
        
          clean
        

      

    

  


Готово!

Happy end


Отныне нам, чтобы изменить версию всего проекта и дать знать об этом всем зависимостям, надо всего-то отредактировать элемент revision> в одном лишь корневом pom.xml. На ревью прилетает не сотня-другая этих файлов с одинаковым изменением, а один. Ну и отпадает необходимость в использовании versions-maven-plugin.

© Habrahabr.ru