Управление сборкой проектов вместе с teamcity. Часть 3

August 3, 2009Comments Off on Управление сборкой проектов вместе с teamcity. Часть 3

Эта статья завершит собой серию материалов посвященных рассказу о том, как teamcity помогает управлять проектами разработки программного обеспечения и, в частности, автоматизирует процесс сборки проекта, запуска тестов и интегрирует эти шаги в жизненный цикл разработки приложения. Прошлые две статьи были посвящены рассказу о том, какое место занимают в ходе разработки программного обеспечения продукты класса “build management and continuous integration ” вообще и teamcity в частности. Мы разобрались с основными понятиями teamcity, научились создавать билд-конфигурации и запускать их на выполнение. Этого должно быть достаточно для повседневной работы, так что сегодняшней статье осталось только “зашлифовать” некоторые не раскрытые моменты.

Прошлую статью я завершил на том, что мы создали билд-конфигурацию и запустили ее на выполнение. После того как свободный билд-агент закончил сборку maven-проекта, мы получили в свое распоряжение несколько отчетов. Во-первых, отчет о результатах запуска автоматических тестов, затем идет отчет о списке изменений в репозитории cvs/svn, которые были включены в текущую сборку. И, в конце концов, у нас в распоряжении оказался полный журнал всех сообщений, которые были сгенерированы билд-сценарием. Остался последний “смешной” вопрос: а где, собственно, находится сам результат выполнения сборки проекта, тот исполнимый файл, архив веб-приложения или “что там мы хотим отдать клиенту”? Если мы вспомним рассказ о maven, то сможем уверенно сказать, что конечный файл сборки проекта может быть найден или в локальном maven-репозитории либо в каталоге target самого проекта. Т.е. мы можем “руками залезть” внутрь каталога "C:\Documents and Settings\MyUserName\.m2\repository" или каталога “E:\Program_Files_2\TeamCity\buildAgent\work\5fa592b1ed40a411” и там найдем результат выполнения сборки. Но, очевидно, что ни один из этих способов неприемлем. Есть два возможных способа дать удобный способ доступа к результатам выполнения билд-сценария, но каждый из них требует небольшого отхода от возможностей, собственно teamcity, и рассмотрения того какие средства предусмотрены, именно, внутри maven. Как часть жизненного цикла сборки maven-проекта входит и фаза deploy – это фаза размещения сгенерированных артефактов на специальном, внешнем, сервере. В том случае, если вам достаточно собрать проект и поместить результат сборки в локальный репозиторий, то используется команда “m2 clean install”. В случае, если вы хотите скопировать результат сборки на удаленный сервер, то используйте команду “m2 clean deploy” (естественно, что вызов deploy включает в себя и фазу install). Теперь нам осталось разобраться с тем, как подсказать maven-у расположение удаленного репозитория, как сообщить имя и пароль для доступа к нему. Начнем с того, что внутри pom.xml файла нужно добавить новую секцию distributionManagement, указав в ней адрес ftp-сервера. Если вы ни разу еще не работали и не знакомы с каким-либо из ftp-серверов, то я могу порекомендовать filezilla (http://sourceforge.net/projects/filezilla/) – бесплатный, простой в настройке и широко известный. Возвращаясь к настройке pom.xml файла, затем в секции build сразу после настройки плагина, выполняющего компиляцию проекта, я подключил еще и плагин “ wagon-ftp”, умеющий работать с ftp-протоколом:
  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/maven-v4_0_0.xsd">
  3.  <modelVersion>4.0.0</modelVersion>
  4.  <groupId>blackzorro</groupId>
  5.  <artifactId>testartifact1</artifactId>
  6.  <packaging>jar</packaging>
  7.  <version>1.0</version>
  8.  <name>Simple Maven 2 Artifact</name>
  9.  <url>http://maven.apache.org</url>
  10.  <dependencies>
  11.     <dependency>
  12.     <groupId>junit</groupId>
  13.     <artifactId>junit</artifactId>
  14.     <version>4.4</version>
  15.     <scope>test</scope>
  16.    </dependency>
  17.  </dependencies>
  18.  <build>
  19.   <plugins>
  20.    <plugin>
  21.     <artifactId>maven-compiler-plugin</artifactId>
  22.     <configuration>
  23.        < source >1.5< / source >
  24.        <target>1.5</target>
  25.      </configuration>
  26.    </plugin>
  27.   </plugins>
  28.   <extensions>
  29.     <extension>
  30.      <groupId>org.apache.maven.wagon</groupId>
  31.      <artifactId>wagon-ftp</artifactId>
  32.      <version>1.0-alpha-6</version>
  33.    </extension>
  34.   </extensions>
  35.  </build>
  36.   <!-- use ftp repository -->
  37.  <distributionManagement>
  38.    <repository>
  39.      <id>ftp-repository</id>
  40.      <url>ftp://center/m2-repo</url>
  41.      <layout>default</layout>
  42.    </repository>
  43.   </distributionManagement>
  44. </project>
Предполагается, что ftp-сервер содержит каталог “m2-repo”, куда и будут складываться артефакты. Последний штрих связан с настройкой учетной записи, используемой для подключения к ftp-серверу. Для этого я отредактировал файл settings.xml, добавив в секцию “servers” имя и пароль пользователя. Обратите внимание на то, что и в файле pom.xml и в файле settings.xml я использовал одинаковое имя репозитория “ftp-repository”, чтобы maven смог между ними поставить соответствие.
  1. <servers>
  2.   <server>
  3.    <id>ftp-repository</id>
  4.    <username>vasyano</username>
  5.    <password>secret</password>
  6.   </server>
  7. </servers>
После того как была выполнена команда “m2 clean deploy”, то на ftp-сервере появится следующая иерархия файлов "m2-repo\blackzorro\testartifact1\1.0\testartifact1-1.0.jar". Как видите, файл артефакта был сохранен по стандартным правилам maven в каталоги с именами сначала группы артефактов, затем каталога с названием самого проекта-артефакта и, наконец, каталог с номером версии проекта. Обратите внимание еще раз на файл pom.xml и, в частности, на строку “default” при регистрации репозитория. Вторым возможным значением кроме “default” является “legacy”, в этом случае файл артефакта будет сохранен под следующим именем " m2-repo\blackzorro\jars\testartifact1-1.0.jar". Если вы обратитесь к сайту со справочной документацией maven, то сможете по аналогии настроить копирование сгенерированных артефактов не только на ftp-сервер, но и через ssh-соединение.

Увы, но показанный выше пример ни на что более сложное, чем пример (извиняюсь за тавтологию) просто не тянет. Поскольку я обошел молчанием два ключевых момента связанных с подготовкой сборки проекта. Во-первых, как быть с нумерацией версий сборок? Второй проблема связана с тем, что только для очень простых, учебных заданий конечный файл сборки представляет собой исполнимый jar-файл или архив веб-приложения. Гораздо чаще сборка – это архив, например, zip, со сложной структурой и в состав которого входят и jar-файлы приложения и каталоги со справочной документацией, и каталоги с библиотеками, и всевозможные инсталляционные сценарии и т.д. Что касается управления упаковкой проекта, то я могу посоветовать обратиться, прежде всего, к восьмой статье в моей серии рассказывающей о maven, а также к справочной документации на официальном сайте maven по плагину “maven-assembly-plugin”. Т.к. задача упаковки проекта слабо связана с настройкой интеграции teamcity и maven, то я не буду подробно на ней останавливаться и сразу перейду к вопросу правильной нумерации версий проекта. Напомню, что версия артефакта (а, следовательно, и имя файла под которым он будет сохранен), например “1.2.67”, состоит из двух частей. Последняя цифра версии – это всегда номер сборки, т.е.“67” – номер билда, а предшествующая ему часть кодирует, собственно, номер версии приложения (здесь это “1.2”). Если с первой частью версии приложения вопросов нет, и мы должны ее явно указать внутри pom.xml файла:
  1. <version>1.0</version>
То вот с номером билда обойтись средствами только maven не возможно: поскольку сборки запускаются из teamcity и teamcity хранит историю сборок и номера их билдов. Значит, мы должны так настроить maven и teamcity, чтобы организовать передачу между ними информации. К счастью, перед тем как выполнить запуск билда, teamcity передает внутрь maven-сценария ряд переменных, среди которых есть и “build.number”, т.е. порядковый номер билда. Сначала я задал зависимость версии проекта-артефакта от переменной “version.long”:
  1. <version>${version.long}</version>
Сама же переменная состоит из двух частей, и как я обещал, вторая часть равна значению служебной teamcity переменной ”build.number”:
  1. <properties>
  2.   <version.short>1.0</version.short>
  3.   <version.long>${version.short}B${build.number}</version.long>
  4. </properties>
Таким образом, после завершения билда у меня на ftp-сервере окажется файл со следующим именем: ftp://center/m2-repo/blackzorro/jars/testartifact1-1.0B10.jar и где 10 - порядковый номер билда. Небольшим недостатком показанной методики указания версии проекта в том, что при запуске билда не с помощью teamcity, а на локальной машине с помощью команды “m2 clean install”, конечный файл проекта будет иметь имя “target\testartifact1-1.0Bnull.jar”. Больших проблем “поломанная версия” проекта не вызывает, но все же смотрится не красиво. Простым способом решения является создание “умной” maven-конфигурации, которая сначала проверит доступность teamcity-переменной “build.number” и если это не так, то назначает номер версии проекта как простое число “1.0” или равной слову “local” т.е. без номера билда. К сожалению, в составе maven нет явно выделенной функциональности условных операторов как в “настоящих языках программирования”, но можно их имитировать с помощью профилей. Напомню, что профиль в терминологии maven – это небольшая модификация жизненного цикла проекта, точнее плагинов и их настроек, привязанных к фазам жизненного цикла. К примеру, мы можем внутри pom.xml файла с проектом определить кроме жизненного цикла по-умолчанию еще и профиль ”for-customer”. Такой профиль сформирует файл проекта уже готовый к непосредственной доставке заказчику когда, например, в состав проекта будет внедрена справка, а компиляция проекта будет выполнена с исключением отладочной информации или с “запутыванием” кода. Обфускация (Obfuscate) - это запутывание кода программы, при котором исполнимый файл приводится к виду, сохраняющему исходную функциональность приложения, но усложняющей анализ и модификацию. Подобные меры противодействия нужны для защиты приложений от “злых” хакеров, которые ломают защиту программы. Применительно к сегодняшней статье я буду использовать профиль только лишь для того, чтобы задать другое значение переменной “version.long” в том случае если переменная “build.number” неопределенна. Когда же запуск maven-сценария будет выполняться на локальной машине без помощи teamcity, то файл проекта будет иметь имя “target\testartifact1-local.jar”.
  1. <profiles>
  2.  <profile>
  3.   <id>default-version</id>
  4.   <activation>
  5.     <property>
  6.      <name>!build.number</name>
  7.    </property>
  8.   </activation>
  9.   <properties>
  10.    <version.long>local</version.long>
  11.    </properties>
  12.  </profile>
  13. </profiles>
В своей практике я использовал как показанный выше способ сохранения результатов сборки проекта на ftp-сервере, так и методику, когда файл на ftp-сервер копируется не средствами maven (точнее плагина отвечающего за фазу “deploy”), а с помощью специального ant-сценария. Т.е. я создавал в teamcity такую build-конфигурацию, что запускала maven-проект на сборку с профилем, например, saveToFtp. Технически, я должен был при создании build-конфигурации на закладке ”Build runner” в графе “Additional Maven command line parameters” я вписал имя профиля, под которым нужно запустить билд “-PsaveToFtp”. Сам же профиль определен внутри файла pom.xml и вся его работа состоит в том, что при наступлении фазы “package” maven запускает ant-сценарий. Который последовательно копирует с помощью команды “copy” файл проекта на другой компьютер по сети \\center\SharedDocs\my-app. Вторым шагом идет копирование файла проекта на ftp-сервер (команда “ftp”). Как раз для того, чтобы последняя команда отработала как требуется, мне пришлось подключить к плагину “maven-antrun-plugin” зависимость от библиотек “ant-commons-net” и “commons-net”.
  1. <profile>
  2.    <id>saveToFtp</id>
  3.    <build>
  4.       <plugins>
  5.          <plugin>
  6.             <groupId>org.apache.maven.plugins</groupId>
  7.             <artifactId>maven-antrun-plugin</artifactId>
  8.             <version>1.2</version>
  9.             <dependencies>
  10.                <dependency>
  11.                   <groupId>ant</groupId>
  12.                   <artifactId>ant-commons-net</artifactId>
  13.                   <version>1.6.5</version>
  14.                </dependency>
  15.                <dependency>
  16.                   <groupId>commons-net</groupId>
  17.                   <artifactId>commons-net</artifactId>
  18.                   <version>2.0</version>
  19.                </dependency>
  20.             </dependencies>
  21.             <executions>
  22.                <execution>
  23.                   <phase>package</phase>
  24.                   <goals>
  25.                      <goal>run</goal>
  26.                   </goals>
  27.                </execution>
  28.             </executions>
  29.             <configuration>
  30.                <tasks>
  31.                   <copy file="target/testartifact1-${version.long}.jar" todir="\\center\SharedDocs\my-app"/>
  32.                   <ftp server="center" binary="true" verbose="true" userid="vasyano" password="secret" remotedir="/">
  33.                      <fileset dir="target">
  34.                         <include name="*.jar"/>
  35.                      </fileset>
  36.                   </ftp>
  37.                </tasks>
  38.             </configuration>
  39.          </plugin>
  40.       </plugins>
  41.    </build>
  42. </profile>
В отдельных случаях можно не выполнять копирование файла с результатами сборки на какой-то ftp-сервер, а попросить teamcity сохранить его как артефакт где-то внутри самого teamcity сервера. У teamcity тоже есть понятие артефактов и по своему значению оно сходно с тем, что под артефактами понимает maven. В последующем любой пользователь может зайти через веб-интерфейс teamcity-сервера на страничку с результатами сборки и увидит там ссылки на все файлы, полученные в ходе выполнения сборки и заявленные как артефакты. Применительно к нашему случаю я хочу зарегистрировать как артефакт файлы, находящиеся в каталоге “target”. Для этого я от имени администратора teamcity захожу на страницу редактирования свойств билд-конфигурации, затем на закладку “General Settings” и в графе “Artifact Paths” я ввел следующие две строки:
target/*.jar
target/surefire-reports/**/*.* => test reports
Каждая строка состоит из двух частей, которые разделены символами “=>”. Первая часть (“target/*.jar” или “target/surefire-reports/**/*.*”) представляют собой пути к файлам или каталогам, которые мы хотим пометить как артефакты. При задании путей мы можем использовать символы подстановок, такие как * и ** (каталоги на любом уровне вложенности). Вторая же часть выражения (обратите внимание, что в первом примере она отсутствует) задает имя файла или “виртуального” подкаталога в который teamcity скопирует файлы артефактов. Так первой строкой я попросил teamcity сохранить все файлы с расширением jar внутри подкаталога target под теми же именами, которые они имеют. А вторая строка скопировала все файлы из подкаталога “surefire-reports” в подкаталог “ test reports” (это файлы с отчетами по результатам выполнения тестов). На рис.1



я показал то, как выглядит страничка с перечнем доступных артефактов, каждый из которых вы можете загрузить к себе на компьютер. Что касается сроков хранения артефактов, равно как и хранения истории запуска билдов, то это можно настроить в панели управления teamcity на странице “Administration -> Clean-up process settings”.

Следующая часть статьи будет посвящена средствам интеграции teamcity со средами разработки. Приятно, что хотя, создавшая teamcity, компания jet brains разрабатывает также и среду для java программистов под названием intellij idea, но jet brains решила не обижать невниманием также и тех программистов, кто предпочитает для работы среду IDE eclipse или даже программирует не на java, а на visual studio. Для того, чтобы установить к себе на компьютер плагин teamcity, необходимо зайти в панели управления teamcity на страницу “My Settings & Tools”, и там вы увидите ряд ссылок для загрузки плагинов. Я скачал файл “TeamCity-IDEAplugin.zip ” плагина для idea, затем распаковал содержимое архива каталог idea/plugins, и после перезапуска среды idea получил в свое распоряжение новое меню “teamcity”. Первым шагом настройки интеграции idea и teamcity является регистрация пользователя. Для этого я выбрал меню “Teamcity -> Login” и в появившемся диалоговом окне указал адрес подключения к teamcity, свое имя и пароль. Первое что мы настроим – это систему извещений о таких событиях как запуск билда и результат его выполнения. Teamcity может посылать сообщения об перечисленных выше событиях, например, по email или jabber клиенту, но гораздо удобнее если извещения показываются в среде разработки т.к. мы получаем дополнительный функционал быстрого перехода к списку изменений произошедших в проекте с момента прошлого билда. Итак, выбираем меню “teamcity -> Edit Notification Rules” затем в открывшемся окне браузера мы вводим свое имя и пароль, чтобы попасть внутрь teamcity и, наконец, перед нами открывается страница редактирования правил извещений. Нас интересует закладка “IDE notifier” (см. рис. 2),



где мы можем выбрать то, когда teamcity пошлет нам извещение. Я выбрал события “The build is successful”, “Responsibility changes” и “The build fails”. Теперь после того как билд будет завершен, то я увижу всплывающее окошко с сообщением об этом. Более того, teamcity плагин предоставил мне доступ к панели наблюдения за статусом билдов. Так на рис. 3



я показал момент, когда сборка проекта завершилась неудачей, и я решил взять на себя ответственность за этот сбой. Т.е. я сообщаю teamcity о том, что именно мои изменения являлись причиной сбоя. После того как я исправлю ошибку в коде и сохраню изменения в cvs|svn, то я смогу попросить teamcity пометить следующий билд как содержащий исправления для предыдущего. Как приятный бонус после установки плагина интеграции teamcity и idea мы получаем функцию быстрого перехода из окна браузера, например, со страницы с перечнем измененных файлов, в окно java редактора. Также панель teamcity содержит функцию просмотра списка последних файлов, а также позволяет просмотреть различия между ними с помощью удобного diff-редактора (см. рис. 4).



Крайне полезна в практике и функция “Remote Run”. Так если я внутри редактора idea изменю какой-то файл и выберу в меню пункт “teamcity -> remote run” то idea отправит файлы с изменениями кода не в cvs/svn репозиторий, а непосредственно на машину с билд агентом. На рис. 5



я показал пример диалогового окна, где я настраиваю параметры Remote Run, так я указал, что если запуск билда с моими правками будет успешен и ни один из тестов не будет провален, то изменения нужно автоматически сохранить и в cvs/svn репозиторий.

На этом я завершаю рассказ об teamcity и том какое место оно занимает в процессе управления сборкой проектов. Естественно, что три статьи серии не могут претендовать на достаточно полное описание возможностей teamcity, но я надеюсь на то, что вы поняли, зачем нужны продукты класса “Build management and continuous integration” вообще и, в частности, один из лучших представителей этого семейства – teamcity.