[Из песочницы] Идеальный мавен. Часть 1
Знаю, он не идеальный, но по крайней мере я попытаюсь рассказать, как его к этому приблизить.
В одну заметку всё не войдёт, поэтому сначала план:
- Постановка задачи — описание той конфигурации проектов с которой мы будем работать, целей и проблем
- Как настроить мавен для разработки в рамках нашей задачи
- Как настроить CI/CD (билды, релизы, деплоймент)
- Нерешенные проблемы
Задача
Итак, начнем с постановки задачи. Предположим у нас есть группа людей (компания, фирма, кружок), которые разрабатывают проекты на Java. При этом у них есть как проекты с открытым кодом (OSS), так и проекты с закрытым кодом. Проекты, назовём их внутренние, разрабатываются независимо друг от друга, но между ними есть зависимости. Что хочется:
- Централизованное управление зависимостями на внешние библиотеки
- OSS проекты в центральном мавен репозитории
- Закрытые проекты в своём мавен репозитории.
- «Простой» релиз внутренних проектов с обновлением зависимости в зависимых проектах.
- Максимальная автоматизация всех хотелок.
Важно понимать, что решать эти проблемы мы будем в комплексе, поэтому без реализации всех хотелок, система работать вообще не будет или будет, но не в полную силу.
Так же я хочу сказать, что все ниже написанное, это моё личное мнение, я осознаю, что мавен можно настроить по-разному, и я со своей стороны очень надеюсь найти нечто новое в обсуждении этой статьи, что поможет сделать существующую модель еще лучше. В свою защиту могу сказать, что модель, которую я буду описывать уже работает, и не один год. Открытая часть лежит на BitBucket, в частности, здесь.
Настраиваем мавен
Централизованное управление зависимостями на внешние библиотеки
Для управления сторонними зависимостями у мавена есть специальная секция dependencyManagement и механизм наследования. Казалась бы — вот и ответ, делаем «корпоративный» POM и наследуем от него корневые POM«ы всех наших проектов. Да, так и будет, но вот детали…. Итак, вот он наш будущий «корпоративный» POM:
4.0.0
org.team
org.team.pom
0-SNAPSHOT
pom
4.3.12.RELEASE
4.12
org.springframework
spring-framework-bom
${spring.version}
pom
import
org.springframework
spring-core
${spring.version}
commons-logging
commons-logging
junit
junit
${junit.ver}
test
maven-compiler-plugin
3.7.0
`
1.8
maven-deploy-plugin
2.8.2
maven-surefire-plugin
2.20.1
maven-war-plugin
3.2.0
maven-clean-plugin
3.0.0
maven-install-plugin
2.5.2
maven-site-plugin
3.5.1
maven-jar-plugin
3.0.2
maven-resources-plugin
3.0.2
maven-assembly-plugin
3.1.0
Всё стандартно, но хочу обратить внимание не некоторые вещи:
- Будуте копировать, уберите апостроф на в конфигурации
maven-compiler-plugin
. Он там для того, что бы местный редактор не заменялна три апострофа.
- Это не финальная версия, а минимальная, которую мы будем дописывать в следующих частях.
- Версии всех компонент вынесены в секцию переменных. Для 2–3 зависимостей не важно, но, когда у вас их 50 и секция dependencyManagement занимает несколько экранов это здорово облегчает обновление версий.
- Кроме собственно версий в секции dependencyManagement можно переопределить область применения (skope) зависимости и убрать некоторые транзитивные зависимости. Данной возможностью лучше не злоупотреблять и всегда писать комментарии зачем и почему это так сделано.
- Так же в нашем POM«е присутствует секция pluginManagement. Ее роль примерно такая-же — централизованное управление плагинами, используемыми для построения проекта. Почему это важно? По умолчанию мавен использует последние доступные версии плагинов. Так что, билд с одних и тех же исходников сейчас и через год может отличатся или просто не пройти. С помощью этой секции мы фиксируем версии плагинов, что по идеи минимизирует возможные расхождения.
- Еще одна возможность — это определить общие конфигурационные параметры для плагинов — например, версию байткода, которую мы используем во всех наших проектах.
- И не очень существенный пункт, пока мы не дошли до релизов, это версия нашего POM«а. Я написал её как
0-SNAPSHOT
. На самом деле важно, чтобы это был любой SNAPSHOT. Мы её менять в будущем не будем. Почему, расскажу в следующих статьях.
С какими проблемами/непонятками обычно сталкиваются при использовании «корпоративного» POM«а?
- Непонятно, как делать релизы (не надо)
- Надо ли включать отдельные проекты как модули (не надо)
- Надо ли в «корпоративном» POM«е описывать версии внутренних проектов (не надо)
- Как отслеживать и как часто обновлять версии внешних библиотек
- Непонимание различия между «корпоративного» и корневым POM отдельного проекта
Все это мы разберём в следующих частях это статьи. Сейчас кратко остановлюсь на двух последних пунктах.
Различие между «корпоративным» POM«ом и корневым POM отдельного проекта
«Корпоративный» POM описывает общие правила для всех ваших проектов в компании — как-то версия Java, зависимости и их версии, общие ограничения на проекты, за которыми может следить мавен, контакты на разработчиков и т.д. В «корпоративном» POM«е не должно быть информации («зависимостей») о конкретных внутренних проектах — их версий, специфичных профайлов и подобных вещей.
Как отслеживать и как часто обновлять версии внешних библиотек
Версии библиотек/плагинов можно легко отслеживать с помощью самого мавена (плагин versions-maven-plugin). Для этого добавим в наш «корпоративный» POM в секцию pluginManagement следующий фрагмент
org.codehaus.mojo
versions-maven-plugin
2.5
file://${user.dir}/rules.xml
false
А рядом с pom.xml создадим файл rules.xml со следующим содержимым
.*-does-not-exist
.*[Aa]lpha.*
.*(?i)beta.*
.*pre.*
.*[Dd]raft.*
.*-rc.*
20041228\.180559
.*jbossorg.*
.*dev.*
\d+\.\d+
.*(19|20)\d\d(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01]).*
.*jboss.*
.*atlassian.*
.*xwiki.*
.*b\d\d
.*_ALPHA
.*M\d
.*RC\d
.*\.jre7
.*\.jre6
.*CR\d
.*M\d*
.*pr\d
.*android
.*m\d*
.*p\d*
В принципе это делать не обязательно, и строчку
можно убрать. У меня это файл служит для фильтрации различных «мусорных» версии которые я предпочитаю игнорировать.
После этого достаточно запустить команды versions:display-dependency-updates
и versions:display-plugin-updates
и получить результаты:
[INFO] The following dependencies in Dependency Management have newer versions:
[INFO] com.amazonaws:aws-java-sdk-core ................. 1.11.221 -> 1.11.237
[INFO] com.amazonaws:aws-java-sdk-dynamodb ............. 1.11.221 -> 1.11.237
[INFO] com.amazonaws:aws-lambda-java-core .................... 1.1.0 -> 1.2.0
[INFO] com.amazonaws:aws-lambda-java-events .................. 2.0.1 -> 2.0.2
[INFO] com.google.guava:guava .......................... 23.3-jre -> 23.5-jre
[INFO] com.google.guava:guava-gwt ...................... 23.3-jre -> 23.5-jre
[INFO] com.google.inject:guice ................................. 3.0 -> 4.1.0
[INFO] io.sentry:sentry-logback .............................. 1.6.1 -> 1.6.3
[INFO] The following plugin updates are available:
[INFO] org.codehaus.mojo:sonar-maven-plugin ......... 3.3.0.603 -> 3.4.0.905
[INFO]
[INFO] All plugins have a version specified.
Кстати, вторая команда предупредит вас если вы используете какой-то плагин без указания его версии (правда, для этого ее надо запускать на проектных POM«ах)
Вкратце это всё про «корпоративный» POM. В следующей части я планирую рассказать о типовой структуре проекта и, возможно, о организации деполоя артефактов в центральный и корпоративный репозитории.