Mono и Moonlight / Построение «правильного» процесса разработки на платформе Mono |
Здравствуйте, гость ( Вход | Регистрация )
Mono и Moonlight / Построение «правильного» процесса разработки на платформе Mono |
13.2.2012, 2:21
Сообщение
#1
|
|
Администратор Группа: Главные администраторы Сообщений: 14349 Регистрация: 12.10.2007 Из: Twilight Zone Пользователь №: 1 |
Элементарный пример цикла разработка примитивного ASP.NET (Mono) приложения с использованием Jenkins CI, по мотивам Построение «правильного» процесса разработки на платформе .NET.
Представленный пример может быть интересен широкой аудитории, т.к. легко может быть адаптирован для разработки под любую другую платформу. Вступление Эта статья никогда бы не была бы написана, если бы не статья-оригинал, которая в своё время сыграла ключевую роль в формировании моего представления о процессе разработки. И, как говориться, «пользуясь случаем хочу». Хочу поблагодарить Евгения за его замечательную статью, которая является просто замечательным стартом для начинающих разработчиков! Огромное тебе спасибо! Данная статья, по большому счету, не является чем-нибудь принципиально новым. Тот же C#-проект, те же тесты на NUnit и та же автоматизация на NAnt. Но есть нюансы. Во-первых: в качестве CI-сервера используется Jenkins CI, а во-вторых: уделено значительное внимание анализу и представлению различных метрик проекта в процессе его сборки. В статье последовательно будет описан процесс настройки рабочей среды и создания сборочно проекта, который будет автоматически отслеживать изменения в исходном коде, производить компиляцию проекта, выполнять юнит и функциональные тесты, а так же собирать метрики, такие как количество строк кода, наличие его дубликатов, наличие в исходном коде технических долгов (TODO, FIXME и т.п.) Стержнем проекта будет являтся NAnt-скрипт, который будет наращиваться по мере рассмотрения материала. На любом этапе проект является рабочим и может быть выполнен, что может оказаться очень удобно для тех кто не сумеет создать весь проект за раз либо не нуждается во всем представленном функционале (а он, откровенно говоря, в некоторых вопросах избыточен). Workspace Для настройки рабочего пространства потребуются: OS GNU/Linux (openSUSE 12.1, LXDE) Операционная система на базе которой будет развернут сервер непрерывной интеграции. CIS Jenkins CI 1.450 Сервер непрерывной интеграции. VCS Subversion 1.6.17 Централизованная система контроля версий (вместо Subversion может быть использована любая другая VCS) CLR Mono 2.6.10 Платформа под которой производится разработка. Testing NUnit 2.4.8 Инструмент для создания и выполнения тестов (юнит, неюнит — это уже зависит от того, кто будет создавать тесты). Selenium RC 2.18.0 Инструмент для выполнения функциональных тестов. Static code analyze Gendarme 2.10.0.0 Статический анализатор кода. Cloneanalyzer 2005-05-30 Утилита для поиска дубликатов кода. StyleCopCmd 0.2.1 Статический анализатор кода. Other tools NAnt 0.90 Утилита для автоматической сборки проекта. Firefox 7.0.1 Web-браузер с помощью которого будут создаваться и выполняться функциональные тесты (выполнять тесты можно и при помощи других браузеров) Selenium IDE 1.6.0 IDE для создания функциональных тестов. Для настройки рабочей среды необходимо выполнить следующие действия: 1. Скачать DVD образ и установить ОС (при выборе окружения рабочего стола указать LXDE). Строго говоря, может быть использовано и другое Desktop Environment, либо не использоваться вообще. В примере используется LXDE, что бы сделать процесс настройки проще и не более. 2. Настроить резпозитории:sudo zypper ar http://download.opensuse.org/repositories/.../openSUSE_11.4/ Mono sudo zypper ar http://pkg.jenkins-ci.org/opensuse/ Jenkins 3. Установить необходимые пакеты:sudo zypper in jenkins mono-complete mono-nunit mono-tools nant subversion-server apache2 http://www.dwheeler.com/sloccount/sloccount-2.26-1.i386.rpm 4. Скачать и установить необходимые утилиты, которые не поставляются в виде rpm-пакетов (StyleCopCmd и CloneAnalyzer). Тут есть несколько нюансов. Во-первых: использовать бинарные файлы под Linux из коробки нет возможности. Приложение в целом работает, но из-за жестко установленного разделителя пути в строке 460 файла ReportBuilder.cs файл с отчетами оказывается не совсем там, где это ожидается: private static string GetViolationsFile(string outputXmlFile) { var offp = Path.GetFullPath(outputXmlFile); var f = string.Format( CultureInfo.CurrentCulture, "{0}{1}.violations.xml", // String No 460, wrong separator here! Path.GetFullPath(Path.GetDirectoryName(offp)), Path.GetFileNameWithoutExtension(outputXmlFile)); return f; } Поправленный вариант, а так же файл конфигурации, можно скачать здесь. Во-вторых: DRY plug-in не распознает отчетов утилиты CloneAnalyze и поэтому необходимо самостоятельно преобразовать отчет CloneAnalyze в один из понятных Jenkins'y (я выбрал CPD). Примеры отчетов, а так же написанный на скорую руку конвертер с исходным кодом можно взять здесь. Создаем директория для дополнительных утилит:sudo mkdir -p /var/lib/jenkins/tools/{StyleCop,CloneAnalyzer,SeleniumRC} # 1. В папке SlyleCop размещаем файлы приложения StyleCopCmd. # ... # 2. Устанавливаем CloneAnalyzer cd /var/lib/jenkins/tools/CloneAnalyzer sudo wget http://sourceforge.net/projects/cloneanaly...ad?source=files sudo unzip CloneAnalyzerPluginInstall_20050530.zip sudo mv eclipse/plugins/CloneAnalyzer . rm -rf eclipse # 3. В одной директории с CloneAnalyzer размещаем конвертер отчетов. # ... # 4. Устанавливаем Selenium Remoute Control. cd /var/lib/jenkins/tools/SeleniumRC sudo wget http://selenium.googlecode.com/files/selen...lone-2.19.0.jar 5. Установить plug-in'ы для Jenkins'a (Jenkins -> Manage Jenkins -> Manage Plugins -> Available): Обязательно Subversion Позволяет автоматизировать операции получения исходного кода из svn-репозитория (установлен по умолчанию) NUnit Позволяет строить отчеты по результатам работы NUnit. NAnt Позволяет задавать NAnt-скрипты в качестве сборочных целей Jenkins-проекта. Static Code Analysis Необходим для DRY плагина. Task Scanner Позволяет строить отчеты о найденных в коде меток (TODO и другие). SLOCCount Позволяет строить отчеты по результатам работы утилиты SLOCCount (отображает скромные метрики кода). DocLinks Позволяет размещать на главной странице проекта ссылку на документацию к проекту. Violations Позволяет строить отчеты по результатам работы различных утилит. В данном примере используется для отображения результатов работы Gendarme и StyleCopCmd. DRY Позволяет строить отчеты о найденных дубликатах кода. <a href="https://wiki.jenkins-ci.org/display/JENKINS/ Seleniumhq+Plugin">Seleniumhq Размещает ссылки на отчет Selenium. Warnings Позволяет строить отчеты, отображая предупреждения компилятора. Рекомендовано: JobConfigHistory Хранит историю изменений настроек проекта. Backup Позволяет упростить процесс создания резервной копии сервера. Опционально: Green Balls Заменяет синий шарик на зеленый. Next Build Number Позволяет устанавливать произвольный номер сборки. Sidebar-Link Позволяет создавать ссылки на главной странице сервера и на страницах проектов. Описание демонстрационного проекта К сожалению придумать простой, но в то же время не перегруженный логикой предметной области и удобный для тестирования проект я не сумел. Представленный проект прост до неприличия — два поля ввода, две кнопки («Сумма» и «Конкатенация») и результат. Для создания приложения создано решение (solution), включающее в себя три проекта:
Создание сборочного скрипта и настройка инструментов В первую очередь необходимо создать Jenkins-проект, для чего необходимо через web-интерфейс, доступный по адресу: http://localhost:8080 (если Jenkins установлен на локальном компьютере), перейти по ссылке New Job, выбрать тип проекта Build a free-style software project, ввести имя проекта и создать его. Проект создан. Как и упоминалось ранее стержнем сборочного проекта будет NAnt-скрипт, для этого необходимо создать в секции Build, цель, которая будет вызывать скрипт:Вообще, может быть несколько подходов к организации проекта, которые имеют свои преимущества и недостатки. В примере все действия помещены в один NAnt-скрипт, который вызывается одной командой в Jenkins-проекте. Это удобно тем, что сборку очень легко произвести минуя Jenkins, достаточно просто выполнить NAnt-скрипт. Но не всегда удобно изменять процесс сборки (сначала нужно внести изменение в NAnt-скрипт, затем выполнить коммит и только тогда процесс сборки обновиться). В противовес этому подходу можно создавать в Jenkins-проекте много целей по выполнению bash-скриптов и всю логику сборки разместить в них. В таком случае удобно редактировать процесс сборки, но выполнить сборку вне Jenkins будет нельзя. Приступим к созданию Nant-скрипта, который имеет следующий вид: <?xml version="1.0"?> <project name="Example" default="cis" basedir="."> <!-- Property --> <!--Targets --> <target name="cis" description="Execute all targets in CIS."> <call target="clean" /> <call target="build" /> <call target="documentation" /> <call target="utest" /> <call target="gendarme" /> <call target="stylecop" /> <call target="sloccount" /> <call target="cloneanalyze" /> <call target="ftest" /> </target> </project> Т.е. сначала объявляются свойства (Property), затем объявляются цели (Target) и в заключении объявляется главная цель (её имя указывается в свойстве default скрипта), которая поочередно вызывает объявленные ранее. Описанный способ не единственный, вместо создания цели вызывающей другие, можно просто прописывать зависимость одних целей от других и тогда вызов целей будет производится автоматически. Далее будут реализованы все цели, которые вызывает цель cis. На любом этапе скрипт может быть выполнен, для чего в главной цели (cis) необходимо закомментировать еще нереализованные цели и неиспользуемые свойства. Для простоты объявим свойства, которые в дальнейшем сократят нам код. Переменная окружения устанавливаемая Jenkins'ом: <property name="work.d" value="${environment::get-variable('WORKSPACE')}" /> Директория в которой собраны инструменты: <property name="tools.d" value="/var/lib/jenkins/tools" /> Алиасы различных директорий, назначение которых очевидно из названия: <property name="bin.d" value="${build.conf}/bin"/> <property name="deploy.d" value="/home/vm/public_html" /> <property name="test.res.d" value="test-results" /> <property name="report.d" value="${work.d}/reports" /> <property name="doc.d" value="${work.d}/doc" /> <property name="core.d" value="${work.d}/ExampleCore" /> <property name="gui.d" value="${work.d}/ExampleGUI" /> <property name="utest.d" value="${work.d}/ExampleUTest" /> <property name="ftest.d" value="${work.d}/ExampleFTest" /> Алиасы бинарного файла и файла настроек StyleCopCmd: <property name="style.exe" value="${tools.d}/StyleCop/Net.SF.StyleCopCmd.Console.exe" /> <property name="style.conf" value="${tools.d}/StyleCop/Settings.StyleCop" /> Алиасы исполняемого файла, конвертера и файла конфигурации CloneAnalyzer: <property name="clone.jar" value="${tools.d}/CloneAnalyzer/CloneAnalyzer.jar" /> <property name="clone.conf" value="${tools.d}/CloneAnalyzer/comments.conf" /> <property name="clone.conv" value="${tools.d}/CloneAnalyzer/ca2cpd.exe" /> Алиасы исполняемого файла, обёрточного скрипта, а так же файла с набором тестов и именем хоста на котором развернуто приложение для SeleniumRC: <property name="selen.jar" value="${tools.d}/SeleniumRC/selenium-server-standalone-2.18.0.jar" /> <property name="selen.sh" value="${tools.d}/SeleniumRC/selenium.sh" /> <property name="selen.host" value="http://192.168.56.210" /> <property name="selen.suite" value="${ftest.d}/Main.html" /> Приступим к созданию целей. 1. Первым делом создадим цель по очистке сборочной директории от старых артефактов и созданию необходимых директорий: <target name="clean" description="Remove binary files, recreate report directory."> <echo message="Target starded at: ${datetime::now()}."/> <delete failonerror="false" dir= "${core.d}/${bin.d}"/> <delete failonerror="false" file="${core.d}/ExampleCore.pidb"/> <delete failonerror="false" dir= "${utest.d}/${bin.d}"/> <delete failonerror="false" dir= "${utest.d}/${test.res.d}"/> <delete failonerror="false" file="${utest.d}/ExampleUTest.pidb"/> <delete failonerror="false" dir= "${gui.d}/${bin.d}"/> <delete failonerror="false" dir= "${gui.d}/${test.res.d}"/> <delete failonerror="false" file="${gui.d}/ExampleGUI.pidb"/> <delete failonerror="false" dir= "${report.d}"/> <delete failonerror="false" dir= "${doc.d}"/> <delete failonerror="false" file="${work.d}/stylecop.report"/> <delete failonerror="false" file="${work.d}/stylecop.violations.xml"/> <mkdir dir="${report.d}"/> <mkdir dir="${report.d}/gendarme"/> <mkdir dir="${report.d}/sloccount"/> <mkdir dir="${report.d}/cloneanalyzer"/> <mkdir dir="${report.d}/selenium"/> <mkdir dir="${doc.d}/xml"/> <mkdir dir="${doc.d}/html"/> <echo message="Target completed at: ${datetime::now()}."/> </target> 2. Вторым шагом могло бы быть получения обновлений из репозитория. Поскольку эта операция выполняется Jenkins'ом, то в данном примере NAnt-скрипт её не содержит, но если бы в ней была необходимость, то её место здесь. Создадим и настроим репозиторий Subversion:su a2enmod dav a2enmod dav_svn a2enmod mod_authz_svn cd /srv/www/htdocs wget http://tortoisesvn.googlecode.com/svn/trun...enucheckout.ico wget http://tortoisesvn.googlecode.com/svn/trun...ex/svnindex.css wget http://tortoisesvn.googlecode.com/svn/trun...ex/svnindex.xsl mkdir -p /srv/svn/{repos,user_access,html} cat > /etc/apache2/conf.d/subversion.conf << EOF <IfModule mod_alias.c> Alias /repos "/srv/svn/html" </IfModule> <Directory /srv/svn/html> Options +Indexes +Multiviews -FollowSymLinks IndexOptions FancyIndexing ScanHTMLTitles NameWidth=* DescriptionWidth=* SuppressLastModified SuppressSize order allow,deny allow from all </Directory> <Location /repos/Example> DAV svn SVNListParentPath on SVNPath /srv/svn/repos/Example SVNIndexXSLT "/svnindex.xsl" AuthType Basic AuthName "Subversion" AuthUserFile /srv/svn/user_access/passwdfile AuthGroupFile /srv/svn/user_access/groupfile AuthzSVNAccessFile /srv/svn/user_access/accessfile Require valid-user </Location> EOF cd /srv/svn/repos svnadmin create --fs-type fsfs Example mkdir -p /srv/svn/repos/Example/dav chown -R wwwrun:www Example/{dav,db,locks} touch /srv/svn/user_access/passwdfile chown root:www /srv/svn/user_access/passwdfile chmod 640 /srv/svn/user_access/passwdfile touch /srv/svn/user_access/groupfile cat > /srv/svn/user_access/groupfile << EOF Example_commiters: Admin User Example_readers: Admin User CIS touch /srv/svn/user_access/accessfile cat > /srv/svn/user_access/accessfile << EOF [groups] admin = Admin user = User cis = CIS [/] * = @admin = rw [Example:/] @user = rw @cis = r /sbin/service apache2 restart exit После этого настроим Subversion плагин: А так же зададим периодичность сборки (производить сборку при наличии обновлений, наличие которых проверять каждый час в рабочие дни недели): 3. Создадим цель которая будет осуществлять компиляцию с генерацию документации в формате xml подпроектов ExampleCore и ExampleGUI: <target name="build" description="Compiles the source code."> <echo message="Target starded at: ${datetime::now()}."/> <echo message="Building ExampleCore."/> <csc codepage="utf8" target="library" output="${core.d}/${bin.d}/${build.conf}/ExampleCore.dll" doc="${doc.d}/xml/ExampleCore.xml"> <sources> <include name="${core.d}/**.cs"/> </sources> </csc> <copy file="${core.d}/${bin.d}/${build.conf}/ExampleCore.dll" tofile="${gui.d}/${bin.d}/${build.conf}/ExampleCore.dll" /> <copy file="${core.d}/${bin.d}/${build.conf}/ExampleCore.dll" tofile="${utest.d}/${bin.d}/${build.conf}/ExampleCore.dll" /> <echo message="Building ExampleGUI."/> <csc codepage="utf8" target="library" output="${gui.d}/${bin.d}/${build.conf}/ExampleGUI.dll" doc="${doc.d}/xml/ExampleGUI.xml"> <sources> <include name="${gui.d}/**.cs" /> </sources> <references> <include name="System.Web.dll" /> <include name="${gui.d}/${bin.d}/${build.conf}/ExampleCore.dll" /> </references> </csc> <echo message="Target completed at: ${datetime::now()}." /> </target> Настроим плагин Warnings таким образом, что бы сообщения компилятора обрабатывались Jenkins'ом: В дальнейшем это позволит получать вот такие отчеты по Warning'ам компилятора: 4. Сгенерируем документацию в формате html: <target name="documentation" description="Generation documentation."> <echo message="Target starded at: ${datetime::now()}."/> <exec program="monodocer" commandline=" -pretty -i:${doc.d}/xml/ExampleCore.xml -assembly:${core.d}/${bin.d}/${build.conf}/ExampleCore.dll -path:${doc.d}/xml"/> <exec program="monodocer" commandline=" -pretty -i:${doc.d}/xml/ExampleGUI.xml -assembly:${gui.d}/${bin.d}/${build.conf}/ExampleGUI.dll -path:${doc.d}/xml"/> <exec program="mdoc" commandline="export-html ${doc.d}/xml -o=${doc.d}/html"/> <echo message="Target completed at: ${datetime::now()}." /> </target> Настроим плагин DocLinks:В результате на главной странице проекта будет создана ссылка на документацию. 5. Соберём и запустим юнит-тесты: <target name="utest" description="Test the source code."> <echo message="Target starded at: ${datetime::now()}."/> <echo message="Building ExampleUTest."/> <csc codepage="utf8" target="library" output="${utest.d}/${bin.d}/${build.conf}/ExampleUTest.dll"> <sources> <include name="${utest.d}/**.cs" /> </sources> <references> <include name="System.Web.dll" /> <include name="${gui.d}/${bin.d}/${build.conf}/ExampleCore.dll" /> <include name="nunit.core.dll" /> <include name="nunit.framework.dll" /> </references> </csc> <echo message="Launch NUnit." /> <nunit2 haltonfailure="false"> <formatter type="Xml" usefile="true" extension=".xml" outputdir="${utest.d}/${test.res.d}" /> <formatter type="Plain" usefile="false" /> <test assemblyname="${utest.d}/${bin.d}/${build.conf}/ExampleUTest.dll" /> </nunit2> <echo message="Target completed at: ${datetime::now()}." /> </target> Настроим плагин NUnit: Отчеты плагина NUnit выглядят следующим образом: 6. Выполним статический анализ кода при помощи Gendarme: <target name="gendarme"> <echo message="Target starded at: ${datetime::now()}."/> <echo message="Check code by Gendarme."/> <exec program="gendarme" failonerror="false" commandline=" --config GendarmeRules.xml ${core.d}/${bin.d}/${build.conf}/ExampleCore.dll --xml ${report.d}/gendarme/ExampleCore.gendarme.xml --severity medium+ --confidence total"/> <exec program="gendarme" failonerror="false" commandline=" --config GendarmeRules.xml ${gui.d}/${bin.d}/${build.conf}/ExampleGUI.dll --xml ${report.d}/gendarme/ExampleGUI.gendarme.xml --severity medium+ --confidence total"/> <echo message="Target completed at: ${datetime::now()}." /> </target> … и StyleCopCmd: <target name="stylecop"> <echo message="Target starded at: ${datetime::now()}."/> <exec program="mono" commandline=" ${style.exe} -r -sc ${style.conf} -d ${work.d} -of ${work.d}/stylecop/stylecop.report"/> <echo message="Target completed at: ${datetime::now()}." /> </target> Что бы избавиться ошибки, вызываемой StyleCopCmd:While saving registry data at /etc/mono/2.0/../registry/last-btime: System.UnauthorizedAccessException: Access to the path "/etc/mono/registry/last-btime" is denied. at System.IO.FileStream..ctor (System.String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean anonymous, FileOptions options) [0x00000] in <filename unknown>:0 at System.IO.FileStream..ctor (System.String path, FileMode mode, FileAccess access, FileShare share) [0x00000] in <filename unknown>:0 at (wrapper remoting-invoke-with-check) System.IO.FileStream:.ctor (string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare) at System.IO.StreamWriter..ctor (System.String path, Boolean append, System.Text.Encoding encoding, Int32 bufferSize) [0x00000] in <filename unknown>:0 at System.IO.StreamWriter..ctor (System.String path, Boolean append, System.Text.Encoding encoding) [0x00000] in <filename unknown>:0 at (wrapper remoting-invoke-with-check) System.IO.StreamWriter:.ctor (string,bool,System.Text.Encoding) at Microsoft.Win32.KeyHandler.SaveRegisteredBootTime (System.String path, Int64 btime) [0x00000] in <filename unknown>:0 Создадим вожделенный файл с правами на запись всем желающим:sudo touch /etc/mono/registry/last-btime sudo chmod 666 /etc/mono/registry/last-btime Настроим плагин Violations: Так будут выглядеть отчеты: Тут есть несколько неприятных моментов: во-первых: для того, что бы успешно отображался детализированный отчет по StyleCop отчет должен лежать в корне проекта (что нарушает общую тенденцию), а во-вторых: детализированный отчет по Gendarme мне так и не удалось настроить (кто сталкивался — прошу помощи). 7. Собираем метрики: <target name="sloccount"> <echo message="Target starded at: ${datetime::now()}."/> <echo message="Analyze code by SLOCCount."/> <exec program="sloccount" output="${report.d}/sloccount/sloccount.report" commandline=" --duplicates --wide --details ${work.d}"/> <echo message="Target completed at: ${datetime::now()}." /> </target> Настроим плагин SLOCCount: Пример отчета: 8. Выполняем поиск дубликатов в два этапа: сначала запустим приложение CloneAnalyzer, а потом выполним конвертацию полученного отчета: <target name="cloneanalyze"> <echo message="Target starded at: ${datetime::now()}."/> <echo message="Find code duplicates by CloneAnalyze."/> <exec program="java" failonerror="false" output="${report.d}/cloneanalyzer/cloneanalyzer.report.txt" commandline=" -jar ${clone.jar} -c ${clone.conf} -f .*.(cs|aspx) -d ${work.d}"/> <echo message="Convert CloneAnalyze report in CPD report."/> <exec program="mono" failonerror="false" commandline=" ${clone.conv} ${report.d}/cloneanalyzer/cloneanalyzer.report.txt ${report.d}/cloneanalyzer/cloneanalyzer.report.xml"/> <echo message="Target completed at: ${datetime::now()}." /> </target> Настроим плагин DRY: Пример отчета: 9. Выполним функциональные тесты, для чего сначала развернем приложение, перезапустим web-сервер и собственно запустим тесты: <target name="ftest"> <echo message="Target starded at: ${datetime::now()}."/> <echo message="Prepare to launch tests."/> <copy todir="${deploy.d}/${bin.d}/"> <fileset basedir="${gui.d}/${bin.d}/${build.conf}"> <include name="*.dll"/> </fileset> </copy> <copy todir="${deploy.d}/"> <fileset basedir="${gui.d}/"> <include name="*.aspx"/> <include name="*.asax"/> <include name="*.config"/> </fileset> </copy> <echo message="Restart apache2 server."/> <exec program="/bin/bash" commandline="-c 'sudo /etc/init.d/apache2 restart'"/> <echo message="Testing project by Selenium."/> <exec program="${selen.sh}" failonerror="false" commandline=" -htmlSuite *firefox ${selen.host} ${selen.suite} ${report.d}/selenium/selenium.html"/> <echo message="Target completed at: ${datetime::now()}." /> </target> Для того, что бы пользователь jenkins мог выполнять перезапуск web-сервера, ему необходимо дать соответствующие права:su cat > /etc/sudoers << EOF jenkins ALL=(ALL) NOPASSWD: /etc/init.d/apache2 EOF exit Для запуска тестов создадим скрип-обёртку, который будет устанавливать необходимые переменные окружения и транслировать через себя параметры командной строки Selenium-серверу:cd /var/lib/jenkins/tools/SeleniumRC touch selenium.sh chmod +x selenium.sh cat > selenium.sh << EOF #!/bin/bash export $(dbas-launch) export NSS_USE_SHARED_DB=ENABLE export DISPLAY=:0 java -jar /var/lib/jenkins/tools/SeleniumRC/selenium-server-standalone-2.18.0.jar $@ EOF Настроим Apache. Отредактируем файл /etc/apache/conf.d/mod_mono и укажем расположение приложения:<IfModule !mod_mono.c> LoadModule mono_module /usr/lib/apache2/mod_mono.so </IfModule> MonoAutoApplication disabled AddHandler mono .aspx .ascx .asax .ashx .config .cs .asmx .axd MonoApplications "/:/home/vm/public_html" AddType application/x-asp-net .aspx AddType application/x-asp-net .asmx AddType application/x-asp-net .ashx AddType application/x-asp-net .asax AddType application/x-asp-net .ascx AddType application/x-asp-net .soap AddType application/x-asp-net .rem AddType application/x-asp-net .axd AddType application/x-asp-net .cs AddType application/x-asp-net .vb AddType application/x-asp-net .master AddType application/x-asp-net .sitemap AddType application/x-asp-net .resources AddType application/x-asp-net .skin AddType application/x-asp-net .browser AddType application/x-asp-net .webinfo AddType application/x-asp-net .resx AddType application/x-asp-net .licx AddType application/x-asp-net .csproj AddType application/x-asp-net .vbproj AddType application/x-asp-net .config AddType application/x-asp-net .Config AddType application/x-asp-net .dll DirectoryIndex index.aspx DirectoryIndex Default.aspx DirectoryIndex default.aspx И создадим конфигурационный файл приложения /etc/apache2/conf.d/Example:Alias / "home/vm/public_html" MonoServerPath Example "/usr/bin/mod-mono-server2" MonoSetEnv Example MONO_IOMAP=all MonoApplications Example "/:/home/vm/public_html" <Location "/"> Allow from all Order allow,deny MonoSetServerAlias Example SetHandler mono SetOutputFilter DEFLATE SetEnvIfNoCase Request_URI ".(?:gif|jpe?g|png)$" no-gzip dont-vary </Location> su cat > /etc/sudoers << EOF jenkins ALL=(ALL) NOPASSWD: /etc/init.d/apache2 EOF exit Настроим плагин Selenium: Пример отчета (Jenkins просто отображает отчет Selenium'a один к одному):На этом формирование NAnt-скрипта закончено. 10. Так же как и задача получения исходного кода из репозитория, так же и задача сканирования кода на предмет открытых задач вызывается непосредственно из Jenkins (минуя Nant-скрипт). Настроим плагин Task Scanner: Пример отчета: Сборочный проект настроен и готов к запуску. Тюнинг Буквально в двух словах хотелось бы остановиться на некоторых других плагинах (коих есть огромное количество). Backup — назначение плагина очевидно из его названия, а его настройка тривиальна. Его описание излишне, т.к. Backup — это самое первое о чем стоит побеспокоиться! JobConfigHistory — бывает в процессе настройки внесенные изменение в конфигурацию проекта оказываются неудачными и для того, что бы легко вернуться к предыдущей версии необходимо самостоятельно принимать мероприятия по сохранению предыдущей версии. Данные плагин ведет историю изменений и позволяет без труда определить внесенные изменения. Green Balls — по умолчанию для отображения статуса Jenkins использует три цвета: красный, желтый и синий. Данный плагин позволяет заменить синий цвет на зеленый. Практическая ценность этого плагина весьма сомнительна, а вот эстетическую переоценить тяжело! Next Build Number — позволяет устанавливать номер следующей сборки. Удобно в случаях, когда при настройке выполняется несколько сборок, которые затем удаляются, а в нумерации образуется дыра. Либо в тех случаях, когда нужно форсировано задать номер версии (например для релиза). Sidebar-Link — очень любопытный плагин. Позволяет размещать ссылки на главной странице или на страницах проектов. Когда это может быть полезно. Например на главной странице можно разместить ссылку на какой-нибудь корпоративный ресурс, базу знаний или ещё что-нибудь (не забываем, что контент размещенный в директории userContent отображается Jenkinso'ом автоматически).Для создания ссылки на главной странице необходимо выполнить настройку сервера (а не проекта): В результате на главной странице появиться ссылка Important: На странице проекта можно разместить ссылку на ресурс специфический для данного проекта (например на svn-репозиторий), или, что может оказаться более полезным, на отчет какой-нибудь утилиты, для которой нет соответствующего Jenkins-плагина. Для создания ссылки на странице проекта, необходимо выполнить его настройку: Обратите внимание на то, что файлы иконок можно загружать на сервер только через настройки сервера, в настройках проекта эта функция отсутствует. Вот так будет выглядеть ссылка Subversion на странице проекта. Вот так в заключении будет выглядеть страница проекта: А вот так страница отчета по билду: Пространные рассуждения (вместо нормального заключения) Конечно же приведенный пример идеализирован. Во-первых: представленный пример не содержит БД, что крайне редко встречается в жизни и лишает сборочный проект занимательной задачи по поддержанию БД в корректном состоянии (то ли всегда ее собирать из скриптов лежащих под контролем, то ли держать под контролем непосредственно бинарный файл, то ли накатывать на бинарный файл подконтрольные скрипты). Во-вторых: выполнять сборку на CI Servere очень часто может быть не достаточно, в большинстве случаев целесообразно создавать Matrix-проект поэтому операция развертывания приложения может оказаться несколько сложнее. В-третьих: Юнит-тесты наверное правильнее выполнять в тестовом окружении, а не на билд-сервере. В примере не рассмотрен ни один из нотификационных плагинов. На практике же их использование может оказаться необходимо. В конце-концов на CI Servere может не оказаться X-сервера механизм запуска функциональных тестов в таком случае несколько изменится (на при мер). Чего хотелось бы еще. Больше всего хочется Pre-Tested Commit. Хотелось бы анализатор покрытия кода тестами. Очень хочется сборщик метрик с более широкими параметрами. Количество строк кода, написанного на C# это конечно же круто, но хотелось бы видеть информацию о цикломатической сложности и степени связности, а возможно и о чем-нибудь еще. Кстати дефолтная IDE с задачей сбора метрик справляется значительно лучше представленной в приложении утилиты. На вкладке Metrics Monodevelop можно увидеть следующую информацию: P.S. Ну и в самом конце, хотелось бы пригласить всех тех, кто предпочитает узнавать об ошибках не через месяц после коммита от заказчика, а на следующий день от билд-сервера, поделиться своим опытом и высказать замечания к представленном примеру. Original source: habrahabr.ru (comments, light). Читать дальше -------------------- |
|
|
Текстовая версия | Сейчас: 28.3.2024, 21:29 | |