Короткая заметочка про PVS Studio в CI (и чего не хватает)

habr.png

Я думаю, нет смысла в очередной раз рекламировать замечательный инструмент для статического анализа — PVS Studio. На хабре уже немало статей ей посвящённых, но я хочу коснуться ещё одного аспекта — использование данного инструмента в системе непрерывной интеграции.

Итак, есть некоторая организация, есть в ней CI, который работает просто: Jenkins получает хук после push-а в Git, после чего запускает некоторый пайплайн. В силу используемых инструментов сборка ведётся для проектов, созданных на C# (msbuild) и C++ (msbuild, CMake). На одном из финишных этапов запускается генерация отчётов в том числе с помощью PVS Studio (среди прочего — cppcheck, но это не важно для дальнейшего повествования).
PVS Studio имеет консольный инструмент анализа, который запускается из командной строки: PVS-Studio_Cmd.exe --target "${projectFile}" --output report.plog --progress
На входе — имя проекта (.sln), на выходе — отчёт.
Отчёт — файл с расширением .plog, представляет собой обычный XML-файл. Схема документа встроена, поэтому никаких неожиданностей по выходному формату быть не может. ПО крайней мере пока разработчики схему не поменяют, но не будем рассматривать этот вариант.
Отчёт состоит из набора записей, каждая из которых указывает на файл и строку в нём, класс ошибки, уровень ошибки, описание и прочие не сильно интересные вещи.
Но читать XML глазами — удовольствие так себе, поэтому нужен какой-то способ просмотра и навигации.
Самый простой и рабочий — это плагин PVS Studio для Visual Studio, с возможностью навигации по коду. Но заставлять технического руководителя или иного заинтересованного человека всякий раз загружать проект в VS — дурной тон, да и история развития проекта не видна.
Поэтому пойдём другим путём и посмотрим, что можно сделать. А есть достаточно стандартный путь, который позволяет преобразовать XML во что-то другое: XSLT. Сейчас, наверное, кого-то из читателей передёрнуло, но, тем не менее, предлагаю продолжить чтение.
XSLT — это язык преобразования XML-документов во что-то другое. Он просто сопоставляет входному шаблону правило преобразования, но Мы для себя сделали преобразование в HTML-отчёт.
Надеюсь, никто не будет судить меня за вёрстку таблицами, ибо данные по своей природе табличные. Каждая запись в отчёте будет соответствовать строке таблицы со следующими столбцами:


  1. Номер строки в таблице.
  2. Имя файла.
  3. Номер строки.
  4. Код ошибки.
  5. Сообщение об ошибке.

Номер строки просто удобно для устной ссылки при обсуждении.
Имя файла совместно с именем строки позволяют создать ссылку на репозиторий. Но об этом чуть позже.
Код ошибки обрамляется ссылкой на сайт разработчиков PVS-Studio: http://viva64.com/en/{ErrorCode} (или /ru/, кому как нравится).
Сообщение об ошибке — без комментариев.

Есть некоторые моменты, с которыми пришлось иметь дело.
Во-первых, хотелось бы, чтобы сообщения сортировались по уровню важности, а также иметь общее количество сообщений каждого типа. Первая задача решается с помощью выражения xsl:sort, вторая — count(тег[условие]).
Второе: имя файла указывается полным, а для формирования ссылки на систему контроля версий нужно относительное имя. Надо просто отрезать префикс, соответствующий имени каталога с проектом, в который клонировался репозиторий (у нас Git, но это легко адаптируется). Но для того, чтобы этот путь появился, нам надо параметризовать XSL-трансформацию с помощью конструкции xsl:param. Дальше относительно просто: удалить из строки с именем файла общий префикс с именем каталога, куда репозиторий склонирован. Надо сказать, в XSLT эта задача решается достаточно изощрённо.
Третье: проверка относится к конкретной ревизии в репозитории, и это тоже надо иметь в виду. Решается с помощью параметра с идентификатором коммита. Аналогично для веток.
Четвёртое: если используются сторонние библиотеки с исходниками, не стоит смешивать предупреждения в них с предупреждениями в нашем проекте. Решается задача следующим образом: все внешние проекты складываем в некоторый каталог, имя которого не содержится в нашем проекте. Теперь, если имя файла содержит этот подкаталог (на самом деле просто подстроку), то запись в plog-е не попадает в отчёт, но считается как «скрытая» в заголовке отчёта. Для большей гибкости можно параметризовать трансформацию и назначить этому каталогу имя по умолчанию:
Ну и ещё одна маленькая задачка: собрать ссылку на репозиторий. Мы используем redmine+gitolite. Опять-таки, адаптируемо.
Поскольку многие параметры являются константыми для преобразования, можно подготовить константный префикс URL-а:


    http://redmine.your-site.com/projects/
    
    /revisions/
    
    /entry/
  

Немного красивостей со стилизацией, и можно пользоваться. CSS внедряем в страницу, просто чтобы иметь отчёт одним файлом. Картинки нам тоже не нужны.
Полный код трансформации под спойлером


XSLT


  

  
  
  
  
  

  
    http://redmine.your-company.com/projects/ 
    
    /revisions/
    
    /entry/
  

  
    
    

    
    

    
      
        
      
      
        
      
    
  

  
    
    
    
    

    
      
        
      
      
        
          
          
          
          
        
      
      
        
      
    
  

    
      
    

    
      
      
        
      
      
        
          
          
          
            
              
              
            
          
          
        
      
    

  

  

    

    

    
      
        
      
      
        

PVS-Studio report

High: Meduim: Low: Hidden:

No error messages.

sev- fa
# File Line Code Message

Мы запускаем трансформацию с помощью маленькой консольной утилиты, написанной на C#, но вы можете сделать это и по-другому (если надо — тоже поделюсь, там нет ничего сложного и секретного).
А дальше из этого можно сделать dashboard, но это уже, как говорится, совсем другая история.

А теперь немного плача в сторону разработчиков. Есть один не то баг, не то фича, которая делает невозможным полноценно сделать то, что описано выше, притом это касается только С++-проектов, в C# такой беды нет. Когда формируется plog-файл, в теге имя всегда приводится к нижнему регистру. А когда redmine (и прочий веб) хостится на UNIX-подобных системах с регистрозависимыми именами файлов, ломается регистр при формировании ссылок на файлы, что делает ссылки неработоспособными. Такая вот печаль.
На письмо в техподдержку я получил ответ, что такое поведение обусловлено внешним API, но непонятно, почему оно такое избирательное и касается только C++, и не касается C#.
Поэтому я пока, как и обещал, взываю к продолжению Paull и надеюсь на плодотворное сотрудничество.

Спасибо за внимание.

© Habrahabr.ru