<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.linuxformat.ru/wiki/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://wiki.linuxformat.ru/wiki/index.php?action=history&amp;feed=atom&amp;title=LXF129%3ACijoe</id>
		<title>LXF129:Cijoe - История изменений</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.linuxformat.ru/wiki/index.php?action=history&amp;feed=atom&amp;title=LXF129%3ACijoe"/>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/index.php?title=LXF129:Cijoe&amp;action=history"/>
		<updated>2026-05-13T00:16:38Z</updated>
		<subtitle>История изменений этой страницы в вики</subtitle>
		<generator>MediaWiki 1.19.20+dfsg-0+deb7u3</generator>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/index.php?title=LXF129:Cijoe&amp;diff=11682&amp;oldid=prev</id>
		<title>Crazy Rebel: викификация, оформление</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/index.php?title=LXF129:Cijoe&amp;diff=11682&amp;oldid=prev"/>
				<updated>2011-04-05T06:32:52Z</updated>
		
		<summary type="html">&lt;p&gt;викификация, оформление&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая страница&lt;/b&gt;&lt;/p&gt;&lt;div&gt;: '''Непрерывная интеграция''' Реальный опыт внедрения технологии контроля качества кода&lt;br /&gt;
&lt;br /&gt;
==''Cijoe'': Следы ''Java'' в проекте ''Django''==&lt;br /&gt;
&lt;br /&gt;
: Помимо легендарной громоздкости, проекты ''Java'' отличаются выверенным подходом к разработке. ''Python'' есть чему у них поучиться, считает '''Роман Богородский'''.&lt;br /&gt;
&lt;br /&gt;
Continuous integration (непрерывная интеграция, CI) – практика разработки программного обеспечения, суть которой заключается в частом объединении кода различных разработчиков и проверке целостности проекта. Обычно это реализуется следующим образом: исходные коды проекта копируются из репозитория и собираются, а затем выполняются тесты.&lt;br /&gt;
&lt;br /&gt;
Традиционно, сборка запускается каждый раз при внесении изменений в репозиторий. Одним из главных преимуществ такого подхода является уверенность в том, что проект собирается и тесты успешно выполняются, и в случае появления в репозитории вредоносного изменения это будет заметно сразу. Техника CI очень популярна среди Java-проектов, и в мире Java существует большое количество программного обеспечения для ее реализации, начиная от тяжелой артиллерии вроде ''AnthillPro'' и заканчивая удобными и простыми в конфигурации инструментами, например, ''Hudson''.&lt;br /&gt;
&lt;br /&gt;
Применение CI для ''Python'' почему-то развито значительно меньше, чем в мире ''Java'', и в этой статье хотелось бы поделиться опытом внедрения CI-сервера в ''Python''-проект.&lt;br /&gt;
&lt;br /&gt;
===Поставим задачу===&lt;br /&gt;
&lt;br /&gt;
Наш проект представляет из себя типичное web-приложение, написанное с использованием каркаса ''Django'' ([[LXF105:Django|LXF105‑108]]), задействующее базу данных и несколько внешних сервисов. Тесты организованы в стандартном для ''Django'' стиле: в каждом приложении [application] находится файл '''tests.py''' с тестами, которые запускаются командой '''manage.py test'''.&lt;br /&gt;
&lt;br /&gt;
Исходные тексты проекта хранятся в репозитории ''Git''. Это во многом повлияло и на выбор CI-сервера – им стал ''cijoe'' (http://github.com/defunkt/cijoe), предлагающий простую интеграцию с ''Git''-репозиториями.&lt;br /&gt;
&lt;br /&gt;
В простейшем случае, для использования ''cijoe'' достаточно указать, какой командой запускать тесты, к примеру:&lt;br /&gt;
&lt;br /&gt;
 git config --add cijoe.runner “./manage.py test app1 app2 appN»&lt;br /&gt;
&lt;br /&gt;
Почему после '''./manage.py test''' идет список приложений? Дело в том, что если запустить ''./manage.py test'' без аргументов, он выполнит тесты для всех приложений, которые указаны в переменной '''INSTALLED_APPS''' в '''settings.py''', в том числе и для стандартных, включенных в состав ''Django'', например, '''Django.auth'''. Тестирование приложений из дистрибутива ''Django'' не является целесообразным, поэтому мы явно перечисляем все приложения, которые требуется тестировать.&lt;br /&gt;
&lt;br /&gt;
Теперь можно запустить ''cijoe'' следующим образом:&lt;br /&gt;
&lt;br /&gt;
 cijoe склонированный_репозиторий&lt;br /&gt;
&lt;br /&gt;
На порту 4567 машины, где выполняется ''cijoe'', станет доступна консоль ''cijoe'', интуитивно понятная в использовании. На данном этапе будет возможно запускать тесты и проверять результаты вручную. Сборка считается успешной, если команда, прописанная в '''cijoe.runner''', завершится с кодом возврата 0.&lt;br /&gt;
&lt;br /&gt;
===Автоматизация===&lt;br /&gt;
&lt;br /&gt;
Гораздо удобнее, когда сборки запускаются автоматически после каждого проталкивания [push] изменений в центральный репозиторий. Для этого последний нужно сконфигурировать таким образом, чтобы после выполнения данной операции совершался POST-запрос по URL, на котором доступен ''cijoe,'' к примеру, http://ci.example.com/.&lt;br /&gt;
&lt;br /&gt;
Еще одним важным моментом является уведомление разработчиков о том, что тесты провалились – ведь какой толкот CI-сервера, если никто не узнает результаты? Все это легко осуществимо посредством «ловушек» [hook]: в случае проваленных тестов cijoe запустит '''.git/hooks/build-failed''', в случае успеха – '''.git/hooks/build-worked'''.&lt;br /&gt;
&lt;br /&gt;
Кто-то может спросить: почему нельзя использовать локальные «ловушки» и запускать тесты перед каждой фиксацией изменений [commit] на машине разработчика? Такой вариант возможен, но в рамках рассматриваемой проблемы у него есть несколько недостатков:&lt;br /&gt;
* Выполнение тестов может занимать довольно много времени, и у разработчиков возникнет соблазн выключать их с помощью опции '''--no-verify''' для ''git commit''.&lt;br /&gt;
* Придется полагаться на то, что разработчики не будут злоупотреблять '''--no-verify'''.&lt;br /&gt;
* Хранить «ловушки» централизованно довольно нетривиально.&lt;br /&gt;
* Далеко не все разработчики влияют на выполнение тестов: например, дизайнеры, занимающиеся в проекте графикой, вряд ли способны своими изменениями повлиять на результаты выполнения тестов.&lt;br /&gt;
&lt;br /&gt;
В нашем случае, для оповещения о крахе теста по электронной почте был написан сценарий примерно такого содержания:&lt;br /&gt;
&lt;br /&gt;
 PROJECT_NAME=”foobar-ng”&lt;br /&gt;
 PROJECT_DIR=”/home/joe/foobar-ng”&lt;br /&gt;
 COMMITTERS=”committers@foobarng.example.com”&lt;br /&gt;
 TEST_RUNNER=”test.sh”&lt;br /&gt;
 echo “To: ${COMMITTERS}&lt;br /&gt;
 Subject: ${PROJECT_NAME}: Tests Failed!&lt;br /&gt;
 Last commit:&lt;br /&gt;
 `git log -1 --pretty=short`&lt;br /&gt;
 Tests output:&lt;br /&gt;
 `cd ${PROJECT_DIR} &amp;amp;&amp;amp; ./test.sh 2&amp;gt;&amp;amp;1`&lt;br /&gt;
 “ |msmtp `echo ${COMMITTERS}|sed 's|,| |'`&lt;br /&gt;
&lt;br /&gt;
В случае возникновения ошибок скрипт посылает письмо с использованием утилиты ''msmtp''. В тело сообщения включается вывод команды, запускающей тесты, и информация о последнем изменении в коде.&lt;br /&gt;
&lt;br /&gt;
Даже в такой простой конфигурации CI-сервер представляется чрезвычайно полезным, так как дает своевременную информацию о состоянии проекта и заставляет разработчиков проверять результаты выполнения тестов перед проталкиванием изменений в центральный репозиторий, или, если это не было сделано, своевременно исправлять ошибки.&lt;br /&gt;
&lt;br /&gt;
===Оценим охват===&lt;br /&gt;
&lt;br /&gt;
Не менее интересным представляется вычисление такой метрики, как покрытие кода. Задача сбора этой информации тоже решается довольно просто. Процент покрытия кода в ''Python'' можно узнать с помощью модуля '''coverage.py''' ('''easy_install coverage''').&lt;br /&gt;
&lt;br /&gt;
Для этого потребуется написать небольшую обертку для средства запуска тестов ''Django''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 import os&lt;br /&gt;
 import shutil&lt;br /&gt;
 import sys&lt;br /&gt;
 import unittest&lt;br /&gt;
 import coverage&lt;br /&gt;
 from django.test.simple import run_tests as django_test_runner&lt;br /&gt;
 from django.conf import settings&lt;br /&gt;
 def test_runner_coverage(test_labels, verbosity=1, interactive=True, extra_tests=[]):&lt;br /&gt;
    coverage.use_cache(0)&lt;br /&gt;
    coverage.start()&lt;br /&gt;
    test_results = django_test_runner(test_labels, verbosity,&lt;br /&gt;
 interactive, extra_tests)&lt;br /&gt;
    coverage.stop()&lt;br /&gt;
    coverage_modules = []&lt;br /&gt;
    for module in test_labels:&lt;br /&gt;
       for i in (“views”, “urls”, “models”):&lt;br /&gt;
        try:&lt;br /&gt;
           coverage_modules.append(__import__(“%s.%s” % (module, i), globals(), locals(), ['']))&lt;br /&gt;
        except ImportError:&lt;br /&gt;
           # not all apps have urls.py module, so it's ok to ignore some import errors&lt;br /&gt;
           pass&lt;br /&gt;
   coverage.report(coverage_modules, show_missing=1)&lt;br /&gt;
   return test_results&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данный «тестопускатель» собирает информацию о покрытии кода для тестируемых приложений и печатает эти сведения в стандартный вывод после того, как все тесты были запущены.&lt;br /&gt;
&lt;br /&gt;
Чтобы '''./manage.py test''' использовал приведенный выше код, нужно добавить в '''settings.py''' следующую опцию:&lt;br /&gt;
&lt;br /&gt;
 TEST_RUNNER='tests.test_runner_with_coverage'&lt;br /&gt;
&lt;br /&gt;
Таким образом, после каждого запуска тестов будет готов отчет о  покрытии приложений тестами и информация о непокрытых участках.&lt;br /&gt;
&lt;br /&gt;
===И так далее===&lt;br /&gt;
&lt;br /&gt;
Думаю, мне удалось показать, что довольно скромными силами можно сделать вполне функциональный CI-сервер с автоматическими сборками по событию, уведомлениями о сломанных сборках по почте и отчетами о покрытии кода тестами. Существенным плюсом также является расширяемость ''cijoe'' – например, вместо уведомлений по почте можно использовать ''Jabber''. Возможны и более интересные применения: например, может оказаться полезным при каждой сборке сохранять информацию о покрытии кода тестами и анализировать динамику соотношения объема кода и его покрытия. К примеру, если объем кода увеличивается, а покрытие уменьшается, это может быть признаком, что разработчики перестали писать тесты для нового функционала.&lt;br /&gt;
&lt;br /&gt;
В общем, возможностей для расширения очень много, и что самое приятное – для их использования надо всего лишь обладать базовыми навыками написания скриптов оболочки.&lt;/div&gt;</summary>
		<author><name>Crazy Rebel</name></author>	</entry>

	</feed>