2 сентября 2009 в 17:26

Continuous integration для php

PHP*
Эту статью написал мой добрый приятель и бывший коллега fred, работающий в команде программистов над большим и сложным проектом, который должен работать 24х7. Если кто-то решит пригласить его на хабр — с удовольствием вышлю его email по хабрапочте. Пожелания и комментарии приветствуются, а я обязуюсь передавать ответы автора в меру своих возможностей.

Меня давно посещала мысль запустить CI-сервер для рабочего проекта. База модульных тестов уже достаточно внушительных размеров, а количество людей в проекте немного увеличилось. Можно было бы наблюдать за тем, как изменяется покрытие тестами кода и соблюдаются стандарты кодирования. И наказывать провинившихся. Шучу.
Некоторое время назад была прочитана книжка Непрерывная интеграция. Улучшение качества программного обеспечения и снижение риска и статья Quality Assurance Tools for PHP, которые и послужили отправной точкой.

Сервер непрерывной интеграции с некоторой периодичностью опрашивает репозиторий проекта на наличие изменений. Если изменения найдены, то он
  1. генерирует документацию в формате phpdoc
  2. проверяет код на соответствие стандартам кодирования
  3. запускает тесты
  4. по результатам тестов и анализа кода строит метрики, а также динамику изменений этих метрик
  5. уведомляет всех заинтересованных в случае успешной или неуспешной сборки

В качество интеграционного сервера был выбран CruiseControl вместе с плагином для php — http://phpundercontrol.org/.

Установка CruiseControl на debian-like машине


Если вы ставите CruiseControl в другой операционной системе, то действия примерно такие-же: установить java, распаковать CruiseControl, сделать сценарии запуска и остановки сервера.
Для запуска самого CruiseControl нам надо установить Java-машину:

sudo apt-get install sun-java6-bin

и прописать её в переменных окружения:

export JAVA_HOME=/usr/lib/jvm/java-6-sun

Сначала создаем в системе пользователя, из-под которого будет запускаться CruiseControl:

sudo adduser cruisecontrol

К сожалению свежих .deb пакетов с CruiseControl я не нашел, а у самого пока руки не дошли сделать, поэтому качаем последнюю версию и распаковываем в директорию по желанию:

s.galkin@java-galkin:/opt$ sudo wget http://sourceforge.net/projects/cruisecontrol/files/CruiseControl/2.8.2/cruisecontrol-bin-2.8.2.zip/download
s.galkin@java-galkin:/opt$ sudo unzip cruisecontrol-bin-2.8.2.zip
s.galkin@java-galkin:/opt$ sudo mv cruisecontrol-bin-2.8.2 cruisecontrol

и делаем владельцем директории нашего пользователя:

s.galkin@java-galkin:/opt$ sudo chown cruisecontrol /opt/cruisecontrol -R

Берем шелл-скрипт из руководства по установке CruiseControl в unix. и сохраняем его в файл /etc/init.d/cruisecontrol .
Теперь можно запустить CC и проверить, что он работает:

s.galkin@java-galkin:/opt$ sudo /etc/init.d/cruisecontrol start

Веб-интерфейс должен быть доступен по адресу http://yourhostname:8080/
Остановить сервер можно соответственно:

s.galkin@java-galkin:/opt$ sudo /etc/init.d/cruisecontrol stop

Переходим к установке php-части.
У вас наверняка уже стоит xdebug и pear, но если нет:

sudo apt-get install php5-xdebug
sudo apt-cache search php pear

Если у вас достаточно много кода и тестов, стоит увеличить количество выделяемой php-процессу памяти:

max_execution_time = 0
memory_limit = 512M

Установка php-пакетов


Теперь устанавливаем пакеты для документирования, тестирования, и оценки кода и сам phpUnderControl:

pear install PhpDocumentor
pear install PHP_CodeSniffer
pear channel-discover pear.phpunit.de
pear install phpunit/PHPUnit
pear channel-discover components.ez.no
pear install --alldeps phpunit/phpUnderControl-beta

Если вы ставите все на отдельной машине, то не забудьте поставить все библиотеки, от которых зависит ваш проект. Заодно можно проверить, что phpunit, phpcs, phpdoc выполняются с теми наборами параметров, которые указаны в build.xml.
Делаем phpUnderControl плагином CruiseControl’а, указав в качестве аргумента директорию, где установлен последний:

phpuc install /opt/cruisecontrol

Настройка проекта


Открываем конфигурационный файл config.xml, находящийся в корневой директории CruiseControl и заменяем его следующим:
<cruisecontrol>
  <property name="ant.dir" value="apache-ant-1.7.0"/>
  <property name="work.dir" value="/opt/cruisecontrol"/>
 
  <property name="logs.dir" value="${work.dir}/logs/${project.name}" />
  <property name="artifacts.dir" value="${work.dir}/artifacts/${project.name}" />
 
  <property name="project.dir" value="${work.dir}/projects/${project.name}" />
  <property name="project.code.dir" value="${project.dir}/source"/>
  <property name="project.build.dir" value="${project.dir}/build"/>
  <property name="project.logs.dir" value="${project.build.dir}/logs"/>
  <property name="project.coverage.dir" value="${project.build.dir}/coverage"/>
  <property name="project.api.dir" value="${project.build.dir}/api"/>
  <property name="project.build.file" value="${project.code.dir}/misc/ci/build.xml"/>
 
  <property name="status.file" value="${logs.dir}/${project.name}/status.txt"/>
 
  <project name="yourProjectName">
    <listeners>
      <currentbuildstatuslistener file="${status.file}"/>
    </listeners>
 
    <bootstrappers>
      <svnbootstrapper localWorkingCopy="${project.code.dir}"/>
    </bootstrappers>
 
    <modificationset>
      <svn localWorkingCopy="${project.code.dir}"/>
    </modificationset>
 
    <schedule interval="300">
      <ant anthome="${ant.dir}" buildfile="${project.build.file}">
        <property name="project.code.dir" value="${project.code.dir}/"/>
        <property name="project.build.dir" value="${project.build.dir}"/>
        <property name="project.logs.dir" value="${project.logs.dir}"/>
        <property name="project.api.dir" value="${project.api.dir}"/>
        <property name="project.coverage.dir" value="${project.coverage.dir}"/>
      </ant>
    </schedule>
 
    <log dir="${logs.dir}">
      <merge dir="${project.logs.dir}"/>
    </log>
 
    <publishers>
      <currentbuildstatuspublisher file="${logs.dir}/buildstatus.txt"/>
      <artifactspublisher dir="${project.coverage.dir}" dest="${artifacts.dir}" subdirectory="coverage" />
      <artifactspublisher dir="${project.api.dir}" dest="${artifacts.dir}" subdirectory="api" />
      <execute command="phpuc graph ${logs.dir} ${artifacts.dir}" />
    </publishers>
  </project>
</cruisecontrol>

Я перенес все пути к файлам и директориям в переменные на самый верх конфигурационного файла, чтобы при надобности было легко их поправить в одном месте.
В качестве сборщика я использовал ant (он явно указан в config.xml в ноде /cruisecontrol/project/schedule), который мне немного знаком. Если ваш проект уже использует phing (что более логично для php-проектов, чем ant), то CruiseControl его отлично поддерживает.
В ноде /cruisecontrol/project/publishers можно кроме обработки результатов тестов и метрик можно также посылать в случае неудачных сборок (возможно и удачных тоже) уведомления заинтересованным лицам на почту/в жаббер.
Подробное описание конфигурационного файла можно найти по ссылке CruiseControl Configuration Reference
Переходим к самому сценарию сборки проекта.
<project name="yourProjectName" default="build">
  <target name="prepare">
    <delete dir="${project.build.dir}"/>
    <mkdir dir="${project.logs.dir}"/>
  </target>
 
  <target name="phpdoc">
    <exec executable="phpdoc" dir="${project.build.dir}" failonerror="false">
      <arg line="
        -o HTML:frames:DOM/earthli
        -ti '${ant.project.name} documentation'
        -q
        -t ${project.api.dir}
        -d ${project.code.dir}
      "/>

    </exec>
  </target>
 
  <target name="phpcs">
    <exec executable="phpcs" dir="${project.build.dir}" failonerror="false" output="${project.logs.dir}/checkstyle.xml">
     <arg line="
        --report=checkstyle
        --standard=PEAR
        ${project.code.dir}
      "/>

    </exec>
  </target>
 
  <target name="phpunit">
    <exec executable="phpunit" dir="${project.build.dir}" failonerror="true">
      <arg line="
        --log-xml ${project.logs.dir}/phpunit.xml
        --log-pmd ${project.logs.dir}/phpunit.pmd.xml
        --log-metrics ${project.logs.dir}/phpunit.metrics.xml
        --coverage-xml ${project.logs.dir}/phpunit.coverage.xml
        --coverage-html ${project.coverage.dir}
        phpucAllTests ${project.code.dir}/utests/AllTests.php
      "/>

  </exec>
  </target>
 
  <target name="build" depends="prepare,phpdoc,phpcs,phpunit"/>
</project>

Все переменные с путями были переданы из config.xml
<ant anthome="${ant.dir}" buildfile="${project.build.file}">
    <property name="project.code.dir" value="${project.code.dir}/"/>
    <property name="project.build.dir" value="${project.build.dir}"/>
    <property name="project.logs.dir" value="${project.logs.dir}"/>
    <property name="project.api.dir" value="${project.api.dir}"/>
    <property name="project.coverage.dir" value="${project.coverage.dir}"/>
</ant>

Я решил сразу положить build.xml в репозиторий, чтобы в будущем его было легче обновлять.
Не забудьте правильно указать путь к нему из config.xml (атрибут buildfile в ноде /cruisecontrol/project/schedule/ant)
Теперь выгружаем в папку /opt/cruisecontrol/projects/yourProjectName/source из репозитория ваш проект и запускаем CruiseControl. Все!

Существующие проблемы


При наличии warning/notice, Codesniffer не подавляет их и в результате получается невалидный xml файл, который CruiseControl не может прочитать. Вообще при любом непонятном поведении можно посмотреть лог /opt/cruisecontrol/cruisecontrol.sh

Итог


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

Полезные ссылки


  1. The CruiseControl Best Practices Series
  2. Quality Assurance Tools for PHP
  3. RunningCruiseControlFromUnixInit
  4. Setting up phpUnderControl
  5. phpUnderControl
  6. CruiseControl Configuration Reference
  7. Запуск CodeSniffer с стандартами кодирование, лежащими в нестандартной директории
Виктор Большов @crocodile2u
карма
132,2
рейтинг 0,0
Похожие публикации
Самое читаемое Разработка

