Харесвате ли GitLab и не харесвате грешки? Искате ли да подобрите качеството на вашия изходен код? Тогава сте попаднали на правилното място. Днес ще ви кажем как да конфигурирате C# анализатора на PVS-Studio за проверка на заявки за сливане. Приятно четене и приятно еднорогово настроение.

PVS-Studio е инструмент, предназначен да открива грешки и потенциални уязвимости в изходния код на програми, написани на C, C++, C# и Java. Работи в 64-битови системи на Windows, Linux и macOS. Може да анализира кода, предназначен за 32-битови, 64-битови и вградени ARM платформи.

PVS-Studio е инструмент, предназначен да открива грешки и потенциални уязвимости в изходния код на програми, написани на C, C++, C# и Java. Работи в 64-битови системи на Windows, Linux и macOS. Може да анализира кода, предназначен за 32-битови, 64-битови и вградени ARM платформи.

Между другото, ние пуснахме PVS-Studio 7.08, който беше пълен с нови хитри „функции“. Например:

  • C# анализатор под Linux и macOS;
  • плъгин за Rider;
  • нов режим за проверка на списък с файлове.

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

Преди това, за да се проверят определени файлове, трябваше да се предаде .xml на анализатора със списък от файлове. Но тъй като това не е много удобно, добавихме възможност за предаване на .txt, което прави живота много по-прост.

За да проверите определени файлове, посочете флага — sourceFiles (-f) и предайте .txt със списъка с файлове. Изглежда така:

pvs-studio-dotnet -t path/to/solution.sln -f fileList.txt -o project.json

Ако се интересувате от конфигуриране на проверки на ангажименти или заявки за изтегляне, можете също да направите това, като използвате този режим. Разликата ще бъде в получаването на списък с файлове за анализ и ще зависи от това кои системи използвате.

Принцип на проверка на заявките за сливане

Основната точка на проверката е да се уверите, че проблемите, открити от анализатора, не попадат в клона master при сливане. Освен това не искаме да анализираме целия проект всеки път. Освен това, когато обединяваме клонове, имаме списък с променени файлове. Затова предлагам да добавите проверка на заявка за сливане.

Ето как изглежда искането за сливане преди въвеждането на статичен анализатор:

С други думи, всички грешки в клона changes ще стигнат до главния клон. Тъй като това не ни харесва, добавяме анализа и сега схемата изглежда по следния начин:

Ние анализираме changes2 и, ако няма грешки, приемаме заявката за сливане, в противен случай я отхвърляме.

Между другото, ако се интересувате от анализиране на ангажименти и заявки за изтегляне за C/C++, можете да прочетете за това тук.

GitLab

GitLab е уеб инструмент за жизнения цикъл на DevOps с отворен код, който предоставя система за управление на кодово хранилище за Git със собствено уики, система за проследяване на грешки, CI/CD конвейер и други функции.

Преди да започнете да прилагате анализа на заявката за сливане, трябва да се регистрирате и да качите проекта си. Ако не знаете как да направите това, предлагам една статия от мой колега.

Забележка. Един от възможните начини за конфигуриране на средата е описан по-долу. Целта е да се покажат стъпките за конфигуриране на средата, необходима за анализиране и стартиране на анализатора. Във вашия случай може би е по-добре да разделите етапите на подготовка на средата (добавяне на хранилища, инсталиране на анализатора) и анализ. Например, подготовка на екземпляри на Docker с необходимата среда и тяхното използване или някакъв друг метод.

За да разберете по-добре какво ще се случи след това, предлагам да разгледате следната схема:

Анализаторът се нуждае от .NET Core SDK 3 за правилна работа, от който ще бъдат инсталирани необходимите зависимости за анализатора. Добавянето на хранилища на Microsoft за различни Linux дистрибуции е описано в съответния документ.

За да инсталирате PVS-Studio чрез мениджъра на пакети, ще трябва също да добавите PVS-Studio хранилища. Добавянето на хранилища за различни дистрибуции е описано по-подробно в съответния раздел на документацията.

Анализаторът се нуждае от лицензен ключ, за да работи. Можете да получите пробен лиценз на страницата за изтегляне на анализатора.

Забележка. Моля, обърнете внимание, че описаният режим на работа (анализ на заявки за сливане) изисква лиценз Enterprise. Ето защо, ако искате да изпробвате този режим на работа, не забравяйте да посочите, че имате нужда от Enterprise лиценз в полето „Съобщение“.

Ако възникне заявка за сливане, трябва да анализираме само списъка с променени файлове, в противен случай анализираме всички файлове. След анализа трябва да конвертираме регистрационните файлове във формата, от който се нуждаем.

Сега, с алгоритъма пред очите ви, можете да продължите с писането на скрипта. За да направим това, трябва да променим файла .gitlab-ci.yml или, ако няма такъв файл, да създадем такъв. За да го създадете, щракнете върху името на вашия проект -› Настройване на CI/CD.

