Pull to refresh

Делаем релизы с помощью Maven в Java

Reading time 8 min
Views 51K

О чем эта статья?


Эта статья о том:
  1. Что такое релиз?
  2. Как нумеруются релизы?
  3. Зачем при релизе нужен бранч?
  4. Почему релиз это больше, чем просто jar (war, ear, zip, etc)?
  5. Что такое maven-release-plugin?
  6. Делаем бранч c помощью release:branch.
  7. Подготовка к релизу с помощью release:prepare.
  8. Выпускаем релиз с помощью release:perform.

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

Первые несколько разделов посвящены общей концепции релизов и их нумерации. Если вы достаточно опытны, skip it!

Что такое релиз и с чем его едят


Для себя релиз я определяю, как закрепление определенного набора функциональности. Закрепляя функциональность, вы говорите: «Эта версия продукта содержит в себе возможность создавать новый документ, перелистывать страницы пальцем или запускать ракеты в космос.» Хорошей практикой является ведение списка закрепленной функциональности в баг-трекинговой системе, позволяя ребятам из QA быстро и просто определить, что умеет ваш релиз, а чего он не может, сказать, что где в вашу систему закралась ошибка и прочее-прочее-прочее.
Рассмотрим пример небольшого проекта. Представим себе, что городской зоопарк заказал нам разработать систему мониторинга состояния животных: в каких вольерах они живут, какой смотритель за ними ухаживает. Так же нужно информировать смотрителя с помощью sms о том, что животное нуждается в уходе.
Пусть проект будет сделан для Web и имеет следующую структуру:
zoo
|---zoo-web
|---zoo-sensor-server

Релизом для нас будет war, который мы можем задеплоить на веб-сервер, и zip c небольшим сервером, принимающим сообщения от датчиков в вольерах с животными.

Нумерация релизов


«Для отслеживания изменений программного обеспечения было создано большое количество схем присвоения номеров версиям программного обеспечения,» — говорит нам Википедия.
И это воистину так. Большинство проектов, компаний, продуктов и индивидуальных разработчиков используют свой способ исчисления версий.
Maven предлагает нам использовать более-менее общепринятую схемой нумерации x.y.z, где:
  • x — номер основной функциональности релиза
  • y — номер дополнительной функциональности релиза
  • z — номер фикса багов

Например, 1.3.23, 0.7.7 и 1.4.112. Будем использовать ее для нашего зоопарка.

Тем временем в зоопарке

Итак, мы договорились дирекцией зоопарка, что перед запуском полноценного продукта, мы дадим им три промежуточные версии. Первая — будет содержать реализацию сервера, собирающего информацию с сенсоров в вольерах. Веб часть будет очень простой, выводящей метрики в неподготовленном виде. Вторая — будет содержать полноценный экран с информацией по вольерам, возможностями сортировки и прочее. Третья — будет содержать функциональность оповещения служащих о необходимых действиях через смс. И лишь когда мы все соберем, и клиенту все понравится — мы выпустим финальный релиз.

0.y.0

Дадим каждой из промежуточных версий имена 0.1.0, 0.2.0, 0.3.0 соответственно.
Первая цифра 0, потому что наш главный релиз еще не вышел, это лишь промежуточный результат.
Вторая цифра равна номеру поставки. Третья — 0, потому что мы считаем, что в ней нет багов на момент сборки.
Когда третья цифра равна 0, ее часто не пишут: 0.1, 0.2, 0.3.
image

Alpha, Beta и прочие RC

Перед тем, как поставить релиз клиенту, даже промежуточный, он должен пройти QA процесс. Подходы к выпуску релизов для тестирования так же могут различаться, но в своих проектах я стараюсь использовать понятие Release Candidate.
Перед выпуском релиза x.y вы собираете x.y-RC1, x.y-RC2 и так далее, пока QA не скажет вам, что релиз стабилен и готов в UAT или Production.
Тогда последний RC становиться тем самым долгожданным релизом.
image

0.1.x

В любом коде существуют ошибки. И пользователь с радостью их найдет. В процессе саппорта заводятся новые баги, вы их правите и должны предоставить версию с исправлениями. Для этого собираются баг-фикс релизы.
Например, вы выпустили версию 0.1.0, и в ходе реальной работы выяснилось, что данные датчика температуры неправильно обрабатываются. Выпускается релиз 0.1.1, который исправляет досадное недоразумение.
image

