Использования Travis CI для генерации документации

Люблю я всякие автоматизации процессов, вот дошла очередь и до генерации документации в проекте 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 Clean Template

Для более тонкой настройки можно использовать конфигурационный файл 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:

GitHub Access Token

Скопируйте его и никому не показывайте, если есть сомнения, что кто-то посягнул на него – перегенируйте токен заново.

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

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.