Сега сме готови да напишем сценария. Нека първо напишем кода, който ще инсталира анализатора и ще въведем лиценза:

before_script:
  - apt-get update && apt-get -y install wget gnupg 
  - apt-get -y install git
  - wget https://packages.microsoft.com/config/debian/10/
packages-microsoft-prod.deb -O packages-microsoft-prod.deb
  - dpkg -i packages-microsoft-prod.deb
  - apt-get update
  - apt-get install apt-transport-https
  - apt-get update
  
  - wget -q -O - https://files.viva64.com/etc/pubkey.txt | apt-key add -
  - wget -O /etc/apt/sources.list.d/viva64.list
https://files.viva64.com/etc/viva64.list
  - apt-get update
  - apt-get -y install pvs-studio-dotnet
  - pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY
  - dotnet restore "$CI_PROJECT_DIR"/Test/Test.sln

Тъй като инсталирането и активирането трябва да се извърши преди всички други скриптове, ние използваме специален етикет before_script. Нека поясня този фрагмент.

Подготовка за инсталиране на анализатора:

- wget https://packages.microsoft.com/config/debian/10/
packages-microsoft-prod.deb -O packages-microsoft-prod.deb
  - dpkg -i packages-microsoft-prod.deb
  - apt-get update
  - apt-get install apt-transport-https
  - apt-get update

Добавяне на PVS-Studio хранилища и анализатор:

- wget -q -O - https://files.viva64.com/etc/pubkey.txt | apt-key add -
  - wget -O /etc/apt/sources.list.d/viva64.list
https://files.viva64.com/etc/viva64.list
  - apt-get update
  - apt-get -y install pvs-studio-dotnet

Активиране на лиценза:

- pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY

$PVS_NAME — потребителско име.

$PVS_KEY — продуктов ключ.

Възстановяване на зависимостите на проекта, където $CI_PROJECT_DIR е пълният път до директорията на проекта:

- dotnet restore "$CI_PROJECT_DIR"/Path/To/Solution.sln

За правилен анализ проектът трябва да бъде успешно изграден и неговите зависимости трябва да бъдат възстановени (например необходимите NuGet пакети трябва да бъдат заредени).

Можете да зададете променливи на средата, съдържащи информация за лиценза, като щракнете върху Настройки и след това върхуCI / CD.

В отварящия се прозорец намерете елемента Променливи, щракнете върху Разширяване вдясно и добавете променливи. Резултатът трябва да е следният:

Сега можем да преминем към анализа. Първо, ще добавим скрипт за пълен анализ. Във флага-t предаваме пътя към решението, а в флага -o записваме пътя до файла, където ще бъдат записани резултатите от анализа. Също така кодът за връщане представлява интерес за нас тук. В този случай бихме искали анализът да продължи, когато код за изход сигнализира, че са били издадени предупреждения по време на анализа. Ето как изглежда този фрагмент:

job:
  script:
  - exit_code=0
  - pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -o 
PVS-Studio.json || exit_code=$?
  - exit_code=$((($exit_code & 8)/8))
  - if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi

Кодовете за изход работят като битови маски. Например, ако в резултат на анализа са издадени предупреждения, изходният код ще бъде равен на 8. Ако лицензът изтече в рамките на един месец, изходният код ще бъде 4. Ако по време на анализа са открити грешки и лицензът изтича в рамките на един месец и двете стойности ще бъдат записани в кода за изход: числата се събират и получаваме крайния код за изход — 8+4=12. По този начин, като проверите съответните битове, можете да получите информация за различни състояния по време на анализа. Кодовете за изход са описани по-подробно в раздела „Кодове за изход на Pvs-studio-dotnet (Linux / macOS)“ на документа „Анализиране на проекти на Visual Studio / MSBuild / .NET Core от командния ред с помощта на PVS-Studio».

В този случай се интересуваме от всички изходни кодове, където се появява 8.

- exit_code=$((($exit_code & 8)/8))

Получаваме 1, когато изходният код има зададен бит, който ни интересува, в противен случай получаваме 0.

Сега е време да добавите анализа на искането за сливане. Преди да направим това, нека отделим малко място за скрипта. Искаме да се изпълнява само когато се появи заявка за сливане. Това изглежда по следния начин:

merge:
  script:
  only:
  - merge_requests

Да преминем към самия скрипт. Попаднах на проблема, че виртуалната машина не знае нищо за origin/master. Така че ще му подадем ръка:

- git fetch origin

Сега получаваме разликата между разклоненията и записваме резултата във файл txt:

- git diff --name-only origin/master $CI_COMMIT_SHA > pvs-fl.txt

Където $CI_COMMIT_SHA е хешът на последния комит.

След това изпълняваме анализ на списъка с файлове, като използваме флага -f. Предаваме му предварително получения .txt файл. По аналогия с пълния анализ проверяваме изходните кодове:

- exit_code=0
  - pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -f 
pvs-fl.txt -o PVS-Studio.json || exit_code=$?
  - exit_code=$((($exit_code & 8)/8))
  - if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi

Пълният скрипт за проверка на искането за сливане ще изглежда така:

merge:
  script:
  - git fetch origin
  - git diff --name-only origin/master $CI_COMMIT_SHA > pvs-fl.txt
  - exit_code=0
  - pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -f 
pvs-fl.txt -o PVS-Studio.json || exit_code=$?
  - exit_code=$((($exit_code & 8)/8))
  - if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi
  only:
  - merge_requests

Остава само да добавите преобразуването на журнала, след като всички скриптове работят. Използваме етикета after_script и помощната програма plog-converter:

after_script:
  - plog-converter -t html -o eLog ./PVS-Studio.json

Помощната програма plog-converter е проект с отворен код, който се използва за преобразуване на отчета за грешка на анализатора в различни форми, като например HTML. За по-подробно описание на помощната програма вижте раздела „Помощна програма Plog Converter“ в „раздела за съответната документация“.

Между другото, ако искате удобно да работите с .json отчет локално от IDE, тогава препоръчвам нашия плъгин за IDE Rider. За повече информация относно използването му вижте специалния документ.

За удобство тук е целият.gitlab-ci.yml:

image: debian
before_script:
  - apt-get update && apt-get -y install wget gnupg 
  - apt-get -y install git
  - wget https://packages.microsoft.com/config/debian/10/
packages-microsoft-prod.deb -O packages-microsoft-prod.deb
  - dpkg -i packages-microsoft-prod.deb
  - apt-get update
  - apt-get install apt-transport-https
  - apt-get update
  
  - wget -q -O - https://files.viva64.com/etc/pubkey.txt | apt-key add -
  - wget -O /etc/apt/sources.list.d/viva64.list
https://files.viva64.com/etc/viva64.list
  - apt-get update
  - apt-get -y install pvs-studio-dotnet
  - pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY
  - dotnet restore "$CI_PROJECT_DIR"/Test/Test.sln
merge:
  script:
  - git fetch origin
  - git diff --name-only origin/master $CI_COMMIT_SHA > pvs-fl.txt
  - exit_code=0
  - pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -f 
pvs-fl.txt -o PVS-Studio.json || exit_code=$?
  - exit_code=$((($exit_code & 8)/8))
  - if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi
  only:
  - merge_requests
job:
  script:
  - exit_code=0
  - pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -o 
PVS-Studio.json || exit_code=$?
  - exit_code=$((($exit_code & 8)/8))
  - if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi
  
after_script:
  - plog-converter -t html -o eLog ./PVS-Studio.json

Веднага след като добавим всичко към файла, щракнете върху Извършете промени. За да се уверите, че всичко е правилно, отидете на CI/CDТръбопроводи -› Изпълнение. Отваря прозореца на виртуалната машина, в края на който трябва да има следното:

След като получите Задачата е успешна — всичко е наред, печалба. Сега можете да тествате какво сте направили.

Примери за работа

Като пример ще създадем прост проект (в master), който ще съдържа няколко файла. След това ще променим само един файл в друг клон и ще се опитаме да направим заявка за сливане.

Нека да разгледаме два случая: когато модифицираният файл съдържа грешка и когато не съдържа. Първо, ще разгледаме пример с грешка.

Да приемем, че има файл Program.cs в главния клон, който не съдържа грешки, а в друг клон разработчикът е добавил грешен код и иска да направи заявка за сливане. Каква грешка са направили не е толкова важно, важното е, че е налице. Например, те са забравили оператора throw (да, хората правят такива грешки):

void MyAwesomeMethod(String name)
{
  if (name == null)
    new ArgumentNullException(....);
  // do something
  ....
}

Нека да разгледаме резултата от анализа за примера с грешка. Освен това, за да се уверя, че е анализиран само един файл, добавих флага -r към командния ред pvs-studio-dotnet:

Както виждаме, анализаторът откри грешка и не позволи сливането на клонове.

Сега нека проверим примера без грешка. Фиксиран код:

void MyAwesomeMethod(String name)
{
  if (name == null)
    throw new ArgumentNullException(....);
  // do something
  ....
}

Резултати от анализа на искане за сливане:

Както виждаме, не бяха открити грешки и задачата беше изпълнена успешно, което искахме да проверим.

Заключение

Филтрирането на лош код преди обединяване на клонове е много удобно и приятно. Така че, ако използвате CI/CD, опитайте да вградите статичен анализатор, за да го проверите. Особено, тъй като може да се направи много просто.

Благодаря за вниманието.