
V analyzátore PVS-Studio pre jazyky C a C++ na Linuxe a macOS, počínajúc verziou 7.04, sa objavila testovacia funkcia na kontrolu zoznamu uvedených súborov. S pomocou nového režimu môžete nastaviť analyzátor na kontrolu commitov a pull requestov. V tomto článku sa dozviete, ako nastaviť kontrolu zoznamu zmenených súborov projektu na GitHub v takých populárnych CI (Continuous Integration) systémoch, ako sú Travis CI, Buddy a AppVeyor.
Režim kontroly zoznamu súborov
— je nástroj na odhaľovanie chýb a potenciálnych zraniteľností v zdrojovom kóde programov napísaných v jazykoch C, C++, C# a Java. Funguje na 64-bitových systémoch Windows, Linux a macOS.
Vo verzii PVS-Studio 7.04 pre Linux a macOS sa objavil režim kontroly zoznamu zdrojových súborov. Funguje to pre projekty, ktorých build systém umožňuje vygenerovať súbor . Je potrebný na to, aby analyzátor extrahoval informácie o kompilácii uvedených súborov. Ak váš build systém nepodporuje generovanie súboru compile_commands.json, môžete sa pokúsiť vygenerovať takýto súbor pomocou utilitky .
Taktiež môžete režim kontroly zoznamu súborov použiť spolu s logom trasovania strace spustení kompilátora (pvs-studio-analyzer trace). Na to budete musieť najskôr vykonať úplnú kompiláciu projektu a sledovať ju, aby analyzátor zhromaždil kompletné informácie o parametroch kompilácie všetkých kontrolovaných súborov.
Tento variant má však významnú nevýhodu — buď budete musieť vykonávať úplnú trasovanie kompilácie celého projektu pri každom spustení, čo samo o sebe protirečí myšlienke rýchlej kontroly commitu. Alebo, ak vyrovnáte výsledok trasovania, následné spustenia analyzátora môžu byť neúplné, ak sa po trasovaní zmení štruktúra závislostí zdrojových súborov (napríklad, ak do jedného zo zdrojových súborov pridáte nový #include).
Preto nedoporučujeme používať režim kontroly zoznamu súborov s logom trasovania na kontrolu commitov alebo pull requestov. Ak môžete pri kontrole commitu vykonávať inkrementálnu kompiláciu, zvážte možnosť použiť režim .
Zoznam zdrojových súborov na analýzu sa ukladá do textového súboru a odovzdáva sa analyzátorovi pomocou parametra -S:
pvs-studio-analyzer analyze ... -f build/compile_commands.json -S check-list.txtV tomto súbore sa uvádzajú relatívne alebo absolútne cesty k súborom, pričom každý nový súbor by mal byť na novom riadku. Je povolené uvádzať nielen názvy súborov na analýzu, ale aj rôzny text. Analytik zistí, že to nie je súbor, a ignoruje riadok. To môže byť užitočné na komentovanie, ak súbory sú uvádzané ručne. Často však bude zoznam súborov generovaný počas analýzy v CI, napríklad to môžu byť súbory z commitu alebo pull requestu.
Teraz pomocou tohto režimu je možné rýchlo kontrolovať nový kód predtým, ako sa dostane do hlavnej vetvy vývoja. Aby systém kontroly reagoval na prítomnosť varovaní analytika, do nástroja plog-converter bol pridaný flag —indicate-warnings:
plog-converter ... --indicate-warnings ... -o /path/to/report.tasks ...S týmto praporom konvertor vráti nenulový kód, ak v správe analytika sú prítomné varovania. Podľa kódu návratu je možné zablokovať pre-commit hook, commit alebo pull request, a vygenerovanú správu analytika zobraziť na obrazovke, zdieľať alebo poslať e-mailom.
Poznámka. Pri prvom spustení analýzy zoznamu súborov bude analyzovaný celý projekt, pretože analytik potrebuje vygenerovať súbor závislostí zdrojových súborov projektu na hlavičkové súbory. Toto je zvláštnosť analýzy C a C++ súborov. V budúcnosti je možné súbor závislostí vyrovnať do cache a bude automaticky aktualizovaný analytikom. Výhodou kontroly commitov pri použití režimu kontroly zoznamu súborov pred použitím režimu inkrementálnej analýzy je, že je potrebné vyrovnať iba tento súbor, nie objektové súbory.
Všeobecné zásady analýzy pull requestu
Analýza celého projektu trvá pomerne dlho, preto má zmysel kontrolovať iba určitú jeho časť. Problém spočíva v tom, ako oddeliť nové súbory od ostatných súborov projektu.
Pozrime sa na príklad stromu commitov so zdvoma vetvami:

Predstavme si, že commit A1 obsahuje dosť veľké množstvo kódu, ktorý už bol skontrolovaný. Predtým sme vytvorili vetvu z commitu A1 a menili sme niektoré súbory.
Iste ste si všimli, že po A1 došlo ešte k dvom commitom, ale to boli taktiež zlúčenia iných vetiev, veď my predsa necommituje do master. A tu nastal čas, keď hotfix je pripravený. Preto sa objavil pull request na zlúčenie B3 a A3.
Samozrejme, mohli by sme skontrolovať celý výsledok ich zlúčenia, ale to by trvalo príliš dlho a bolo by neopodstatnené, pretože bolo zmenených len niekoľko súborov. Preto je efektívnejšie analyzovať iba zmenené.
Na to získame rozdiel medzi vetvami, nachádzajúc sa v HEAD vetvy, z ktorej chceme zlúčiť do master:
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list$MERGE_BASE o ktorom sa podrobne budeme rozprávať neskôr. Vec je taká, že nie každý CI služba poskytuje potrebné informácie o základni na zlúčenie, preto musíme zakaždým prichádzať s novými spôsobmi získania týchto údajov. To bude podrobne opísané nižšie v každom z opísaných webových služieb.
Takže sme získali rozdiel medzi vetvami, presnejšie povedané — zoznam názvov súborov, ktoré boli zmenené. Teraz musíme odovzdať súbor .pvs-pr.list (do ktorého sme presmerovali výstup vyššie) analyzátorovi:
pvs-studio-analyzer analyze -j8
-o PVS-Studio.log
-S .pvs-pr.listPo analýze musíme konvertovať súbor logov (PVS-Studio.log) do formátu, ktorý je pohodlne zrozumiteľný:
plog-converter -t errorfile PVS-Studio.log --cerr -wTento príkaz vygeneruje zoznam chýb v (štandardný tok výstupu správ o chybách).
Lenže potrebujeme nielen vydať chyby, ale aj informovať našu službu na zostavenie a testovanie o prítomnosti problémov. Na to bol do konvertora pridaný prepínač -W (—indicate-warnings). Pri prítomnosti aspoň jednej výstrahy analyzátora sa návratový kód nástroja plog-converter zmení na 2, čo, naopak, oznámi CI službe o prítomnosti potenciálnych chýb v súboroch pull requestu.
Travis CI
Konfigurácia je vykonaná vo forme súboru .travis.yml. Pre pohodlie odporúčam všetko presunúť do samostatného bash skriptu s funkciami, ktoré budú volané zo súboru .travis.yml (bash názov_skriptu.sh názov_funkcie).
Budeme pridávať potrebný kód do skriptu v bash, týmto spôsobom získame väčšiu funkcionalitu. V sekcii install napíšeme nasledovné:
install:
- bash .travis.sh travis_installAk ste mali nejaké pokyny, môžete ich presunúť do skriptu a odstrániť pomlčky.
Otvorte súbor .travis.sh a pridajte inštaláciu analyzátora do funkcie 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
}Teraz pridáme do sekcie script spustenie analýzy:
script:
- bash .travis.sh travis_scriptA v bash skripte:
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
}Tento kód je třeba spustit po sestavení projektu, například pokud jste použili CMake:
travis_script() {
CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
cmake $CMAKE_ARGS CMakeLists.txt
make -j8
}Bude to vypadat takto:
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
}Pravděpodobně jste si již všimli uvedených proměnných prostředí: $TRAVIS_PULL_REQUEST a $TRAVIS_BRANCH. Travis CI je vyhlašuje automaticky:
- $TRAVIS_PULL_REQUEST uchovává číslo pull requestu nebo nepravda, pokud se jedná o běžnou větev;
- $TRAVIS_REPO_SLUG uchovává název repozitáře projektu.
Algoritmus práce této funkce:

Travis CI reaguje na návratové kódy, takže přítomnost varování způsobí, že služba označí commit jako obsahující chyby.
A nyní se podívejme podrobněji na tento řádek kódu:
git diff --name-only origin/HEAD > .pvs-pr.listDůvod je ten, že Travis CI automaticky provádí sloučení větví během analýzy pull requestu:

Proto analyzujeme A4, a ne B3->A3. Kvůli této vlastnosti musíme počítat rozdíl s A3, která je právě vrcholem větve z origin.
Zůstává jedna důležitá věc — cachování závislostí hlavičkových souborů od kompilovaných jednotek překladu (*.c, *.cc, *.cpp atd.). Tyto závislosti analyzátor počítá při prvním spuštění v režimu kontroly seznamu souborů a poté je ukládá do adresáře .PVS-Studio. Travis CI umožňuje cachovat složky, takže uložíme data adresáře .PVS-Studio/:
cache:
directories:
- .PVS-Studio/Tento kód je třeba přidat do souboru .travis.yml. Tento adresár uchováva rôzne údaje zozbierané po analýze, ktoré výrazne urýchlia následné spustenia analýzy zoznamu súborov alebo inkrementálnej analýzy. Ak to neurobíte, analytik bude v podstate pri každom spustení analyzovať všetky súbory.
Buddy
Rovnako ako Travis CI, poskytuje možnosť automatizovanej zostavy a testovania projektov, ktoré sú uložené na GitHub. Na rozdiel od Travis CI je možné ho nastaviť v webovom rozhraní (podpora bash je k dispozícii), takže nie je potrebné uchovávať konfiguračné súbory v projekte.
Predovšetkým musíme pridať novú akciu do zostavovacej línie:

Určíme kompilátor, ktorý bol použitý na zostavenie projektu. Všimnite si docker kontajner, ktorý je nainštalovaný v tejto akcii. Napríklad pre GCC existuje špeciálny kontajner:

Teraz nainštalujeme PVS-Studio a potrebné utilíty:

Pridáme do editora nasledujúce riadky:
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-studioTeraz prejdeme na kartu Run (prvá ikona) a do príslušného poľa editora pridáme nasledujúci kód:
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 -wAk ste čítali kapitolu venovanú Travs-CI, tento kód vám už je známy, avšak teraz sa objavil nový krok:

Ide o to, že teraz analyzujeme nie výsledok zlúčenia, ale HEAD vetvy, z ktorej sa robí pull request:

Preto sa nachádzame v podmienenom commite B3 a musíme získať rozdiel s 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.listPre určenie A3 využijeme API GitHub:
https://api.github.com/repos/${USERNAME}/${REPO}/pulls/${PULL_REQUEST_ID}Použili sme nasledujúce premenné, ktoré poskytuje Buddy:
- $BUDDY_EXECUTION_PULL_REQEUST_NO — číslo pull requestu;
- $BUDDY_REPO_SLUG — kombinácia mena používateľa a repozitára (napríklad max/test).
Teraz uložíme zmeny pomocou tlačidla nižšie a aktivujeme analýzu pull requestu:

Na rozdiel od Travis CI, nemusíme špecifikovať .pvs-studio pre vyrovnávanie pamäte, pretože Buddy automaticky vyrovnáva všetky súbory pre nasledujúce spustenia. Zostáva teda posledné — uložiť prihlásenie a heslo pre PVS-Studio v Buddy. Po uložení zmien sa vrátime späť do Pipeline. Musíme prejsť k nastaveniu premenných a pridať prihlásenie a kľúč pre PVS-Studio:

Po tomto vytvorenie nového pull requestu alebo commitu spustí kontrolu. Ak commit obsahuje chyby, Buddy na to poukáže na stránke pull requestu.
AppVeyor
Nastavenie AppVeyor je podobné ako Buddy, pretože všetko sa deje v webovom rozhraní a nie je potrebné pridávať súbor *.yml do repozitára projektu.
Prejdime na kartu Nastavenia v prehľade projektu:

Posuňme túto stránku nadol a aktivujeme vyrovnávanie pamäte pre zostavenie pull requestov:

Teraz prejdeme na kartu Prostredie, kde uvedieme obraz pre zostavenie a potrebné premenné prostredia:

Ak ste si prečítali predchádzajúce časti, určite už poznáte tieto dve premenné — PVS_KEY a PVS_USERNAME. Ak nie, tak vám pripomeniem, že sú nevyhnutné pre kontrolu licencie analyzátora PVS-Studio. V budúcnosti sa s nimi opäť stretneme v Bash skriptoch.
Na tejto istej stránke dole uvedieme adresár na vyrovnávanie pamäte:

Ak to neurobíme, budeme analyzovať namiesto pár súborov celý projekt, ale výsledok dostaneme len pre zadané súbory. Preto je dôležité zadať správny názov adresára.
Teraz nastal čas na skript pre kontrolu. Otvoríme kartu Testy a vyberieme Skript:

Do tohto formulára je potrebné vložiť nasledujúci kód:
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 -wVenovať pozornosť nasledujúcej časti kódu:
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
fiNa prvý pohľad sa môže zdať zvláštne priradiť hodnotu príkazu pwd do premennej, ktorá by mala túto hodnotu uchovávať ako predvolenú, no teraz vám to všetko vysvetlím.
Počas nastavenia analyzátora v AppVeyor som sa stretol s mimoriadne zvláštnym správaním analyzátora. Na jednej strane všetko fungovalo správne, ale analýza sa nespustila. Strávil som veľa času tým, že som si všimol, že sme v adresári /home/appveyor/projects/testcalc/, zatiaľ čo analyzátor bol presvedčený, že sme v /opt/appveyor/build-agent/. Potom som pochopil, že premenná $PWD klame. Preto som pred spustením analýzy ručne aktualizoval jej hodnotu.
A ďalej to pokračuje ako predtým:

Teraz sa pozrime na nasledujúci 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"`V ňom získavame rozdiel medzi vetvami, na ktorých bol vyhlásený pull request. Na to potrebujeme nasledujúce premenné prostredia:
- $APPVEYOR_PULL_REQUEST_NUMBER — číslo pull requestu;
- $APPVEYOR_REPO_NAME — meno používateľa a názov projektu.
Záver
Samozrejme, nezohľadnili sme všetky možné služby kontinuálnej integrácie, no všetky majú veľmi podobnú špecifiku fungovania. S výnimkou cache, každá služba robí svoje "kolo", takže to vždy vyzerá inak.
Niektoré ako v Travis-CI, kde pár riadkov kódu umožní bezchybné cachovanie; niektoré ako v AppVeyor, kde stačí zadať adresár v nastaveniach; ale niektoré vyžadujú vytvorenie unikátnych kľúčov a snažia sa presvedčiť systém, aby vám umožnil prepísať cachovaný fragment. Preto, ak chcete nastaviť analýzu pull requestov na službe kontinuálnej integrácie, ktorá nebola vyššie diskutovaná, najskôr sa uistite, že s cache nebudete mať problémy.
Ďakujem za pozornosť. Ak máte nejaké otázky alebo sa niečo nedarí, neváhajte nám napísať na . Rádi vám poradíme a pomôžeme.
Ak chcete zdieľať tento článok s anglicky hovoriacou verejnosťou, prosím, použite odkaz na preklad: Maxim Zvyagintsev. .
Zdroj: habr.com
