Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor pomocí PVS-Studio

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio
V analyzátoru PVS-Studio pro jazyky C a C++ na Linuxu a macOS, počínaje verzí 7.04, se objevila testovací možnost zkontrolovat seznam uvedených souborů. Pomocí nového režimu můžete nakonfigurovat analyzátor pro kontrolu commitů a pull requestů. V tomto článku se dozvíte, jak nastavit kontrolu seznamu změněných souborů GitHub projektu v populárních systémem CI (Continuous Integration), jako jsou Travis CI, Buddy a AppVeyor.

Režim kontroly seznamu souborů

PVS-Studio — je nástroj pro odhalování chyb a potenciálních zranitelností v zdrojovém kódu programů napsaných v jazycích C, C++, C# a Java. Funguje na 64bitových systémech Windows, Linux a macOS.

Ve verzi PVS-Studio 7.04 pro Linux a macOS byl přidán režim kontroly seznamu zdrojových souborů. To funguje pro projekty, jejichž systém sestavení umožňuje vygenerovat soubor compile_commands.json. Je potřeba, aby analyzátor extrahoval informace o kompilaci uvedených souborů. Pokud váš systém sestavení nepodporuje generování souboru compile_commands.json, můžete se pokusit tento soubor vygenerovat pomocí utility Bear.

Režim kontroly seznamu souborů lze také použít spolu s logem trasování strace spuštění kompilátoru (pvs-studio-analyzer trace). Pro to budete potřebovat nejprve provést plnou sestavu projektu a sledovat ji, aby analyzátor shromáždil úplné informace o parametrech kompilace všech kontrolovaných souborů.

Tento způsob však má zásadní nevýhodu — je nutné buď provádět plné trasování celé sestavy projektu při každém spuštění, což se samo o sobě příčí myšlence rychlé kontroly commitu. Nebo, pokud se uloží výsledek trasování do cache, mohou se při následných spuštěních analyzátoru ukázat jako neúplné, pokud se po trasování změní struktura závislostí zdrojových souborů (například pokud bude do jednoho ze zdrojových souborů přidán nový #include).

Proto nedoporučujeme používat režim kontroly seznamu souborů s logem trasování pro kontrolu commitů nebo pull requestů. V případě, že můžete provádět inkrementální sestavu při kontrole commitu, zvažte možnost použít režim inkrementální analýzy.

Seznam zdrojových souborů pro analýzu je uložen do textového souboru a předán analyzátoru pomocí parametru -S:

pvs-studio-analyzer analyze ... -f build/compile_commands.json -S check-list.txt

V tomto souboru se uvádějí relativní nebo absolutní cesty k souborům, přičemž každý nový soubor musí být na novém řádku. Je také možné uvádět nejen názvy souborů pro analýzu, ale i různé texty. Analyzátor uvidí, že to není soubor, a tuto řádku ignoruje. To může být užitečné pro komentování, pokud jsou soubory uváděny ručně. Nicméně seznam souborů bude často generován během analýzy v CI, například to mohou být soubory z commitu nebo pull requestu.

Nyní pomocí tohoto režimu lze rychle kontrolovat nový kód, než se dostane do hlavní vývojové větve. Aby aplikační systém reagoval na přítomnost varování analyzátoru, je třeba do nástroje plog-converter byla přidána možnost --indicate-warnings:

plog-converter ... --indicate-warnings ... -o /path/to/report.tasks ...

S touto možností konvertor vrátí nenulový kód, pokud jsou ve zprávě analyzátoru přítomna varování. Podle návratového kódu je možné blokovat pre-commit hook, commit nebo pull request, a vygenerovanou zprávu analyzátoru zobrazit na obrazovce, sdílet nebo poslat e-mailem.

Poznámka: Při prvním spuštění analýzy seznamu souborů bude analyzován celý projekt, protože analyzátor musí vygenerovat soubor závislostí původních souborů projektu na hlavičkových souborech. Toto je vlastnost analýzy souborů C a C++. V budoucnu lze soubor závislostí vyrovnat do mezipaměti a bude automaticky aktualizován analyzátorem. Výhoda kontroly commitů při použití režimu kontroly seznamu souborů oproti použití režimu inkrementální analýzy spočívá v tom, že je třeba vyrovnat do mezipaměti pouze tento soubor, a ne objektové soubory.

Obecné zásady analýzy pull requestu

Analýza celého projektu trvá dost dlouho, proto má smysl kontrolovat pouze určitou jeho část. Problém spočívá v tom, že je třeba oddělit nové soubory od ostatních souborů projektu.

Podívejme se na příklad stromu commitů se dvěma větvemi:

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio

Představme si, že commit A1 obsahuje poměrně velké množství kódu, který již byl zkontrolován. O něco dříve jsme vytvořili větev z commitu A1 a měnili jsme některé soubory.

Samozřejmě jste si všimli, že po A1 došlo ještě k dalším dvěma commitům, ale to byla také sloučení jiných větví, vždyť my přece necommituje do master. A teď přišel čas, kdy hotfix je připraven. Proto se objevil pull request na sloučení B3 a A3.

Samozřejmě, bylo by možné zkontrolovat celý výsledek jejich sloučení, ale to by bylo příliš dlouhé a neopodstatněné, protože bylo změněno pouze několik souborů. Takže efektivnější je analyzovat pouze změněné.

K tomu získáme rozdíl mezi větvemi, když jsme v HEAD větvi, ze které chceme sloučit do master:

git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list

$MERGE_BASE budeme se podrobněji zabývat později. Je pravda, že ne každý CI servis poskytuje potřebné informace o základně pro sloučení, takže pokaždé musíme vymýšlet nové způsoby, jak tyto údaje získat. To bude podrobně popsáno níže v každém z uvedených webových služeb.

Takže jsme získali rozdíl mezi větvemi, přesněji řečeno — seznam názvů souborů, které byly změněny. Teď musíme poskytnout soubor .pvs-pr.list (do kterého jsme přesměrovali výstup výše) analyzátoru:

pvs-studio-analyzer analyze -j8 
                            -o PVS-Studio.log 
                            -S .pvs-pr.list

Po analýze musíme převést soubor s logy (PVS-Studio.log) do přehledného formátu:

plog-converter -t errorfile PVS-Studio.log --cerr -w

Tento příkaz vypíše seznam chyb v stderr (standardní výstup atribuce chyb).

Jenže potřebujeme nejen vypisovat chyby, ale také informovat náš servis pro sestavování a testování o přítomnosti problémů. K tomu byl do konvertoru přidán příznak -W (--indicate-warnings). Pokud se objeví alespoň jedno upozornění analyzátoru, návratový kód utility plog-converter se změní na 2, což zase informuje CI servis o přítomnosti potenciálních chyby v souborech pull requestu.

Travis CI

Konfigurace je provedena v podobě souboru .travis.yml. Pro pohodlí doporučuji vše vyjmout do samostatného bash skriptu s funkcemi, které budou vyvolány ze souboru .travis.yml (bash jméno_skriptu.sh název_funkce).

Budeme do skriptu přidávat potřebný kód v bash, tím získáme větší funkčnost. V sekci install napíšeme následující:

install:
  - bash .travis.sh travis_install

Pokud jste měli nějaké pokyny, můžete je přenést do skriptu a odstranit pomlčky.

Otevřeme soubor .travis.sh a přidáme instalaci analyzátoru do funkce 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 
}

Nyní přidáme do sekce script spuštění analýzy:

script:
  - bash .travis.sh travis_script

A v bash skriptu:

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 měli sestavení na 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
}

Jistě jste si již všimli uvedených proměnných prostředí $TRAVIS_PULL_REQUEST a $TRAVIS_BRANCH. Travis CI je automaticky deklaruje:

  • $TRAVIS_PULL_REQUEST ukládá číslo pull requestu nebo false, pokud se jedná o běžnou větev;
  • $TRAVIS_REPO_SLUG ukládá název repozitáře projektu.

Algoritmus této funkce:

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio
Travis CI reaguje na návratové kódy, proto 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.list

Faktem je, že Travis CI automaticky provádí sloučení větví během analýzy pull requestu:

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio
Proto analyzujeme A4, a ne B3->A3. Kvůli této vlastnosti je třeba počítat rozdíl s A3, která je právě vrcholem větve z origin.

Zůstává jedna důležitá část — caching závislostí hlavičkových souborů od překládaných jednotek (*.c, *.cc, *.cpp atd.). Tyto závislosti analyzátor vypočí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 cache adresáře, proto 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ář uchovává různé údaje shromážděné po analýze, které výrazně urychlají následné spuštění analýzy seznamu souborů nebo inkrementální analýzy. Pokud to neuděláte, analyzátor v podstatě pokaždé prozkoumá všechny soubory.

Buddy

Stejně jako Travis CI, Buddy poskytuje možnost automatizované sestavy a testování projektů, které jsou uloženy na GitHubu. Na rozdíl od Travisu CI se nastavuje v webovém rozhraní (podpora bash je k dispozici), takže není potřeba uchovávat konfigurační soubory v projektu.

Nejdříve musíme přidat novou akci do řady sestavení:

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio
Určíme překladač, který byl použit pro sestavení projektu. Všimněte si docker kontejneru, který je nainstalován v této akci. Například pro GCC je k dispozici speciální kontejner:

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio
Nyní nainstalujeme PVS-Studio a potřebné nástroje:

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio
Přidáme do editoru následující řádky:

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

Nyní přejdeme na kartu Run (první ikona) a do příslušného pole editoru přidáme následující 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 -w

Pokud jste četli část věnovanou Travs-CI, pak už vám tento kód je známý, nyní však nastala nová fáze:

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio
Jde o to, že nyní analyzujeme nikoli výsledek sloučení, ale HEAD větve, ze které se provádí pull request:

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio
Proto se nacházíme v podmíněném commitu B3 a potřebujeme získat rozdíl 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.list

Pro určení A3 využijeme API GitHub:

https://api.github.com/repos/${USERNAME}/${REPO}/pulls/${PULL_REQUEST_ID}

Použili jsme následující proměnné, které poskytuje Buddy:

  • $BUDDY_EXECUTION_PULL_REQEUST_NO — číslo pull requestu;
  • $BUDDY_REPO_SLUG — kombinace uživatelského jména a repozitáře (například max/test).

Nyní uložíme změny pomocí tlačítka níže a aktivujeme analýzu pull requestu:

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio
Na rozdíl od Travis CI není potřeba uvádět .pvs-studio pro mezipaměť, protože Buddy automaticky ukládá všechny soubory pro následná spuštění. Takže zbývá poslední — uložit přihlašovací údaje a heslo pro PVS-Studio v Buddy. Po uložení změn se vrátíme zpět do Pipeline. Musíme přejít k nastavení proměnných a přidat přihlašovací údaje a klíč pro PVS-Studio:

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio
Poté každé nové pull request nebo commit spustí kontrolu. Pokud commit obsahuje chyby, Buddy na to upozorní na stránce pull requestu.

AppVeyor

Nastavení AppVeyoru je podobné jako v Buddy, protože vše probíhá v webovém rozhraní a není potřeba přidávat soubor *.yml do repozitáře projektu.

Přejdeme na kartu Nastavení v přehledu projektu:

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio
Srolujeme tuto stránku dolů a aktivujeme ukládání mezipaměti pro sestavení pull requestů:

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio
Nyní přejdeme na kartu Prostředí, kde uvedeme obraz pro sestavení a potřebné proměnné prostředí:

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio
Pokud jste četli předchozí části, měli byste být dobře obeznámeni s těmito dvěma proměnnými — PVS_KEY a PVS_USERNAME. Pokud ne, pak připomínám, že jsou potřebné pro ověření licence analyzátoru PVS-Studio. V budoucnu se s nimi znovu setkáme v skriptech Bash.

Na této stránce dolů uvedeme složku pro mezipaměť:

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio
Pokud to neuděláme, budeme analyzovat místo několika souborů celý projekt, ale výstup obdržíme pro uvedené soubory. Proto je důležité zadat správný název adresáře.

Nyní je čas na skript pro kontrolu. Otevřeme kartu Testy a vybereme Skript:

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio
Do tohoto formuláře je třeba vložit následující 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 -w

Věnujme pozornost následující části 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
fi

Na první pohled se zdá podivné přidělovat hodnotu příkazu pwd proměnné, která by tuto hodnotu měla uchovávat jako výchozí. Ale teď to vysvětlím.

Při nastavování analyzátoru v AppVeyoru jsem se setkal s velmi podivným chováním analyzátoru. Z jedné strany to fungovalo správně, ale analýza se nespouštěla. Strávil jsem nějaký čas tím, že jsem si všiml, že se nacházíme ve složce /home/appveyor/projects/testcalc/, zatímco analyzátor byl přesvědčen, že jsme v /opt/appveyor/build-agent/. Tehdy jsem pochopil, že proměnná $PWD trochu lže. Z tohoto důvodu jsem ji před spuštěním analýzy ručně aktualizoval.

A dál už to jde jako dřív:

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio
Nyní se podívejme na následující 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 něm získáváme rozdíl mezi větvemi, na které byl vyhlášen pull request. K tomu potřebujeme následující proměnné prostředí:

  • $APPVEYOR_PULL_REQUEST_NUMBER — číslo pull request;
  • $APPVEYOR_REPO_NAME — jméno uživatele a repo projektu.

Závěr

Samozřejmě jsme neprošli všechny možné služby kontinuální integrace, ale všechny mají velmi podobné pracovní specifikace. Kromě caching, každá služba dělá svůj "vlastní kolo", takže je vždycky všechno jinak.

Někde, jako v Travis-CI, pár řádků kódu a caching funguje bezchybně; někde, jako v AppVeyoru, je třeba pouze zadat složku v nastavení; ale někde je třeba vytvořit unikátní klíče a pokusit se přesvědčit systém, aby vám umožnil přepsat cache fragment. Takže pokud chcete nastavit analýzu pull requestů na službě kontinuální integrace, která nebyla probrána výše, ujistěte se nejprve, že s cachingem nebudete mít problémy.

Děkujeme za pozornost. Pokud něco nefunguje, neváhejte nám napsat na podporu. Poradíme a pomůžeme.

Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor s pomocí PVS-Studio

Pokud chcete sdílet tento článek s anglicky mluvícím publikem, prosím použijte odkaz na překlad: Maxim Zvyagintsev. Analýza commitů a pull requestů v Travis CI, Buddy a AppVeyor pomocí PVS-Studio.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster