Для получения триального ключа
заполните форму ниже
Team License (базовая версия)
Enterprise License (расширенная версия)
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
GBP
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Бесплатная лицензия PVS-Studio для специалистов Microsoft MVP
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Мне интересно попробовать плагин на:
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте папку
Spam/Junk и нажмите на письме кнопку "Не спам".
Так Вы не пропустите ответы от нашей команды.

>
>
Анализ коммитов и Pull Requests в Travi…
Сообщения PVS-Studio
Диагностики общего назначения (General Analysis, C++)
Диагностики общего назначения (General Analysis, C#)
Диагностики общего назначения (General Analysis, Java)
Диагностика микро-оптимизаций (C++)
Диагностика 64-битных ошибок (Viva64, C++)
Cтандарт MISRA
Стандарт AUTOSAR
Стандарт OWASP (C#)
Дополнительная информация
Оглавление

Анализ коммитов и Pull Requests в Travis CI, Buddy и AppVeyor

06 Апр 2021

В данной статье описана проверка Pull Requests на Linux и macOS. Проверка Pull Requests на Windows описана в соответствующем разделе документации утилит PVS-Studio_Cmd и CLMonitor (подраздел "Задание отдельных файлов для проверки").

Проверка Pull Requests доступна только для Enterprise лицензии PVS-Studio. Вы можете запросить пробную Enterprise лицензию на странице загрузки.

Режим проверки списка файлов

В PVS-Studio, начиная с версии 7.04, для Linux и macOS существует режим проверки списка исходных файлов. Работает это для проектов, сборочная система которых позволяет сгенерировать файл 'compile_commands.json'. Он нужен для того, чтобы анализатор извлёк информацию о компиляции указанных файлов. Если ваша сборочная система не поддерживает генерацию файла 'compile_commands.json', вы можете попробовать сгенерировать такой файл с помощью утилиты Bear.

Также режим проверки списка файлов можно использовать вместе с логом трассировки 'strace' запусков компилятора (pvs-studio-analyzer trace). Для этого вам нужно сначала провести полную сборку проекта в режиме трассировки, чтобы анализатор собрал полную информацию о параметрах компиляции всех файлов.

Однако у такого варианта есть существенный недостаток - нужно будет либо производить полную трассировку сборки всего проекта при каждом запуске, что само по себе противоречит идее быстрой проверки коммита. Либо, если закэшировать сам результат трассировки, последующие запуски анализатора могут оказаться неполными, если после трассировки поменяется структура зависимостей исходных файлов (например, в один из исходных файлов будет добавлен новый #include).

Поэтому мы не рекомендуем использовать режим проверки списка файлов с логом трассировки для проверки коммитов или Pull Requests. В случае, если вы можете делать при проверке коммита инкрементальную сборку, рассмотрите возможность использовать режим инкрементального анализа.

Список исходных файлов для анализа сохраняется в текстовой файл и передаётся анализатору с помощью параметра '-S':

pvs-studio-analyzer analyze ... -f build/compile_commands.json -S check-list.txt

В этом файле указываются относительные или абсолютные пути к файлам, причем каждый новый файл должен быть на новой строке. Текст, который не является путем к файлу с исходным кодом, игнорируется. Это может быть полезно для комментирования, если файлы указываются вручную. Однако зачастую список файлов будет сгенерирован во время анализа в CI, например, это могут быть файлы из коммита или Pull Request.

Для корректной работы режима проверки списка файлов, при первом запуске анализа будет сгенерирован файл зависимостей всех исходных файлов проекта от заголовочных. Необходимость такого файла - особенность анализа C/C++ файлов. В дальнейшем файл зависимостей закэшируется и будет обновляться анализатором автоматически.

Для того, чтобы сгенерировать или обновить файл зависимостей без запуска анализа, можно воспользоваться флагом '--regenerate-depend-info' с ключом 'skip-analysis':

pvs-studio-analyzer analyze ... -f build/compile_commands.json \ 
                                –-regenerate-depend-info skip-analysis

Если по каким-либо причинам требуется проанализировать списков файлов или проект целиком, принудительно обновив при этом кэш зависимостей, то можно воспользоваться флагом '--regenerate-depend-info' с ключом 'run-analysis':

pvs-studio-analyzer analyze ... -S source_files \
                                -f build/compile_commands.json \
                                --regenerate-depend-info run-analysis

Теперь с помощью этого режима можно быстро проверять новый код до попадания его в основную ветку разработки. Чтобы система проверки реагировала на наличие предупреждений анализатора, в утилите 'plog-converter' существует флаг '--indicate-warnings':

plog-converter ... --indicate-warnings ... -o /path/to/report.tasks ...

С этим флагом конвертер вернёт ненулевой код, если в отчёте анализатора присутствуют предупреждения. По коду возврата можно заблокировать прекоммит хук, коммит или Pull Request, а сгенерированный отчёт анализатора вывести на экран или отправить по почте.

Общие принципы анализа Pull Request

Анализ всего проекта занимает достаточно много времени, поэтому есть смысл в том, чтобы проверять только некоторую его часть. Проблема в том, что нужно отделить новые файлы от остальных файлов проекта.

Рассмотрим пример дерева коммитов с двумя ветками:

PullRequestAnalysis_ru/image1.png

Представим, что коммит 'A1' содержит достаточно большое количество кода, который уже проверили. Немного ранее была создана ветка 'hotfix' от коммита 'A1' и были изменены какие-то файлы.

Как видно из примера, после 'A1' в ветку 'master' произошло ещё два коммита. Как только ветка 'hotfix' готова к слиянию, открывается Pull Request на слияние изменений 'B3' и 'A3'.

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

Для этого необходимо получить разницу между ветками, находясь в HEAD ветки, из которой хотим залить изменения в 'master':

git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list

Переменная '$MERGE_BASE' будет подробно рассмотрена позже. Дело в том, что далеко не каждый CI сервис дает необходимую информацию про базу для слияния, поэтому каждый раз приходится придумывать новые способы получения этих данных. Это будет подробно расписано ниже в каждом из описанных веб-сервисов.

После того, как была получена разница между ветками, а точнее - список имен файлов, которые были изменены, необходимо передать файл '.pvs-pr.list' анализатору:

pvs-studio-analyzer analyze -j8 \
                            -o PVS-Studio.log \
                            -S .pvs-pr.list

После анализа необходимо сконвертировать файл отчета (PVS-Studio.log) в удобный для восприятия формат:

plog-converter -t errorfile PVS-Studio.log --cerr -w

Эта команда выведет список ошибок в stderr (стандартный поток вывода сообщений об ошибках).

Помимо вывода ошибок, часто бывает полезно сообщить сервису для сборки и тестирования о наличии проблем. Для этого в 'plog-converter' необходимо добавить флаг '-W' ('--indicate-warnings'). При наличии хоть одного предупреждения анализатора, код возврата утилиты 'plog-converter' изменится на 2, что, в свою очередь, сообщит CI сервису о наличии потенциальных ошибок в файлах Pull Request.

Travis CI

Конфигурация выполнена в виде файла '.travis.yml'. Для удобства советуем вынести всё в отдельный bash-скрипт с функциями, которые будут вызваны из файла '.travis.yml' ('bash имя_скрипта.sh имя_функции').

Добавим необходимый код в скрипт на 'bash'. В секции 'install' пропишем следующее:

install:
  - bash .travis.sh travis_install

Откроем файл '.travis.sh' и добавим установку анализатора в функцию 'travis_install()':

travis_install() {
  wget -q -O - https://files.pvs-studio.com/etc/pubkey.txt \
    | sudo apt-key add -
  sudo wget -O /etc/apt/sources.list.d/viva64.list \
    https://files.pvs-studio.com/etc/viva64.list
  
  sudo apt-get update -qq
  sudo apt-get install -qq pvs-studio 
}

Добавим в секцию 'script' запуск анализа:

script:
  - bash .travis.sh travis_script

И в bash-скрипте:

travis_script() {
  pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY
  
  if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
    git diff --name-only origin/HEAD > .pvs-pr.list
    pvs-studio-analyzer analyze -j8 \
                                -o PVS-Studio.log \
                                -S .pvs-pr.list \
                                --disableLicenseExpirationCheck
  else
    pvs-studio-analyzer analyze -j8 \
                                -o PVS-Studio.log \
                                --disableLicenseExpirationCheck
  fi
  
  plog-converter -t errorfile PVS-Studio.log --cerr -w
}

Этот код нужно запустить после сборки проекта, например, если производится сборка на CMake:

travis_script() {
  CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
  cmake $CMAKE_ARGS CMakeLists.txt
  make -j8
}

Получится так:

travis_script() {
  CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
  cmake $CMAKE_ARGS CMakeLists.txt
  make -j8
  
  pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY
  
  if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
    git diff --name-only origin/HEAD > .pvs-pr.list
    pvs-studio-analyzer analyze -j8 \
                                -o PVS-Studio.log \
                                -S .pvs-pr.list \
                                --disableLicenseExpirationCheck
  else
    pvs-studio-analyzer analyze -j8 \
                                -o PVS-Studio.log \
                                --disableLicenseExpirationCheck
  fi
  
  plog-converter -t errorfile PVS-Studio.log --cerr -w
}

Travis CI самостоятельно объявляет переменные окружения '$TRAVIS_PULL_REQUEST' и '$TRAVIS_BRANCH':

  • '$TRAVIS_PULL_REQUEST' хранит номер Pull Request или 'false', если это обычная ветка;
  • '$TRAVIS_REPO_SLUG' хранит имя репозитория проекта.

Алгоритм работы этой функции:

PullRequestAnalysis_ru/image2.png

Travis CI реагирует на коды возврата, поэтому наличие предупреждений укажет сервису пометить коммит как содержащий ошибки.

Рассмотрим подробнее эту строку кода:

git diff --name-only origin/HEAD > .pvs-pr.list

Дело в том, что Travis CI автоматически делает слияние веток во время анализа Pull Request:

PullRequestAnalysis_ru/image3.png

При таком варианте анализируется 'A4', а не 'B3->A3'. Из-за этой особенности необходимо высчитывать разницу с 'А3', которая как раз и является вершиной ветки из 'origin'.

Осталась одна важная деталь - кэширование зависимостей заголовочных файлов от компилируемых единиц трансляции (*.c, *.cc, *.cpp и т.д.). Эти зависимости анализатор вычисляет при первом запуске в режиме проверки списка файлов и сохраняет затем в директории '.PVS-Studio'. Travis CI позволяет кэшировать папки, поэтому мы сохраним данные директории '.PVS-Studio':

cache:
  directories:
    - .PVS-Studio/

Этот код нужно добавить в файл '.travis.yml'. Эта директория хранит различные данные, собранные после анализа, которые существенно ускорят последующие запуски анализа списка файлов или инкрементального анализа. Если этого не сделать, то анализатор фактически каждый раз будет анализировать все файлы.

Buddy

Как и Travis CI, Buddy предоставляет возможность автоматизированной сборки и тестирования проектов, которые хранятся на GitHub. В отличие от Travis CI, он настраивается в веб интерфейсе (поддержка bash имеется), поэтому нет необходимости хранить файлы конфигурации в проекте.

В первую очередь необходимо добавить новое действие в линию сборки:

PullRequestAnalysis_ru/image4.gif

Укажем компилятор, который использовался для сборки проекта. Обратите внимание на docker контейнер, который установлен в этом действии. Например, для GCC есть специальный контейнер:

PullRequestAnalysis_ru/image5.png

Теперь установим PVS-Studio и необходимые утилиты:

PullRequestAnalysis_ru/image6.gif

Добавим в редактор следующие строки:

apt-get update && apt-get -y install wget gnupg jq

wget -q -O - https://files.pvs-studio.com/etc/pubkey.txt | apt-key add -
wget -O /etc/apt/sources.list.d/viva64.list \
  https://files.pvs-studio.com/etc/viva64.list

apt-get update && apt-get -y install pvs-studio

Теперь перейдем на вкладку 'Run' (первая иконка), и в соответствующее поле редактора добавим следующий код:

pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY

if [ "$BUDDY_EXECUTION_PULL_REQUEST_NO" != '' ]; then
  PULL_REQUEST_ID="pulls/$BUDDY_EXECUTION_PULL_REQUEST_NO"
  MERGE_BASE=`wget -qO - \
    https://api.github.com/repos/${BUDDY_REPO_SLUG}/${PULL_REQUEST_ID} \
    | jq -r ".base.ref"`

  git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
  pvs-studio-analyzer analyze -j8 \
                              -o PVS-Studio.log \
                              --disableLicenseExpirationCheck \
                              -S .pvs-pr.list
else
  pvs-studio-analyzer analyze -j8 \
                              -o PVS-Studio.log \
                              --disableLicenseExpirationCheck
fi

plog-converter -t errorfile PVS-Studio.log --cerr -w

Если вы прочитали раздел, посвященный Travis-CI, то этот код уже вам знаком, однако, теперь появился новый этап:

PullRequestAnalysis_ru/image7.png

Дело в том, что теперь необходимо анализировать не результат слияния, а HEAD ветки, из которой делается Pull Request:

PullRequestAnalysis_ru/image1.png

Поэтому при нахождении в условном коммите 'B3' необходимо получить разницу с 'A3':

PULL_REQUEST_ID="pulls/$BUDDY_EXECUTION_PULL_REQUEST_NO"
  MERGE_BASE=`wget -qO - \
    https://api.github.com/repos/${BUDDY_REPO_SLUG}/${PULL_REQUEST_ID} \
    | jq -r ".base.ref"`
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list

Для определения 'A3' воспользуемся API GitHub:

https://api.github.com/repos/${USERNAME}/${REPO}/pulls/${PULL_REQUEST_ID}

Buddy предоставляет следующие переменные окружения:

  • '$BUDDY_EXECUTION_PULL_REQEUST_NO' - номер Pull Request;
  • '$BUDDY_REPO_SLUG' - сочетание имени пользователя и репозитория (например max/test).

Теперь сохраним изменения, воспользовавшись кнопкой внизу, и включим анализ Pull Request:

PullRequestAnalysis_ru/image8.gif

В отличии от Travis CI, нет необходимости указывать папку '.PVS-Studio' для кеширования, так как Buddy автоматически кеширует все файлы для последующих запусков. Поэтому осталось последнее - сохранить логин и пароль для PVS-Studio в Buddy. После сохранения изменений необходимо вернуться обратно в 'Pipeline', перейти к настройке переменных и добавить логин и ключ для PVS-Studio:

PullRequestAnalysis_ru/image9.gif

После этого появление нового Pull Request или коммита будет запускать проверку. Если коммит содержит ошибки, то Buddy укажет на это на странице Pull Request.

AppVeyor

Настройка AppVeyor похожа на Buddy, так как всё происходит в web интерфейсе, и нет нужды добавлять файл '*.yml' в репозиторий проекта.

Перейдем на вкладку 'Settings' в обзоре проекта:

PullRequestAnalysis_ru/image10.png

Прокрутим эту страницу вниз и включим сохранение кэша для сборки Pull Requests:

PullRequestAnalysis_ru/image11.png

Теперь перейдем на вкладку 'Environment', где укажем образ для сборки и необходимые переменные окружения:

PullRequestAnalysis_ru/image12.png

Если вы прочитали предыдущие разделы, ты вы хорошо знакомы с этими двумя переменными – 'PVS_KEY' и 'PVS_USERNAME'. Они необходимы для проверки лицензии анализатора PVS-Studio.

На этой же странице внизу укажем папку для кэширования:

PullRequestAnalysis_ru/image13.png

Без этой настройки будет анализироваться весь проект вместо пары файлов, но вывод получим по указанным файлам. Поэтому важно ввести правильное название директории.

Теперь настало время скрипта для проверки. Откроем вкладку 'Tests' и выберем 'Script':

PullRequestAnalysis_ru/image14.png

В эту форму нужно вставить следующий код:

sudo apt-get update && sudo apt-get -y install jq

wget -q -O - https://files.pvs-studio.com/etc/pubkey.txt \
  | sudo apt-key add -
sudo wget -O /etc/apt/sources.list.d/viva64.list \
  https://files.pvs-studio.com/etc/viva64.list

sudo apt-get update && sudo apt-get -y install pvs-studio

pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY

PWD=$(pwd -L)
if [ "$APPVEYOR_PULL_REQUEST_NUMBER" != '' ]; then
  PULL_REQUEST_ID="pulls/$APPVEYOR_PULL_REQUEST_NUMBER"
  MERGE_BASE=`wget -qO - \
    https://api.github.com/repos/${APPVEYOR_REPO_NAME}/${PULL_REQUEST_ID} \
    | jq -r ".base.ref"`

  git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
  pvs-studio-analyzer analyze -j8 \
                              -o PVS-Studio.log \
                              --disableLicenseExpirationCheck \
                              --dump-files --dump-log pvs-dump.log \
                              -S .pvs-pr.list
else
  pvs-studio-analyzer analyze -j8 \
                              -o PVS-Studio.log \
                              --disableLicenseExpirationCheck
fi

plog-converter -t errorfile PVS-Studio.log --cerr -w

Обратим внимание на следующую часть кода:

PWD=$(pwd -L)
if [ "$APPVEYOR_PULL_REQUEST_NUMBER" != '' ]; then
  PULL_REQUEST_ID="pulls/$APPVEYOR_PULL_REQUEST_NUMBER"
  MERGE_BASE=`wget -qO - \
   https://api.github.com/repos/${APPVEYOR_REPO_NAME}/${PULL_REQUEST_ID} \
   | jq -r ".base.ref"`

  git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
  pvs-studio-analyzer analyze -j8 \
                              -o PVS-Studio.log \
                              --disableLicenseExpirationCheck \
                              --dump-files --dump-log pvs-dump.log \
                              -S .pvs-pr.list
else
  pvs-studio-analyzer analyze -j8 \
                              -o PVS-Studio.log \
                              --disableLicenseExpirationCheck
fi

Достаточно специфичное присваивание значения команды 'pwd' переменной '$PWD' необходимо для корректной работы анализатора, поскольку AppVeyor модифицирует переменную для своих служебных целей в другое значение.

А дальше всё, как и раньше:

PullRequestAnalysis_ru/image15.png

Теперь рассмотрим следующий фрагмент:

PULL_REQUEST_ID="pulls/$APPVEYOR_PULL_REQUEST_NUMBER"
MERGE_BASE=`wget -qO - \
  https://api.github.com/repos/${APPVEYOR_REPO_NAME}/${PULL_REQUEST_ID} \
  | jq -r ".base.ref"`

В нём мы получаем разницу между ветками, над которыми объявлен Pull Request. Для этого нам нужны следующие переменные окружения:

  • '$APPVEYOR_PULL_REQUEST_NUMBER' - номер Pull Request;
  • '$APPVEYOR_REPO_NAME' - имя пользователя и репозиторий проекта.

Этот сайт использует куки и другие технологии, чтобы предоставить вам более персонализированный опыт. Продолжая просмотр страниц нашего веб-сайта, вы принимаете условия использования этих файлов. Если вы не хотите, чтобы ваши данные обрабатывались, пожалуйста, покиньте данный сайт. Подробнее →
Принять