Дженкинс строит продукт, состоящий из многих проектов Maven? (с плагином Jenkins Pipeline?)

У нас есть продукт, который состоит из многих проектов Maven, которые зависят друг от друга. Все эти проекты Maven объединяются в один проект, который доставляет конечный продукт.

Проекты Maven имеют один и тот же жизненный цикл. Другими словами, они не управляются отдельными группами людей с явными изменениями <dependency> для поиска новых версий других проектов. Скорее, когда кто-то что-то изменяет в одном из проектов, результат должен перейти непосредственно в конечный продукт без дополнительных изменений.

Мы используем Jenkins в качестве инструмента непрерывной интеграции.

Основные пожелания, которые мы имеем, следующие:

  • Не нужно копировать все межпроектные зависимости в конфигурацию Jenkins: они должны находиться в одном месте, в идеале - в файлах pom.xml.
  • Избегайте ненужных сборок: при изменении SCM создавайте только потенциально затронутые проекты.
  • В случае зависимости от алмаза (C зависит как от B1, так и от B2, которые оба зависят от A), если нижний (A) изменяется, то конечный продукт (C) всегда должен использовать версию A, которая также была используется для сборки/тестирования B1 и B2.

Вопрос: Каков наилучший подход для этого с Дженкинсом?

В настоящее время мы думаем использовать одно задание, используя плагин Jenkins Pipeline, который анализирует зависимости Maven и изменения SCM, решает, что нужно построить и в каком порядке, а затем фактически создавать проекты.

Ответы

Ответ 1

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

Из вашего вопроса:

Не нужно копировать все межпроектные зависимости в конфигурацию Jenkins: они должны находиться в одном месте, в идеале - в файлах pom.xml.

Используя aggregator/multi-module pom, вы можете иметь единственную точку входа (файл pom.xml) для сборки maven, которая затем создайте все определенные модули:

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

То есть, файл pom.xml выглядит следующим образом:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sample</groupId>
    <artifactId>project</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <modules>
        <module>module-1</module>
        <module>module-2</module>
        <module>module-n</module>
    </modules>
</project>

Является минимальным примером: определите список модулей (другие проекты maven), которые будут созданы, начиная с этого проекта maven (пустой проект, целью которого является создание других проектов maven). Обратите внимание на pom упаковку, требуемую для модулей, сообщая maven, что этот проект предоставляет только pom (никаких дополнительных артефактов).

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


Кроме того, из вашего вопроса:

Избегайте ненужных сборок: при изменении SCM создавайте только потенциально затронутые проекты.

Чтобы выполнить это требование, вы можете использовать incremental-build-plugin:

Поскольку он ищет модификацию модулей уникального проекта, Maven Incremental Plugin воспринимает его только в проектах с несколькими модулями. Если обнаружено изменение в модуле, выходной каталог удаляется.

Этот плагин проверяет, будет ли какой-либо из pom файла, ресурсов, источников, источников тестов, тестовых ресурсов изменяться в модуле, и если случай удалит его выходной каталог. Таким образом, экономия времени сборки для соответствующего модуля и цепочки для всего мультимодульного проекта (в этом случае наша собственная сборка).

Чтобы включить этот механизм, вы можете настроить в вышеупомненном агрегаторе следующее:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sample</groupId>
    <artifactId>project</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>module-1</module>
        <module>module-2</module>
        <module>module-n</module>
    </modules>

    <properties>
        <skip.incremental>true</skip.incremental>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>net.java.maven-incremental-build</groupId>
                <artifactId>incremental-build-plugin</artifactId>
                <version>1.6</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>incremental-build</goal>
                        </goals>
                        <configuration>
                            <noIncrementalBuild>${skip.incremental}</noIncrementalBuild>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Выше мы просто добавили incremental-build-plugin в сборку агрегатора и свойство skip.incremental, которое пропустит выполнение плагина для первой сборки, пустой агрегатор, включив ее в модули следующим образом:

<project>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.sample</groupId>
        <artifactId>project</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>simple-module</artifactId>

    <properties>
        <skip.incremental>false</skip.incremental>
    </properties>
</project>

