
Iubiți GitLab și nu vă plac erorile? Doriți să îmbunătățiți calitatea codului sursă? Atunci sunteți la locul potrivit. Astăzi vă vom explica cum să configurați analiza C# PVS-Studio pentru a verifica cererile de fuzionare. Vă dorim o stare de spirit plină de unicorni și o lectură plăcută.
— este un instrument pentru identificarea erorilor și a vulnerabilităților potențiale în codul sursă al programelor scrise în limbajele C, C++, C# și Java. Funcționează în sisteme de 64 de biți pe Windows, Linux și macOS. Poate analiza cod destinat platformelor de 32 de biți, 64 de biți și ARM încorporate.
Apropo, am lansat PVS-Studio 7.08, în care am realizat multe îmbunătățiri . De exemplu:
- analizator C# pentru Linux și macOS;
- plugin pentru Rider;
- nou mod de verificare a listei de fișiere.
Modul de verificare a listei de fișiere
Anterior, pentru a verifica anumite fișiere, era necesar să trimitem analizatorului un fișier .xml cu lista de fișiere. Dar, deoarece acest lucru nu era foarte convenabil, am adăugat posibilitatea de a folosi un fișier .txt, ceea ce simplifică foarte mult viața.
Pentru a verifica anumite fișiere, trebuie să specificați flagul —sourceFiles (-f) și să trimiteți un fișier .txt cu lista de fișiere. Acesta arată astfel:
pvs-studio-dotnet -t path/to/solution.sln -f fileList.txt -o project.jsonDacă sunteți interesat să configurați verificarea comitelor sau a cererilor de fuzionare, puteți face acest lucru folosind acest mod. Diferența constă în obținerea listei de fișiere pentru analiză și va depinde de sistemele pe care le utilizați.
Principiul verificării cererilor de fuzionare
Senzația principală a verificării este că problemele identificate de analizator să nu ajungă în master ramură. De asemenea, nu dorim să analizăm de fiecare dată întregul proiect. Cu atât mai mult cu cât, la fuzionarea ramurilor, avem o listă de fișiere modificate. Așadar, propun să adăugăm verificarea cererilor de fuzionare.
Iată cum arată cererea de fuzionare înainte de implementarea analizatorului static:

Adică toate erorile care erau în ramura changes, vor trece în ramura principală. Deoarece nu ne-ar plăcea acest lucru, adăugăm analiza și acum schema arată astfel:

Analizăm changes2 și, dacă nu sunt erori, acceptăm cererea de fuzionare, altfel o respingem.
Apropo, dacă sunteți interesați de analiza comitelor și a cererilor de fuzionare pentru C/C++, puteți citi despre aceasta .
GitLab
— un instrument web pentru ciclul de viață DevOps cu sursă deschisă, care oferă un sistem de gestionare a repositoarelor de cod pentru Git, cu o wiki proprie, un sistem de urmărire a erorilor, un pipeline CI/CD și alte funcții.
Înainte de a începe implementarea analizei cererilor de fuziune, trebuie să te înregistrezi și să încarci proiectul tău. Dacă nu știi cum să faci asta, îți propun colegul meu.
Notă. Metoda de configurare a mediului descrisă mai jos este una dintre opțiuni. Scopul este de a arăta pașii necesari pentru configurarea mediului pentru analiză și pentru a lansa analizatorul. Este posibil să fie mai optim în cazul tău să separi etapele de pregătire a mediului (adăugarea de repository-uri, instalarea analizatorului) de etapa de analiză: de exemplu, pregătirea imaginilor Docker cu mediul necesar și utilizarea acestora sau o altă metodă.
Pentru a înțelege mai bine ce se va întâmpla, îți propun să aruncăm o privire la următoarea diagramă:

Pentru funcționarea sa, analizatorul necesită .NET Core SDK 3, așadar înainte de instalarea analizatorului, trebuie să adaugi repository-urile Microsoft din care vor fi instalate dependențele necesare pentru analizator. Adăugarea repository-urilor Microsoft pentru diferite distribuții Linux .
Pentru instalarea PVS-Studio prin managerul de pachete, va trebui să adaugi, de asemenea, repository-urile PVS-Studio. Adăugarea repository-urilor pentru diferite distribuții este descrisă mai detaliat în .
Pentru funcționarea analizatorului, este necesar un cheie de licență. Poți obține o licență de probă pe .
Notă. Te rugăm să observi că pentru modul de funcționare descris (analiza cererilor de fuziune) este necesară o licență Enterprise. Prin urmare, dacă vrei să încerci acest mod de lucru, nu uita să menționezi în câmpul "Mesaj" că îți trebuie o licență Enterprise.
Dacă are loc o cerere de fuziune, va trebui să analizăm doar lista fișierelor modificate, altfel analizăm toate fișierele. După analiză, este necesar să convertim log-urile în formatul necesar.
Acum, având în față algoritmul de lucru, putem trece la scrierea scriptului. Pentru a face asta, trebuie să modifici fișierul .gitlab-ci.yml sau, dacă nu există, să creezi unul. Pentru a-l crea, trebuie să dai clic pe denumirea proiectului tău -> Set up CI/CD.

Acum suntem gata să scriem scriptul. Să începem prin a scrie codul care va instala analizatorul și va introduce licența:
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.slnDin moment ce instalarea și activarea trebuie să aibă loc înaintea tuturor celorlalte scripturi, folosim o etichetă specială before_script. Voi explica puțin acest fragment.
Pregătirea pentru instalarea analizei:
- 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 updateAdăugarea repositoarelor PVS-Studio și analizei:
- 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-dotnetActivarea licenței:
- pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY$PVS_NAME — numele utilizatorului.
$PVS_KEY — cheia produsului.
Restaurarea dependențelor proiectului, unde $CI_PROJECT_DIR – calea completă către directorul proiectului:
- dotnet restore "$CI_PROJECT_DIR"/Path/To/Solution.slnPentru o analiză corectă, proiectul trebuie să se compileze cu succes, iar dependențele trebuie să fie restaurate (de exemplu, pachetele NuGet necesare trebuie să fie descărcate).
Variabilele de mediu, care conțin informații despre licență, pot fi setate apăsând pe Setare, iar apoi pe CI / CD.

În fereastra deschisă, găsim secțiunea Variabile, în dreapta apăsăm butonul Extinde și adăugăm variabilele. Rezultatul ar trebui să fie următorul:

Acum putem trece la analiză. Mai întâi, să adăugăm scriptul pentru analiza completă. În flagul -t punem calea către soluție, în flagul -o scriem calea către fișierul în care vor fi salvate rezultatele analizei. De asemenea, ne interesează codul de întoarcere. În acest caz, ne interesează ca execuția să se oprească când codul de întoarcere conține informații că au fost emise avertismente în timpul analizei. Iată cum arată acest 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; fiCodurile de întoarcere funcționează pe baza principiului măștii de biți. De exemplu, dacă analiza a generat avertizări, codul de întoarcere va fi 8. Dacă licența expiră în termen de o lună, codul de întoarcere va fi 4. Dacă în timpul analizei au fost descoperite erori, iar licența expiră în termen de o lună, codul de întoarcere va conține ambele valori: adunăm numerele împreună și obținem codul de întoarcere final — 8+4=12. Astfel, verificând biții corespunzători, putem obține informații despre diferite stări în timpul analizei. Mai multe detalii despre codurile de întoarcere sunt descrise în secțiunea "Coduri de întoarcere pvs-studio-dotnet (Linux / macOS)" a documentului.".
În acest caz, ne interesează toate codurile de întoarcere care includ 8.
- exit_code=$((($exit_code & 8)/8))Vom obține 1 atunci când codul de întoarcere conține bitul de interes, altfel vom obține 0.
A sosit vremea să adăugăm analiza cererii de fuziune. Înainte de a face acest lucru, să pregătim locul pentru script. Este necesar să se execute doar atunci când are loc o cerere de fuziune. Arată astfel:
merge:
script:
only:
- merge_requestsSă trecem la scriptul propriu-zis. Am întâmpinat problema că mașina virtuală nu știe nimic despre origin/master. Așadar, o ajutăm puțin:
- git fetch originAcum vom obține diferența dintre ramuri și vom salva rezultatul în txt fișier:
- git diff --name-only origin/master $CI_COMMIT_SHA > pvs-fl.txtUnde $CI_COMMIT_SHA – hash-ul ultimei comiterii.
Apoi, vom lansa analiza listei de fișiere, folosind flag-ul -f. Îi vom transmite anterior obținutul fișier .txt. Și, similar cu analiza completă, vom verifica codurile de întoarcere:
- 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; fiScriptul complet pentru verificarea cererii de fuziune va arăta astfel:
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_requestsRămâne doar să adăugăm conversia jurnalului după ce toate scripturile au fost executate. Folosim eticheta after_script și utilitarul plog-converter:
after_script:
- plog-converter -t html -o eLog ./PVS-Studio.jsonUtilitarul — este un proiect open source, care este utilizat pentru a transforma raportul de erori al analizatorului în diverse forme, cum ar fi HTML. O descriere mai detaliată a utilitatii este prezentată în subsecțiunea "Utilitarul Plog Converter" .
Apropo, dacă doriți să lucrați convenabil cu raportul .json local din IDE, vă recomandăm pentru IDE Rider. Utilizarea sa este descrisă în detaliu în .
Pentru comoditate, iată .gitlab-ci.yml întreg:
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.jsonOdată ce am adăugat tot în fișier, apăsăm pe Commit changes. Pentru a verifica dacă totul este corect, intrăm în CI/CD -> Pipeline-uri -> Running. Se va deschide fereastra mașinii virtuale, la finalul căreia ar trebui să fie următorul text:

Am văzut Job succeeded – succes, totul este minunat. Acum putem testa și ce am realizat.
Exemple de lucru
Pentru a exemplifica, vom crea un proiect simplu (în master) în care vor fi mai multe fișiere. După aceea, în altă ramură, vom schimba doar un singur fișier și vom încerca să facem un merge request.
Vom analiza două cazuri: când fișierul modificat conține o eroare și când nu. Mai întâi, un exemplu cu eroare.
Presupunem că, în ramura master, există un fișier Program.cs, care nu conține erori, iar într-o altă ramură, dezvoltatorul a adăugat un cod eronat și dorește să facă un merge request. Ce eroare a comis el – nu este atât de important, principalul este că există. De exemplu, a uitat operatorul throw (da, ):
void MyAwesomeMethod(String name)
{
if (name == null)
new ArgumentNullException(....);
// faceți ceva
....
}Să ne uităm la rezultatul analizei exemplului cu eroare. De asemenea, pentru a ne asigura că doar un singur fișier a fost analizat, am adăugat un flag -r în linia de comandă pvs-studio-dotnet:

Vedem că analizatorul a găsit o eroare și nu a permis să se efectueze o fuziune a ramurilor.
Verificăm exemplul fără eroare. Corectăm codul:
void MyAwesomeMethod(String name)
{
if (name == null)
throw new ArgumentNullException(....);
// faceți ceva
....
}Rezultatele analizei merge request-ului:

După cum vedem, nu au fost găsite erori, iar execuția sarcinii a fost efectuată cu succes, ceea ce am dorit să verificăm.
Concluzie
Filtrarea codului prost înainte de fuziunea ramurilor este foarte convenabilă și plăcută. Așadar, dacă folosiți CI/CD, încercați să integrați un analizator static pentru verificare. În plus, este destul de simplu de implementat.
Vă mulțumesc pentru atenție.
Dacă doriți să împărtășiți acest articol cu o audiență vorbitoare de limbă engleză, vă rog să folosiți linkul pentru traducere: Nikolay Mironov. .
Sursa: habr.com
