Опыт использования 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>.

    Родитель
    <project>
      <modelVersion>4.0.0</modelVersion>
      <parent>
        <groupId>org.apache</groupId>
        <artifactId>apache</artifactId>
        <version>18</version>
      </parent>
      <groupId>org.apache.maven.ci</groupId>
      <artifactId>ci-parent</artifactId>
      <name>First CI Friendly</name>
      <version>${revision}${sha1}${changelist}</version>
      …
      <properties>
        <revision>1.3.1</revision>
        <changelist>-SNAPSHOT</changelist>
        <sha1/>
      </properties>
    </project>

    Потомок
    <project>
      <modelVersion>4.0.0</modelVersion>
      <parent>
        <groupId>org.apache.maven.ci</groupId>
        <artifactId>ci-parent</artifactId>
        <version>${revision}${sha1}${changelist}</version>
      </parent>
      <groupId>org.apache.maven.ci</groupId>
      <artifactId>ci-child</artifactId>
       …
    </project>


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

        mvn -Drevision=2.0.0 clean package

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

        mvn -Dchangelist= clean package

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

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


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

    <parent>
        <groupId>org.apache</groupId>
        <artifactId>apache</artifactId>
        <version>${revision}</version>
    </parent>


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


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

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

    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>flatten-maven-plugin</artifactId>
        <version>1.1.0</version>
        <configuration>
          <updatePomFile>true</updatePomFile>
          <flattenMode>resolveCiFriendliesOnly</flattenMode>
        </configuration>
        <executions>
          <execution>
            <id>flatten</id>
            <phase>process-resources</phase>
            <goals>
              <goal>flatten</goal>
            </goals>
          </execution>
          <execution>
            <id>flatten.clean</id>
            <phase>clean</phase>
            <goals>
              <goal>clean</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>


    Готово!

    Happy end


    Отныне нам, чтобы изменить версию всего проекта и дать знать об этом всем зависимостям, надо всего-то отредактировать элемент <revision> в одном лишь корневом pom.xml. На ревью прилетает не сотня-другая этих файлов с одинаковым изменением, а один. Ну и отпадает необходимость в использовании versions-maven-plugin.
    • +10
    • 3,2k
    • 4
    76,15
    Делаем средства разработки бизнес-приложений
    Поделиться публикацией

    Комментарии 4

      +3
      flatten-maven-plugin вообще хорошая вещь. Если задуматься, то иерархия помов нужна только для разработки. После релиза компоненты она только усложняет жизнь. Сколько раз я видел, как после добавления зависимости или нового плагина билд падал с криком, что он не может найти парента (или парента парента) этой зависимости. Так вот flatten-maven-plugin решает эту (и кучу сопутствующих проблем при развлетлённой структуре) просто и элегантно — после релиза вся информация о компоненте не размазана по дереву, а собрана в pom.xml этой самой компоненты.

      В частности, это позволяет НЕ делать релиз парентов (речь идёт о глобальных парентах) при релизе самой компоненты. Например, корневой pom.xml в моих проектах уже лет 5 как 29-SNAPSHOT, при том что релиз компонент делается каждую ночь при наличии изменений.

      В общем, всем советую :)
        0

        Подскажите, а как насчет IDE??? Такое решение все известные поддерживают???

          0
          Эклипс его просто игнорирует. Этот плагин важен для релиза, возможно для install.
            0
            Idea 2019 и Ecipse нормально работают

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое