Всем привет!
На данный момент для сборки Java/Kotlin проектов используются два основных инструмента: Maven и Gradle. Можно вспомнить Ant, сказать: «Покойся с миром» - и забыть) Их можно сравнивать по разным параметрам, но сегодня я хочу остановиться на инкрементальной сборке. Может возникнуть вопрос - что тут сравнивать, в Maven ее нет, в Gradle - есть. Но не все так очевидно) На самом деле в maven-compile-plugin такая опция заявлена https://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html и даже включена по умолчанию. Но фактически не работает( Почему?
Для начала стоит разделить понятия сборки в целом и компиляции как одну из частей сборки. В Maven жизненный цикл сборки - это линейная последовательность фаз сборки, запуск каждой из которых не зависит от результата предыдущих фаз. В Gradle цикл - граф из task, а у каждой таски есть inputs и outputs, являющиеся файлами на диске. Т.к результат сборки в конечном итоге - файлы. Выходы одной таски являются входами другой. Если входы не изменились - таска пропускается. Причём проверка идёт по контрольной сумме, не по дате изменения. Т.об. если не менялся боевой код и код его теста, то тест не будет запущен повторно. В Maven этого нет в принципе.
По-разному работает и собственно компиляция. Если maven видит изменения в любом классе модуля или в модуле, от которого зависит текущий - идёт полная перекомпиляция модуля. И далее по цепочке( Gradle же во-первых умеет отслеживать зависимости по классам, а во-вторых проверять изменился ли интерфейс, application binary interface, ABI если быть точным, или только реализация, и в зависимости от этого перекомпилировать только нужные файлы. Кроме того в Gradle с появлением Java Library plugin появилась возможность разделять compile зависимости на api и implementation. Любые изменения в implementation зависимости не приводят к повторной компиляции использующих ее модулей.
Вывод: ребята из Gradle сильно заморочились скоростью сборки. Результаты можно увидеть тут: https://blog.gradle.org/incremental-compiler-avoidance. А ведь ещё есть Gradle Cache, от котором расскажу отдельно.
P.S. для Maven есть сторонний плагин, заменяющий 5 стандартных и предоставляющий настоящую инкрементальную сборку http://takari.io/book/40-lifecycle.html Честно скажу, не тестировал, смущает, что решение внешнее #buildtool #java #ci
На данный момент для сборки Java/Kotlin проектов используются два основных инструмента: Maven и Gradle. Можно вспомнить Ant, сказать: «Покойся с миром» - и забыть) Их можно сравнивать по разным параметрам, но сегодня я хочу остановиться на инкрементальной сборке. Может возникнуть вопрос - что тут сравнивать, в Maven ее нет, в Gradle - есть. Но не все так очевидно) На самом деле в maven-compile-plugin такая опция заявлена https://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html и даже включена по умолчанию. Но фактически не работает( Почему?
Для начала стоит разделить понятия сборки в целом и компиляции как одну из частей сборки. В Maven жизненный цикл сборки - это линейная последовательность фаз сборки, запуск каждой из которых не зависит от результата предыдущих фаз. В Gradle цикл - граф из task, а у каждой таски есть inputs и outputs, являющиеся файлами на диске. Т.к результат сборки в конечном итоге - файлы. Выходы одной таски являются входами другой. Если входы не изменились - таска пропускается. Причём проверка идёт по контрольной сумме, не по дате изменения. Т.об. если не менялся боевой код и код его теста, то тест не будет запущен повторно. В Maven этого нет в принципе.
По-разному работает и собственно компиляция. Если maven видит изменения в любом классе модуля или в модуле, от которого зависит текущий - идёт полная перекомпиляция модуля. И далее по цепочке( Gradle же во-первых умеет отслеживать зависимости по классам, а во-вторых проверять изменился ли интерфейс, application binary interface, ABI если быть точным, или только реализация, и в зависимости от этого перекомпилировать только нужные файлы. Кроме того в Gradle с появлением Java Library plugin появилась возможность разделять compile зависимости на api и implementation. Любые изменения в implementation зависимости не приводят к повторной компиляции использующих ее модулей.
Вывод: ребята из Gradle сильно заморочились скоростью сборки. Результаты можно увидеть тут: https://blog.gradle.org/incremental-compiler-avoidance. А ведь ещё есть Gradle Cache, от котором расскажу отдельно.
P.S. для Maven есть сторонний плагин, заменяющий 5 стандартных и предоставляющий настоящую инкрементальную сборку http://takari.io/book/40-lifecycle.html Честно скажу, не тестировал, смущает, что решение внешнее #buildtool #java #ci
Всем привет!
Хочу рассказать собрать в одном посте несколько мало и среднеизвестных фичей Maven.
Поехали!
Для начала немного теории. Жизненный цикл сборки = фиксированная последовательность фаз сборки. К фазе сборки можно подключить плагин(ы), а точнее goal плагина. goal плагина - это некое действие, которое реализовано в плагине. Например у плагина compile есть goal compile. БольшАя часть goal стандартных плагинов уже подключена к нужным фазам сборки, но есть возможность переконфигурации в pom файле. https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
Общего механизма исключения той или иной фазы нет, исключение должен реализовать конкретный плагин.
1) Пропуск тестов и их компиляции: mvn install -Dmaven.test.skip=true. В отличие от mvn install -DskipTests также пропускает компиляцию тестов. Может быть полезно, если тесты вдруг сломались, и надо быстро сделать сборку. https://maven.apache.org/surefire/maven-surefire-plugin/examples/skipping-tests.html На всякий случай уточню - сломавшиеся тесты нужно чинить, откладывать исправление в долгий ящик - не нужно!)
2) Пропуск компиляции. Придумать случай, когда это может быть полезно, сложно. Если нужно выполнить какой-то один шаг сборки, без компиляции, то для этого есть более простой вариант, см. ниже. Но знать о возможности будет полезно: mvn package -Dmaven.main.skip
https://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html#skipMain
3) Запуск отдельной goal. Наряду с запуском цикла сборки можно запустить отдельную фазу. Например: mvn clean package sonar:sonar вначале выполняет два цикла сборки clean и package, а потом одну goal - sonar:sonar. В качестве альтернативы goal можно привязать к конкретной фазы. Кстати, порядок выполнения совпадает с порядком в коммандной строке.
https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html
4) Запуск падающего теста несколько раз, полезно в момент отладки, если тест "мигающий": mvn -Dsurefire.rerunFailingTestsCount=2 test
https://maven.apache.org/surefire/maven-surefire-plugin/examples/rerun-failing-tests.html
5) Среди стандартных плагинов Maven есть с виду неприметный help плагин. https://maven.apache.org/plugins/maven-help-plugin/
Среди его goal есть такие: mvn help:system - выдает информацию о системе: версию и производителя JDK, локаль, таймзоны, переменные среды.
mvn help:all-profiles - список активных профилей проекта.
На сегодня все. To be continued... #buildtool
Хочу рассказать собрать в одном посте несколько мало и среднеизвестных фичей Maven.
Поехали!
Для начала немного теории. Жизненный цикл сборки = фиксированная последовательность фаз сборки. К фазе сборки можно подключить плагин(ы), а точнее goal плагина. goal плагина - это некое действие, которое реализовано в плагине. Например у плагина compile есть goal compile. БольшАя часть goal стандартных плагинов уже подключена к нужным фазам сборки, но есть возможность переконфигурации в pom файле. https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
Общего механизма исключения той или иной фазы нет, исключение должен реализовать конкретный плагин.
1) Пропуск тестов и их компиляции: mvn install -Dmaven.test.skip=true. В отличие от mvn install -DskipTests также пропускает компиляцию тестов. Может быть полезно, если тесты вдруг сломались, и надо быстро сделать сборку. https://maven.apache.org/surefire/maven-surefire-plugin/examples/skipping-tests.html На всякий случай уточню - сломавшиеся тесты нужно чинить, откладывать исправление в долгий ящик - не нужно!)
2) Пропуск компиляции. Придумать случай, когда это может быть полезно, сложно. Если нужно выполнить какой-то один шаг сборки, без компиляции, то для этого есть более простой вариант, см. ниже. Но знать о возможности будет полезно: mvn package -Dmaven.main.skip
https://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html#skipMain
3) Запуск отдельной goal. Наряду с запуском цикла сборки можно запустить отдельную фазу. Например: mvn clean package sonar:sonar вначале выполняет два цикла сборки clean и package, а потом одну goal - sonar:sonar. В качестве альтернативы goal можно привязать к конкретной фазы. Кстати, порядок выполнения совпадает с порядком в коммандной строке.
https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html
4) Запуск падающего теста несколько раз, полезно в момент отладки, если тест "мигающий": mvn -Dsurefire.rerunFailingTestsCount=2 test
https://maven.apache.org/surefire/maven-surefire-plugin/examples/rerun-failing-tests.html
5) Среди стандартных плагинов Maven есть с виду неприметный help плагин. https://maven.apache.org/plugins/maven-help-plugin/
Среди его goal есть такие: mvn help:system - выдает информацию о системе: версию и производителя JDK, локаль, таймзоны, переменные среды.
mvn help:all-profiles - список активных профилей проекта.
На сегодня все. To be continued... #buildtool
maven.apache.org
Introduction to the Build Lifecycle – Maven
Всем привет!
Про фишки Maven, часть вторая.
Поехали.
1) У maven, также как у Gradle, есть wrapper. Что это такое? Это по сути встроенный в проект maven. А точнее в проекте появляется .mvn\wrapper\maven-wrapper.jar, а также скачивается дистрибутив maven в папку локального репозитория .m2. Позволяет не зависеть от наличия и версии maven в системе.
Установка: mvn wrapper:wrapper
Использование: ./mvnw clean package вместо mvn clean package
Добавленные при установке wrapper в проект файлы нужно закоммитить в git.
https://maven.apache.org/wrapper/
2) Maven daemon. Тоже перетекание хороших идей из Gradle. Как следует из названия это Maven, который запускается в фоновом режиме. Что позволяет убрать фазу инициализации maven при втором и последующих запусках и существенно ускорить сборку на маленьких проектах. К сожалению, это сторонний проект, поэтому не совместим с maven wrapper.
https://github.com/apache/maven-mvnd
3) Maven умеет запускать сборку в несколько потоков. Рекомендуется сделать число потоков равное числу ядер процессора:
mvn -T 1C clean package
Но можно указать и конкретное число потоков:
mvn -T 4 clean package
И даже число потоков на ядро:
mvn -T 1.5C clean package
Список плагинов, которые могут работать параллельно и другую информацию можно найти здесь:
https://cwiki.apache.org/confluence/display/MAVEN/Parallel+builds+in+Maven+3
Также эта настройка есть в IntelliJ IDEA.
Про настройки параллельного запуска для JUnit тестов можно почитать тут: https://www.baeldung.com/maven-junit-parallel-tests
4) Плагин Maven Enforсer. Позволяет при сборке на фазе validate проверять:
а) версию и вендора JDK
б) версию maven
в) отсутствие SNAPSHOT версий
г) наличие и отсутствие в проекте определенных файлов и их контрольную сумму
д) отсутствие repositories в pom файлах (они должны быть в settings.xml)
е) ОС, на которой запущен maven
и многое другое.
https://maven.apache.org/enforcer/enforcer-rules/index.html
5) BuildPlan плагин. Показывает какие плагины используются при сборке, какие goal связаны с каждой фазой. Запускать нужно с теми же ключами -D и -P,
с которыми проводится сборка:
mvn buildplan:list
http://buildplan.jcgay.fr/
#buildtool
Про фишки Maven, часть вторая.
Поехали.
1) У maven, также как у Gradle, есть wrapper. Что это такое? Это по сути встроенный в проект maven. А точнее в проекте появляется .mvn\wrapper\maven-wrapper.jar, а также скачивается дистрибутив maven в папку локального репозитория .m2. Позволяет не зависеть от наличия и версии maven в системе.
Установка: mvn wrapper:wrapper
Использование: ./mvnw clean package вместо mvn clean package
Добавленные при установке wrapper в проект файлы нужно закоммитить в git.
https://maven.apache.org/wrapper/
2) Maven daemon. Тоже перетекание хороших идей из Gradle. Как следует из названия это Maven, который запускается в фоновом режиме. Что позволяет убрать фазу инициализации maven при втором и последующих запусках и существенно ускорить сборку на маленьких проектах. К сожалению, это сторонний проект, поэтому не совместим с maven wrapper.
https://github.com/apache/maven-mvnd
3) Maven умеет запускать сборку в несколько потоков. Рекомендуется сделать число потоков равное числу ядер процессора:
mvn -T 1C clean package
Но можно указать и конкретное число потоков:
mvn -T 4 clean package
И даже число потоков на ядро:
mvn -T 1.5C clean package
Список плагинов, которые могут работать параллельно и другую информацию можно найти здесь:
https://cwiki.apache.org/confluence/display/MAVEN/Parallel+builds+in+Maven+3
Также эта настройка есть в IntelliJ IDEA.
Про настройки параллельного запуска для JUnit тестов можно почитать тут: https://www.baeldung.com/maven-junit-parallel-tests
4) Плагин Maven Enforсer. Позволяет при сборке на фазе validate проверять:
а) версию и вендора JDK
б) версию maven
в) отсутствие SNAPSHOT версий
г) наличие и отсутствие в проекте определенных файлов и их контрольную сумму
д) отсутствие repositories в pom файлах (они должны быть в settings.xml)
е) ОС, на которой запущен maven
и многое другое.
https://maven.apache.org/enforcer/enforcer-rules/index.html
5) BuildPlan плагин. Показывает какие плагины используются при сборке, какие goal связаны с каждой фазой. Запускать нужно с теми же ключами -D и -P,
с которыми проводится сборка:
mvn buildplan:list
http://buildplan.jcgay.fr/
#buildtool
GitHub
GitHub - apache/maven-mvnd: Apache Maven Daemon
Apache Maven Daemon. Contribute to apache/maven-mvnd development by creating an account on GitHub.
Всем привет!
Сегодня расскажу о нескольких неочевидных особенностях работы Maven.
1) за каждый этап жизненного цикла сборки Maven отвечает какой-то плагин. Один плагин может покрывать несколько этапов. Это не новость. Я надеюсь) Интересно то, что эти плагины не обязательно указывать в pom, вот минимальный рабочий pom, с которым ваш проект скомпилируется - https://maven.apache.org/guides/introduction/introduction-to-the-pom.html#Minimal_POM
Работает принцип convention over configuration.
А вот описание алгоритма определения нужного плагина: https://maven.apache.org/guides/introduction/introduction-to-plugin-prefix-mapping.html
Перескажу его вкратце.
Если вы указали при сборке фазу жизненного цикла, например, maven install, то определяются все необходимые шаги сборки и требуемые плагины как описано вот тут https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
А далее Maven ищет специальные файлы maven-metadata во всех подключенных к проекту репо, сливает их в один и ищет плагин по атрибуту prefix, который равен указаному вот тут как plugin https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#default-lifecycle-bindings-packaging-ejb-ejb3-jar-par-rar-war
Вот пример базового maven-metadata из Maven Central https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-metadata.xml
Как можно заметить, у большинства плагинов, поисковый префикс является частью artefactId. Это соглашение о наименовании, хотя и не обязательное. Т.е. всегда можно сделать свой maven-metadata-local.xml и привязать нужный плагин к нужной фазе там. Но я бы не рекомендовал так делать, т.к. это завязка на конкретный сборщик, которая хранится отдельно от кода вашего проекта. Также при создании плагина можно назвать его как угодно и указать к какой фазе сборки он привязан, может быть полезно, когда одним словом сложно выразить задачу плагина.
Если вы явно указываете цель для сборки, например, compiler:compile, то выполняется только эта цель, Maven пропускает разбор жизненного цикла сборки, сразу переходит к поиску нужного плагина в maven-metadata, в данном случае по префиксу compiler.
Вопрос - а как Maven определяет версию плагина? Есть еще один maven-metadata файлик с версиями у каждого плагина https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-compiler-plugin/maven-metadata.xml
И как раз здесь лежит подводный камень: когда Maven-у понадобится конкретный плагин - он возьмет последнюю версию из тех, что найдет в подключенных к проекту репозиториях. А брать последнюю версию не всегда хорошо - там могут быть баги, или она просто может криво закачаться, если речь про внутренний прокси репозиторий.
Поэтому рекомендую начинать с минимальным POM, а перед выходом на ПРОМ фиксировать все версии плагинов.
Еще может возникнуть вопрос - а нельзя ли этот фокус провернуть с неофициальными плагинами? Ответ - можно, нужно лишь указать в settings.xml где еще искать maven-metadata.xml:
<pluginGroups>
<pluginGroup>org.codehaus.modello</pluginGroup>
</pluginGroups>
Еще момент - всегда можно добавить в pom конфигурацию плагина и там переопределить фазу сборки, на которой он запустится.
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
В примере цель из плагина jacoco-maven-plugin привяза к фазе test.
Выше я описывал, как работает Maven в режиме convention over configuration.
Продолжение следует...
#maven #buildtool #conv_over_conf
Сегодня расскажу о нескольких неочевидных особенностях работы Maven.
1) за каждый этап жизненного цикла сборки Maven отвечает какой-то плагин. Один плагин может покрывать несколько этапов. Это не новость. Я надеюсь) Интересно то, что эти плагины не обязательно указывать в pom, вот минимальный рабочий pom, с которым ваш проект скомпилируется - https://maven.apache.org/guides/introduction/introduction-to-the-pom.html#Minimal_POM
Работает принцип convention over configuration.
А вот описание алгоритма определения нужного плагина: https://maven.apache.org/guides/introduction/introduction-to-plugin-prefix-mapping.html
Перескажу его вкратце.
Если вы указали при сборке фазу жизненного цикла, например, maven install, то определяются все необходимые шаги сборки и требуемые плагины как описано вот тут https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
А далее Maven ищет специальные файлы maven-metadata во всех подключенных к проекту репо, сливает их в один и ищет плагин по атрибуту prefix, который равен указаному вот тут как plugin https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#default-lifecycle-bindings-packaging-ejb-ejb3-jar-par-rar-war
Вот пример базового maven-metadata из Maven Central https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-metadata.xml
Как можно заметить, у большинства плагинов, поисковый префикс является частью artefactId. Это соглашение о наименовании, хотя и не обязательное. Т.е. всегда можно сделать свой maven-metadata-local.xml и привязать нужный плагин к нужной фазе там. Но я бы не рекомендовал так делать, т.к. это завязка на конкретный сборщик, которая хранится отдельно от кода вашего проекта. Также при создании плагина можно назвать его как угодно и указать к какой фазе сборки он привязан, может быть полезно, когда одним словом сложно выразить задачу плагина.
Если вы явно указываете цель для сборки, например, compiler:compile, то выполняется только эта цель, Maven пропускает разбор жизненного цикла сборки, сразу переходит к поиску нужного плагина в maven-metadata, в данном случае по префиксу compiler.
Вопрос - а как Maven определяет версию плагина? Есть еще один maven-metadata файлик с версиями у каждого плагина https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-compiler-plugin/maven-metadata.xml
И как раз здесь лежит подводный камень: когда Maven-у понадобится конкретный плагин - он возьмет последнюю версию из тех, что найдет в подключенных к проекту репозиториях. А брать последнюю версию не всегда хорошо - там могут быть баги, или она просто может криво закачаться, если речь про внутренний прокси репозиторий.
Поэтому рекомендую начинать с минимальным POM, а перед выходом на ПРОМ фиксировать все версии плагинов.
Еще может возникнуть вопрос - а нельзя ли этот фокус провернуть с неофициальными плагинами? Ответ - можно, нужно лишь указать в settings.xml где еще искать maven-metadata.xml:
<pluginGroups>
<pluginGroup>org.codehaus.modello</pluginGroup>
</pluginGroups>
Еще момент - всегда можно добавить в pom конфигурацию плагина и там переопределить фазу сборки, на которой он запустится.
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
В примере цель из плагина jacoco-maven-plugin привяза к фазе test.
Выше я описывал, как работает Maven в режиме convention over configuration.
Продолжение следует...
#maven #buildtool #conv_over_conf
maven.apache.org
Introduction to the POM – Maven
Всем привет!
Продолжим про Maven.
2) Несмотря на то, что к каждой фазе жизненного цикла по умолчанию привязана одна цель (goal) из конкретного плагина, на каждую фазу можно повесить сколько угодно целей. Порядок выполнения - как указано в pom.xml. Это еще одна одна причина, почему полезно явно обьявлять плагины в pom.
3) Если у вас в settings.xml указано несколько репозиториев с артифактами, и поиск по всем не дал результата - будет ошибка, но с некорректным текстом. В ней будет сказано, что артифакта нет в первом по списку репозитории
4) Если какие-то из репозиториев в settings.xml требуют аутентификации, данные для аутентификации были указаны и протухли, то вы узнаете об этом только тогда, когда понадобится обновить библиотеку, которая есть только в этом репозитории. Ошибка с аутентификацией будет в логах каждой сборки, но сборку не ломает
5) Может возникнуть вопрос - а зачем Maven каждый раз ходит по удаленным репозиториям, если зависимости не менялись. Это поведение контролируется параметром репозитория updatePolicy в settings.xml:
<repository>
<id>central</id>
<url>https://repo1.maven.org/maven2</url>
<releases>
<updatePolicy>always</updatePolicy>
</releases>
</repository>
Возможные значения: "always", "daily" (default), "interval:XXX" (in minutes) or "never".
Можно установить never, но есть два риска:
а) не будут подтягиваться новые snapshot,
б) не будут подтягиваться новые версии уже закачанных артифактов. А эту информацию индексирует IDEA и использует при AutoComplition
6) Если сохраненные локально зависимости были повреждены, то принудительно их перезагрузить можно через очистку локального репозитория, который находится в папке .m2. Командой mvn dependency:purge-local-repository, подробнее тут https://www.baeldung.com/maven-force-update или просто грохнув нужную папку в .m2
7) согласно уже упоминаемому ранее принципу convention over configuration по умолчанию в список репозиториев неявно включается Maven Central. Подробнее про settings.xml и его опции можно почитать тут https://habr.com/ru/post/339902/
8) список репозиториев можно задать как в pom.xml, так и в settings.xml. Предпочтительнее второй вариант, особенно при разработке библиотек, особенно внутренних. Причина: адрес репозитория может поменяться, а settings.xml проще обновить централизованно. Не говоря уже про библиотеки, которые придется перевыпускать. Конечно, если вы ходили по ссылке из предыдущего пункта - у нас есть возможность переопределить любой репозиторий из pom через зеркала\mirror в settings.xml. Причем при настройке зеркала можно не только указывать явно заменяемый репозиторий, но и использовать операторы * и ! Но это все же костыль)
#maven #buildtool #conv_over_conf
Продолжим про Maven.
2) Несмотря на то, что к каждой фазе жизненного цикла по умолчанию привязана одна цель (goal) из конкретного плагина, на каждую фазу можно повесить сколько угодно целей. Порядок выполнения - как указано в pom.xml. Это еще одна одна причина, почему полезно явно обьявлять плагины в pom.
3) Если у вас в settings.xml указано несколько репозиториев с артифактами, и поиск по всем не дал результата - будет ошибка, но с некорректным текстом. В ней будет сказано, что артифакта нет в первом по списку репозитории
4) Если какие-то из репозиториев в settings.xml требуют аутентификации, данные для аутентификации были указаны и протухли, то вы узнаете об этом только тогда, когда понадобится обновить библиотеку, которая есть только в этом репозитории. Ошибка с аутентификацией будет в логах каждой сборки, но сборку не ломает
5) Может возникнуть вопрос - а зачем Maven каждый раз ходит по удаленным репозиториям, если зависимости не менялись. Это поведение контролируется параметром репозитория updatePolicy в settings.xml:
<repository>
<id>central</id>
<url>https://repo1.maven.org/maven2</url>
<releases>
<updatePolicy>always</updatePolicy>
</releases>
</repository>
Возможные значения: "always", "daily" (default), "interval:XXX" (in minutes) or "never".
Можно установить never, но есть два риска:
а) не будут подтягиваться новые snapshot,
б) не будут подтягиваться новые версии уже закачанных артифактов. А эту информацию индексирует IDEA и использует при AutoComplition
6) Если сохраненные локально зависимости были повреждены, то принудительно их перезагрузить можно через очистку локального репозитория, который находится в папке .m2. Командой mvn dependency:purge-local-repository, подробнее тут https://www.baeldung.com/maven-force-update или просто грохнув нужную папку в .m2
7) согласно уже упоминаемому ранее принципу convention over configuration по умолчанию в список репозиториев неявно включается Maven Central. Подробнее про settings.xml и его опции можно почитать тут https://habr.com/ru/post/339902/
8) список репозиториев можно задать как в pom.xml, так и в settings.xml. Предпочтительнее второй вариант, особенно при разработке библиотек, особенно внутренних. Причина: адрес репозитория может поменяться, а settings.xml проще обновить централизованно. Не говоря уже про библиотеки, которые придется перевыпускать. Конечно, если вы ходили по ссылке из предыдущего пункта - у нас есть возможность переопределить любой репозиторий из pom через зеркала\mirror в settings.xml. Причем при настройке зеркала можно не только указывать явно заменяемый репозиторий, но и использовать операторы * и ! Но это все же костыль)
#maven #buildtool #conv_over_conf
Baeldung
Force Repository Update with Maven | Baeldung
Explore the options and goals of Maven that forcibly updates our local repository.
Всем привет!
Есть интересная тема - инструменты сборки для JVM проектов. А в рамках нее другая горячая тема - управление конфликтами зависимостей. Когда в проект подтягивается, как правило транзитивно, две версии одной и той же зависимости. А должна остаться только одна)
Отличное сравнение 3 систем сборки по управлению конфликтами зависимостей еще 10+ лет назад проведено в этой статье: https://habr.com/ru/companies/jugru/articles/191246/
Вывод из статьи - в Maven все сделано, скажет так, странно)))
Приходится явно указывать нужную версию каждой конфликтной зависимости в проекте.
Первый вопрос, который приходит на ум - зачем в Maven так сделали и когда собираются исправлять.
Ответ тут - https://stackoverflow.com/questions/34201120/maven-set-dependency-mediation-strategy-to-newest-rather-than-nearest
Спойлер - исправлять не собираются, считают, что так сборка будет более предсказуемой и повторяющейся. Т.е. описанный выше подход - запускай приложение, находи конфликты в runtime и указывай явно версию в своем модуле - считается правильным. Но есть лайфхак - см. ответ на stackoverflow.
Ну а чтобы найти версии проблемной зависимости - нужен mvn dependency:tree. О его "секретных" (на самом деле полезных) ключах этой таски Maven можно почитать тут https://www.digitalocean.com/community/tutorials/maven-dependency-tree-resolving-conflicts
Ну и если хочется копнуть глубже, например понять, как разрешается конфликт scope-ов зависимости или узнать про то, как разработчик библиотеки может уменьшить возможность появления конфликта (optional) - см. главный источник истины по Maven - его документацию https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
#maven #gradle #java #buildtool #dependency_management
Есть интересная тема - инструменты сборки для JVM проектов. А в рамках нее другая горячая тема - управление конфликтами зависимостей. Когда в проект подтягивается, как правило транзитивно, две версии одной и той же зависимости. А должна остаться только одна)
Отличное сравнение 3 систем сборки по управлению конфликтами зависимостей еще 10+ лет назад проведено в этой статье: https://habr.com/ru/companies/jugru/articles/191246/
Вывод из статьи - в Maven все сделано, скажет так, странно)))
Приходится явно указывать нужную версию каждой конфликтной зависимости в проекте.
Первый вопрос, который приходит на ум - зачем в Maven так сделали и когда собираются исправлять.
Ответ тут - https://stackoverflow.com/questions/34201120/maven-set-dependency-mediation-strategy-to-newest-rather-than-nearest
Спойлер - исправлять не собираются, считают, что так сборка будет более предсказуемой и повторяющейся. Т.е. описанный выше подход - запускай приложение, находи конфликты в runtime и указывай явно версию в своем модуле - считается правильным. Но есть лайфхак - см. ответ на stackoverflow.
Ну а чтобы найти версии проблемной зависимости - нужен mvn dependency:tree. О его "секретных" (на самом деле полезных) ключах этой таски Maven можно почитать тут https://www.digitalocean.com/community/tutorials/maven-dependency-tree-resolving-conflicts
Ну и если хочется копнуть глубже, например понять, как разрешается конфликт scope-ов зависимости или узнать про то, как разработчик библиотеки может уменьшить возможность появления конфликта (optional) - см. главный источник истины по Maven - его документацию https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
#maven #gradle #java #buildtool #dependency_management
Хабр
Разрешение конфликтов в транзитивных зависимостях — Хороший, Плохой, Злой
Вместо предисловия В ближайшую субботу мы с EvgenyBorisov будем выступать в Питере на JUG.ru . Будет много веселого трэша и интересной инфы (иногда не разберешь, где проходит граница), и одно из моих...
Всем привет!
Вдогонку ко вчерашней теме про управление зависимостями.
В Maven есть две фичи, смягчающие боль по управлению зависимостями:
1) bom - Bill Of material - pom-ник, объявляющий версии протестированного и гарантированного рабочего набора обязательных зависимостей, например, библиотеки Spring Security
2) dependencyManagemenet - возможность в одном месте, как правило это корневой pom, объявить все версии используемых в проекте библиотек. Туда же можно подключать уже готовые bom-ы. После этого задача поднятия версии какой-то зависимости по всему многомодульному проекту упрощается
Есть ли что-то подобное в Gradle?
Да, есть.
Вот тут описывается как "сэмулировать" bom в Gradle - https://habr.com/ru/articles/784784/
Ключевые слова platform и constraints https://docs.gradle.org/current/userguide/dependency_constraints.html
Почему я говорю сэмулировать: если посмотреть на структуру bom - это типичный Maven xml файл. Gradle публикует bom в двух форматах - maven для совместимости и свой json, вот пример https://repo1.maven.org/maven2/io/github/mfvanek/pg-index-health-bom/0.10.2/
Но на самом деле Gradle умеет чуть больше - есть такая штука, как catalog - по сути позволяющая структурировать зависимости в древовидную структуру и дать имя-ссылку каждому уровню. См. https://docs.gradle.org/current/userguide/platforms.html Причем объявлять завимости можно как в build.gradle, так и в отдельном toml файле. Каталог можно использовать сам по себе - как набор версий, так и ограничивать с помощью него версии транзитивных зависимостей - через те же constraints и platform.
#gradle #maven #depenedency_management #buildtool
Вдогонку ко вчерашней теме про управление зависимостями.
В Maven есть две фичи, смягчающие боль по управлению зависимостями:
1) bom - Bill Of material - pom-ник, объявляющий версии протестированного и гарантированного рабочего набора обязательных зависимостей, например, библиотеки Spring Security
2) dependencyManagemenet - возможность в одном месте, как правило это корневой pom, объявить все версии используемых в проекте библиотек. Туда же можно подключать уже готовые bom-ы. После этого задача поднятия версии какой-то зависимости по всему многомодульному проекту упрощается
Есть ли что-то подобное в Gradle?
Да, есть.
Вот тут описывается как "сэмулировать" bom в Gradle - https://habr.com/ru/articles/784784/
Ключевые слова platform и constraints https://docs.gradle.org/current/userguide/dependency_constraints.html
Почему я говорю сэмулировать: если посмотреть на структуру bom - это типичный Maven xml файл. Gradle публикует bom в двух форматах - maven для совместимости и свой json, вот пример https://repo1.maven.org/maven2/io/github/mfvanek/pg-index-health-bom/0.10.2/
Но на самом деле Gradle умеет чуть больше - есть такая штука, как catalog - по сути позволяющая структурировать зависимости в древовидную структуру и дать имя-ссылку каждому уровню. См. https://docs.gradle.org/current/userguide/platforms.html Причем объявлять завимости можно как в build.gradle, так и в отдельном toml файле. Каталог можно использовать сам по себе - как набор версий, так и ограничивать с помощью него версии транзитивных зависимостей - через те же constraints и platform.
#gradle #maven #depenedency_management #buildtool
Хабр
Создание и использование BOM в Gradle
Привет Хабр! В каждой компании (а если она крупная, то, скорее всего, в каждом подразделении) должна быть выстроена культура использования BOM ( bill of materials ) для управления версиями...
Всем привет!
Есть такое известное правило - DRY - Don't Repeat Yourself. Оно касается кода, оно касается и настроек. Окей, задали мы настройки в одном месте - например, в корневом pom файле или build.gradle(.kts). Как пробросить их во все необходимые файлы при сборке? Этот процесс называется property expansion. К слову - в Maven есть понятие resource filtering. Это нечто большее - проход по всем ресурсным файлам, их фильтрация и кастомизация. Но обычно как раз таки используется для property expansion. Так вот, нашел неплохую статью как сделать это в Maven и Gradle https://www.baeldung.com/spring-boot-auto-property-expansion Что интересно - решение Maven выглядит более продуманным.
#gradle #maven #buildtool
Есть такое известное правило - DRY - Don't Repeat Yourself. Оно касается кода, оно касается и настроек. Окей, задали мы настройки в одном месте - например, в корневом pom файле или build.gradle(.kts). Как пробросить их во все необходимые файлы при сборке? Этот процесс называется property expansion. К слову - в Maven есть понятие resource filtering. Это нечто большее - проход по всем ресурсным файлам, их фильтрация и кастомизация. Но обычно как раз таки используется для property expansion. Так вот, нашел неплохую статью как сделать это в Maven и Gradle https://www.baeldung.com/spring-boot-auto-property-expansion Что интересно - решение Maven выглядит более продуманным.
#gradle #maven #buildtool
Baeldung
Automatic Property Expansion with Spring Boot | Baeldung
Learn about the property expansion mechanism provided by Spring through Maven and Gradle build methods.
С чем проще работать - Maven vs Gradle?
Как ни странно - ответ на этот вопрос не очевиден.
Если говорить о чтении глазами разработчиком - Gradle выглядит попроще т.к. там почти нет boilerplate кода. И тот, и другой инструмент придерживаются принципа convention over configuration, но Maven проигрывает из-за xml.
Но если проект начинает развиваться - что-то может пойти не так) Gradle позволяет легко выстрелить себе в ногу создав очень сложный скрипт деплоя. Причем много кода появляется там, где его не ожидаешь - в build скрипте. И этот код не на Java, т.е. может отличаться от кода проекта. А если добавить сюда multiproject - разбираться в этом становится сложно. Maven выносит весь императивный код в плагины, скрипты сборки чисто декларативные.
И можно глянуть с другой стороны - со стороны tooling, например, той же IDEA. Тут победа на стороне Maven - распарсить xml легко, а вот чтобы понять структуру Gradle проекта - нужно начать его исполнять. Это и дольше, и процесс подвержен ошибками, а в теории и уязвимостям.
Вывод - оба инструмента хороши, имеют свои плюсы и минусы. Рекомендую изучить оба. Я для себя не определился)
#buildtool #maven #gradle #conv_over_conf
Как ни странно - ответ на этот вопрос не очевиден.
Если говорить о чтении глазами разработчиком - Gradle выглядит попроще т.к. там почти нет boilerplate кода. И тот, и другой инструмент придерживаются принципа convention over configuration, но Maven проигрывает из-за xml.
Но если проект начинает развиваться - что-то может пойти не так) Gradle позволяет легко выстрелить себе в ногу создав очень сложный скрипт деплоя. Причем много кода появляется там, где его не ожидаешь - в build скрипте. И этот код не на Java, т.е. может отличаться от кода проекта. А если добавить сюда multiproject - разбираться в этом становится сложно. Maven выносит весь императивный код в плагины, скрипты сборки чисто декларативные.
И можно глянуть с другой стороны - со стороны tooling, например, той же IDEA. Тут победа на стороне Maven - распарсить xml легко, а вот чтобы понять структуру Gradle проекта - нужно начать его исполнять. Это и дольше, и процесс подвержен ошибками, а в теории и уязвимостям.
Вывод - оба инструмента хороши, имеют свои плюсы и минусы. Рекомендую изучить оба. Я для себя не определился)
#buildtool #maven #gradle #conv_over_conf