Комментарии (44)

  • 0
    Не разбираюсь в пхп, но описали все очень подробно, спасибо :) А небольшой заменой конфига можно распространить руководство и на другие типы проектов.
  • 0
    держите плюс, понадобится вам для инвайта. спасибо за статью очень познавательно. давно искал тулзы для метрик под пхп…
  • –1
    Прикольно, но вот это

    > проверяет код на соответствие стандартам кодирования

    пожалуй излишне. Гемора случаем не будет? Например, решила команда разработчиков кое-где сделать исключение из правил форматирования. И объяснить это исключение серверу сложно или невозможно. Значит не видать нам нового билда? Такие вещи лучше проверять при помощи code review или парного программирования.
    • 0
      Значит, сервер CI выдаст варнинг в логи. Никто вам по рукам бить не собирается.
    • 0
      ИМХО соблюдения общих стандартов кодирования в большинстве случаев очень помогает. Хотя бы читаемость кода и т.д… А code review для более детальных проверок, с которыми checkstyle не всегда справиться.
    • 0
      при оценке кода всегда первым делом смотрю на стиль, если стиль не выдержан, то заношу его в разряд опасных, каким бы он провереным и обложеным тестами не был. если код не выдержан, значит разработчик заработался, потерял концентрацию, а качество кода в такие моменты падает раньше чем стиль.
    • 0
      Если хочется изменить стандарт кодирования или сделать исключение — можно изменить проверяльщика кода. Как показала практика, проблем с проверкой стандартов почти не возникает (а те, что возникают, быстро решаются), а вот код становится почище.
  • 0
    «Открываем конфигурационный файл config.xml, находящийся в корневой директории CruiseControl и заменяем его следующим:»

    phpuc project <project_name>
  • НЛО прилетело и опубликовало эту надпись здесь
    • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    У нас со стилями кодирования еще более жестко. Сам движок в режиме продакшина проверяет на соответствие стилям все, что в нем твориться и пока не назовешь все правильно — даже работать не будет :)
    Например, если написать приватный метод без знака подчеркивания в начале и т.п. Правила хорошо продуманы и четко описаны.
    • 0
      вы не могли бы дать ссылочку на док о хорошем стиле PHP? ну или хотя бы перечислить три самых важных по вашему мнению правила (специфичных для PHP =)
  • 0
    Супер. Сам с недавнего времени смотрю в сторону Continous Integration, статья очень пригодится :)
  • +1
    Спасибо!
    На счет залить ручками код в папку — можно добавить секцию в конфиг, которая будет с репозитория кода брать изменения. Можно было бы ее для красоты добавить. Но это к слову.

    Что интересует:
    Не очень понята работа этой системы с тестовым сервером. Ведь хотелось бы, чтобы если все тесты прошли успешно (и метрики в порядке), то система автоматически разворачивала бы тестовую версию на тестовом сервере. Вот как тут быть? Ведь нужно не просто код скопировать на тестовый сервак, а создать базу данных с нуля, залить туда какие-то тестовые данные, «настроить» конфигурационные параметры кода и т.п.
    Как с этим быть?

    Тоже самое с продакшен сервером. Может ли CI использоваться для того, чтобы развернуть свежую версию на production сервере? Если да, то как это делается. Тут опять проблемы не только кода, но и обновления базы данных (причем не создать БД с нуля по схеме, а обновить существующую схему + оставить в порядке существующие данные).

    Спасибо за статью!

    • +1
      ну если проект, например, на фреймворке Симфония, то можно написать скрипт, который просто выполняет:

      php symfony configure:database --name=doctrine --class=sfDoctrineDatabase «mysql:host=TestServer;dbname=TestDatabase» ProjectUser SecretPassword

      php symfony doctrine:build-all-reload

      Первая команда «перекидывает» конфиг базы данных на тестовый сервер, вторая — дропает тестовую БД, создает таблицы, загружает тестовые данные. Кажется, там же есть процедура миграции между версиями БД (но ей я не пользовался :)

      Таким образом, процедура клонирования проекта очень зависит от организации этого проекта.
      • 0
        Спасибо большое за комментарий. К сожалению, у меня не Симфония, но кому-нибудь точно пригодиться.
        И что главное — мне вам коммент дал понимание, что используя ORM для работы с базой данных проблема миграции между версиями БД становится много легче (раньше я с подозрением относился к ORM).
        • 0
          кстати, нужны скринкасты по Симфонии, или это будет мартышкин труд? я уже устал ждать когда официальные доки переведут на русский язык, а записать это всё на вебкамеру — один вечер.
        • 0
          ORM замечательно проявляет себя еще и в других кошмарных ситуациях: смена базы данных (с Oracle на MySQL, ага), работа с БД которую параллельно и без всякого согласования изменяет кто-то (не ты). Или для заказчиков, постоянно требующих «deploy now!» для новых непротестированных фич: в хаосе из конфигов ORM гораздо проще разобраться, чем в хаосе SQL changeset'ов.

          Doctrine и Propel доступны сами по себе, без Симфонии. Все что нужно для воссоздания описанного выше функционала — описание схемы БД в формате yaml. Примеры есть на сайте Доктрины.

          А в Симфонии просто есть плагин для подключения Doctrine. Это позволяет делать несколько красивых фишек с генерацией страниц и роутингом URL.
          • 0
            На счет скринкастов — это не ко мне, но, думаю, что людям будет полезно!

            На счет ORM — спасибо за разъяснения! Суть для меня понятна — БД контролируется кодом программы, а код контролировать гораздо легче, чем базу! Это действительно супер!

            Про Doctrine и Propel наслышан, просто подозрительно к самой идеи относился. И главное, что трудно тенденции уловить — толи вещь становится популярной, толи не особо:) А спросить некого:)

            Теперь пригляжусь подробнее :)
            Спасибо!
    • 0
      если все прошло успешно, то вызываем задачу переноса.
      в идеале оформляется как отдельный сценарий, возможен вариант когда сцернарий лежит на отдельном сервере, а задача только нажимает на спусковой крючек(вплоть до передачи запроса по http).
      А вот деплой на продакшен я б не стал доверять ci, сценарий деплоя накатать это, да но вот вызывать его должен человек.
      • 0
        Спасибо! Теперь я начинаю понимать, почему пишут, что CI — это индивидуальный процесс, а не стандартное решение:) Видимо даже разворачивание на тестовом сервере нельзя свести к общим правилам.
        • 0
          да можно наверное, но любое универсальное решение проиграет индивидуальному подходу.
          для небольших однотипных проектов делал сценарий под ант
          svn_update
          run_update_db_scripts
          run_tests
          если что то не так то rollback
          send_result_mail

          ну и был спусковой крючек вывешенный на ружу по хттп, вариант не ахти, но причесывать сначало было лень, а потом не когда
          • 0
            Спасибо огромное!
            А как вы делали rollback? Вы уже выполнили скрипт базы данных — как ее откатить? Или у вас на каждую ревизию в SVN прилагался набор скриптов к БД для этой ревизии?
            И что включали из себя скрипты базы данных? Это только новая схема базы данных на тестовом серваке разворачивалась? или какие-то тестовые данные «накидывались»?
            И почему это было сделано до запуска тестов? Ведь тесты с базой данных напрямую не работают. Точнее для этого не обязательно базу данных иметь — я имею ввиду Stub'ы, когда БД это просто тестовый xml файлик с тестовыми данными.
            • 0
              не знаю как правильно сказать, не проснулся еще:-)
              в общем если появляется код для которого нужны изменеия в бд, он попадает в одну ревизию с апдейт скриптами и со сриптом для ролбека. если в ревизии появился апдейт скрипт, то соответсвенно сценарий его применяет.)
              в ту же ревизию попадает дамп с тестовыми данными, у нас он назвался эталонным(иногда ленились и просто пересоздавали бд заного, благо эталонное состояние было). он нужен для интеграционных тестов и для функциональных(только начинали внедрять).
              стюбы не подходят потому как тестовый это копия продакшена, так что надо быть 100% уверенным, что все будет в ажуре на реально действующей бд
              тесты шли всей пачкой последовательно юнит, интеграционные, функциональные.
              по хорошему наверное действительно стоило вынести юнит тесты до накатывания изминений базы
              • 0
                Хм, вот не очень понимаю зачем нужна эталонный дамп. Ведь когда тесты запускаются, то в них идет последовательность проверок
                1) данных в таблице нет вообще
                2) а если такие данные, то все ок?
                3) а если такие?
                и т.п.
                Т.е. все равно эталонные данные будут удалены. Эталонные данные будут ценны только для тестового сервера, где ты смотришь на продукт целиком. Т.е. для юнит тестирования создавать разные начальные xml с данными получается выгоднее. Но с другой стороны я с вами согласен, что тестирование на настоящей БД ценнее :) В общем, совсем запутался:)
                • 0
                  скорее всего некоторое расхождение в терминах, потому и не понятно:-)
                  юнит тесты тестирование одного класаа
                  интеграционное тестирование тестирование цельного компонента системы, тут собственно dbunit(вернее его порт из phpunit), да можно обойтись кусками схемы, но лично мне кажется полезным тестировать на цельном массиве данных. интеграционные отработали, испортили к чертям бд, вернули к эталонному для фунекциональный
                  функциональные это то как пользовался бы этим конечный пользователь, в моем случае селениум, но есть и другие системы, и вот тут без эталонного состояния вообще тяжка.
                  добавь специфику, небольшие проекты, если бы был большой возможно пришлось бы делать набор эталонных состояний для разных кусков системы
                  был еще мысль притянуть тестировать, на случайные данный, недавно узнал, что это фуззинг:-)
                  ну и в конце еще раз поднимаем аталонное состояние, что б человек из qa смог нормально пройтись по тестовому серверу

                  ЗЫ: я не тестировщик, я программист, просто было интересно этим заниматься. так что с теоретической базой есть некоторый недохват
    • 0
      Насчет действий по факту удачного построения, можно добавить в /cruisecontrol/project/publishers ноду antpublisher со ссылкой на ваш build.xml на действие вроде «successfulBuild», которое будет создавать новый тэг в репозитории, или паковать архив и т.д.

      Насчет подготовки внешних ресурсов перед проведением теста, то в build.xml можно кроме задачи prepare создать recreateDataBase, clearCache и подобные.

      С продакшн мы подобную схему не используем и в ближайщее время не планируем (хотя есть примеры подобных проектов). Можно написать ant сценарий, который будет выполнять запуск миграционный sql-скриптов, настраивать конфигурационные файлы и выкладывать новый код.
      • 0
        Спасибо за комментари!
        А разве создавать новый тег и т.п. не следует делать после тестирования ручками — т.е. залез на тестовый сервер и убедился, что все работает как нужно. Ведь unit tests не говорят о качестве системы в целом.
        • 0
          Кстати, у вас в проекте конфиг напоминает тот, что в топике? Или намного сложнее?
          Если сложнее, то не могли бы привести последовательность действий вашего сценария. Т.е. интересует, что делается и какова последовательность действий. Что-то типа update svn, clear cache, run unit tests, if success --> copy code to test env, etc. Было бы здорово посмотреть на рабочую схему.
          • 0
            svn up запускается из config.xml в ноде /cruisecontrol/project/modificationset/svn.

            Новые билды мы автоматически не строим. В build.xml в prepare у нас ещё настраиваются конфигурационные файлы.
        • +1
          Поэтому мы в данный момент этого не делаем. Сейчас у нас СI выполняет фукнцию более быстрой обратной связи о каких-то проблемах в коде.
          Если практически вся функциональность закрыта ещё и интеграционными и приемочными тестами, то тогда можно и тэг создавать и на продакшн выкладывать автоматически :-)
          • 0
            не продакшен это святое, автоматика это очень хорошо, но все равно ответственный дядя/тятя должны руками пробежать
    • 0
      Возможно кто-то уже ответил на ваш вопрос, если повторюсь не серчайте
      В нашей работе тоже используем CI и у нас база обновляется каждый раз из дампа sql который лежит в SVN. т.е. порядок действий следующий, CI сливает все с SVN, разворачивает сызнова базу из дампа, запускает все проверки. Тем самым мы имеем всегда актуальную базу под рукой и по сути проект готовый к работе на любой машине нужно только забрать данные из SVN.
      По поводу обновления production сервера, видел несколько практик в сети. Одни практикуют самописный скрипт портирования, который проводит все необходимые сверки и добавляет все что нужно на рабочий сервер. Естественно этот скрипт запускается автоматом из CI. Другие пишут сборочные скрипты которые генерируют после выполнения вроде инсталятора который ложится в директорию проекта CI и после вы можете посмотреть их для каждого билда.
      Но сам убежден что лучше это делать вручную, потому что рабочий сервер это рабочий сервер.
  • +1
    Ух ты, а топик-то набрал силу! Fred сейчас офлайн, но мы с ним свяжемся буквально вот скоро. Инвайт есть, так что он сам ответит на комментарии. А я прошу прощения — вчера как вышел с работы — к компу больше не подходил, так что ответить не было возможности.
  • 0
    Когда было время поразвлекаться с билд сценариями(недолго, быстро нашли более приоритетные задачи), я занимался еще функциональными тестами на Seleniume
    Машинка была слабая, пришлось зоопарк браузеров раскидывать по виртуальным машинам и делать сценарий ванькувстаньку для виртуалок.
    Еще могу сказать, что проковырявшись пхпюнитом решил, что для Selenium сценариев лучше писать тесты на java(до этого момента java была на уровне хеловорлда) инструментарий на порядок гибче и удобнее.
  • 0
    Па-Бам!!! Встречаем Автора!!! fred84 — прошу любить и жаловать! Все, кто по ошибке приплюсовал карму мне — могут теперь эту ошибку исправить и отправить свою признательность за интересную информацию — по адресу.
    • 0
      Сергей привет :)
  • НЛО прилетело и опубликовало эту надпись здесь
  • –1
    Нашел более расширенный мануал, но на английском тут:
    techportal.ibuildings.com/2009/03/03/getting-started-with-phpundercontrol/

    В Windows у меня вот некоторые проблемы пока возникают:

    C:\>phpuc example "C:\Program Files\CruiseControl"
    Missing cli tool 'phpdoc', check the PATH variable.

    Несмотря на то что в командной строке phpdoc работает нормально.
    • –1
      Проблема оказалась связана с тем что в PATH путь был заключен в кавычки.
      Так что либо убираем кавычки оттуда либо добавляем обработку в phpuc.

      www.phpunit.de/ticket/341#comment:6
    • –1
      Еще пришлось поставить PHP_CodeBrowser
      C:\>pear install phpunit/PHP_CodeBrowser-alpha
      phpunit/PHP_CodeBrowser can optionally use PHP extension "xdebug" (version >= 2.0.5)
      downloading PHP_CodeBrowser-0.1.1.tgz ...
      Starting to download PHP_CodeBrowser-0.1.1.tgz (75,138 bytes)
      .................done: 75,138 bytes
      install ok: channel://pear.phpunit.de/PHP_CodeBrowser-0.1.1


      После чего был остановлен сервис апача и запещен сервис круиз контрола и наконец запустился phpUnderControl но ксожадению ничего не билдится пока (example project) и в части разделов падает ява. Ох уж этот виндовз.
      • –1
        Да, еще небольшая проблема в том что из-за Skype Apache сидит на 8080 а CC запускается на нем же по умолчанию. Так что кто первый того и тапки, но это видимо можно и пофиксить будет.

        Броузер кода порадовал — это единственное что пока работает там =)
  • 0
    Некробамп: описание более современного CI сервера TeamCity.

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.