Люблю я всякие автоматизации процессов, вот дошла очередь и до генерации документации в проекте Bluz
Постановка задачи
Возникла необходимость генерировать и публиковать документацию к проекту Bluz, который размещён на GitHub, в автоматическом режиме, ибо “ручками” сие делать уже не с руки.
GitHub
В качестве хостинга документации будем использовать мощности самого GitHub’а, в частности – GitHub Pages, так что первое что потребуется сделать – создать репозиторий вида bluzphp/bluzphp.github.io, где bluzphp – имя организации (а может быть именем пользователя).
Travis
Данная статья предназначена для тех, кто уже знаком с Travis CI, но до генерации и автоматической публикации “руки не дошли”, так что руководство для начинающих вам надо будет поискать на другом ресурсе, хотя в дальнейшем может появиться и тут ;)
Если же с английским вы дружны, то лучше чем официальное руководство трудно будет что-то найти.
TravisCI уже использовался в проекте, так что осталось дело за малым – генерировать документацию, и заливать её в репозиторий на GitHub.
Для генерации документации будем использовать PHPDocumentor, добавить его в сборку можно двумя способами – используя composer – позволяет контролировать версию, но с зависимостями могут возникнуть проблемы, да и медленно это – для данного варианта необходимо добавить в composer.json
следующую зависимость:
{ "require-dev": { "phpdocumentor/phpdocumentor": "2.*" } }
как альтернатива – скачивать phar-архив:
wget http://phpdoc.org/phpDocumentor.phar
Затем вносим изменения в файл .travis.yml
, это будет выглядеть следующим образом (если установка была через composer):
before_script: - mkdir docs after_script: - php vendor/bin/phpdoc -d ./src -t ./docs
или так (если использовался phar архив):
before_script: - mkdir docs after_script: - wget http://phpdoc.org/phpDocumentor.phar - php phpDocumentor.phar -d ./src -t ./docs
Директорию
docs
можно создать “на лету” как в данном примере, или создать её в самом репозитории как это сделано в моём проекте
PHPDocumentor
После запуска билда в папке docs
будет создан статический сайт, который будет выглядеть как-то так (шаблон clean):
Для более тонкой настройки можно использовать конфигурационный файл phpdoc.xml
, приведу пример моей конфигурации с пояснениями:
<?xml version="1.0" encoding="UTF-8" ?> <phpdoc> <!-- Название проекта --> <title>Bluz</title> <parser> <!-- Рабочая директория, тут будет хранится кеш --> <target>phpdoc</target> <encoding>utf8</encoding> <markers> <item>TODO</item> <item>FIXME</item> </markers> <extensions> <extension>php</extension> <extension>phtml</extension> </extensions> <default-package-name>Bluz</default-package-name> </parser> <transformer> <!-- Директория, где будет конечный результат генерации --> <target>docs</target> </transformer> <transformations> <!-- Шаблон на выбор: responsive, responsive-twig, checkstyle, clean, zend, new-black --> <template name="responsive-twig" /> </transformations> <files> <!-- Директория с исходным кодом --> <directory>src</directory> </files> </phpdoc>
GitHub
Так, документация есть, теперь её необходимо залить в репозиторий bluzphp/bluzphp.github.io. Для этого нам потребуется создать Access Token в своём профиле на GitHub:
Скопируйте его и никому не показывайте, если есть сомнения, что кто-то посягнул на него – перегенируйте токен заново.
Travis
Возвращаемся к Travis – теперь нам нужно установить консольное приложение travis, и с его помощью мы закодируем наш токен, чтобы никто его не смог подсмотреть в нашем конфигурационном файле:
gem install travis travis encrypt GITHUB_TOKEN=secretvalue -r bluzphp/framework
Полученный таким образом ключ необходимо добавить в ваш конфигурационный файл travis.yml
:
env: global: - secure: "encryptedsecretvalue"
Подробнее разобраться в происходящей тут магии вам поможет официальная документация по шифрованию ключей и переменным окружения
Если вдруг вы не можете понять, почему не устанавливаются глобально ваши зашифрованные переменные, то поясню для таких же невнимательных как и я – эта фича не работает для pull-запросов из форков
Идём дальше – теперь необходимо с использованием данного ключа обновить наш репозиторий. Для удобства всех дальнейших манипуляции с документацией был создан отдельный bash скрипт .travis.sh
, а в .travis.yml
оставлен лишь его запуск:
after_script: - bash .travis.sh
В bash скрипте:
# скачиваем phpDocumentor wget http://phpdoc.org/phpDocumentor.phar # и запускаем его в "тихом" режиме # по умолчанию, он подхватит конфигурационный файл из корня проекта php phpDocumentor.phar --quiet # перенесём документацию в домашнюю директорию cp -R docs $HOME/docs-latest cd $HOME # настраиваем git git config --global user.email "travis@travis-ci.org" git config --global user.name "travis-ci" git config --global push.default simple # клонируем репозиторий страниц # вот тут мы и будем использовать наш шифрованный токен git clone --quiet https://${GITHUB_TOKEN}@github.com/bluzphp/bluzphp.github.io > /dev/null cd bluzphp.github.io # очищаем git rm -rf ./ > /dev/null # переносим документацию cp -Rf $HOME/docs-latest/* ./ # добавляем все файлы в репозиторий git add -f . # комит git commit -m "PHPDocumentor (Travis Build: $TRAVIS_BUILD_NUMBER@$TRAVIS_TAG)" # пуш git push -fq origin > /dev/null
Теперь чуть-чуть ограничим билды для которых будет обновляться документация следующим условием:
if [ "$TRAVIS_REPO_SLUG" == "bluzphp/framework" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_PHP_VERSION" == "7.0" ]; then # всё что выше будет тут # ... fi
Полный список переменных окружения на Travis есть в документации – Default Environment Variables
Всё готово – запускаем билд и смотрим на то, что получилось… и вот тут меня PHPDocumentor разочаровал, не знает он ничего о функциях с переменным числом аргументов (хотя если быть придирчивым, то проблема всё же в используемой версии библиотеки PHP-Parser), ошибки непонятные показывал, ну и ругался сильно, так что пошёл я за альтернативами, хотя вариант рабочий, и грех было о нём не рассказать.
PHPDox
Альтернатива нашлась сразу – PHPDox, скачиваем и поехали – начнём всё с конфигурации по умолчанию:
# скачиваем phar архив wget http://phpdox.de/releases/phpdox.phar # генерируем шаблонный конфиг php phpdox.phar --skel > phpdox.xml
Полученный таким образом файл был добавлен в репозиторий проекта с мелкими правками. Для миграции CI на PHPDox потребовалось лишь слегка исправить .travis.sh
:
# было wget http://phpdoc.org/phpDocumentor.phar php phpDocumentor.phar --quiet # стало wget http://phpdox.de/releases/phpdox.phar php phpdox.phar
Результат получился вполне приемлемый, но PHPDox умеет большее – у него есть поддержка PHPUnit, PHPCS, PHPMD, PHPLoc и Git’a, так что я решил “прокачать” систему по полной.
Из замеченных недостатков – проблема с форматированием примеров кода записанного в doc-блоках
Git
Начну с самого простого – для добавление поддержки Git’a достаточно добавить соответствующий раздел в phpdox.xml
:
<generator output="${basedir}/docs"> <enrich base="${basedir}"> <source type="git"> <git binary="/usr/bin/git" /> <history enabled="true" limit="15" cache="${phpDox.project.workdir}/gitlog.xml" /> </source> </enrich> </generator>
В результате данной манипуляции в документации появится возможность просматривать историю изменений на основе комментариев к комитам (вы же пишите комментарии в каждом комите?).
PHPUnit
Тесты уже были в проекте, но я напомню как их подключать:
{ "require-dev": { "phpunit/phpunit": "~4.7", } }
Запуск тестов претерпел небольшие изменения – добавлена генерация покрытия в XML (на данный момент для PHP 7.0 xdebug автоматом не устанавливается, так что “если чё” – устанавливайте через PECL):
before_script: - mkdir .reports script: - php vendor/bin/phpunit --configuration ./phpunit.xml.dist --coverage-clover=.reports/clover.xml --coverage-xml=.reports/coverage
Конфигурация PHPDox так же была изменена:
<generator output="${basedir}/docs"> <enrich base="${basedir}"> <source type="phpunit"> <coverage path=".reports/coverage" /> </source> </enrich> </generator>
PHP_CodeSniffer
Утилита анализа кода PHP_CodeSniffer уже использовалась в проекте, подключается она через composer:
{ "require-dev": { "squizlabs/php_codesniffer": "~2.3" } }
Конфигурационный файл для проверки исходного кода и тестов на соответствие стандартам PSR1 и PSR2 выглядит вот так:
<?xml version="1.0"?> <ruleset name="Bluz"> <description>The coding standard for Bluz project</description> <!-- где берём сорцы --> <file>./src</file> <file>./tests/src</file> <!-- игнорируем файлы в этих директориях --> <exclude-pattern>./tests/src/Fixtures</exclude-pattern> <exclude-pattern>./tests/src/Common/Fixtures</exclude-pattern> <!-- используем перечисленные стандарты --> <rule ref="PSR1"/> <rule ref="PSR2"/> </ruleset>
Запускаем:
script: # Code style - php vendor/bin/phpcs --report=xml --report-file=.reports/phpcs.xml
Подключаем результаты к PHPDox:
<generator output="${basedir}/docs"> <enrich base="${basedir}"> <!-- PHP Code Sniffer --> <source type="phpcs"> <file name=".reports/phpcs.xml" /> </source> </enrich> </generator>
У меня билд “ломается”, если со стандартами есть проблемы, у вас же поведение CI может отличаться от моего, и тогда проблемные места будут отображены в документации (наверное :)
PHPLoc
Подключаем:
{ "require-dev": { "phploc/phploc": "*" } }
Запускаем:
script: # Lines of code and etc - php vendor/bin/phploc --log-xml=.reports/phploc.xml src
Анализируем результаты в PHPDox:
<generator output="${basedir}/docs"> <enrich base="${basedir}"> <!-- PHPLoc --> <source type="phploc"> <file name=".reports/phploc.xml" /> </source> </enrich> </generator>
PHPMessDetector
Подключаем:
{ "require-dev": { "phpmd/phpmd": "*" } }
Запускаем:
script: # Mess detection - php vendor/bin/phpmd ./src xml codesize,unusedcode,naming --reportfile .reports/phpmd.xml || true
Тут пришлось пойти на хитрость – в случае если phpmd находит какие-то нарушения правил (к примеру слишком короткое имя переменной), то он вернёт exit code равный 2, что “ломает” билд, поэтому пришлось его заглушить, а все найденные проблемы “скормить” в документацию.
Анализируем результаты в PHPDox:
<generator output="${basedir}/docs"> <enrich base="${basedir}"> <!-- PHPMessDetector --> <source type="pmd"> <file name=".reports/phpmd.xml" /> </source> </enrich> </generator>
Результат
Вот что у меня получилось в результате всех описанных манипуляций – смотрите и щупайте – http://bluzphp.github.io/.
Исходные файлы конфигураций доступны в репозитории на GitHub:
Один момент
Есть у данного решения один недостаток – нет в паблике версионирования документации (логи изменений не в счёт), чтобы решить данную проблему, нужно не так много – добавлять документацию для каждого тега (потребуется переменная $TRAVIS_TAG
), а в репозитории документации подхватывать все новые директории (вроде как функционала страниц хватит для этого), но это пока отложено в долгий ящик.
P.S. При написании данного руководства использовались материалы из статьи Publier automatiquement une PHPDoc sur GitHub avec Travis CI