Финальный релиз и далее

После серии из промежуточных поставок вы собираете 1.0-RC, заканчиваете процесс QA и собираете 1.0. Если впоследствии заказчик захочет функциональность автоматического открытия клеток по ночам, чтобы животные могли порезвиться, и вы напишите и соберете 1.1. Найдет пару десяток сотню багов и вы выпустите 1.1.47.
Если он вдруг захочет написать все заново, красивее и круче, то вам скорее всего понадобиться 2.0, потом 2.1.45 и так далее, и так далее.
image

Бранч при выпуске релиза


Итак, релиз — это закрепление функциональности. То есть мы создали сервер по сбору данных с сенсоров в вольерах. Сделали простой веб-интерфейс. Протестировали и отдали все это в зоопарк, пусть ставят датчики. Мы пока начнем делать красивый и дружелюбный интерфейс. И конечно же все разберем при этом.
Возникает несколько вопросов:
  1. Где должен писаться новый код дружелюбного интерфейса?
  2. Где мы будем править ошибку в обработке информации с датчика, если ее вдруг найдут в зоопарке?

В транке мы, конечно, должны поправить ошибку. Но мы не можем собрать за несколько дней новую версию и отдать в зоопарк. Мы же все разобрали ради красивого интерфейса.
Поэтому, обычно, выпуск релиза с основной или дополнительной функциональностью сопровождается созданием ветвления в VCS (бранча). Это ветвление будет содержать в себе фикс багов, найденных в текущей production версии клиента. В транке вы можете делать, что угодно. И при этом у вас всегда есть стабильный код, который содержит только исправления ошибок.
Обычно такой бранч носит название <имя проекта>-0.1.x, то есть бранч от релиза 0.1, который содержит фикс багов данной версии.
image

Почему релиз это больше, чем сборка war


Конечный продукт — это не просто war у вас на руках. У продукта есть жизненный цикл. Он должен быть доступен для других продуктов. Мы можем собрать релиз заново, если все сборки были утеряны в результате пожара в серверной зоопарка.
Релиз должен выполнять две задачи:
  1. Закрепление и обеспечение доступности собранного продукта.
  2. Закрепление исходного кода релиза, на случай повторной сборки или начала новой ветки из этого релиза.

Таким образом вам нужно найти, где будет лежать собранный war и zip для зоопарка, а так же запомнить на уровне VCS, что именно это состояние кода соответствует релизу.
image

Запоминаем состояние кода

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

Выкладываем собранный продукт

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

Все вместе

Нам надо сделать:
  1. Если это релиз основной или дополнительной функциональности, сделать ветку для фикса багов.
  2. Сделать тег, чтобы запомнить состояние кода в момент релиза.
  3. Сделать сборку продукта и выложить его для общего доступа.


maven-release-plugin


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

Настройка плагина

Для работы плагина ему необходима следующая информация в pom.xml главного модуля вашего проекта:

Информация о системе контроля версий

Во-первых, нам надо указать, где храниться исходный код проекта. Для этого используется стандартный для Maven тег:
<scm>
    <connection>scm:svn:http://svn.zoo.com/zoo/trunk</connection>
</scm>

scm:svn:http расшифровывается как: используй протокол scm для взаимодействия с репозиторием svn по пути http:. SCM это протокол Maven для работы с системами контроля версий.
Если мы будем писать зоопарк с использованием Mercurial, то надо написать следующее:
<scm>
   <connection>scm:hg:http://svn.zoo.com/zoo/trunk</connection>
</scm>


Конфигурация параметров сборки

Для того, чтобы задать параметры самого релиза используется подключение плагина в секцию
<build><plugins>.

 <plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-release-plugin</artifactId>
   <configuration>
      <tagBase>svn://svn.zoo.com/zoo/tags</tagBase>
      <branchBase>svn://svn.zoo.com/zoo/branches</branchBase>
      <preparationGoals>clean install</preparationGoals>
      <goals>deploy</goals>
      <autoVersionSubmodules>true</autoVersionSubmodules>
   </configuration>
</plugin>

В конфигурации:
  • tagBase — путь к папке в вашем репозитории, где будут храниться теги.
  • branchBase — путь к папке в вашем репозитории, где будут храниться ветки.
  • preparationGoals — задачи, который нужно выполнить при подготовке к релизу, перед созданием тега. Обычно это стандартный цикл сборки.
  • goals — задачи, которые нужно сделать при самом релизе. Обычно это интеграционные тесты и деплой в общий репозиторий.
  • autoVersionSubmodules — это полезная настройка, позволяющая указать новую версию сразу для всех модулей в проекте.

Так же плагин использует версию проекта:
<version>0.1-SNAPSHOT</version>


Общие требования

Для создания релиза так же небходимо иметь установленный в системе клиент для VCS. Он должен быть доступен из консоли и быть в PATH (svn, hg, git).
Так же плагин не позволит вам создать релиз, если у вас есть локальные модификации в коде. И правильно сделает!
Для создания релиза плагину нужен write-доступ в систему контроля версий. Убедитесь, что в авторизационном кеше на вашей машине есть необходимая информация или используйте -Duser=<vcs-user> -Dpassword=<vcs-password>.

Создаем релиз zoo-0.1


Соберем релиз первой поставки для нашего зоопарка. У нас на руках транк с версией 0.1-RC3-SNAPSHOT. QA команда сообщила нам, что RC2 был достаточно хорош, чтобы мы могли делать релиз.

Создание бранча для релиза — release:branch

Этот пункт нужно выполнять, только если вы собираете релиз с основной или дополнительной функциональностью. Если бы мы собирали багфиксинг релиз zoo-0.1.2, то этот пункт мы бы пропустили.
Если мы собираем Release Candidate, то этот шаг так же пропускаем.
Для создания бранча нужно выполнить:
mvn release:branch -DbranchName=zoo-0.1.x

В ходе выполнения, Maven спросит нас, какая следующая версия для транка, по умолчанию предложив 0.2-SNAPSHOT.
What is the new working copy version for "Zoo"? (com.zoo:zoo) 0.2-SNAPSHOT:


Подготовка к релизу — release:prepare

Фаза подготовки к релизу в терминах maven-release-plugin включает в себя проверку проекта (компиляция, тесты, сборка) и создание тега в VCS. Теги будут создавать в папке, заданной при конфигурации.
Релиз будем делать из созданного бранча, предварительно выбрав его из репозитория. Транк еще на предыдущем шаге начал жить новой жизнью и его больше не трогаем.
image
Если мы собираем баг-фикс релиз, то выбирать ничего не нужно. Мы и так в ветке для баг-фиксов.
Если вы собираем Release Candidate, то эту фазу мы выполняем из транка.
Выполним следующую команду:
mvn release:prepare

Maven последовательно спросит нас номер собираемой версии, название для тега и номер следующей версии:
На последний вопрос ответим ему 0.1.1-SNAPSHOT, ведь это и есть первый будущий багфикс релиз.

Выпуск релиза — release:perform

Фаза выполнения релиза включает в себя чекаут исходного кода из тега и сборку его (обычно до фазы deploy). Да, именно так, чекаут исходного кода из тега. Зачем это нужно, если у нас уже есть исходный код рабочей копии? Потому что Maven хочет быть уверен, что эта сборка будет идентична той, что потом можно сделать выбрав тег вручную.
Для завершения релиза надо выполнить:
mvn release:perform

На этот раз вас ничего не будут спрашивать, просто сделают все что надо. Результатом будет выложенный в общий репозиторий артефактов релиз.

Если что-то пошло не так.


Если в процессе использования плагина, что-то сломалось, то у вас есть три варианта:
  1. Если, это произошло по внешним факторам, например сервер с системой контроля версий был недоступен, то запустите задачу еще раз. Плагин помнит последнее успешное действие и постарается продолжить.
  2. Если плагин в процессе произошла ошибка самой сборки, например, интеграционный тест не прошел, используйте release:rollback, эта команда откатит все изменения версий и удалит неудачные теги из системы контроля версий
  3. Если вы уверены, что откатывать нечего, и просто хотите начать заново, используйте release:clean
Tags:
Hubs:
+56
Comments 24
Comments Comments 24

Articles