Fork me on GitHub

Отчеты coverage в TeamCity Sep 26, 2016

Мы, в WB—Tech в качестве системы непрерывной интеграции используем TeamCity. А саму разработку ведем в приватных репозиториях на github. С задачей запуска тестов и публикации статуса выполнения в ветку на github TeamCity справляется отлично. Но выводить отчет по покрытию кода из коробки умеет только для Java и .NET, а это не наш профиль. Хотелось получить собственную систему, похожую на Coveralls работающую с python.

В результате в пулреквест выводится показатель покрытия кода тестами, учитывая необходимый минимум 85%, а также предоставляет ссылку на отчет.

pending

failure

success

Формирование отчета

Первым делом, необходимо сформировать данные о покрытии кода. Делаем это с помощью утилиты Coverage.py. Т.к. для удобства работы с проектом, мы используем Makefile, то пропишем в нем дополнительные команды, для запуска тестов с покрытием кода, и формирования отчета.

VENV_PATH := $(HOME)/venv/bin
PROJ_NAME := my_awesome_project

# ...

ci_test: cover_test cover_report

cover_test:
    $(VENV_PATH)/coverage run --source=$(PROJ_NAME) manage.py test -v 2 --noinput

cover_report:
    $(VENV_PATH)/coverage report -m
    $(VENV_PATH)/coverage html
    $(VENV_PATH)/coverage-badge > htmlcov/coverage.svg

Команда cover_test запускает джанговские тесты, и замеряет покрытие кода. Команда cover_report выводит в консоль отчет о покрытии, а также формирует html отчет и, при помощи утилиты coverage-badge формирует красивый бейджик со статусом покрытия кода badge.

После того, как исходные данные для отчета подготовлены, мы можем отображать результат. Для этого нужно сконфигурировать сбор артефактов в teamcity. Делается это на вкладке General Settings в настройках проекта. Мы копируем в артефакты папку htmlcov содержащую отчет и бейджик.

General Settings

После следующего запуска тестов, перейдя во вкладку Artifacts, можно увидеть дерево артефактов данного билда.

Artifacts tree

Сами артефакты также доступны авторизованным пользователям TeamCity напрямую по ссылкам вида:

  • /repository/download/%teamcity.project.id%/%teamcity.build.id%:id/htmlcov/index.html
  • /repository/download/%teamcity.project.id%/.lastFinished/htmlcov/index.html

Более подробно о доступе к артефактам в документации.

Уведомления статуса на Github

Имея готовый отчет будем отправлять вебхуки на github с указанием статуса покрытия кода. Для этого добавим простые build steps.

Build steps

Coverage pending hook

Заставляем гитхаб ждать отчета по покрытию кода.

  • Runner type Command Line
  • Execute step Even if some of the previous steps failed

Custom script

OWNER="<GITHUB OWNER>";
REPO="<REPO NAME>";
SHA="%build.vcs.number%";

curl "https://api.github.com/repos/$OWNER/$REPO/statuses/$SHA" \
    -X POST \
    -H "Content-Type: application/json" \
    -H "Authorization: token <GITHUB API TOKEN>" \
    -d '{
        "state": "pending",
        "description": "Coverage pending.",
        "context": "continuous-integration/coverage"
    }'

Badge copy

Копируем сформированный бейджик, в папку доступную напрямую через вебсервер. Для того, чтобы github имел доступ к бейджику без аутентификации в teamcity. Если у вас разрешен гостевой доступ - то этот шаг выполнять не обязательно.

  • Runner type Command Line
  • Execute step Even if some of the previous steps failed

Custom script

BADGE="/path/to/public/dir/badges/%teamcity.project.id%/%teamcity.build.branch%-coverage.svg"
DIR=$(dirname "${BADGE}")
mkdir -p $DIR
cp -f htmlcov/coverage.svg $BADGE

Coverage finish hook

По окончанию тестов, отправляем отчет на гитхаб.

  • Runner type Command Line
  • Execute step Even if some of the previous steps failed

Custom script

OWNER="<GITHUB OWNER>";
REPO="<REPO NAME>";
SHA="%build.vcs.number%";

REPORT_URL="http://<YOU TEAMCITY DOMAIN>/repository/download/%teamcity.project.id%/%teamcity.build.id%:id/htmlcov/index.html";

COVERAGE=$(cat ./htmlcov/index.html | grep '<span class="pc_cov">' | grep -o '[0-9]\+');

if [ "$COVERAGE" -ge "85" ]; then
    STATUS='success';
else
    STATUS='failure';
fi

curl "https://api.github.com/repos/$OWNER/$REPO/statuses/$SHA" \
    -X POST \
    -H "Content-Type: application/json" \
    -H "Authorization: token <GITHUB API TOKEN>" \
    -d '{
        "state": "'$STATUS'",
        "target_url": "'$REPORT_URL'",
        "description": "Coverage '$COVERAGE'%",
        "context": "continuous-integration/coverage"
    }'

В данном случае, если покрытие менее 85%, то данная проверка будет считаться ошибкой, и в гитхабе отметиться красным крестиком.

fail

success

Бейджик в readme

Для отображения бейджика в README.md добавим ссылку, на последний успешний билд.

[![coverage report](http://<TEAMCITY DOMAIN>/badges/<TEAMCITY PROJ ID>/master-coverage.svg)](http://<TEAMCITY DOMAIN>/repository/download/<TEAMCITY PROJ ID>/.lastFinished/htmlcov/index.html)

Где /badges/<TEAMCITY PROJ ID>/ доступна для анонимных посетителей, чтобы github мог закешировать изображение.

Теперь в README виден кликабельный бейджик с покрытием кода.

readme

Кликнув на который, мы попадаем в отчет по покрытию кода.

report