Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio
Î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

PVS-Studio este un instrument de identificare a erorilor și potențialelor vulnerabilități în codul sursă al programelor scrise în C, C++, C# și Java. Funcționează pe sisteme pe 64 de biți pe Windows, Linux și macOS.

Î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 compile_commands.json. Este necesar ca analizorul să extragă informații despre compilarea fișierelor specificate. Dacă sistemul dvs. de compilare nu acceptă generarea fișierului compile_commands.json, puteți încerca să generați un astfel de fișier folosind utilitarul Urs.

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 analiză incrementală.

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:

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio

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 stderr (ieșire mesaj de eroare standard).

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:

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio
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:

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio
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, Prieteni oferă posibilitatea de a construi și testa automat proiecte stocate pe GitHub. Spre deosebire de Travis CI, acesta este configurat în interfața web (suportul bash este disponibil), deci nu este nevoie să stocați fișierele de configurare în proiect.

În primul rând, trebuie să adăugăm o nouă acțiune la linia de asamblare:

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio
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:

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio
Acum să instalăm PVS-Studio și utilitățile necesare:

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio
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ă:

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio
Cert este că acum analizăm nu rezultatul îmbinării, ci HEAD-ul ramurii din care se face cererea de extragere:

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio
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:

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio
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:

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind 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:

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio
Să derulăm în jos această pagină și să activăm salvarea în cache pentru colectarea solicitărilor de extragere:

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio
Acum să mergem la fila Mediu, unde specificăm imaginea pentru asamblare și variabilele de mediu necesare:

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio
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:

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio
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:

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio
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:

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio
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 a sustine. Vă vom sfătui și vă vom ajuta.

Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio

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. Analiza commit-urilor și solicitărilor de extragere în Travis CI, Buddy și AppVeyor folosind PVS-Studio.

Sursa: www.habr.com

Adauga un comentariu