
I analysatorn PVS-Studio för sprÄken C och C++ pÄ Linux och macOS, frÄn version 7.04, har en testfunktion införts för att kontrollera listan över angivna filer. Med den nya lÀget kan analysatorn konfigureras för att kontrollera commits och pull requests. I denna artikel kommer vi att diskutera hur man stÀller in kontrollen av listan med Àndrade filer i ett GitHub-projekt i populÀra CI-system som Travis CI, Buddy och AppVeyor.
FilkontrolllÀge
Àr ett verktyg för att identifiera fel och potentiella sÄrbarheter i programkod som skrivits i sprÄk som C, C++, C# och Java. Det fungerar pÄ 64-bitarsystem i Windows, Linux och macOS.
I version PVS-Studio 7.04 för Linux och macOS har ett filkontrolllÀge lagts till. Detta fungerar för projekt vars byggsystem kan generera en fil . Denna fil behövs för att analysatorn ska kunna extrahera information om kompileringen av de angivna filerna. Om ditt byggsystem inte stöder generering av filen compile_commands.json kan du försöka generera en sÄdan fil med hjÀlp av verktyget .
. FilkontrolllÀget kan ocksÄ anvÀndas tillsammans med loggen frÄn strace över kompilatorns körningar (pvs-studio-analyzer trace). För detta behöver du först genomföra en fullstÀndig byggen av projektet och spÄra den, sÄ att analysatorn samlar in fullstÀndig information om kompileringstillstÄnden för alla kontrollerade filer.
Men denna metod har en betydande nackdel - det krÀvs antingen att du gör en fullstÀndig spÄrning av hela projektbyggen vid varje körning, vilket gÄr emot syftet med snabb kontroll av commiten. Eller, om du cacher resultatet av spÄrningen, kan efterföljande körningar av analysatorn bli ofullstÀndiga ifall struktureringen av beroendena i kÀllfilerna Àndras (till exempel om en ny #include lÀggs till i en av kÀllfilerna).
DÀrför rekommenderar vi inte att anvÀnda filkontrolllÀget med spÄrningsloggen för att kontrollera commits eller pull requests. Om du kan göra en inkrementell byggning vid kontroll av en commit, övervÀg att anvÀnda lÀget .
Listan över kÀllfiler för analys sparas i en textfil och överlÀmnas till analysatorn med parametern -S:
pvs-studio-analyzer analyze ... -f build/compile_commands.json -S check-list.txtDenna fil innehÄller relativa eller absoluta sökvÀgar till filer, dÀr varje ny fil ska anges pÄ en ny rad. Det Àr tillÄtet att ange inte bara filnamn för analysen, utan ocksÄ olika text. Analysatorn kommer att se att detta inte Àr en fil och ignorera raden. Detta kan vara anvÀndbart för kommentar, om filerna anges manuellt. Men oftast kommer fillistan att genereras under analysen i CI, till exempel kan det vara filer frÄn en commit eller pull request.
Nu kan man snabbt kontrollera ny kod innan den hamnar i huvudutvecklingsgrenen med hjĂ€lp av detta lĂ€ge. För att kontrollsystemet ska reagera pĂ„ analyserarens varningsmeddelanden, i verktyget plog-converter har en flagga lagts till âindicate-warnings:
plog-converter ... --indicate-warnings ... -o /path/to/report.tasks ...Med detta flagga kommer konverteraren att returnera en icke-noll kod om det finns varningar i analyserarens rapport. UtifrÄn returkoden kan man blockera pre-commit hook, commit eller pull request, och den genererade analyserarens rapport kan visas pÄ skÀrmen, delas eller skickas via e-post.
Observera. Vid första körningen av filanalysen kommer hela projektet att analyseras, eftersom analysatorn mÄste generera en beroendefil för projektets kÀllfiler till header-filer. Detta Àr en egenskap hos analysen av C- och C++-filer. I framtiden kan beroendefilen cachas och kommer att uppdateras automatiskt av analysatorn. Fördelen med commit-kontroll med hjÀlp av filanalyslÀget jÀmfört med inkremental analys Àr att man bara behöver cacha denna fil och inte objektfiler.
AllmÀnna principer för analys av pull request
Att analysera hela projektet tar ganska mycket tid, sÄ det Àr meningsfullt att bara kontrollera en del av det. Problemet Àr att man mÄste separera nya filer frÄn övriga filer i projektet.
LÄt oss titta pÄ ett exempel pÄ ett commit-trÀd med tvÄ grenar:

LÄt oss förestÀlla oss att commit A1 innehÄller en tillrÀckligt stor mÀngd kod som redan har granskats. Tidigare gjorde vi en gren frÄn commit A1 och Àndrade nÄgra filer.
Ni har sÀkert mÀrkt att efter A1 har det skett ytterligare tvÄ commits, men dessa var ocksÄ sammanslagningar av andra grenar, eftersom vi inte commit:ar i master. Och nu har tiden kommit dÄ hotfix Àr redo. DÀrför har det skapats en pull request för att slÄ samman B3 och A3.
SjÀlvklart skulle man kunna kontrollera hela resultatet av deras sammanslagning, men det skulle ta för lÄng tid och vara orimligt, eftersom endast nÄgra filer har Àndrats. DÀrför Àr det effektivare att analysera endast de Àndrade filerna.
För detta fÄr vi skillnaden mellan grenarna, medan vi Àr i HEAD-grenen som vi vill slÄ ihop till master:
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list$MERGE_BASE vi kommer att gÄ igenom detta mer ingÄende senare. Saken Àr den att lÄngt ifrÄn varje CI-tjÀnst tillhandahÄller nödvÀndig information om basen för sammanslagning, sÄ varje gÄng mÄste vi komma pÄ nya sÀtt att fÄ dessa data. Detta kommer att beskrivas mer detaljerat nedan i varje beskrivna webbtjÀnst.
SĂ„ vi har fĂ„tt skillnaden mellan grenarna, eller mer specifikt â listan över filnamn som har Ă€ndrats. Nu behöver vi ge filen .pvs-pr.list (vi har omdirigerat utdata dit ovan) till analyzern:
pvs-studio-analyzer analyze -j8
-o PVS-Studio.log
-S .pvs-pr.listEfter analysen mÄste vi konvertera loggfilen (PVS-Studio.log) till ett mer lÀttlÀst format:
plog-converter -t errorfile PVS-Studio.log --cerr -wDetta kommando kommer att skriva ut en lista över fel i (standard utdataflöde för felmeddelanden).
Men vi behöver inte bara skriva ut fel, utan Ă€ven meddela vĂ„r bygg- och testtjĂ€nst om förekomsten av problem. För detta har en flagga lagts till i konverteraren -W (âindicate-warnings). Om det finns minst en varning frĂ„n analyzern, kommer Ă„tervĂ€ndande koden för verktyget plog-converter att Ă€ndras till 2, vilket i sin tur meddelar CI-tjĂ€nsten om potentiella fel i pull request-filerna.
Travis CI
Konfigurationen görs i form av en fil .travis.yml. För bekvÀmlighetens skull rekommenderar jag att flytta allt till ett separat bash-skript med funktioner som kommer att anropas frÄn filen .travis.yml (bash namn_pÄ_skriptet.sh funktionsnamn).
Vi kommer att lÀgga till nödvÀndig kod i skriptet pÄ bash, pÄ sÄ sÀtt fÄr vi mer funktionalitet. I avsnittet install ska vi skriva följande:
install:
- bash .travis.sh travis_installOm du har haft nÄgra instruktioner, kan du flytta dem till skriptet och ta bort bindestrecken.
Vi öppnar filen .travis.sh och lÀgger till installationen av analyzern i funktionen 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
}Nu lÀgger vi till i avsnittet script kör analys:
script:
- bash .travis.sh travis_scriptOch i bash-skriptet:
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
}Denna kod ska köras efter att projektet har byggts, till exempel om du har en byggning med CMake:
travis_script() {
CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
cmake $CMAKE_ARGS CMakeLists.txt
make -j8
}Det blir sÄ hÀr:
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
}Du har antagligen redan noterat de angivna miljövariablerna $TRAVIS_PULL_REQUEST och $TRAVIS_BRANCH. Travis CI deklarerar dem automatiskt:
- $TRAVIS_PULL_REQUEST innehÄller numret pÄ pull requesten eller false, om det Àr en vanlig gren;
- $TRAVIS_REPO_SLUG innehÄller namnet pÄ projektets repository.
Algoritmen för denna funktion:

Travis CI reagerar pÄ returkoder, sÄ förekomsten av varningar kommer att indikera för tjÀnsten att markera commit som innehÄllande fel.
Och nu lÄt oss ta en nÀrmare titt pÄ denna kodrad:
git diff --name-only origin/HEAD > .pvs-pr.listPoÀngen Àr att Travis CI automatiskt gör sammanslagningar av grenar under analysen av pull requests:

DÀrför analyserar vi A4, inte B3->A3. PÄ grund av denna egenskap behöver vi berÀkna skillnaden med A3, vilket just Àr toppen av grenen frÄn origin.
Det finns en viktig detalj kvar â cache av beroenden i huvudfilsskĂ€l frĂ„n de kompilationsenheter som översĂ€tts (*.c, *.cc, *.cpp osv.). Dessa beroenden berĂ€knas av analysatorn vid första körningen i filkollĂ€ge och sparas sedan i katalogen .PVS-Studio. Travis CI möjliggör cachning av mappar, sĂ„ vi sparar data frĂ„n katalogen .PVS-Studio/:
cache:
directories:
- .PVS-Studio/Denna kod mÄste lÀggas till i filen .travis.yml. Denna katalog lagrar olika data som samlas in efter analysen, vilket vÀsentligt snabbar upp efterföljande körningar av filanalyslistan eller inkrementell analys. Om detta inte görs, kommer analysatorn faktiskt att analysera alla filer varje gÄng.
Buddy
Precis som Travis CI, möjliggör automatiserad byggnation och testning av projekt som lagras pÄ GitHub. Till skillnad frÄn Travis CI, konfigureras det i webbgrÀnssnittet (bash-stöd finns), sÄ det Àr inte nödvÀndigt att lagra konfigurationsfiler i projektet.
Först mÄste vi lÀgga till en ny ÄtgÀrd i bygglinjen:

Vi anger kompilatorn som anvÀndes för att bygga projektet. Observera dockerbehÄllaren som Àr installerad i denna ÄtgÀrd. Till exempel, för GCC finns det en speciell behÄllare:

Nu installerar vi PVS-Studio och nödvÀndiga verktyg:

LÀgg till följande rader i redigeraren:
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-studioNu gÄr vi till fliken Run (den första ikonen) och lÀgger till följande kod i det angivna redigeringsfÀltet:
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 -wOm du har lÀst avsnittet om Travs-CI, sÄ Àr denna kod redan bekant för dig, men nu har ett nytt steg tillkommit:

Det handlar om att vi nu analyserar inte resultatet av sammanslagningen, utan HEAD pÄ den gren som pull requesten görs frÄn:

DÀrför befinner vi oss i ett hypotetiskt commit B3 och vi behöver fÄ skillnaden med 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.listFör att faststÀlla A3 anvÀnder vi GitHub API:
https://api.github.com/repos/${USERNAME}/${REPO}/pulls/${PULL_REQUEST_ID}Vi anvÀnde följande variabler som tillhandahÄlls av Buddy:
- $BUDDY_EXECUTION_PULL_REQEUST_NO â numret pĂ„ pull requesten;
- $BUDDY_REPO_SLUG â en kombination av anvĂ€ndarnamn och repository (t.ex. max/test).
Nu sparar vi Àndringarna med hjÀlp av knappen nedan och aktiverar analysen av pull request:

Till skillnad frĂ„n Travis CI behöver vi inte specificera .pvs-studio för caching, eftersom Buddy automatiskt cacherar alla filer för efterföljande körningar. Det Ă„terstĂ„r bara en sak â att spara inloggningen och lösenordet för PVS-Studio i Buddy. NĂ€r Ă€ndringarna sparas kommer vi tillbaka till Pipeline. Vi behöver gĂ„ till instĂ€llningarna för variabler och lĂ€gga till inloggning och nyckel för PVS-Studio:

Efter detta kommer en ny pull request eller commit att starta en kontroll. Om commiten innehÄller fel kommer Buddy att pÄpeka detta pÄ sidan för pull request.
AppVeyor
InstÀllningen av AppVeyor liknar Buddy, eftersom allt sker i webgrÀnssnittet och det inte behövs att lÀgga till en fil *.yml i projektets repository.
GÄ till fliken InstÀllningar i projektöversikten:

Rulla ner pÄ sidan och aktivera cachning för pull request-byggnader:

Nu gÄr vi till fliken Miljö, dÀr vi anger bild för byggandet och nödvÀndiga miljövariabler:

Om du har lĂ€st de föregĂ„ende avsnitten Ă€r du redan bekant med dessa tvĂ„ variabler â PVS_KEY och PVS_USERNAME. Om inte, pĂ„minner jag dig om att de behövs för att verifiera licensen för PVS-Studio-analysatorn. Vi kommer att trĂ€ffa dem igen i Bash-skripten.
LÀngst ner pÄ samma sida anger vi en mapp för caching:

Om vi inte gör detta kommer vi att analysera hela projektet istÀllet för ett par filer, men fÄ output baserat pÄ de angivna filerna. DÀrför Àr det viktigt att ange rÀtt katalognamn.
Nu Àr det dags för skriptet för kontroll. Vi öppnar fliken Tester och vÀljer Skript:

I detta formulÀr behöver vi klistra in följande kod:
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 -wLÄt oss titta nÀrmare pÄ den följande delen av koden:
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
fiAtt tilldela vÀrdet av kommandot pwd till en variabel som bör lagra detta vÀrde som standard kan verka konstigt vid första anblick, men jag ska förklara det nu.
NÀr jag satte upp analyzern i AppVeyor stötte jag pÄ ett extremt mÀrkligt beteende hos analyzern. à ena sidan fungerade allt korrekt, men analysen startade aldrig. Jag spenderade mycket tid pÄ att inse att vi var i katalogen /home/appveyor/projects/testcalc/, medan analyzern var övertygad om att vi var i /opt/appveyor/build-agent/. DÄ insÄg jag att variabeln $PWD ljuger lite grann. DÀrför uppdaterade jag dess vÀrde manuellt innan jag startade analysen.
Och sedan Àr det som vanligt:

LÄt oss nu titta pÄ nÀsta 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"`HÀr fÄr vi skillnaden mellan de grenar som en pull request Àr deklarerad för. För detta behöver vi följande miljövariabler:
- $APPVEYOR_PULL_REQUEST_NUMBER â numret pĂ„ pull requesten;
- $APPVEYOR_REPO_NAME â anvĂ€ndarnamn och projektnamn.
Slutsats
SjÀlvklart har vi inte granskat alla möjliga tjÀnster för kontinuerlig integrering, men de har alla en extremt liknande arbetsspecifikation. Med undantag för caching, gör varje tjÀnst sin "egen cykel", sÄ det Àr alltid olika.
NÄgonstans, som i Travis-CI, krÀvs nÄgra rader kod och cache fungerar felfritt; nÄgonstans, som i AppVeyor, mÄste du bara ange mappen i instÀllningarna; men nÄgonstans mÄste du skapa unika nycklar och försöka övertyga systemet att ge dig möjlighet att ÄsidosÀtta den cachade delen. SÄ, om du vill stÀlla in analys av pull requests pÄ en tjÀnst för kontinuerlig integrering som inte diskuterades ovan, se först till att du inte fÄr problem med cache.
Tack för att du lyssnade. Om nÄgot inte fungerar, tveka inte att skriva till oss pÄ . Vi hjÀlper gÀrna till.
Om du vill dela denna artikel med en engelsktalande publik, vÀnligen anvÀnd lÀnken till översÀttningen: Maxim Zvyagintsev. .
KĂ€lla: habr.com
