Решил довнедрять в повседневную жизнь связку hudson+phing, которую мы начали внедрять ещё после Symfony Camp UA 2010 и как-то этот процесс затянулся. Попутно напишу несколько заметок для закрепления материала.
Начну с phpcpd
phpcpd — утилита написанная Себастьяном Бергманом (автором PHPUnit), основное предназначение которой поиск copy-past кода.
Её исходники доступны на github. Там же есть руководство по установке и использованию.
Установка
Команды для установки phpcpd с PEAR канала в Debian based ОС:
$ sudo pear channel-discover pear.phpunit.de; sudo pear channel-discover components.ez.no; sudo pear install phpunit/phpcpd |
Работает. Приятно 🙂
Для проверки работы я натравил её на исходники ZFEngine:
$ phpcpd /var/www/work/skidkaest.ru/library/ZFEngine/ phpcpd 1.3.2 by Sebastian Bergmann. Found 1 exact clones with 8 duplicated lines in 2 files: - Module/UserBase/models/Base/Mailer.php:20-28 Module/UserExtended/models/Base/Mailer.php:20-28 0.07% duplicated lines out of 12233 total lines of code. Time: 2 seconds, Memory: 24.50Mb |
Сразу нашелся небольшой копипаст 🙂
Дополнительные возможности
Если запустить phpcpd без параметров или с ключем –help, то можно увидеть кратку справку:
$ phpcpd phpcpd 1.3.2 by Sebastian Bergmann. Usage: phpcpd [switches] <directory|file> ... --log-pmd <file> Write report in PMD-CPD XML format to file. --min-lines <N> Minimum number of identical lines (default: 5). --min-tokens <N> Minimum number of identical tokens (default: 70). --exclude <directory> Exclude <directory> from code analysis. --suffixes <suffix,...> A comma-separated list of file suffixes to check. --help Prints this usage information. --version Prints the version and exits. --verbose Print progress bar. |
Как видим ключей немного.
Например, для того чтобы сохранить результат в формате PMD-CPD, нужно запустить утилиту с параметром –log-pmd
$ phpcpd --log-pmd ./build/logs/pmd.xml |
Получился вот такой результат:
<?xml version="1.0" encoding="UTF-8"?> <pmd-cpd version="phpcpd 1.3.2"> <duplication lines="8" tokens="26"> <file path="/var/www/work/skidkaest.ru/library/ZFEngine/Module/UserBase/models/Base/Mailer.php" line="20"/> <file path="/var/www/work/skidkaest.ru/library/ZFEngine/Module/UserExtended/models/Base/Mailer.php" line="20"/> <codefragment> public function setTableDefinition() { $this->setTableName('mailer'); $this->hasColumn('id', 'integer', 4, array( 'type' => 'integer', 'unsigned' => true, 'primary' => true, 'autoincrement' => true, </codefragment> </duplication> </pmd-cpd> |
Ещё можно регулировать параметры –min-lines и –min-tokens для того чтобы ужесточить или наоборот ослабить условия поиска.
Также при сканировании больших библиотек полезным будет ключ –verbose, чтобы отображать прогресс бар.
phpcpd + Phing
Phing это инструмент предназначенный для автоматической сборки билдов (Apache Ant для PHP). За последние несколько лет я несколько раз пробовал его внедрить, но реальное удобство заключается именно в использовании Phing вместе с Hudson.
Устанавливается phing достаточно просто. Читайте офф. документацию.
Итак, создаю в /var/www/work/skidkaest.ru/library/ZFEngine/ файл build.xml:
<?xml version="1.0" encoding="UTF-8"?> <project name="zfengine" basedir="." default="build"> <property name="builddir" value="./build" /> <target name="init"> <mkdir dir="${builddir}" /> <mkdir dir="${builddir}/logs" /> </target> <target name="clean"> <echo msg="Clean..." /> <delete dir="${builddir}" /> </target> <target name="build" depends="clean,init,phpcpd" /> <target name="phpcpd"> <exec command="phpcpd --log-pmd ${builddir}/logs/pmd.xml ." escape="false" /> </target> </project> |
И запускаю:
$ phing Buildfile: /var/www/work/skidkaest.ru/library/ZFEngine/build.xml zfengine > clean: [echo] Clean... [delete] Deleting directory /var/www/work/skidkaest.ru/library/ZFEngine/build zfengine > init: [mkdir] Created dir: /var/www/work/skidkaest.ru/library/ZFEngine/build [mkdir] Created dir: /var/www/work/skidkaest.ru/library/ZFEngine/build/logs zfengine > phpcpd: [exec] Executing command: phpcpd --log-pmd ./build/logs/pmd.xml . 2>&1 zfengine > build: BUILD FINISHED Total time: 0.5840 seconds |
Проверяю или создался лог:
$ ls -l build/logs/ total 4 -rw-r--r-- 1 stfalcon stfalcon 693 2010-12-01 02:47 pmd.xml |
Работает. Приятно 🙂
phpcpd + phing + Hudson
Осталось совсем немного. Для чувства выполненного долга нужно выполнять эти проверки в Hudson.
Hudson это бесплатный и открытый сервер для CI. Недавно на Хабре была опубликована толковая статья “Непрерывная интеграция на примере Hudson“, которая и сподвигла меня разобраться в этом хозяйстве самостоятельно.
Установка Hudson в Debian based ОС тоже достаточно тривиальна. Читайте заметку в офф. вики проекта.
После установки нужно активировать плагины:
Duplicate Code Scanner Plug-in
Hudson Phing plugin
Первым делом я добавил конфиг build.xml в репозиторий ZFEngine. После чего создал новый проект (Build a free-style software project).
Настройки билда и дествий которые выполняются после билда:
Здесь главное добавить в build steps “Invoke Phing targets” и положить в репозиторий или workspace конфиг для Phing build.xml.
Пробуем сделать билд “Build Now” и если все ок, то шарик будет голубым или зеленым (плагин Green Balls).
Видите сообщение о 2х ошибках “Duplicate Code: 2 warnings from one analysis file.”? Если щелкнуть на ссылку в сообщении, то будет видна следующая картина:
В моем случае копипастом (а точнее cгенерированным Doctrine кодом) оказалась часть кода базовой модели пользователя:
Вот и все. Первые шаги к CI сделаны и завтра я буду двигаться дальше.
PS. Ну как вам Кейт Хадсон :)?
UPD.
В ходе чтения мануала по Phing увидел, что есть готовый task для phpcdp.
Т.е. правильней этот эту часть конфига в build.xml будет оформить так:
<target name="phpcpd"> <phpcpd> <fileset dir="." id="filestocpd"> <include name="*.php" /> </fileset> <formatter type="pmd" outfile="${builddir}/logs/pmd.xml"/> </phpcpd> </target> |
UPD2. Читайте продолжение “Непрерывная интеграция ZF проекта при помощи Hudson & Phing“
Вижу фраза “Работает. Приятно” зацепила не только меня =)))
За материал спасибо!
Пожалуйста ;). А фраза действительно цепляет 🙂
Кстати возможно выскажете свое мнение по поводу плюсов/минусов данного подхода перед подходом, описанным Ростиславом тут http://zendframework.ru/articles/continuous-integration-and-cruisecontrol ?
пока не рискну :]. я только начинаю использовать Hudson и совсем не работал с Cruise Control
Слова “Работает. Приятно.” напомнили “Я поставил стеклянные окна, он тоже поставил. Я сделал камин, он тоже сделал. Я купил радио, он не накопил. Радостно.” 😀