Прежде чем начинать все устанавливать, настраивать и улучшать, скажем несколько слов о непрерывной интеграции в принципе. Постоянная интеграция — это практика, которая позволяет как можно быстрее выявить возможные интеграционные проблемы в проекте. Это достигается благодаря частым автоматизированным сборкам проекта. Как правило, участие человека здесь сводится к минимуму: на отдельном сервере по мере коммита нового кода в центральный репозиторий, запускаются различные тесты, которые могут сказать появились ли вместе с нововведениями какие-то проблемы.
Если это первый проект, который вы подключаете к серверу непрерывной интеграции, то скорее всего стоит использовать CruiseControl с установленным дополнением phpUnderControl. Для PHP-проектов такая конфигурация является (или покрайней мере являлась) своеобразном стандартом.
Переходим от слов к делу. Нам понадобится один сервер, свежие версии CruiseControl и phpUnderControl, Subversion (в нашем примере будет использована эта система контроля версий), пакеты sun-java6-jre, sun-java6-jdk. Кроме того далее будут упоминаться различные утилиты, которые также потребуется установить на сервере CI.
Начнем с установки CruiseControl:
unzip cruisecontrol-bin-2.8.4.zip -d /opt
ln -s /opt/cruisecontrol-bin-2.8.4 /opt/cruisecontrol
Чтобы это приложение можно было легче запускать, останавливать и перезапускать, пригодится следующий скрипт, который изначально был опубликован в этой статье. #!/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin: . /lib/lsb/init-functions JAVA_HOME=/usr NAME=cruisecontrol DAEMON=/opt/cruisecontrol/cruisecontrol.sh PIDFILE=/opt/cruisecontrol/cc.pid test -x $DAEMON || exit 5 RUNASUSER=cruisecontrol UGID=$(getent passwd $RUNASUSER | cut -f 3,4 -d:) || true case $1 in start) log_daemon_msg "Starting Cruisecontrol server" "cc" if [ -z "$UGID" ]; then log_failure_msg "user \"$RUNASUSER\" does not exist" exit 1 fi cd /opt/cruisecontrol/ ./cruisecontrol.sh > /dev/null 2>&1 log_end_msg $? ;; stop) log_daemon_msg "Stopping Cruisecontrol server" "cc" start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE log_end_msg $? rm -f $PIDFILE ;; restart|force-reload) $0 stop && sleep 2 && $0 start ;; status) pidofproc -p $PIDFILE $DAEMON >/dev/null status=$? if [ $status -eq 0 ]; then log_success_msg "Cruisecontrol server is running." else log_failure_msg "Cruisecontrol server is not running." fi exit $status ;; *) echo "Usage: $0 {start|stop|restart|force-reload|status}" exit 2 ;; esacЭтот скрипт нужно поместить в /etc/init.d/cruisecontrol и установить права на исполнение. Нужно также обратить внимание на пользователя
RUNASUSER=cruisecontrol.Приступаем к установке phpUnderControl, и здесь все сводится к выполнению нескольких команд:
pear channel-discover components.ez.no
pear channel-discover pear.phpundercontrol.org
pear install --alldeps phpuc/phpUnderControl-beta
/usr/bin/phpuc install /opt/cruisecontrol
Проверим, что наш сервер постоянной интеграции запускается, запускаем его /etc/init.d/cruisecontrol start и смотрим в браузере http://localhost:8080/cruisecontrol/.Теперь займемся конфигурацией самого проекта. У CruiseControl конфигурация всех проектов хранится в одном файле config.xml. Установим наш проект:
<cruisecontrol> <project name="Example" buildafterfailed="false"> <plugin name="svnbootstrapper" classname="net.sourceforge.cruisecontrol.bootstrappers.SVNBootstrapper" /> <plugin name="svn" classname="net.sourceforge.cruisecontrol.sourcecontrols.SVN" /> <plugin name="phing" classname="net.sourceforge.cruisecontrol.builders.PhingBuilder" /> <listeners> <currentbuildstatuslistener file="logs/${project.name}/status.txt" /> </listeners> <bootstrappers> <svnbootstrapper localWorkingCopy="projects/${project.name}/source/" /> </bootstrappers> <modificationset quietperiod="0"> <svn localWorkingCopy="projects/${project.name}/source/" /> </modificationset> <schedule interval="120"> <phing buildfile="projects/${project.name}/source/build-development.xml" uselogger="true" usedebug="false" /> </schedule> <log dir="logs/${project.name}"> <merge dir="projects/${project.name}/source/" /> </log> <publishers> <artifactspublisher dir="projects/${project.name}/build/coverage" dest="logs/${project.name}" subdirectory="coverage" /> <artifactspublisher dir="projects/${project.name}/public/apidocs" dest="logs/${project.name}" subdirectory="api" /> <execute command="/usr/bin/phpuc graph logs/${project.name}" /> <htmlemail mailhost="xx.xx.xx.xx" returnaddress="noreply@example.com" buildresultsurl="http://localhost:8080/buildresults/${project.name}" returnname="phpUnderControl server" logdir="logs/${project.name}"> <failure address="fail@example.com" reportWhenFixed="true" /> </htmlemail> </publishers> </project> </cruisecontrol>Обращу внимание на самое главное, исходных код будет располагаться в
projects/example/source. Здесь же мы должны самостоятельно выполнить checkout проекта. Директивами svn, svnbootstrapper мы указываем, чтобы CruiseControl выполнял в каталоге с исходным кодом svn up. По мере появления новых изменений (в данном случае из центрального svn-репозитория) будет запущен процесс сборки проекта. Для сборки мы используем Phing и скрипт похожий на тот, который обсуждали в прошлом посте. Секция publishers помимо прочего содержит настройки для отправки уведомлений в случае неудачного билда.Теперь стоит взглянуть на сам build-скрипт. Мы немного его дополним: добавим задачу по запуску проверки кода на «дурные запахи», поиск дублирования кода, и т.д.
<?xml version="1.0" encoding="UTF-8"?> <project name="Example" default="default"> <property name="build.dir" value="." /> <!-- ============================================ --> <!-- (DEFAULT) Target: default --> <!-- ============================================ --> <target name="default" depends="run.tests, run.mess.detector, run.copypast.detector, run.phpcodesniffer, api.docs"> <echo msg="All done." /> </target> <!-- ============================================ --> <!-- Target: api.docs --> <!-- ============================================ --> <target name="api.docs"> <phpdoc title="API Documentation" destdir="${build.dir}/public/apidocs" sourcecode="false" templatebase="/usr/share/php/data/phpUnderControl/data/phpdoc" output="HTML:Phpuc:phpuc"> <fileset dir="${build.dir}/classes"> <include name="**/*.php" /> </fileset> </phpdoc> </target> <!-- ============================================ --> <!-- Target: run.tests --> <!-- ============================================ --> <target name="run.tests"> <phpunit haltonfailure="true" haltonerror="true"> <formatter type="xml" usefile="true" todir="${build.dir}/build/phpunit" /> <formatter type="plain" usefile="false" /> <batchtest> <fileset dir="${build.dir}/tests"> <include name="*Test.php" /> </fileset> </batchtest> </phpunit> </target> <!-- ============================================ --> <!-- Target: run.mess.detector --> <!-- ============================================ --> <target name="run.mess.detector"> <phpmd> <fileset dir="${build.dir}/classes"> <include name="**/*.php" /> </fileset> <formatter type="xml" outfile="${build.dir}/build/phpmd/phpmd.xml" /> <formatter usefile="false" type="text" /> </phpmd> </target> <!-- ============================================ --> <!-- Target: run.copypast.detector --> <!-- ============================================ --> <target name="run.copypast.detector"> <phpcpd> <fileset dir="${build.dir}/classes"> <include name="**/*.php" /> </fileset> <formatter type="pmd" outfile="${build.dir}/build/phpcpd/phpcpd.xml" /> <formatter usefile="false" type="default" /> </phpcpd> </target> <!-- ============================================ --> <!-- Target: run.phpcodesniffer --> <!-- ============================================ --> <target name="run.phpcodesniffer"> <phpcodesniffer standard="Zend" showSniffs="true" showWarnings="true"> <fileset dir="${build.dir}/classes"> <include name="**/*.php" /> </fileset> <formatter type="checkstyle" outfile="${build.dir}/build/phpcodesniffer/phpcodesniffer.xml" /> <formatter type="summary" usefile="false" /> </phpcodesniffer> </target> </project>Этот скрипт мы можем проверить, запустив самостоятельно
phing -f build-development.xml. Конечно, чтобы все это работало, нужно установить phpdoc, phpcs, phpunit и xdebug.Теперь можно выполнить несколько тестовых коммитов и понаблюдать за статистикой новых build'ов. Можно даже что-то специально сломать, чтобы проверить, как сервер непрерывной интеграции сообщит о проблеме.
0 коммент.:
Отправить комментарий