
Kochasz GitLab i nie lubisz błędów? Chcesz poprawić jakość swojego kodu? W takim razie trafiłeś we właściwe miejsce. Dziś opowiemy, jak skonfigurować analizator C# PVS-Studio do sprawdzania merge requestów. Życzymy wszystkim Jednorożców miłego czytania.
— to narzędzie do wykrywania błędów i potencjalnych podatności w kodzie źródłowym programów napisanych w językach C, C++, C# i Java. Działa w systemach 64-bitowych na Windows, Linux i macOS. Może analizować kod przeznaczony dla platform 32-bitowych, 64-bitowych oraz wbudowanych ARM.
Przy okazji, wydaliśmy PVS-Studio 7.08, w którym dokonaliśmy wielu zmian . Na przykład:
- analizator C# dla Linux i macOS;
- wtyczka do Ridera;
- nowy tryb sprawdzania listy plików.
Tryb sprawdzania listy plików
Wcześniej, aby sprawdzić określone pliki, konieczne było przesłanie analizatorowi pliku .xml z listą plików. Jednak ponieważ to nie było zbyt wygodne, dodaliśmy możliwość przesyłania pliku .txt, co bardzo ułatwia życie.
Aby sprawdzić określone pliki, należy podać flagę --sourceFiles (-f) i przesłać plik .txt z listą plików. Wygląda to następująco:
pvs-studio-dotnet -t path/to/solution.sln -f fileList.txt -o project.jsonJeśli chcesz skonfigurować sprawdzanie commitów lub pull requestów, również możesz to zrobić, korzystając z tego trybu. Różnica polega na tym, jak uzyskujesz listę plików do analizy, i zależy od używanych systemów.
Zasada sprawdzania merge requestów
Głównym celem sprawdzania jest to, aby problemy wykryte przez analizator nie trafiły do master gałęzi. Ponadto nie chcemy analizować całego projektu za każdym razem. Zwłaszcza, że przy łączeniu gałęzi mamy listę zmienionych plików. Dlatego proponuję dodać sprawdzanie merge requestów.
Tak wygląda merge request przed wdrożeniem statycznego analizatora:

To znaczy, że wszystkie błędy, które były w gałęzi changes, przejdą do gałęzi master. Ponieważ nie chcielibyśmy, aby się tak stało, dodajemy analizę, a teraz schemat wygląda następująco:

Analizujemy changes2 i, jeśli nie ma błędów, akceptujemy merge request, a w przeciwnym razie go odrzucamy.
Przy okazji, jeśli interesuje Cię analiza commitów i pull requestów dla C/C++, możesz o tym poczytać. .
GitLab
— narzędzie do cyklu życia DevOps z otwartym kodem źródłowym, reprezentujące system zarządzania repozytoriami kodu dla Gita z własną wiki, systemem śledzenia błędów, pipeline'm CI/CD i innymi funkcjami.
Zanim przystąpimy do analizy merge requestów, musisz się zarejestrować i przesłać swój projekt. Jeśli nie wiesz, jak to zrobić, proponuję mojego kolegi.
Uwaga. Opisany poniżej sposób konfiguracji środowiska jest jednym z możliwych. Celem jest pokazanie kroków potrzebnych do skonfigurowania środowiska do analizy i uruchomienia analizatora. Możliwe, że w twoim przypadku bardziej optymalne będzie rozdzielenie etapów przygotowania środowiska (dodanie repozytoriów, instalacja analizatora) i analizy: na przykład przygotowanie obrazów Docker z wymaganym środowiskiem i ich wykorzystanie lub inny sposób.
Aby lepiej zrozumieć, co się teraz wydarzy, proponuję spojrzeć na następujący schemat:

Aby analizator mógł działać, wymaga .NET Core SDK 3, dlatego przed jego instalacją należy dodać repozytoria Microsoft, z których będą instalowane niezbędne zależności. Dodanie repozytoriów Microsoft dla różnych dystrybucji Linux .
Aby zainstalować PVS-Studio za pomocą menedżera pakietów, również należy dodać repozytoria PVS-Studio. Dodanie repozytoriów dla różnych dystrybucji opisano szczegółowo w .
Aby analizator mógł działać, potrzebny jest klucz licencyjny. Można uzyskać wersję próbną na .
Uwaga. Zwróć uwagę, że do opisanego trybu pracy (analiza merge requestów) potrzebna jest licencja Enterprise. Dlatego jeśli chcesz wypróbować ten tryb pracy, w polu "Wiadomość" nie zapomnij zaznaczyć, że potrzebujesz licencji Enterprise.
Jeśli dochodzi do merge requestu, będziemy musieli przeanalizować tylko listę zmienionych plików, w przeciwnym razie analizujemy wszystkie pliki. Po analizie należy skonwertować logi do potrzebnego formatu.
Teraz, mając przed sobą algorytm działania, możemy przejść do pisania skryptu. Aby to zrobić, musisz zmienić plik .gitlab-ci.yml lub, jeśli go nie ma, stworzyć go. Aby go stworzyć, należy kliknąć na nazwę swojego projektu -> Skonfiguruj CI/CD.

Teraz jesteśmy gotowi do napisania skryptu. Najpierw napiszmy kod, który zainstaluje analizator i wprowadzi licencję:
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.slnPonieważ instalacja i aktywacja muszą się odbywać przed wszystkimi innymi skryptami, użyjemy specjalnego znaku before_script. Krótko wyjaśnię ten fragment.
Przygotowanie do instalacji analizatora:
- 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 updateDodanie repozytoriów PVS-Studio i analizatora:
- 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-dotnetAktywacja licencji:
- pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY$PVS_NAME — nazwa użytkownika.
$PVS_KEY — klucz produktu.
Odzyskiwanie zależności projektu, gdzie $CI_PROJECT_DIR – pełna ścieżka do katalogu projektu:
- dotnet restore "$CI_PROJECT_DIR"/Path/To/Solution.slnAby pomyślnie analizować projekt, musi on być poprawnie zbudowany, a jego zależności muszą być przywrócone (na przykład muszą zostać załadowane niezbędne pakiety NuGet).
Aby ustawić zmienne środowiskowe zawierające informacje o licencji, możesz kliknąć Ustawienia, a następnie — na CI / CD.

W otwartym oknie znajdź element Zmienne, a po prawej stronie kliknij przycisk Rozwiń i dodaj zmienne. Powinno to zakończyć się następującym rezultatem:

Teraz możemy przejść do analizy. Najpierw dodamy skrypt do pełnej analizy. W fladze -t przekazujemy ścieżkę do rozwiązania, w fladze -o podajemy ścieżkę do pliku, w którym będą zapisane wyniki analizy. Interesuje nas również kod wyjścia. W tym przypadku interesuje nas, aby praca została przerwana, gdy kod wyjścia zawiera informacje o tym, że w trakcie analizy wystąpiły ostrzeżenia. Oto jak wygląda ten fragment:
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; fiKody zwrotu działają na zasadzie maski bitowej. Na przykład, jeśli w wyniku analizy wydano ostrzeżenia, kod zwrotu wynosi 8. Jeśli licencja wygaśnie w ciągu miesiąca, kod zwrotu wyniesie 4. Jeśli podczas analizy wykryto błędy oraz licencja wygasa w ciągu miesiąca, oba wartości zostaną zapisane w kodzie zwrotu: sumujemy liczby i otrzymujemy końcowy kod zwrotu — 8+4=12. Sprawdzając odpowiednie bity, można uzyskać informacje o różnych stanach podczas analizy. Kody zwrotu są dokładniej opisane w sekcji "Kody zwrotu pvs-studio-dotnet (Linux / macOS)" dokumentu.".
W tym przypadku interesują nas wszystkie kody zwrotu, w których występuje 8.
- exit_code=$((($exit_code & 8) / 8))Otrzymamy 1, gdy kod zwrotu zawiera interesujący nas bit liczby, w przeciwnym razie otrzymamy 0.
Nadszedł czas, aby dodać analizę żądania scalania. Zanim to zrobimy, przygotujmy miejsce na skrypt. Musi on działać tylko w momencie wystąpienia żądania scalania. Wygląda to tak:
merge:
script:
only:
- merge_requestsPrzechodzimy do samego skryptu. Napotkałem problem, że maszyna wirtualna nie wie nic o origin/master. Dlatego będziemy jej w tym pomagać:
- git fetch originTeraz uzyskujemy różnice między gałęziami i zapisujemy wynik w txt plik:
- git diff --name-only origin/master $CI_COMMIT_SHA > pvs-fl.txtGdzie $CI_COMMIT_SHA – hash ostatniego commit.
Następnie uruchamiamy analizę listy plików, używając flagi -f. Przekazujemy wcześniej uzyskany plik .txt. Podobnie jak w przypadku pełnej analizy, sprawdzamy kody zwrotu:
- 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; fiPełny skrypt do sprawdzania żądania scalania będzie wyglądać tak:
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_requestsPozostaje tylko dodać konwersję logu po tym, jak wszystkie skrypty zostały wykonane. Używamy etykiety after_script i narzędzia plog-converter:
after_script:
- plog-converter -t html -o eLog ./PVS-Studio.jsonNarzędzie — to projekt open source, który jest używany do przekształcania raportów o błędach analizatora w różne formy, na przykład HTML. Szczegółowy opis narzędzia znajduje się w podrozdziale "Narzędzie Plog Converter" .
Przy okazji, jeśli chcesz wygodnie pracować z raportem .json lokalnie z IDE, to proponuję nasz dla IDE Rider. Bardziej szczegółowe informacje o jego użyciu są opisane w .
Dla wygody oto .gitlab-ci.yml w całości:
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.jsonGdy dodasz wszystko do pliku, kliknij na Commit changes. Aby sprawdzić, czy wszystko jest w porządku, wejdź w CI/CD -> Pipelines -> Running. Otworzy się okno maszyny wirtualnej, na końcu którego powinno być następujące:

Zobaczyłeś Job succeeded – sukces, wszystko w porządku. Teraz można również przetestować to, co zostało zrobione.
Przykłady pracy
Dla przykładu stworzymy prosty projekt (w master) z kilkoma plikami. Następnie w innej gałęzi zmienimy tylko jeden plik i spróbujemy zrobić merge request.
Rozważmy dwa przypadki: kiedy zmieniony plik zawiera błąd, a kiedy nie. Najpierw przykład z błędem.
Załóżmy, że w gałęzi master znajduje się plik Program.cs, który nie zawiera błędów, a w innej gałęzi programista dodał błędny kod i chce zrobić merge request. Jakiego błędu się dopuścił – nie jest tak istotne, najważniejsze, że jest. Na przykład zapomniał o operatorze throw (tak, ):
void MyAwesomeMethod(String name)
{
if (name == null)
new ArgumentNullException(....);
// coś zrób
....
}Przyjrzyjmy się wynikom analizy przykładu z błędem. Również, aby upewnić się, że tylko jeden plik został przeanalizowany, dodałem flagę -r do linii uruchamiania pvs-studio-dotnet:

Widzimy, że analizator znalazł błąd i nie pozwolił na złączenie gałęzi.
Sprawdzamy przykład bez błędu. Poprawiamy kod:
void MyAwesomeMethod(String name)
{
if (name == null)
throw new ArgumentNullException(....);
// coś zrób
....
}Wyniki analizy merge request:

Jak widzimy, błędy nie zostały znalezione, a wykonanie zadania zakończyło się pomyślnie, co chcieliśmy sprawdzić.
Podsumowanie
Filtrowanie złego kodu przed złączeniem gałęzi jest bardzo wygodne i przyjemne. Dlatego, jeśli korzystasz z CI/CD, spróbuj wbudować statyczny analizator do sprawdzenia. Tym bardziej, że jest to całkiem proste do zrobienia.
Dziękujemy za uwagę.
Jeśli chcesz podzielić się tym artykułem z anglojęzyczną publicznością, użyj linku do tłumaczenia: Nikolay Mironov. .
Źródło: habr.com
