Автоматизация процессов сборки и тестирования

Сервер сборки на базе CruiseControl для непрерывной интеграции

Automate your team's build and unit-testing process

Original article: http://www-128.ibm.com/developerworks/java/library/j-cc/index.html

First published by IBM developerWorks at
http://www.ibm.com/developerWorks

Translated by: Ivan Pesin, June 2006

Уровень: средний

Марк Уилкинсон (Mark Wilkinson, mhw@codehaus.org), консультант, Codehaus

Перевод: Иван Песин

11 октября 2005

Экстремальное программирование и agile-методики рекомендуют, чтобы процесс разработки включал непрерывную интеграцию и модульное тестирование. Практическим подходом, использующим данные методы, является настройка автоматизированной системы для сборки и тестирования последней версии вашего кода после каждого его изменения. Эта статья рассматривает практические вопросы, возникающие при настройке собственного сервера для сборки Java™-проектов, основанного на Linux™.
Эта статья знакомит вас с CruiseControl, программным обеспечением с открытым исходным кодом, которое вы можете использовать для автоматизации процессов сборки и модульного тестирования в проектах, где задействовано несколько разработчиков. Мы рассмотрим, почему автоматические сборки являются необходимыми для успешных команд разработчиков, и опишем процессы установки, настройки и сопровождения системы непрерывной интеграции на базе CruiseControl.

Зачем нужна автоматическая сборка?

Использование систем управления версиями, таких как CVS или Subversion (см. Ресурсы), на сегодняшний день является общепринятой практикой.  Когда над одной системой работает много разработчиков, такая координация становится необходимой. Другой подход, набирающий популярность, это написание модульных тестов и включение их выполнения в процесс сборки. Например, утилита сборки Maven выполняет модульные тесты JUnit в процессе обычной сборки (см. Ресурсы). Но использование этих методов — всего лишь начало. Они формируют основу многих простых и практичных методик разработки программного обеспечения, возникших за последние несколько лет.

Непрерывная интеграция в mozilla.org
Много полезной информации можно почерпнуть из методов разработки, используемых в проекте Mozilla, одном из крупнейших проектов, ведущихся на всеобщем обозрении. Ключевой частью процесса является поддержание исходного кода в собираемом состоянии. Кроме того, все используемые подходы тщательно документируются. Важной частью процесса разработки является система tinderbox, которая постоянно собирает и тестирует проект на различных платформах (см Ресурсы).

Когда над одним проектом работает много разработчиков, важно быть уверенным, что последняя версия кода, находящаяся в системе управления версиями (транк), всегда собирается. Это хороший метод для проектов с замкнутыми командами разработчиков; когда разработчики периодически синхронизируют свои рабочие области с транком, несобирающийся исходный код задержит процесс разработки до исправления проблемы. Для проектов с открытым исходным кодом, сохранение транка в рабочем состоянии жизненно важно. Потенциальные программисты могут загрузить код в любой момент и если он будет в нерабочем состоянии, это может оттолкнуть их.

Методология "экстремального программирования" (XP) пропагандирует непрерывную интеграцию. Разработчики интегрируют свой код в транк как можно чаще — обычно раз в несколько часов — проверяя при этом успешное выполнение всех тестов. Другие agile-методики вторят этому совету.

Для адаптации непрерывной интеграции и модульного тестирования необходимо, чтобы ваша команда прониклась этими методиками. Однако часто этого недостаточно. Эти методы состоят из неавтоматизированных шагов — интеграции кода, выполнения тестов и постоянном внесении кода в репозиторий — все это может повлечь ошибки. Автоматизированная система, собирающая код и выполняющая модульные тесты, является гораздо более надежным решением.

Настройка сервера сборки

Последующая часть статьи рассматривает процесс настройки сервера сборки для ваших Java-проектов с помощью CruiseControl, программного обеспечения для управления процессами автоматической сборки (см. Ресурсы). Вам понадобится надежная машина с большим диском, но не обязательно особо мощная (вам нужны регулярные сборки, не важно, будет на них тратиться 2 минуты, или 20). Настраиваемый сервер будет работать под управлением Fedora Core 4, дистрибутива Linux, разрабатываемого открытым сообществом программистов и спонсируемого Red Hat (см. Ресурсы), так что предполагаются некоторые знания Unix. Ниже перечислены основные задачи, рассматриваемые в статье:

Начальная конфигурация

Первым делом нужно убедиться, что все необходимое ПО для разработки на Java установлено в вашей системе. Fedora Core 4 включает инструментарий Java, основанный на gcj, компиляторе Java из проекта GNU Compiler Collection (gcc), но, по соображениям совместимости, разумно будет установить JDK от IBM или Sun. Самым красивым решением является сборка и установка собственного RPM-пакета. Инструкции по сборке приведены на сайте jpackage.org (см. Ресурсы). Пакет xerces-j2 включенный в Fedora Core 4 собран некорректно, в результате реализация XSLT от Xalan отказывается работать. Потому вам будет необходимо установить обновленный пакет xerces-j2 из репозитория разработки Fedora (см. Ресурсы).

Вам, также, понадобится следующее ПО:

Для выполнения следующих шагов, вы должны быть зарегистрированы в системе как root. Вот список RPM-пакетов, которые должны быть установлены в вашей системе:

[root@fcvm ~]# ls
java-1.4.2-sun-1.4.2.08-1jpp.i586.rpm
java-1.4.2-sun-alsa-1.4.2.08-1jpp.i586.rpm
java-1.4.2-sun-demo-1.4.2.08-1jpp.i586.rpm
java-1.4.2-sun-devel-1.4.2.08-1jpp.i586.rpm
java-1.4.2-sun-fonts-1.4.2.08-1jpp.i586.rpm
java-1.4.2-sun-jdbc-1.4.2.08-1jpp.i586.rpm
java-1.4.2-sun-plugin-1.4.2.08-1jpp.i586.rpm
java-1.4.2-sun-src-1.4.2.08-1jpp.i586.rpm
xerces-j2-2.6.2-5jpp_2fc.i386.rpm
xerces-j2-demo-2.6.2-5jpp_2fc.i386.rpm
xerces-j2-javadoc-apis-2.6.2-5jpp_2fc.i386.rpm
xerces-j2-javadoc-dom3-2.6.2-5jpp_2fc.i386.rpm
xerces-j2-javadoc-impl-2.6.2-5jpp_2fc.i386.rpm
xerces-j2-javadoc-other-2.6.2-5jpp_2fc.i386.rpm
xerces-j2-javadoc-xni-2.6.2-5jpp_2fc.i386.rpm
xerces-j2-scripts-2.6.2-5jpp_2fc.i386.rpm
xmlstarlet-1.0.1-1.i586.rpm
[root@fcvm ~]#

Установите пакеты Java, Xerces, XMLStarlet и Subversion:

[root@fcvm ~]# rpm -ivh java-1.4.2-sun-1.4.2.08-1jpp.i586.rpm \
java-1.4.2-sun-alsa-1.4.2.08-1jpp.i586.rpm \
java-1.4.2-sun-devel-1.4.2.08-1jpp.i586.rpm \
java-1.4.2-sun-fonts-1.4.2.08-1jpp.i586.rpm \
java-1.4.2-sun-plugin-1.4.2.08-1jpp.i586.rpm \
java-1.4.2-sun-src-1.4.2.08-1jpp.i586.rpm

Preparing... ################################# [100%]
1:java-1.4.2-sun ################################# [ 17%]
2:java-1.4.2-sun-alsa ################################# [ 33%]
3:java-1.4.2-sun-devel ################################# [ 50%]
4:java-1.4.2-sun-fonts ################################# [ 67%]
5:java-1.4.2-sun-plugin ################################# [ 83%]
6:java-1.4.2-sun-src ################################# [100%]
[root@fcvm ~]# java -version
java version "1.4.2_08"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_08-b03)
Java HotSpot(TM) Client VM (build 1.4.2_08-b03, mixed mode)
[root@fcvm ~]# rpm -Uvh xerces-j2-2.6.2-5jpp_2fc.i386.rpm \
xerces-j2-demo-2.6.2-5jpp_2fc.i386.rpm \
xerces-j2-javadoc-apis-2.6.2-5jpp_2fc.i386.rpm \
xerces-j2-javadoc-dom3-2.6.2-5jpp_2fc.i386.rpm \
xerces-j2-javadoc-impl-2.6.2-5jpp_2fc.i386.rpm \
xerces-j2-javadoc-other-2.6.2-5jpp_2fc.i386.rpm \
xerces-j2-javadoc-xni-2.6.2-5jpp_2fc.i386.rpm \
xerces-j2-scripts-2.6.2-5jpp_2fc.i386.rpm

Preparing... ################################# [100%]
1:xerces-j2 ################################# [ 13%]
2:xerces-j2-demo ################################# [ 25%]
3:xerces-j2-javadoc-apis ################################# [ 38%]
4:xerces-j2-javadoc-dom3 ################################# [ 50%]
5:xerces-j2-javadoc-impl ################################# [ 63%]
6:xerces-j2-javadoc-other################################# [ 75%]
7:xerces-j2-javadoc-xni ################################# [ 88%]
8:xerces-j2-scripts ################################# [100%]
[root@fcvm ~]# rpm -ivh xmlstarlet-1.0.1-1.i586.rpm
Preparing... ################################# [100%]
1:xmlstarlet ################################# [100%]
[root@fcvm ~]# yum install subversion
[...]
Installed: subversion.i386 0:1.2.3-2.1
Complete!
[root@fcvm ~]#

Вам так же нужно создать на сервере нового пользователя, который будет владеть файлами и процессами CruiseControl:

[root@fcvm ~]# useradd cruise
[root@fcvm ~]# su - cruise
[cruise@fcvm ~]$ pwd
/home/cruise
[cruise@fcvm ~]$

Наконец, поскольку некоторые проекты для сборки используют Maven, вам нужно его загрузить, установить и задать соответствующие переменные окружения (см. Ресурсы) (переменная JAVA_HOME должна содержать /usr/lib/jvm/java). Положим, все дополнительные пакеты, такие как Maven и CruiseControl, мы будем устанавливать в каталог pkg. Полная инструкция по установке доступна на веб-сайте Maven, потому я не буду ее описывать:

[cruise@fcvm ~]$ mkdir pkg
[cruise@fcvm ~]$ cd pkg
[cruise@fcvm pkg]$ [установите Maven]

Установка CruiseControl

Следующая наша задача — загрузить CruiseControl (см. Ресурсы) и установить его в каталоге pkg:

[cruise@fcvm pkg]$ wget -q http://heanet.dl.sourceforge.net/\
sourceforge/cruisecontrol/cruisecontrol-2.2.1.zip

[cruise@fcvm pkg]$ unzip cruisecontrol-2.2.1.zip
Archive: cruisecontrol-2.2.1.zip
creating: cruisecontrol-2.2.1/
creating: cruisecontrol-2.2.1/contrib/
[...]
inflating: cruisecontrol-2.2.1/reporting/jsp/webcontent/xsl/testdeta
ils.xsl
inflating: cruisecontrol-2.2.1/reporting/jsp/webcontent/xsl/unittest
s.xsl
[cruise@fcvm pkg]$ rm cruisecontrol-2.2.1.zip
[cruise@fcvm pkg]$

Вам не нужно собирать CruiseControl, поскольку пакет включает собранный JAR-файл.

Теперь вы можете запустить свою первую автоматизированную сборку. Будем использовать исходный код проекта XStream в качестве начального примера (см. Ресурсы). Позже, вы научитесь добавлять проекты с локальными и удаленными репозиториями исходных кодов. CruiseControl читает информацию о проектах, которые он должен собирать, из файла config.xml в своем стартовом каталоге. В нашем случае, это домашний каталог  /home/cruise. Листинг 1 содержит простой конфигурационный файл config.xml с которого мы и начнем. Скопируйте его к себе в систему:


Листинг 1. Простой конфигурационный файл CruiseControl (config.xml) для сборки XStream
<?xml version="1.0"?>
<cruisecontrol>
<project name="xstream" buildafterfailed="false">
<listeners>
<currentbuildstatuslistener
file="log/build/xstream/status.txt"/>
</listeners>
<modificationset>
<filesystem folder="/home/cruise/force-build/xstream"/>
<svn LocalWorkingCopy="src/xstream"/>
</modificationset>
<schedule interval="3600">
<ant antscript="/usr/bin/ant"
uselogger="true"
antworkingdir="src/xstream"
multiple="1"
target="library"/>
<ant antscript="/usr/bin/ant"
uselogger="true"
antworkingdir="src/xstream"
multiple="5"
target="clean library"/>
</schedule>
<log dir="log/build/xstream"/>
<dateformat format="dd/MM/yyyy HH:mm:ss"/>
</project>
</cruisecontrol>

Конфигурационный файл CruiseControl содержит три основных блока информации для каждого собираемого проекта:

Теперь вам нужно получить исходный код XStream из репозитория проектов Subversion. Чтобы быть последовательными, загрузите все дерево исходных кодов в подкаталог xstream каталога /home/cruise/src, как указано в файле config.xml:

[cruise@fcvm pkg]$ cd
[cruise@fcvm ~]$ mkdir src
[cruise@fcvm ~]$ cd src
[cruise@fcvm src]$ svn co https://svn.codehaus.org/\
xstream/trunk/xstream

A xstream/LICENSE.txt
A xstream/continuous-integration.xml
[...]
A xstream/build.xml
U xstream
Checked out revision 614.
[cruise@fcvm src]$

Далее, настройте подкаталог force-build :

[cruise@fcvm src]$ cd ..
[cruise@fcvm ~]$ mkdir force-build
[cruise@fcvm ~]$ touch force-build/xstream
[cruise@fcvm ~]$

Последний шаг необходим, потому что CruiseControl откажется запускаться, если файл, указанный в элементе <filesystem> файла config.xml, не существует. 

Возможно, что на данном этапе не все утилиты, нужные для сборки проекта работают правильно, поскольку можно упустить из виду некоторые их зависимости. Таким образом, стоит вручную проверить правильность процесса сборки XStream:

Проблемы при сборке XStream?
При сборке XStream вы можете столкнуться с ошибкой  NoClassDefFoundError для класса  org.w3c.dom.TypeInfo. В действительности, процесс сборки прошел практически успешно. Скрипт сборки XStream выполняет задачу <junitreport> для генерации HTML-отчета о результатах тестов JUnit. Эта задача использует преобразования XSLT, из-за чего возникает ошибка в пакете xerces-j2, упомянутая в разделе Начальная конфигурация.
[cruise@fcvm ~]$ cd src/xstream
[cruise@fcvm xstream]$ ant library
Buildfile: build.xml

compile:
[mkdir] Created dir: /home/cruise/src/xstream/build/java
[echo] Java version used for compile: 1.4.2_08
[javac] Compiling 150 source files to /home/cruise/src/xstream/bui
ld/java

[...]

library:

BUILD SUCCESSFUL
Total time: 1 minute 44 seconds
[cruise@fcvm xstream]$

Когда вы будете добавлять новые проекты, вам будет нужно знать имена целей, которые используются для сборки кода и очистки его от созданных артефактов. Эту информацию нужно будет указать в файле config.xml.

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

[cruise@fcvm xstream]$ cd
[cruise@fcvm ~]$ java -jar \
pkg/cruisecontrol-2.2.1/main/dist/cruisecontrol.jar

[cc]Aug-24 20:09:31 Main - CruiseControl Version 2.2.1
[cc]Aug-24 20:09:32 trolController- projectName = [xstream]
[cc]Aug-24 20:09:32 trolController- No previously serialized project f
ound: /home/cruise/xstream
[cc]Aug-24 20:09:32 Project - Project xstream: reading settings
from config file [/home/cruise/config.xml]
[cc]Aug-24 20:09:32 BuildQueue - BuildQueue started
[cc]Aug-24 20:09:32 Project - Project xstream starting
[cc]Aug-24 20:09:32 Project - Project xstream: idle
[cc]Aug-24 20:09:32 Project - Project xstream started
[cc]Aug-24 20:09:32 Project - Project xstream: next build in 1
hours
[cc]Aug-24 20:09:32 Project - Project xstream: waiting for next
time to build
[cc]Aug-24 21:09:33 Project - Project xstream: in build queue
[cc]Aug-24 21:09:33 BuildQueue - now adding to the thread queue: xs
tream
[cc]Aug-24 21:09:33 Project - Project xstream: reading settings
from config file [/home/cruise/config.xml]
[cc]Aug-24 21:09:33 Project - Project xstream: bootstrapping
[cc]Aug-24 21:09:33 Project - Project xstream: checking for mod
ifications
[cc]Aug-24 21:09:59 Project - Project xstream: No modifications
found, build not necessary.
[cc]Aug-24 21:09:59 Project - Project xstream: Building anyway,
since build was explicitly forced.
[cc]Aug-24 21:09:59 Project - Project xstream: now building
Buildfile: build.xml
[cc]Aug-24 21:11:29 Project - Project xstream: merging accumula
ted log files
[cc]Aug-24 21:11:30 Project - Project xstream: build successful
[cc]Aug-24 21:11:30 Project - Project xstream: publishing build
results
[cc]Aug-24 21:11:30 Project - Project xstream: idle
[cc]Aug-24 21:11:30 Project - Project xstream: next build in 1
hours
[cc]Aug-24 21:11:30 Project - Project xstream: waiting for next
time to build
[завершите CruiseControl, нажав Ctrl-C]
[cruise@fcvm ~]$

Запуск CruiseControl в режиме демона

CruiseControl уже работает, но вы еще не можете запустить его в полностью автоматическом режиме. Он работает в терминальном окне, т.е пользователь cruise должен быть постоянно зарегистрирован в системе. Терминал также является единственным средством управления программой: вы можете завершить CruiseControl, нажав Ctrl+C, и перезапустить его, повторно выполнив команду. Вы не можете это сделать удаленно, не применяя средств, на подобие VNC (Virtual Network Computing). Если CruiseControl (или JVM) аварийно завершится, вам нужно будет перезапускать его вручную. А после перезагрузки машины, CruiseControl не запустится, пока вы не откроете терминал и не введете команду его запуска. Нам нужно что-то, что позволит выполнять CruiseControl как сервис, или демон, в терминологии Unix.

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

Подход, который использовал я, состоит в установке пакета daemontools Дениела Бернштайна (Daniel J. Bernstein, см. Ресурсы). Это маленький пакет программ, которые берут на себя запуск и контроль над набором сервисов. Для установки daemontools вы должны быть зарегистрированы в системе как пользователь root:

[root@fcvm ~]# mkdir -p /package
[root@fcvm ~]# chmod 1755 /package
[root@fcvm ~]# cd /package
[root@fcvm package]# wget -q http://cr.yp.to/\
daemontools/daemontools-0.76.tar.gz

[root@fcvm package]# gunzip daemontools-0.76.tar.gz
[root@fcvm package]# tar -xpf daemontools-0.76.tar
[root@fcvm package]# rm daemontools-0.76.tar
rm: remove regular file 'daemontools-0.76.tar'? y
[root@fcvm package]#

Для успешной компиляции пакета в Fedora Core 4 вам будет нужно внести маленькое изменение в исходный код. С помощью любого текстового редактора измените строку 6 файла src/error.h с extern int errno; на #include <errno.h>. Вот, как это можно сделать с помощью ed:

[root@fcvm package]# cd admin/daemontools-0.76
[root@fcvm daemontools-0.76]# ed src/error.h
595
6
extern int errno;
c
#include <errno.h>
.
wq
596
[root@fcvm daemontools-0.76]#

Теперь можно завершить установку:

[root@fcvm daemontools-0.76]# package/install
Linking ./src/* into ./compile...
Compiling everything in ./compile...
[...]
Creating /service...
Adding svscanboot to inittab...
init should start svscan now.
[root@fcvm daemontools-0.76]# ps -ef | grep svs
root 21160 1 0 16:09 ? 00:00:00 /bin/sh /command/svscanboot
root 21162 21160 0 16:09 ? 00:00:00 svscan /service
root 21173 20051 0 16:10 pts/1 00:00:00 grep svs
[root@fcvm daemontools-0.76]#

daemontools содержит программу-демон svscan, которая занимается управлением сервисами. Каждый сервис представляется подкаталогом каталога /service, так что вам нужно создать там каталог для CruiseControl. Для каждого подкаталога  в /service, svscan запускает процесс supervise.

supervise это программа, которая работает непосредственно с сервисом, таким как CruiseControl. Она запускает сервис, вызывая программу run из подкаталога сервиса (например, /service/cruisecontrol/run). Если этот процесс-потомок вдруг завершит свое выполнение, supervise его запустит повторно. Кроме того, supervise может останавливать и перезапускать свои процессы-потомки посылая им сигналы.

daemontools предоставляет два механизма для протоколирования работы сервисов. Первый — программа readproctitle, которая перехватывает вывод в стандартный файл ошибок (System.errв мире Java) и копирует его в небольшой буфер, который является частью названия процесса. Увидеть его можно с помощью команды ps:

[root@fcvm daemontools-0.76]# ps -ef | grep proctitle
root 25040 25037 0 20:58 ? 00:00:00 readproctitle service
errors: ..............................................................
......................................................................
......................................................................
......................................................................
......................................................................
..........................................................
root 25047 24006 0 20:59 pts/1 00:00:00 grep proctitle
[root@fcvm daemontools-0.76]#

При запуске буфер инициализируется точками, которые заменяются на сообщения об ошибках по мере их появления. Этот механизм удобен для маленьких объемов информации, таких как критические сообщения об ошибках. Но маленький размер буфера неудобен при больших объемах журнальной информации, кроме того эта информация не сохраняется на диске, потому ее сложно анализировать во времени. Для протоколирования больших объемов информации daemontools предлагает другой механизм — программу multilog. Он записывает строки поступающие на стандартный ввод в журнальный файл, с учетом указанных в командной строке ключей. С их помощью можно задать ротацию файлов, максимальный размер журнальных файлов, чтобы не переполнить диск и пр. Например, команда multilog /home/cruise/log протоколирует информацию в файл в каталоге /home/cruise/log, сменяет файл по достижении 99,999 байт и хранит последних 10 файлов.

multilog предназначен для работы с supervise, также как и любой другой сервис. В каталоге каждого сервиса svscan ищет подкаталог log и создает дополнительный процесс supervise для выполнения скрипта run, который там находится. Также он создает канал для передачи стандартного вывода основного процесса на стандартный ввод журналирующего процесса.

Так что же нужно сделать, чтобы daemontools управляли CruiseControl-ом? Вы должны создать структуру каталогов для него и его партнера — multilog. Далее, для каждого сервиса вы должны создать скрипт run и каталог для журнальных файлов. Сначала назовем каталог сервиса .cruisecontrol. Лидирующая точка говорит svscan игнорировать каталог, что позволит нам все настроить до первого запуска сервиса:

[cruise@fcvm ~]$ mkdir -p log/cruisecontrol
[cruise@fcvm ~]$ su -
Password: [введите пароль пользователя root]
[root@fcvm ~]# cd /service
[root@fcvm service]# mkdir .cruisecontrol
[root@fcvm service]# cd .cruisecontrol
[root@fcvm .cruisecontrol]# mkdir log
[root@fcvm .cruisecontrol]#

Теперь создайте каталог env. Содержимое этого каталога используется для установки переменных окружения CruiseControl-а и процессов, которые он будет запускать. Здесь вам нужно убедиться, что переменная JAVA_HOME содержит правильное значение. И здесь же вы задаете другие переменные, такие как MAVEN_HOME, необходимые для утилит сборки:

[root@fcvm .cruisecontrol]# mkdir env
[root@fcvm .cruisecontrol]# cd env
[root@fcvm env]# echo /usr/lib/jvm/java >JAVA_HOME
[root@fcvm env]# echo /home/cruise/pkg/maven-1.0.2 >MAVEN_HOME
[root@fcvm env]# ls
JAVA_HOME MAVEN_HOME
[root@fcvm env]# cd ..
[root@fcvm .cruisecontrol]#

В листинге 2 приведено содержимое скрипта /service/cruisecontrol/run:


Листинг 2. Содержимое /service/cruisecontrol/run
#!/bin/sh
svc=`pwd`
cd /home/cruise
exec 2>&1
exec setuidgid cruise \
envdir ${svc}/env \
java -jar pkg/cruisecontrol-2.2.1/main/dist/cruisecontrol.jar

Этот скрипт относительно прост. Он выполняет следующие действия:

  1. Сохраняет имя каталога сервиса (в нашем случае /service/cruisecontrol) для дальнейшего использования.
  2. Меняет текущий каталог на /home/cruise.
  3. Перенаправляет по каналу стандартный вывод ошибок процессу multilog, который уже подключен к стандартному выводу.
  4. Запускает JVM для CruiseControl от пользователя cruise и создает переменные окружения, считывая файлы из каталога /service/cruisecontrol/env.

Листинг 3 демонстрирует скрипт /service/cruisecontrol/log/run, который еще проще. Он запускает multilog от пользователя cruise :


Листинг 3. Содержимое /service/cruisecontrol/log/run
#!/bin/sh
exec setuidgid cruise multilog /home/cruise/log/cruisecontrol

Обратите внимание, что вы должны выполнить команду chmod для скриптов, чтобы они стали исполняемыми. Также, оба скрипта используют команду exec, которая замещает одну программу другой, не создавая при этом нового процесса. Это важно, поскольку supervise может управлять только своими непосредственными процессами-потомками. Если вы не будете использовать exec, то JVM запустится как процесс-потомок командного интерпретатора, выполнявшего скрипт. Когда supervise будет слать сигнал завершения своему процессу-потомку, его получит и завершит свою работу командный интерпретатор, а JVM продолжит свое, уже неуправляемое, выполнение. supervise об этом знать не будет и может запустить вторую копию демона — совсем не то, что вам нужно.

После настройки каталога сервиса, его нужно переименовать, исключив точку из названия. svscan автоматически запустит CruiseControl, а его вывод появится в журнальном файле:

[root@fcvm .cruisecontrol]# cd ..
[root@fcvm service]# mv .cruisecontrol cruisecontrol
[root@fcvm service]# cat /home/cruise/log/cruisecontrol/current
[cc]Aug-24 21:45:45 Main - CruiseControl Version 2.2.1
[cc]Aug-24 21:45:46 trolController- projectName = [xstream]
[cc]Aug-24 21:45:46 Project - Project xstream: reading settings
from config file [/home/cruise/config.xml]
[cc]Aug-24 21:45:47 BuildQueue - BuildQueue started
[cc]Aug-24 21:45:47 Project - Project xstream starting
[cc]Aug-24 21:45:47 Project - Project xstream: idle
[cc]Aug-24 21:45:47 Project - Project xstream started
[cc]Aug-24 21:45:47 Project - Project xstream: next build in 1
hours
[cc]Aug-24 21:45:47 Project - Project xstream: waiting for next
time to build
[root@fcvm service]#

Упрощение настройки CruiseControl

Теперь у вас есть CruiseControl, который работает в хорошо настроенной среде. Вероятно, вам нужно добавлять свои проекты в его конфигурацию. Как вы можете догадаться, все описания проектов в файле config.xml выглядят однотипно, за исключением некоторых деталей, вроде утилит необходимых для сборки проекта. Вы можете поддерживать файл config.xml вручную, используя копирование в текстовом редакторе. Но есть технология, менее подверженная ошибкам — генерация файла config.xml из более простого XML-документа с помощью таблицы стилей XSLT. Набор файлов, реализующий эту схему доступен для загрузки в виде сжатого tar-файла (см. Ресурсы). Распакуйте этот архив в каталог /home/cruise:

[cruise@fcvm ~]$ ls
config.xml force-build pkg xstream.ser
cruisecontrol.log log src
[cruise@fcvm ~]$ tar xvzf [...]/simple-cc.tar.gz
meta-config-params.xsl
meta-config.xsl
meta-config.xml
mkconfig
[cruise@fcvm ~]$ ls
config.xml meta-config-params.xsl pkg
cruisecontrol.log meta-config.xml src
force-build meta-config.xsl xstream.ser
log mkconfig
[cruise@fcvm ~]$

Упрощенный конфигурационный файл называется meta-config.xml. Этот файл преобразуется с помощью таблицы стилей meta-config.xsl в конфигурационный файл CruiseControl config.xml. Простой скрипт mkconfig выполняет преобразование с использованием установленной ранее утилиты XMLStarlet. Запустите mkconfig для перегенерации конфигурационного файла CruiseControl config.xml.

Наблюдение за сборкой

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

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

Листинг 4 содержит общий синтаксис файла meta-config.xml:


Листинг 4. Синтаксис файла meta-config.xml
<projects>
<project name="project-name" [interval="seconds"]>
<svn/>|<cvs/>
<ant/>|<maven/>
<clean>goals or targets to clean source tree</clean>
<build>goals or targets to build</build>
[<srcdir>source directory</srcdir>]
[<remote-project/>]
[<repo-dependency>groupId</repo-dependency>*]
[<srcdir-dependency>project-name</srcdir-dependency>*]
[<modificationset>CruiseControl elements</modificationset>]
</project>*
</projects>

Конфигурационный файл состоит из тегов <project>. Каждый проект имеет атрибут name. Опциональный атрибут interval переопределяет значение интервала между сборками, которое по-умолчанию равно пяти минутам. Вы должны увеличить интервал для удаленных проектов, чтобы уменьшить нагрузку на их системы управление версиями.

С помощью обязательных пустых элементов <svn/> или <cvs/> для каждого проекта задается утилита системы контроля версий, которая должна использоваться для обновления дерева исходных кодов. Кроме того, тегами <ant/> или <maven/> должна быть задана утилита сборки проекта. Проект также должен содержать два элемента, определяющих цели, используемые для очистки и сборки исходных кодов. Типичные значения для Maven, это <clean>clean</clean> и <build>jar:install-snapshot</build>. Для Ant, вам нужно будет изучить файл build.xml и найти имена целей.

Исходный код проекта должен находится в подкаталоге каталога /home/cruise/src, носящем имя проекта. Таким образом, проект, у которого атрибут name равен  my-project должен находиться в каталоге /home/cruise/src/my-project. Некоторые проекты имеют большое дерево исходных кодов, с подкаталогами, которые могут собираться отдельно; для поддержки таких проеков, секция <project> может содержать тег <srcdir>, который задает конкретный подкаталог каталога /home/cruise/src. Например:

<project name="my-utils">
<srcdir>big-project/my-utils</srcdir>
...

По-умолчанию, CruiseControl рассылает сообщения всем, кто внес изменения в код со времени последней сборки. Если вы загружаете код из удаленного репозитория, укажите тег <remote-project/>. В результате, сообщения будут отправляться по адресу указанному параметром developers-address в файле meta-config.xsl.

Зависимости между проектами

CruiseControl ничего не знает о зависимостях между проектами. У вас может существовать проект, который создает JAR-файл, содержащий вспомогательный классы, используемые многими другими проектами, но CruiseControl будет оставаться в неведении до тех пор, пока вы не объясните ему эти зависимости. Вы можете внести изменения во вспомогательные классы, что обусловит их пересборку, но проекты, зависящие от этих классов, пересобраны с новой версией вспомогательных классов не будут. Это могло бы ограничить возможности интеграционного тестирования, потому решения данной проблемы существуют.

Основной способ, предлагаемый CruiseControl, заключается в теге <filesystem>. Вы можете включать его в раздел <modificationset>, что позволит пересобирать проект в случае изменения некоторой части файловой системы. Наш первый вариант файла config.xml, приведенный в листинге 1, использует этот подход для принудительной пересборки при изменении каталога force-build. Все проекты создают или изменяют файлы в определенных местах файловой системы (например, проект вспомогательных классов в результате сборки обновит свой JAR-файл). Вы можете использовать местоположение этого файла в теге <filesystem>, чтобы инициировать пересборку проекта, который от него зависит.

Ant предоставляет большую гибкость в способе сборки проекта, потому невозможно сказать, какая часть файловой системы будет модифицирована в результате пересборки. Единственным способом точно определить это, является изучение файла build.xml каждого проекта. Тогда вы сможете добавить соответствующие теги <filesystem> в описание зависящего проекта. Упрощенный файл meta-config.xml позволяет задавать тег <modificationset>, который может содержать любые допустимые в нем элементы настройки CruiseControl. Они будут скопированы в результирующий файл config.xml. Например, проект который зависит от XStream, может включать такое описание:

<project name="my-project">
[...]
<modificationset>
<filesystem
folder="/home/cruise/src/xstream/xstream-SNAPSHOT.jar"/>
</modificationset>
</project>

Maven реализует единый процесс сборки, потому вы можете определить общие правила зависимостей проектов, собираемых с помощью Maven. Проект может определять зависимость от объектов в репозитории Maven, который создаются определенной группой. Точнее, указав <repo-dependency>classworlds</repo-dependency>, проект будет пересобран, если любой файл в каталоге /home/cruise/.maven/repository/classworlds был изменен. Предположив, что процесс сборки classworlds устанавливает полученный JAR-файл в локальный репозиторий Maven, любой проект, который включает этот элемент, будет автоматически пересобран.

Проект, также, может задавать зависимость от результатов сборки другого проекта. Указав строку <srcdir-dependency>classworlds</srcdir-dependency>, вы обуславливаете пересборку проекта при изменении любого файла в каталоге ${srcdir}/target, где ${srcdir} исходный каталог названного проекта.

Добавление проекта для сборки

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

  1. Под пользователем cruise загрузить исходный код в каталог /home/cruise/src.
  2. Проверить, что код успешно собирается вручную.
  3. Добавить описание проекта в файл meta-config.xml.
  4. Запустить ./mkconfig.
  5. Перезапустить CruiseControl, чтобы он перечитал новые описания из файла config.xml. Вы можете использовать команду ps для определения идентификатора процесса выполняющейся JVM, после чего уничтожить этот процесс с помощью команды kill. Либо выполнить от пользователя root команду svc -t /service/cruisecontrol, чтобы daemontools завершили процесс. В любом случае, supervise перезапустит CruiseControl.
  6. Опционально, обновить время модификации файла /home/cruise/force-build/${project-name}, чтобы CruiseControl принудительно выполнили пересборку проекта.

Веб-приложение CruiseControl

Работающая система CruiseControl отсылает результаты сборок разработчикам по электронной почте. Однако, возможно, есть люди, которые принимают участие в процессе разработки, но сообщения эти не получающие. Например менеджеры или тестеры. CruiseControl включает в себя простое веб-приложение, которое позволяет этим людям следить за сборками.

Веб-приложение CruiseControl работает с сервером приложений Apache Tomcat, который включен в дистрибутив Fedora Core 4. Вам будет нужно установить пакеты tomcat5 и tomcat5-admin-webapps:

[root@fcvm ~]# yum install tomcat5 tomcat5-admin-webapps
[...]
Installed: tomcat5.i386 0:5.0.30-5jpp_6fc tomcat5-admin-webapps.i386 0:5.0.30-5jpp_6fc
Dependency Installed: tomcat5-jasper.i386 0:5.0.30-5jpp_6fc
Complete!
[root@fcvm ~]#

Кроме того, необходимо установить реализацию Java Transaction API (JTA). Вы можете собрать свой RPM-пакет JTA с помощью spec-файла, который можно получить на сайте JPackage (см. Ресурсы), но проще установить пакеты geronimo-specs и geronimo-specs-compat из репозитория разработки Fedora:

[root@fcvm ~]# rpm -Uvh http://download.fedora.redhat.com/\
pub/fedora/linux/core/development/i386/Fedora/RPMS/\
geronimo-specs-1.0-0.M2.2jpp_4fc.i386.rpm

Preparing... ################################### [100%]
1:geronimo-specs ################################### [100%]
[root@fcvm ~]# rpm -Uvh http://download.fedora.redhat.com/\
pub/fedora/linux/core/development/i386/Fedora/RPMS/\
geronimo-specs-compat-1.0-0.M2.2jpp_4fc.i386.rpm

Preparing... ################################### [100%]
1:geronimo-specs-compat ################################### [100%]
[root@fcvm ~]#

Веб-приложение CruiseControl не может найти подходящую реализацию JAXP TransformerFactory в стандартной установке Tomcat, потому  вам нужно добавить преобразователь JAXP XML по-умолчанию в каталог классов endorsed:

[root@fcvm ~]# cd /usr/share/tomcat5/common/endorsed
[root@fcvm endorsed]# ln -s /usr/share/java/jaxp_transform_impl.jar \
\[jaxp_transform_impl\].jar

[root@fcvm endorsed]# ls -l
total 12
lrwxrwxrwx 1 root root 36 Sep 19 01:33 [jaxp_parser_impl].jar -> /usr
/share/java/jaxp_parser_impl.jar
lrwxrwxrwx 1 root root 39 Sep 19 01:47 [jaxp_transform_impl].jar -> /
usr/share/java/jaxp_transform_impl.jar
lrwxrwxrwx 1 root root 36 Sep 19 01:33 [xml-commons-apis].jar -> /usr
/share/java/xml-commons-apis.jar
[root@fcvm endorsed]#

Веб-приложение CruiseControl может рисовать графики важной статистики о сборках, например отношение успешных и неудавшихся сборок. Библиотеки, которые рисуют графики используют Java AWT, поэтому вам будет нужно запускать JVM в режиме headless. Для этого, откройте файл /etc/tomcat5/tomcat5.conf в редакторе и вставьте возле десятой строки:  JAVA_OPTS="-Djava.awt.headless=true".

Теперь добавьте веб-приложение CruiseControl в конфигурацию Tomcat, создав файл cruisecontrol.xml в каталоге /etc/tomcat5/Catalina/localhost. Содержимое файла приведено в листинге 5:


Листинг 5. Содержимое файла /etc/tomcat5/Catalina/localhost/cruisecontrol.xml
<Context path="/cruisecontrol"
docBase="/home/cruise/pkg/cruisecontrol-2.2.1/reporting/jsp/d
ist/cruisecontrol.war">
<Parameter name="logDir"
value="/home/cruise/log/build"
override="false"/>
<Parameter name="cacheRoot"
value="/var/cache/tomcat5/cruisecontrol"
override="false"/>
</Context>

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

Также, вам нужно создать каталог для хранения скэшированных веб-приложением CruiseControl страниц:

[root@fcvm ~]# cd /var/cache/tomcat5
[root@fcvm tomcat5]# mkdir cruisecontrol
[root@fcvm tomcat5]# chgrp tomcat cruisecontrol
[root@fcvm tomcat5]# chmod g+w cruisecontrol
[root@fcvm tomcat5]# ls -l
total 24
drwxrwxr-x 2 root tomcat 4096 Sep 16 09:32 cruisecontrol
drwxrwxr-x 2 root tomcat 4096 May 10 11:57 temp
drwxrwxr-x 3 root tomcat 4096 Sep 15 22:53 work
[root@fcvm tomcat5]#

Теперь вы можете запустить Tomcat и задать его автоматический запуск при загрузке системы. Скрипты запуска выдают предупреждения, которые можно проигнорировать:

[root@fcvm ~]# service tomcat5 start
Starting tomcat5: find: warning: you have specified the -mindepth opti
on after a non-option argument -type, but options are not positional (
-mindepth affects tests specified before it as well as those specified
after it). Please specify options before other arguments.

find: warning: you have specified the -maxdepth option after a non-opt
ion argument -type, but options are not positional (-maxdepth affects
tests specified before it as well as those specified after it). Pleas
e specify options before other arguments.

Using CATALINA_BASE: /usr/share/tomcat5
Using CATALINA_HOME: /usr/share/tomcat5
Using CATALINA_TMPDIR: /usr/share/tomcat5/temp
Using JAVA_HOME: /usr/lib/jvm/java
[ OK ]
[root@fcvm ~]# chkconfig tomcat5 on
[root@fcvm ~]# chkconfig --list tomcat5
tomcat5 0:off 1:off 2:on 3:on 4:on 5:on 6:off
[root@fcvm ~]#

Теперь вы можете воспользоваться браузером и доступиться к веб-приложению CruiseControl по адресу http://localhost:8080/cruisecontrol/. На рисунке 1 показан пример того, что вы должны увидеть:


Рис 1. Веб-приложение CruiseControl

CruiseControl Web application screenshot

Вопросы безопасности

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

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

Заключение

Эта статья содержит описание установки сервера сборки для непрерывной интеграции на базе CruiseControl. Вы установили CruiseControl и изучили, что нужно для поддержания его постоянной работы. Вы получили представление о ежедневных задачах по управлению сервером сборки. И вы вычленили наиболее важные части конфигурации, включая тип системы управления версиями, утилиты сборки и цель для сборки проекта,  в более простой XML-документ.

Вы также знаете, как задавать зависимости между собираемыми проектами. Это немного проще для проектов, которые собираются с помощью Maven, благодаря однотипности процесса сборки и разделяемого репозитория получаемых объектов. Ant позволяет индивидуально настраивать процесс сборке для каждого проекта, но если у вас есть несколько проектов, собираемых с помощью Ant и имеющих общий процесс сборки, вы можете использовать теги <filesystem>, расширяющие конфигурацию для создания межпроектных зависимостей. CruiseControl имеет множество других настроек, которые могут использоваться для улучшения процесса непрерывной интеграции. Их можно легко задействовать, добавив в рассмотренную выше таблицу стилей XSLT.

Мы поверхностно рассмотрели шаги, необходимые для запуска веб-приложения CruiseControl, но открытыми остались вопросы безопасности и надежности. Более безопасная система должна использовать веб-сервер Apache для обработки и передачи запросов Tomcat. Для увеличения надежности стоит передать контроль над Tomcat JVM системе daemontools таким же образом, как и в случае с самим CruiseControl. Кроме того, вы должны рассмотреть вопросы безопасности, связанные с запуском тестов на сервере сборки, их доступом к сети и утилитам Linux.

Цель этой статьи — сделать ваш процесс разработки более быстрым и активным, улучшить качество разрабатываемого программного обеспечения, применяя для этого подход непрерывной интеграции. Создание сервера сборок это конкретный и практический шаг в использовании agile-методик, а адаптируя другие, вы сможете добиться дальнейшего улучшения процесса разработки ПО. Рекомендую прочесть информацию об этих идеях (начните со ссылко, приведенных в разделе Ресурсы) и применять их на практике. 

Загрузки

Описание Имя Размер Метод загрузки
Утилиты из примера j-simple-cc.tar.gz 2 KB FTP
Информация о методах загрузки Загрузить Adobe® Reader®

Ресурсы

Обучение

Продукты и технологии

Обсуждения

Об авторе

Марк Уилкинсон является независимым консультантом, специализирующемся на архитектуре ПО, дизайне и процессах разработки. Он руководил небольшими командами программистов, разрабатывавших инновационные решения для различных клиентов. Марк разработал практический подход к управлению процессом разработки, который интенсивно использует автоматизацию и такие системы как CruiseControl. Он также работает над несколькими проектами в Codehaus. Марк имеет степень доктора компьютерных наук Йоркского университета.