﻿# Запуск PVS\-Studio в GitLab CI/CD

## Запуск PVS\-Studio в GitLab CI/CD

[GitLab](https://about.gitlab.com/) — это онлайн\-сервис для управления репозиториями\. Его можно использовать прямо в браузере на официальном сайте, зарегистрировав аккаунт, или установить и развернуть на собственном сервере\.

**Обратите внимание**: вы можете посмотреть пример интеграции, приведённый в документации, на нашем [демо\-стенде в Gitlab](https://gitlab.com/PVS-Studio/pvs_studio_demo_cs_project)\.


> В данной документации рассматривается пример интеграции PVS\\\-Studio для анализа C\\\# проекта на Linux\\\. Команды запуска PVS\\\-Studio для анализа C, C\\\+\\\+ или Java кода будут отличаться\\\. Смотрите соответствующие разделы документации: "\[Как запустить PVS\\\-Studio на Linux и macOS\]\(https://pvs\-studio\.ru/ru/docs/manual/0036/\)" и "\[Работа с ядром Java анализатора из командной строки\]\(https://pvs\-studio\.ru/ru/docs/manual/6703/\)"\\\.

При запуске задачи GitLab CI берёт инструкции из файла `.gitlab-ci.yml`\. Его можно добавить либо кликнув на кнопку **Set up CI/CD**, либо создав в локальном репозитории и загрузив на сайт\. 

## Окружение для сборки и анализа

CI/CD пайплайны в Gitlab могут выполняться как на предоставленных машинах, так и в Docker\-контейнерах\. При этом Gitlab позволяет хранить образы контейнеров в регистре образов, находящемуся непосредственно в проекте\. Мы воспользуемся этой возможностью для демонстрации работы с PVS\-Studio\.

Для начала создадим `Dockerfile`, в котором опишем процесс установки зависимостей для сборки и анализа проекта\. В нашем случае демонстрация проводится на примере `.NET` проекта:

```cpp
FROM ubuntu:24.04

RUN apt update && apt install gpg wget software-properties-common -y

RUN add-apt-repository ppa:dotnet/backports && apt install dotnet-sdk-9.0 -y

RUN wget -qO- https://files.pvs-studio.com/etc/pubkey.txt | \
      gpg --dearmor -o /etc/apt/trusted.gpg.d/viva64.gpg \
 && wget -O /etc/apt/sources.list.d/viva64.list \
      https://files.pvs-studio.com/etc/viva64.list \
 && apt update && apt install pvs-studio pvs-studio-dotnet -y
```

После подготовки `Dockerfile` необходимо собрать образ с корректным тегом и загрузить его в Registry проекта\. Тэг должен включать url Gitlab, неймспейс и название проекта\.

```cpp
docker build -t registry.gitlab.com/namespace/name .
docker push registry.gitlab.com/namespace/name
```

**Примечание**: если использование контейнера не выглядит удобным, то установку анализатора можно произвести и в самом пайплайне\. 

## Пайплайн

Как говорилось выше, пайплайн будет исполнятся в ранее созданном Docker\-контейнере\. Отразим данный факт в тексте файла `.gitlab-ci.yml`\. Помимо этого, укажем, что данный пайплан выполняется при Merge Request, коммитах в основную ветку и коммите тэгов\. Также, опишем стадии пайплайна\.

```cpp
image: registry.gitlab.com/namespace/name

workflow:
  rules:
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
    - if: $CI_COMMIT_TAG
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    
stages:
  - build
  - analyze
```

Наш демонстрационный проект собирается очень просто:

build:

  stage: build

  script:

    \- 'dotnet build'

После того, как мы убедились, что проект собирается, мы можем запустить его анализ с помощью анализатора PVS\-Studio\. Инструменты анализа уже установлены в контейнере, поэтому нам остаётся только ввести лицензию \(которая заранее внесена в соответствующие переменные проекта\), запустить анализ и провести необходимые трансформации отчёта\.

```cpp
analyze:
  stage: analyze
  needs: [build]
  dependencies: []
  script:
    - 'pvs-studio-analyzer \
           credentials $PVS_STUDIO_LICENSE_NAME $PVS_STUDIO_LICENSE_KEY'
    - 'pvs-studio-dotnet -t dotnetcore.csproj -o pvs.json || :'
    - 'plog-converter -t gitlab -a all -o pvs_codequality.json pvs.json'
    - 'plog-converter -t html   -a all -o pvs_report.html      pvs.json'
    - 'plog-converter -t totals -a all -o pvs_metrics.txt      pvs.json'
  artifacts:
    expose_as: 'PVS-Studio report'
    paths: ['pvs_report.html', 'pvs_metrics.txt']
    reports:
      codequality: pvs_codequality.json
```

Переменные определяются в настройках по пути **Settings \> CI/CD \> Variables**\.

![GitLab_ru/image1.png](https://import.viva64.com/docx/blog/GitLab_ru/image1.png)

Для ввода лицензии необходимо вызвать утилиту `pvs-studio-analyzer` с флагом `credentials`, в который передаются имя пользователя анализатора, привязанное к ключу, и ключ лицензии соответственно\. Данные ключи можно хранить, например, в переменных проекта, как показано в нашем примере\.

Обратите внимание, как анализатор \(в нашем случае утилита `pvs-studio-dotnet`\) создаёт файл `pvs.json`\. Это отчёт анализатора\. Далее он преобразовывается в другие форматы с помощью утилиты `plog-converter` — конвертатора отчётов PVS\-Studio\. Результирующие отчёты сохраняются в артефактах задачи для последующей демонстрации в Merge Request, для реализации Quality Gate, а также загружаются в **Code Quality**\.

Следующий этап — использование результатов анализа PVS\-Studio в качестве Quality Gate\. Quality Gate — это механизм, который предназначен для контроля качества проекта через оценку различных метрик\. В нашем случае метрикой выступает количество различных предупреждений, содержащихся в отчётах анализатора PVS\-Studio\.

```cpp
quality_gate:
  stage: analyze
  needs: [analyze]
  dependencies: [analyze]
  script:
    - read PVS_HIGH_LEVEL_COUNT PVS_MID_LEVEL_COUNT \
    < <(grep "Total L1:" pvs_metrics.txt | \
      sed -E 's/.*L1:([0-9]+) \+ L2:([0-9]+).*/\1 \2/')
    - '[ "$PVS_HIGH_LEVEL_COUNT" -gt "$PVS_MAX_HIGH_LEVEL_COUNT" ] && \
    { echo "ERROR: Higl Level warnings number ($PVS_HIGH_LEVEL_COUNT)\
    exceed maximum allowed ($PVS_MAX_HIGH_LEVEL_COUNT)"; exit 1; } || :'
    - '[ "$PVS_MID_LEVEL_COUNT"  -gt "$PVS_MAX_MID_LEVEL_COUNT"  ] && \
    { echo "ERROR: Mid Level warnings number ($PVS_MID_LEVEL_COUNT) \
    exceed maximum allowed ($PVS_MAX_MID_LEVEL_COUNT)"; exit 1; } || :'
```

Мы используем файл `pvs_metrics.txt`, полученный на предыдущем этапе из изначального отчёта PVS\-Studio\. В нём содержится информация о количестве различных ошибок, найденных в проверяемом проекте\. В этом примере мы получаем количество ошибок с уровнями **High** и **Medium**, после чего сравниваем их с заранее определёнными пороговыми значениями, которые хранятся в переменных проекта\. Для реализации Quality Gate также рекомендуется использовать специализированные инструменты непрерывного мониторинга качества кода, например [SonarQube](https://pvs-studio.ru/ru/docs/manual/0037/)\.

## Загрузка результатов анализа в Code Quality

Ранее мы уже рассмотрели процесс загрузки отчёта в Code Quality\. Для этого использовалась утулита `plog-converter`:

```cpp
plog-converter -t gitlab -a all -o pvs_codequality.json pvs.json
```

Получаемый из данной утилиты отчёт загружается в **Code Quality** как артефакт:

```cpp
  artifacts:
    reports:
      codequality: pvs_codequality.json
```

Результаты **Code Quality** можно посмотреть, например, из окна **Merge Request**:

![GitLab_ru/image2.png](https://import.viva64.com/docx/blog/GitLab_ru/image2.png)

В нём будут показываться новые и исправленные предупреждения анализатора\. 

Список всех предупреждений можно посмотреть в отчёте в html\-формате, также полученном с помощью утилиты `plog-converter`:

```cpp
plog-converter -t html -a all -o pvs_report.html  pvs.json
```

Этот отчёт далее сохраняется как артефакт и прикрепляется ссылкой к Merge Request через `expose_as`:

```cpp
artifacts:
  expose_as: 'PVS-Studio report'
  paths: ['pvs_report.html', 'pvs_metrics.txt']
```

## Анализ изменённый файлов

Gitlab позволяет получить дельту изменённых файлов\. Для этого можно использовать следующий код:

```cpp
get_file_changes:
  stage: analyze
  script:
    - |
      if [ "$CI_PIPELINE_SOURCE" = "merge_request_event" ]; then
        BASE=$CI_MERGE_REQUEST_TARGET_BRANCH_SHA
      else
        BASE=$CI_COMMIT_BEFORE_SHA
        if [ "$BASE" = "0000000000000000000000000000000000000000" ]; then
          BASE=$(git rev-parse HEAD~1)
        fi
      fi
    - |
        'git diff-tree --no-commit-id --name-only -r $BASE -r $CI_COMMIT_SHA 
         -- "*.cs" > changed_files.txt'
  artifacts:
    paths:
      - changed_files.txt
```

Важно отметить, что в зависимости от типа события, запустившего пайплайн, способ получения дельты файлов будет отличаться\.

Полученные файлы можно использовать на последующих этапах, так как анализатор PVS\-Studio поддерживает анализ списка файлов\. В случае с проектами на C\#, вызова анализатора будет выглядеть следующим образом:

```cpp
if [ -s changed_files.txt ]; then
    pvs-studio-dotnet -t dotnetcore.csproj -f changed_files.txt -o pvs.json || :
else
    echo "{ \"version\": 3, \"warnings\": [] }" > pvs.json
fi
```

Подробнее о режиме проверки списка файлов можно прочитать в [нашей документации](https://pvs-studio.ru/ru/docs/manual/0055/#source_list)\.