În analizatorul PVS-Studio pentru limbile C și C++ pe Linux și macOS, începând cu versiunea 7.04, a apărut o opțiune de testare pentru a verifica lista fișierelor specificate. Folosind noul mod, puteți configura analizorul pentru a verifica comitările și solicitările de extragere. Acest articol vă va spune cum să configurați verificarea listei de fișiere modificate ale unui proiect GitHub în sisteme CI (integrare continuă) populare precum Travis CI, Buddy și AppVeyor.
Mod de verificare a listei de fișiere
În versiunea PVS-Studio 7.04 pentru Linux și macOS, a apărut un mod de verificare a listei de fișiere sursă. Acest lucru funcționează pentru proiectele al căror sistem de construcție vă permite să generați un fișier
De asemenea, modul de verificare a listei de fișiere poate fi utilizat împreună cu jurnalul de urmărire strace al lansărilor compilatorului (urma pvs-studio-analyzer). Pentru a face acest lucru, va trebui mai întâi să realizați o construcție completă a proiectului și să o urmăriți, astfel încât analizatorul să colecteze informații complete despre parametrii de compilare ai tuturor fișierelor verificate.
Cu toate acestea, această opțiune are un dezavantaj semnificativ - va trebui fie să efectuați o urmă de construcție completă a întregului proiect de fiecare dată când îl rulați, ceea ce în sine contrazice ideea de a verifica rapid un commit. Sau, dacă memorați în cache rezultatul urmăririi în sine, rulările ulterioare ale analizorului pot fi incomplete dacă structura de dependență a fișierelor sursă se modifică după urmărire (de exemplu, un nou #include este adăugat la unul dintre fișierele sursă).
Prin urmare, nu vă recomandăm să utilizați modul de verificare a listei de fișiere cu jurnalul de urmărire pentru a verifica comiterile sau solicitările de extragere. În cazul în care puteți face o construcție incrementală atunci când verificați un commit, luați în considerare utilizarea modului
Lista fișierelor sursă pentru analiză este salvată într-un fișier text și transmisă analizorului folosind parametrul -S:
pvs-studio-analyzer analyze ... -f build/compile_commands.json -S check-list.txt
Acest fișier specifică căi relative sau absolute către fișiere și fiecare fișier nou trebuie să fie pe o linie nouă. Este acceptabil să specificați nu numai nume de fișiere pentru analiză, ci și diverse texte. Analizatorul va vedea că acesta nu este un fișier și va ignora linia. Acest lucru poate fi util pentru a comenta dacă fișierele sunt specificate manual. Cu toate acestea, adesea o listă de fișiere va fi generată în timpul analizei în CI, de exemplu, acestea ar putea fi fișiere dintr-o cerere de commit sau de extragere.
Acum, folosind acest mod, puteți verifica rapid codul nou înainte de a ajunge în ramura principală de dezvoltare. Pentru a se asigura că sistemul de scanare răspunde la avertismentele analizorului, utilitarul Plog-convertor steagul adăugat --indicați-avertismente:
plog-converter ... --indicate-warnings ... -o /path/to/report.tasks ...
Cu acest indicator, convertorul va returna un cod diferit de zero dacă există avertismente în raportul analizorului. Folosind codul de returnare, puteți bloca o cerere precommit hook, commit sau pull, iar raportul generat de analizor poate fi afișat, partajat sau trimis prin e-mail.
Notă. Când începeți pentru prima dată să analizați o listă de fișiere, întreg proiectul va fi analizat, deoarece analizatorul trebuie să genereze un fișier de dependențe ale fișierelor sursă ale proiectului pe fișierele antet. Aceasta este o caracteristică a analizei fișierelor C și C++. În viitor, fișierul de dependență poate fi stocat în cache și va fi actualizat automat de analizor. Avantajul verificării comiterilor atunci când utilizați modul de verificare a listei de fișiere față de utilizarea modului de analiză incrementală este că trebuie doar să puneți în cache acel fișier și nu fișierele obiect.
Principii generale ale analizei cererilor de tragere
Analizarea întregului proiect necesită mult timp, așa că este logic să verificați doar o anumită parte a acestuia. Problema este că trebuie să separați noile fișiere de restul fișierelor de proiect.
Să ne uităm la un exemplu de arbore de comitere cu două ramuri:
Să ne imaginăm acest angajament A1 conține o cantitate destul de mare de cod care a fost deja testat. Puțin mai devreme am făcut o ramură din comit A1 și am schimbat câteva fișiere.
Desigur, ai observat asta după A1 Au mai avut loc două comiteri, dar acestea au fost și fuziuni ale altor sucursale, pentru că noi nu ne angajăm maestru. Și acum a sosit momentul când remediere rapidă gata. De aceea a apărut un pull request pentru fuziune B3 и A3.
Desigur, ar fi posibil să se verifice întregul rezultat al fuziunii lor, dar acest lucru ar consuma prea mult timp și ar fi nejustificat, deoarece doar câteva fișiere au fost modificate. Prin urmare, este mai eficient să le analizăm doar pe cele modificate.
Pentru a face acest lucru, obținem diferența dintre ramuri, aflându-ne în CAPUL ramurii din care vrem să contopim în master:
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
$MERGE_BASE îl vom privi în detaliu mai târziu. Cert este că nu fiecare serviciu CI oferă informațiile necesare despre baza de date pentru fuzionare, așa că de fiecare dată trebuie să veniți cu noi modalități de a obține aceste date. Acest lucru va fi descris în detaliu mai jos în fiecare dintre serviciile web descrise.
Deci, am obținut diferența dintre ramuri, sau mai degrabă, o listă de nume de fișiere care au fost modificate. Acum trebuie să dăm fișierul .pvs-pr.list (am redirecționat rezultatul de mai sus către acesta) către analizor:
pvs-studio-analyzer analyze -j8
-o PVS-Studio.log
-S .pvs-pr.list
După analiză, trebuie să convertim fișierul jurnal (PVS-Studio.log) într-un format ușor de citit:
plog-converter -t errorfile PVS-Studio.log --cerr -w
Această comandă va lista erorile în
Numai că acum trebuie nu numai să afișăm erori, ci și să informăm serviciul nostru de asamblare și testare despre prezența problemelor. În acest scop, a fost adăugat un steag la convertor -W (--indicați-avertismente). Dacă există cel puțin o avertizare de analizor, codul de returnare a utilitarului Plog-convertor se va schimba în 2, care, la rândul său, va informa serviciul CI despre prezența unor potențiale erori în fișierele de solicitare de extragere.
Travis C.I.
Configurarea se face ca fișier .travis.yml. Pentru comoditate, vă sfătuiesc să puneți totul într-un script bash separat cu funcții care vor fi apelate din fișier .travis.yml (bash script_name.sh function_name).
Vom adăuga codul necesar la script la pocni, astfel vom obține mai multe funcționalități. In sectiune instala hai sa scriem urmatoarele:
install:
- bash .travis.sh travis_install
Dacă ai avut instrucțiuni, le poți transfera în script, eliminând cratimele.
Să deschidem fișierul .travis.sh și adăugați setarea analizorului la funcție travis_install():
travis_install() {
wget -q -O - https://files.viva64.com/etc/pubkey.txt
| sudo apt-key add -
sudo wget -O /etc/apt/sources.list.d/viva64.list
https://files.viva64.com/etc/viva64.list
sudo apt-get update -qq
sudo apt-get install -qq pvs-studio
}
Acum să adăugăm la secțiune scenariu rulați analiza:
script:
- bash .travis.sh travis_script
Și în scriptul bash:
travis_script() {
pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
git diff --name-only origin/HEAD > .pvs-pr.list
pvs-studio-analyzer analyze -j8
-o PVS-Studio.log
-S .pvs-pr.list
--disableLicenseExpirationCheck
else
pvs-studio-analyzer analyze -j8
-o PVS-Studio.log
--disableLicenseExpirationCheck
fi
plog-converter -t errorfile PVS-Studio.log --cerr -w
}
Acest cod trebuie rulat după construirea proiectului, de exemplu, dacă ați avut o versiune pe CMake:
travis_script() {
CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
cmake $CMAKE_ARGS CMakeLists.txt
make -j8
}
Se va dovedi astfel:
travis_script() {
CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
cmake $CMAKE_ARGS CMakeLists.txt
make -j8
pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
git diff --name-only origin/HEAD > .pvs-pr.list
pvs-studio-analyzer analyze -j8
-o PVS-Studio.log
-S .pvs-pr.list
--disableLicenseExpirationCheck
else
pvs-studio-analyzer analyze -j8
-o PVS-Studio.log
--disableLicenseExpirationCheck
fi
plog-converter -t errorfile PVS-Studio.log --cerr -w
}
Probabil că ați observat deja aceste variabile de mediu $TRAVIS_PULL_REQUEST и $TRAVIS_BRANCH. Travis CI le declară independent:
- $TRAVIS_PULL_REQUEST stochează numărul cererii de tragere sau fals, dacă aceasta este o ramură obișnuită;
- $TRAVIS_REPO_SLUG stochează numele depozitului de proiect.
Algoritmul pentru această funcție:
Travis CI răspunde la codurile de returnare, așa că prezența avertismentelor va spune serviciului să marcheze commit-ul ca conținând erori.
Acum să aruncăm o privire mai atentă la această linie de cod:
git diff --name-only origin/HEAD > .pvs-pr.list
Faptul este că Travis CI îmbină automat ramurile în timp ce analizează o cerere de extragere:
De aceea analizăm A4Și nu B3->A3. Din cauza acestei caracteristici, trebuie să calculăm diferența cu A3, care este tocmai vârful ramului de la origine.
A mai rămas un detaliu important - memorarea în cache a dependențelor fișierelor antet de unitățile de traducere compilate (*.c, *.cc, *.cpp etc.). Analizatorul calculează aceste dependențe atunci când este lansat pentru prima dată în modul de verificare a unei liste de fișiere și apoi le salvează în directorul .PVS-Studio. Travis CI vă permite să stocați în cache dosare, așa că vom salva datele directorului .PVS-Studio/:
cache:
directories:
- .PVS-Studio/
Acest cod trebuie adăugat la fișier .travis.yml. Acest director stochează diverse date colectate după analiză, ceea ce va accelera în mod semnificativ rulările ulterioare ale analizei listei de fișiere sau ale analizei incrementale. Dacă acest lucru nu se face, atunci analizorul va analiza de fapt toate fișierele de fiecare dată.
Prieteni
La fel ca Travis CI,
În primul rând, trebuie să adăugăm o nouă acțiune la linia de asamblare:
Să indicăm compilatorul care a fost folosit pentru a construi proiectul. Observați containerul docker care este instalat în această acțiune. De exemplu, există un container special pentru GCC:
Acum să instalăm PVS-Studio și utilitățile necesare:
Să adăugăm următoarele rânduri în editor:
apt-get update && apt-get -y install wget gnupg jq
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
Acum să mergem la fila Run (prima pictogramă) și să adăugăm următorul cod în câmpul editor corespunzător:
pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY
if [ "$BUDDY_EXECUTION_PULL_REQUEST_NO" != '' ]; then
PULL_REQUEST_ID="pulls/$BUDDY_EXECUTION_PULL_REQUEST_NO"
MERGE_BASE=`wget -qO -
https://api.github.com/repos/${BUDDY_REPO_SLUG}/${PULL_REQUEST_ID}
| jq -r ".base.ref"`
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
pvs-studio-analyzer analyze -j8
-o PVS-Studio.log
--disableLicenseExpirationCheck
-S .pvs-pr.list
else
pvs-studio-analyzer analyze -j8
-o PVS-Studio.log
--disableLicenseExpirationCheck
fi
plog-converter -t errorfile PVS-Studio.log --cerr -w
Dacă citiți secțiunea despre Travs-CI, atunci acest cod vă este deja familiar, cu toate acestea, acum există o nouă etapă:
Cert este că acum analizăm nu rezultatul îmbinării, ci HEAD-ul ramurii din care se face cererea de extragere:
Deci suntem într-un commit condiționat B3 și trebuie să obținem diferența de la A3:
PULL_REQUEST_ID="pulls/$BUDDY_EXECUTION_PULL_REQUEST_NO"
MERGE_BASE=`wget -qO -
https://api.github.com/repos/${BUDDY_REPO_SLUG}/${PULL_REQUEST_ID}
| jq -r ".base.ref"`
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
A determina A3 Să folosim API-ul GitHub:
https://api.github.com/repos/${USERNAME}/${REPO}/pulls/${PULL_REQUEST_ID}
Am folosit următoarele variabile pe care Buddy le oferă:
- $BUDDY_EXECUTION_PULL_REQEUST_NO — numărul cererii de tragere;
- $BUDDY_REPO_SLUG — o combinație de nume de utilizator și depozit (de exemplu max/test).
Acum să salvăm modificările folosind butonul de mai jos și să activăm analiza cererii de extragere:
Spre deosebire de Travis CI, nu trebuie să specificăm .pvs-studio pentru stocarea în cache, deoarece Buddy memorează automat toate fișierele pentru lansările ulterioare. Prin urmare, ultimul lucru rămas este să salvați login și parola pentru PVS-Studio în Buddy. După salvarea modificărilor, vom fi duși înapoi la Pipeline. Trebuie să trecem la configurarea variabilelor și adăugarea unui login și a unei chei pentru PVS-Studio:
După aceasta, apariția unei noi cereri de extragere sau comitere va declanșa revizuirea. Dacă o comitere conține erori, Buddy va indica acest lucru pe pagina de solicitare de extragere.
AppVeyor
Configurarea AppVeyor este similară cu Buddy, deoarece totul se întâmplă în interfața web și nu este nevoie să adăugați un fișier *.yml în depozitul de proiect.
Să mergem la fila Setări din prezentarea generală a proiectului:
Să derulăm în jos această pagină și să activăm salvarea în cache pentru colectarea solicitărilor de extragere:
Acum să mergem la fila Mediu, unde specificăm imaginea pentru asamblare și variabilele de mediu necesare:
Dacă ați citit secțiunile anterioare, sunteți foarte familiarizat cu aceste două variabile − PVS_KEY и PVS_USERNAME. Dacă nu, permiteți-mi să vă reamintesc că acestea sunt necesare pentru verificarea licenței analizorului PVS-Studio. Le vom vedea din nou în scripturile Bash în viitor.
Pe aceeași pagină de mai jos indicăm folderul pentru cache:
Dacă nu facem acest lucru, vom analiza întregul proiect în loc de câteva fișiere, dar vom obține rezultatul din fișierele specificate. Prin urmare, este important să introduceți numele corect al directorului.
Acum este timpul ca scenariul să fie testat. Deschideți fila Teste și selectați Script:
Trebuie să lipiți următorul cod în acest formular:
sudo apt-get update && sudo apt-get -y install jq
wget -q -O - https://files.viva64.com/etc/pubkey.txt
| sudo apt-key add -
sudo wget -O /etc/apt/sources.list.d/viva64.list
https://files.viva64.com/etc/viva64.list
sudo apt-get update && sudo apt-get -y install pvs-studio
pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY
PWD=$(pwd -L)
if [ "$APPVEYOR_PULL_REQUEST_NUMBER" != '' ]; then
PULL_REQUEST_ID="pulls/$APPVEYOR_PULL_REQUEST_NUMBER"
MERGE_BASE=`wget -qO -
https://api.github.com/repos/${APPVEYOR_REPO_NAME}/${PULL_REQUEST_ID}
| jq -r ".base.ref"`
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
pvs-studio-analyzer analyze -j8
-o PVS-Studio.log
--disableLicenseExpirationCheck
--dump-files --dump-log pvs-dump.log
-S .pvs-pr.list
else
pvs-studio-analyzer analyze -j8
-o PVS-Studio.log
--disableLicenseExpirationCheck
fi
plog-converter -t errorfile PVS-Studio.log --cerr -w
Să acordăm atenție următoarei părți a codului:
PWD=$(pwd -L)
if [ "$APPVEYOR_PULL_REQUEST_NUMBER" != '' ]; then
PULL_REQUEST_ID="pulls/$APPVEYOR_PULL_REQUEST_NUMBER"
MERGE_BASE=`wget -qO -
https://api.github.com/repos/${APPVEYOR_REPO_NAME}/${PULL_REQUEST_ID}
| jq -r ".base.ref"`
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
pvs-studio-analyzer analyze -j8
-o PVS-Studio.log
--disableLicenseExpirationCheck
--dump-files --dump-log pvs-dump.log
-S .pvs-pr.list
else
pvs-studio-analyzer analyze -j8
-o PVS-Studio.log
--disableLicenseExpirationCheck
fi
Atribuirea destul de specifică a valorii comenzii pwd unei variabile care ar trebui să stocheze această valoare implicită pare ciudată la prima vedere, totuși, voi explica totul acum.
În timpul instalării analizorului în AppVeyor, am întâlnit un comportament extrem de ciudat al analizorului. Pe de o parte, totul a funcționat corect, dar analiza nu a început. Am petrecut mult timp observând că ne aflăm în directorul /home/appveyor/projects/testcalc/, iar analizatorul este sigur că suntem în /opt/appveyor/build-agent/. Apoi mi-am dat seama că variabila $PWD minte puțin. Din acest motiv, i-am actualizat manual valoarea înainte de a începe analiza.
Și apoi totul este ca înainte:
Acum luați în considerare următorul fragment:
PULL_REQUEST_ID="pulls/$APPVEYOR_PULL_REQUEST_NUMBER"
MERGE_BASE=`wget -qO -
https://api.github.com/repos/${APPVEYOR_REPO_NAME}/${PULL_REQUEST_ID}
| jq -r ".base.ref"`
În el obținem diferența dintre ramurile peste care este declarată cererea de pull. Pentru a face acest lucru avem nevoie de următoarele variabile de mediu:
- $APPVEYOR_PULL_REQUEST_NUMBER — numărul cererii de extragere;
- $APPVEYOR_REPO_NAME - numele de utilizator și depozitul de proiect.
Concluzie
Desigur, nu am luat în considerare toate serviciile posibile de integrare continuă, totuși, toate au specificități de operare extrem de asemănătoare între ele. Cu excepția caching-ului, fiecare serviciu își face propria „bicicletă”, așa că totul este întotdeauna diferit.
Undeva, ca în Travis-CI, câteva linii de cod și memorarea în cache funcționează impecabil; undeva, ca în AppVeyor, trebuie doar să specificați folderul în setări; dar undeva trebuie să creați chei unice și să încercați să convingeți sistemul să vă ofere posibilitatea de a suprascrie fragmentul din cache. Prin urmare, dacă doriți să configurați analiza cererilor de extragere pe un serviciu de integrare continuă care nu a fost discutat mai sus, atunci asigurați-vă mai întâi că nu veți avea probleme cu stocarea în cache.
Vă mulțumim pentru atenție. Dacă ceva nu merge, nu ezitați să ne scrieți la
Dacă doriți să împărtășiți acest articol unui public vorbitor de engleză, vă rugăm să utilizați linkul de traducere: Maxim Zvyagintsev.
Sursa: www.habr.com