Примечание: в pom выше примерного модуля мы указываем на файл pom агрегатора как родительский, следовательно, используя наследование maven в комбинации с агрегацией (классическое использование) и, как таковая, с многомодульной сборкой плюс общее управление построением, предоставляемое общим родителем для всех объявленных модулей (в этом случае общее управление построением обеспечивает дополнительную конфигурацию incremental-build-plugin). Кроме того, каждый модуль перенастраивает свойство skip.incremental, чтобы не пропускать вышеупомянутый плагин. Это трюк: теперь плагин будет выполняться только в модулях, а не в его корне (что бы не имело смысла и в этом случае фактически выдавало бы ошибку в противном случае).

Очевидно, что в связанном задании Дженкинса в разделе "Управление исходным кодом" нам не нужно настраивать новую новую проверку как часть каждой сборки, иначе никакие изменения не будут обнаружены (и каждый раз, когда она начиналась с нуля, что является хорошей практикой для релизов на самом деле).

Кроме того, ваша команда maven не должна вызывать жизненный цикл clean, который также удаляет target в каждой сборке и, как таковой, также не может обнаруживать изменения.


Кроме того, из вашего вопроса:

В случае "алмазных зависимостей" (C зависит как от B1, так и от B2, которые оба зависят от A), если нижний (A) изменяется, то конечный продукт (C) всегда должен использовать версию A, которая был также использован для построения/тестирования B1 и B2.

Maven позаботится об этом требовании как часть многомодульной сборки и ее механизм :

Механизм в Maven, который обрабатывает многомодульные проекты, называется реактором. Эта часть ядра Maven делает следующее:

  • Собирает все доступные модули для сборки
  • Сортирует проекты в правильный порядок сборки
  • Создает выбранные проекты в порядке

По умолчанию реактор также создаст порядок сборки и всегда будет создавать модуль до своего зависимого/потребительского модуля. Это также означает, что последний построенный модуль фактически будет модулем, ответственным за создание финального артефакта, поставляемого продукта в зависимости от части или всех других модулей (например, модуль, ответственный за доставку файла war, вероятно, будет последний, чтобы построить в мультимодульном проекте webapp).


Дальнейшее родственное чтение относительно Maven и пропустить действия, когда что-то не изменилось:

  • maven-jar-plugin предоставляет forceCreation который по умолчанию уже включен

    Требовать, чтобы плагин jar создавал новый JAR, даже если ни одно из содержимого не изменилось. По умолчанию этот плагин смотрит, существует ли выходной банд, и входы не изменились. Если эти условия верны, плагин пропускает создание банки.

  • maven-compiler-plugin предоставляет useIncrementalCompilation, хотя не работает должным образом на данный момент.
  • maven-war-plugin предоставляет recompressZippedFiles который также может быть использован для ускорения сборки и предотвращения повторного выполнения чего-либо (чтобы переключиться на false в этом случае):

    Указывает, должны ли быть сжаты архивы zip (jar, zip и т.д.), добавленные к войне. Сжатие снова может привести к меньшему размеру архива, но значительно увеличивает время выполнения.
    По умолчанию: true


Обновить

Проекты Maven имеют один и тот же жизненный цикл.

Это требование также обеспечит использование проекта агрегатора/мультимодуля, но может также применяться к различным проектам, связанным через зависимости.

они не управляются отдельными группами людей с явными изменениями для поиска новых версий других проектов.

Этот момент также предусматривает использование многомодульного проекта. В многомодульном проекте у вас могут быть разные версии среди модулей, однако распространенная практика и рекомендация - использовать одну и ту же версию, определенную родительским проектом (агрегатором) и каскадированную через его модули. Таким образом, его централизация и управление позволят избежать несоосности и ошибок.

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

Опять же, это будет автоматически обрабатываться многомодульным проектом. То же самое произойдет с разными проектами, каждый из которых использует версии SNAPSHOT, тогда нет необходимости менять версию зависимостей в своем потребительском проекте (тот, кто отвечает за создание конечного продукта). Тем не менее, хотя версии SNAPSHOT действительно полезны (и рекомендуются) во время разработки, они, безусловно, не должны использоваться при доставке конечного продукта, поскольку воспроизводство сборки будет в опасности (то есть вы не сможете повторно построить ту же версию позже поскольку он полагался на версии SNAPSHOT, следовательно, не замороженные версии). Следовательно, SNAPSHOT не является решением для серебряных пулей и должен использоваться только на определенных этапах SDLC продукта, а не в качестве окончательного и замороженного решения.


Обновление 2
Стоит также взглянуть на новый Maven Incremental Module Builder для Maven 3.3.1 + и Java 7.

Подробнее о: