Мы, в WB—Tech в качестве системы непрерывной интеграции используем TeamCity. А саму разработку ведем в приватных репозиториях на github. С задачей запуска тестов и публикации статуса выполнения в ветку на github
TeamCity
справляется отлично. Но выводить отчет по покрытию кода из коробки умеет только для Java
и .NET
, а это не наш профиль. Хотелось получить собственную систему, похожую на Coveralls работающую с python
.
В результате в пулреквест выводится показатель покрытия кода тестами, учитывая необходимый минимум 85%
, а также предоставляет ссылку на отчет.
Формирование отчета
Первым делом, необходимо сформировать данные о покрытии кода. Делаем это с помощью утилиты 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 формирует красивый бейджик со статусом покрытия кода .
После того, как исходные данные для отчета подготовлены, мы можем отображать результат. Для этого нужно сконфигурировать сбор артефактов в teamcity
. Делается это на вкладке General Settings
в настройках проекта. Мы копируем в артефакты папку htmlcov
содержащую отчет и бейджик.
После следующего запуска тестов, перейдя во вкладку Artifacts
, можно увидеть дерево артефактов данного билда.
Сами артефакты также доступны авторизованным пользователям 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
.
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%, то данная проверка будет считаться ошибкой, и в гитхабе отметиться красным крестиком.
Бейджик в 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
виден кликабельный бейджик с покрытием кода.
Кликнув на который, мы попадаем в отчет по покрытию кода.