Удобная подсветка покрытия кода тестами в Merge Request GitLab

—

от автора

Проблема

Основным средством для командной работы с репозиторием компании, в которой я работаю, является Gitlab. На первый взгляд, он хорош: и бесплатной версии хватает сполна, и CI/CD — пайплайн имеется, и хранить артефакты тоже можно (долой Nexus). Однако, и у GitLab есть свои минусы.

Так, например, разработчики до сих пор не смогли реализовать визуализацию покрытия тестов. Да, она у них есть, но для её реализации нужно сгенерировать и загрузить в GitLab отчет о покрытии в устаревшем формате Cobertura, а не в актуальном Jacoco. Основная же проблема в том, что Cobertura plugin последний раз обновлялся в далеком 2015 году. 

То есть этот плагин уже не поддерживается Java 8. Прикрепляю ссылки на официальные источники, чтобы вы могли понять, насколько там все запущено))

И что же нам предлагает сделать GitLab? Он сделал все «по-человечески»? Нет))) он предложил использовать скрипт на Python для перевода отчета в формате Jacoco в отчет в формате Cobertura.

Выглядит это так:

test-jdk11:   stage: test   image: maven:3.6.3-jdk-11   script:     - mvn $MAVEN_CLI_OPTS clean org.jacoco:jacoco-maven-plugin:prepare-agent test jacoco:report   artifacts:     paths:       - target/site/jacoco/jacoco.xml  coverage-jdk11:   # Must be in a stage later than test-jdk11's stage.   # The `visualize` stage does not exist by default.   # Please define it first, or choose an existing stage like `deploy`.   stage: visualize   image: registry.gitlab.com/haynes/jacoco2cobertura:1.0.7   script:     # convert report from jacoco to cobertura, using relative project path     - python /opt/cover2cover.py target/site/jacoco/jacoco.xml $CI_PROJECT_DIR/src/main/java/ > target/site/cobertura.xml   needs: ["test-jdk11"]   artifacts:     reports:       coverage_report:         coverage_format: cobertura         path: target/site/cobertura.xml

Подробнее об этом решении по ссылке.

Громоздко, правда? Даже приходится подключать дополнительный образ, чтобы скрипт заработал.

Наша компания не единственная, кто заметил эту проблему. Так в 2020 году Markus Schuch создал запрос разработчикам GitLab о добавлении поддержки отчетов о покрытии в формате Jacoco. Но решение данной проблемы так и не сдвинулось с места. Поэтому руководством нашей компании мне было поручено написать плагин, который будет переводить отчет jacoco.xml в cobertura.xml. Таким образом, в компании решили сразу 2 задачи: и получили необходимый функционал, и заняли делом джуна.

Решение

Было решено написать плагин, который упростит создание отчета в формате Cobertura. Принцип работы плагина: перевести отчет формата Jacoco в Cobertura.

Проблемы написания плагина

Подбор библиотек

Сначала для парсинга файла формата XML необходимо было подобрать библиотеку. Так как существует множество разновидностей библиотек со своими плюсами и минусами выбор оказался непростым.

Например, DOM парсер – это древовидный синтаксический анализатор. Таким парсером очень удобно искать элементы в файле, но у него есть недостаток – скорость.

SAX парсер работает иначе, он не создает никакой доменной структуры, а последовательно читает/записывает XML файл. Поэтому SAX парсер работает гораздо быстрее чем DOM, но он не умеет так же хорошо искать элементы файла. Поэтому мной была выбрана библиотека JDOM2 для чтения jacoco.xml и SAX для записи в cobertura.xml.

Написание алгоритма преобразования Jacoco в Cobertura

Основная идея алгоритма была позаимствована из питоновского скрипта cover2cover.py. Однако, немного изменить логику алгоритма всё же пришлось. Например, различная работа XML библиотек в Python и Java, различный результат при математических вычислениях чисел с плавающей запятой.

После того как стало понятно, что алгоритм, написанный на Java, выдает такие же отчеты, что и cover2cover.py необходимо было реализовать удобство применения в сторонних java приложениях. Очевидно, что для этого необходимо написать плагин. О том как написать плагин есть хорошая статья.

Всего в мой плагин можно передать 3 переменные:

  • source — путь к файлу формата Jacoco (дефолтное значение: target/site/jacoco/jacoco.xml);

  • result — путь, куда файл cobertura.xml будет размещен после работы плагина (дефолтное значение: target/site/cobertura/cobertura.xml);

  • pathsToProject — список путей к классам относительно корня проекта (дефолтное значение: /src/main/java/).

Важно, чтобы по пути, указанному в source, лежал jacoco.xml, иначе перевод не отработает. Также в pathsToProject можно передавать как один путь к пакетам, так и несколько путей, если проект мультимодульный.

Например, для проекта со структурой:

pet-parent/     +- pet/         +- src/             +- main/                 +- java/                     +- pom.xml                     ...     +- pet-api/         +- src/             +- main/                 +- java/                     +- pom.xml                     ...     +- pet-test/         +- pom.xml     +- pom.xml

Необходимо передать пути /pet-api/src/main/java/ и /pet/src/main/java/. Теперь покрытия тестами обоих модулей будут видны!

Как пользоваться

В pom.xml

Плагин очень просто добавить в pom.xml, и он будет генерировать отчет cobertura.xml туда, куда Вам потребуется. В общем, работает он также, как и Jacoco плагин, а главное условие выполнения — правильно указать параметры и поставить его в pom.xml после Jacoco плагина.

Вот фрагмент pom.xml, в котором наглядно показано, как настраивать плагин:

<project>     ...     <build>         <!-- To use the plugin goals in your POM or parent POM -->         <plugins>             ...             <plugin>               <groupId>ru.siblion.lab</groupId>               <artifactId>jacocoToCobertura-maven-plugin</artifactId>               <version>0.0.2</version>               <executions>                 <execution>                   <goals>                     <goal>convert</goal>                   </goals>                 <phase>test</phase>               </execution>             </executions>             <configuration>               <source>path to jacoco.xml</source>               <result>path to cobertura.xml</result>               <pathsToProject>path to project files</pathsToProject>                    </configuration>           </plugin>             ...         </plugins>     </build>     ... </project>

А для мультимодульного проекта (возьмем пример из прошлой главы) параметр pathsToProject будет выглядеть так:

<pathsToProject>/pet/src/main/java/,/pet-api/src/main/java/</pathsToProject>

То есть просто перечисляем через запятую. Теперь каждый раз после запуска тестов будет появляться отчет в формате Cobertura)))

В .gitlab-ci.yml необходимо будет добавить, чтобы GitLab увидел отчет:

artifacts:     reports:       coverage_report:         coverage_format: cobertura         path: target/cobertura/cobertura.xml

В CI/CD пайплайне

Иногда не хочется лишний раз изменять pom.xml, чтобы ничего не поломалось. Поэтому работу jacocoToCobertura плагина можно настроить в файле .gitlab-ci.yml:

mvn-test:   stage: test   script:     - "./mvnw -ntp -s .m2/settings.xml --batch-mode clean test"   artifacts:     paths:       - target/site/jacoco/jacoco.xml    only:     - merge_requests     - main  coverage:   stage: visualize   script:     - "./mvnw $MAVEN_CLI_OPTS dependency:get -Dartifact=ru.siblion.lab:jacocoToCobertura-maven-plugin:0.0.2"     - "./mvnw $MAVEN_CLI_OPTS ru.siblion.lab:jacocoToCobertura-maven-plugin:0.0.2:convert         -Dsource="target/site/jacoco/jacoco.xml"         -Dresult="target/site/cobertura/cobertura.xml"         -DpathesToProject="${CI_PROJECT_DIR}/src/main/java/""   coverage: "/Total.*?([0-9]{1,3})%/"   artifacts:     reports:       coverage_report:         coverage_format: cobertura         path: target/site/cobertura/cobertura.xml    only:     - merge_requests     - main

Результат

Теперь после успешного выполнения пайплайна в изменениях в merge request появится красивая подсветка, которая показывает какой код покрыт тестами, а какой нет.

Кроме того, после выполнения пайплайна итоговое покрытие проекта будет отображаться в Jobs пайплайна.

Технические ограничения

Плагин написан на Java 17. Требуется наличие Jacoco plugin, стоящий в файле pom.xml выше, чем jacocoToCobertura-plugin. Визуализация покрытия сохраняется неделю, но затем пропадает.

Ограничения от GitLab: не более 100 источников source в отчете, то есть не более 100 модулей в проекте. Размер одного XML-файла Cobertura не может превышать 10 МБ. Подробнее про ограничения от GitLab тут.

Заключение

Этот плагин выложен на Maven Central, я надеюсь что он сможет сделать ваш merge request чуточку ярче))) Если есть идеи и предложения по улучшению, пишите. Исходники прикреплены.

Авторы

  • Дмитриев Егор

  • Митрофанов Сергей

Ссылки


ссылка на оригинал статьи https://habr.com/ru/articles/758066/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *