In de PVS-Studio-analyzer voor C- en C++-talen op Linux en macOS, vanaf versie 7.04, is een testmogelijkheid verschenen om de lijst met opgegeven bestanden te controleren. Met de nieuwe modus kunt u de analysator configureren om commits en pull-aanvragen te controleren. In dit artikel wordt uitgelegd hoe u een GitHub-projectbestandslijstcontrole instelt in populaire CI-systemen (Continuous Integration), zoals Travis CI, Buddy en AppVeyor.
Controlemodus voor bestandslijst
De versie van PVS-Studio 7.04 voor Linux en macOS heeft een modus voor het controleren van de lijst met bronbestanden. Dit werkt voor projecten waarvan het bouwsysteem u in staat stelt een bestand te genereren
Ook kan de modus voor het controleren van de lijst met bestanden worden gebruikt in combinatie met de strace-tracering van compiler-runs (pvs-studio-analyzer-tracering). Om dit te doen, moet u eerst een volledige build van het project uitvoeren en het volgen, zodat de analysator volledige informatie verzamelt over de compilatieparameters van alle bestanden die worden gecontroleerd.
Deze optie heeft echter een aanzienlijk nadeel: u moet bij elke lancering een volledige build-tracering van het hele project uitvoeren, wat op zichzelf in tegenspraak is met het idee van een snelle commit-controle. Of, als u het traceringsresultaat zelf in de cache opslaat, kunnen latere lanceringen van de analysator onvolledig blijken te zijn als de afhankelijkheidsstructuur van het bronbestand verandert na het traceren (er wordt bijvoorbeeld een nieuwe #include toegevoegd aan een van de bronbestanden).
Daarom raden we af om de bestandslijstcontrolemodus te gebruiken met een traceerlogboek om commits of pull-aanvragen te controleren. Als je een incrementele build kunt doen bij het controleren van een commit, overweeg dan om de modus te gebruiken
De lijst met bronbestanden voor analyse wordt opgeslagen in een tekstbestand en doorgegeven aan de analysator met behulp van de parameter -S:
pvs-studio-analyzer analyze ... -f build/compile_commands.json -S check-list.txt
Dit bestand specificeert relatieve of absolute paden naar bestanden en elk nieuw bestand moet op een nieuwe regel staan. Het is toegestaan om niet alleen de namen van bestanden voor analyse op te geven, maar ook verschillende teksten. De parser ziet dat dit geen bestand is en negeert de regel. Dit kan handig zijn voor commentaar als bestanden handmatig worden opgegeven. De lijst met bestanden wordt echter vaak gegenereerd tijdens CI-parsing, bijvoorbeeld bestanden van een commit of een pull-verzoek.
Met deze modus kunt u nu snel nieuwe code testen voordat deze in de hoofdontwikkelingstak terechtkomt. Om ervoor te zorgen dat het verificatiesysteem reageert op waarschuwingen van de analysator, moet het hulpprogramma plog-converter vlag toegevoegd --indicatie-waarschuwingen:
plog-converter ... --indicate-warnings ... -o /path/to/report.tasks ...
Met deze vlag retourneert de converter een code die niet gelijk is aan nul als er waarschuwingen in het analysatorrapport staan. Met behulp van de retourcode kunt u een precommit hook, commit of pull request blokkeren en het gegenereerde analysatorrapport op het scherm weergeven, delen of per e-mail verzenden.
Opmerking. De eerste keer dat u begint met het analyseren van de lijst met bestanden, wordt het hele project geanalyseerd, omdat de analysator moet een bestand genereren met de afhankelijkheden van de bronbestanden van het project op de headerbestanden. Dit is een kenmerk van het parseren van C- en C++-bestanden. In de toekomst kan het afhankelijkheidsbestand in de cache worden opgeslagen en wordt het automatisch bijgewerkt door de analysator. Het voordeel van het controleren van commits bij het gebruik van de bestandslijst-controlemodus ten opzichte van het gebruik van de incrementele parseermodus is dat alleen dat bestand in de cache hoeft te worden geplaatst, niet de objectbestanden.
Algemene principes van analyse van pull-aanvragen
De analyse van het hele project kost veel tijd, dus het is logisch om slechts een deel ervan te controleren. Het probleem is dat u de nieuwe bestanden moet scheiden van de rest van de projectbestanden.
Overweeg een voorbeeld van een commit-boom met twee takken:
Laten we doen alsof de commit A1 bevat een vrij grote hoeveelheid code die al is gecontroleerd. Iets eerder hebben we een branch gemaakt van de commit A1 en enkele bestanden gewijzigd.
Dat merkte je natuurlijk achteraf A1 er waren nog twee commits, maar dit waren ook fusies van andere branches, omdat we niet committen meester. En nu is de tijd gekomen dat hotfix klaar. Daarom verscheen er een pull-verzoek voor de samenvoeging B3 и A3.
Natuurlijk zou het mogelijk zijn om het volledige resultaat van hun samenvoeging te controleren, maar dit zou te lang en onterecht zijn, aangezien er maar een paar bestanden zijn gewijzigd. Daarom is het efficiënter om alleen de gewijzigde te analyseren.
Om dit te doen, krijgen we het verschil tussen de takken, omdat we ons in de HEAD bevinden van de tak van waaruit we willen samenvoegen tot master:
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
$MERGE_BASE we zullen later in detail bekijken. Feit is dat niet elke CI-service de nodige informatie geeft over de basis voor de samenvoeging, dus elke keer moet je nieuwe manieren bedenken om aan deze gegevens te komen. Dit wordt hieronder beschreven in elk van de beschreven webservices.
Dus we hebben het verschil tussen de branches, of beter gezegd, de lijst met bestandsnamen die zijn gewijzigd. Nu moeten we het bestand geven .pvs-pr.lijst (we hebben de uitvoer hierboven ernaar omgeleid) naar de analysator:
pvs-studio-analyzer analyze -j8
-o PVS-Studio.log
-S .pvs-pr.list
Na analyse moeten we het logbestand (PVS-Studio.log) converteren naar een leesbaar formaat:
plog-converter -t errorfile PVS-Studio.log --cerr -w
Met deze opdracht worden de fouten weergegeven in
Alleen hier hoeven we niet alleen fouten weer te geven, maar ook onze service voor montage en testen te informeren over de aanwezigheid van problemen. Hiervoor is een vlag toegevoegd aan de converter -W (--indicatie-waarschuwingen). Als er ten minste één analysatorwaarschuwing is, de retourcode van het hulpprogramma plog-converter verandert in 2, wat op zijn beurt de CI-service op de hoogte stelt van mogelijke fouten in de pull-aanvraagbestanden.
Travis CI
De configuratie wordt gemaakt in de vorm van een bestand .travis.yml. Voor het gemak raad ik je aan om alles in een apart bash-script te zetten met functies die vanuit het bestand worden aangeroepen .travis.yml (bash scriptnaam.sh functienaam).
We zullen de benodigde code toevoegen aan het script op slaan, dus we krijgen meer functionaliteit. In sectie installeren laten we het volgende schrijven:
install:
- bash .travis.sh travis_install
Als u instructies had, kunt u deze naar het script verplaatsen door de koppeltekens te verwijderen.
Laten we het bestand openen .travis.sh en voeg de analysatorinstelling toe aan de functie 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
}
Laten we nu toevoegen aan de sectie script loop analyse:
script:
- bash .travis.sh travis_script
En in bash-script:
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
}
Deze code moet worden uitgevoerd nadat het project is gebouwd, bijvoorbeeld als u een CMake-build had:
travis_script() {
CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
cmake $CMAKE_ARGS CMakeLists.txt
make -j8
}
Het zal zo worden:
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
}
De gespecificeerde omgevingsvariabelen zijn u waarschijnlijk al opgevallen. $TRAVIS_PULL_REQUEST и $TRAVIS_BRANCH. Travis CI verklaart ze zelf:
- $TRAVIS_PULL_REQUEST slaat het pull-aanvraagnummer op, of valsals het een normale tak is;
- $TRAVIS_REPO_SLUG slaat de naam van de projectrepository op.
Het algoritme van deze functie:
Travis CI reageert op retourcodes, dus de aanwezigheid van waarschuwingen zal de service vertellen om de commit als buggy te markeren.
Laten we deze coderegel eens nader bekijken:
git diff --name-only origin/HEAD > .pvs-pr.list
Feit is dat Travis CI branches automatisch samenvoegt tijdens de analyse van een pull request:
Daarom analyseren we A4En niet B3->A3. Vanwege deze functie moeten we het verschil berekenen van A3, dat is gewoon de bovenkant van de tak van herkomst.
Er blijft één belangrijk detail over: het cachen van de afhankelijkheden van headerbestanden op gecompileerde vertaaleenheden (*.c, *.cc, *.cpp, enz.). De analysator berekent deze afhankelijkheden bij de eerste start in de modus van het controleren van de lijst met bestanden en slaat ze vervolgens op in de .PVS-Studio-directory. Met Travis CI kunt u mappen cachen, zodat we directorygegevens opslaan .PVS-Studio/:
cache:
directories:
- .PVS-Studio/
Deze code moet aan het bestand worden toegevoegd .travis.yml. In deze map worden verschillende gegevens opgeslagen die na analyse zijn verzameld, wat de volgende uitvoeringen van bestandslijstanalyse of incrementele analyse aanzienlijk zal versnellen. Gebeurt dit niet, dan zal de analysator eigenlijk elke keer alle bestanden analyseren.
Maat
Zoals Travis C.I.,
Allereerst moeten we een nieuwe actie toevoegen aan de bouwregel:
Geef de compiler op die is gebruikt om het project te bouwen. Let op de docker-container die in deze activiteit is geïnstalleerd. Zo is er een speciale container voor GCC:
Laten we nu PVS-Studio en de benodigde hulpprogramma's installeren:
Voeg de volgende regels toe aan de 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
Laten we nu naar het tabblad Uitvoeren gaan (het eerste pictogram) en de volgende code toevoegen aan het overeenkomstige editorveld:
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
Als je het gedeelte over Travs-CI hebt gelezen, dan is deze code je al bekend, maar nu is er een nieuwe stap:
Het feit is dat we nu niet het resultaat van de samenvoeging analyseren, maar de HEAD van de branch van waaruit het pull-verzoek is gedaan:
We zitten dus in een voorwaardelijke commit B3 en we moeten het verschil er uit halen 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
Om te bepalen A3 Laten we de GitHub API gebruiken:
https://api.github.com/repos/${USERNAME}/${REPO}/pulls/${PULL_REQUEST_ID}
We gebruikten de volgende variabelen van Buddy:
- $BUDDY_EXECUTION_PULL_REQEUST_NR - pull-aanvraagnummer;
- $BUDDY_REPO_SLUG - een combinatie van gebruikersnaam en repository (bijvoorbeeld max/test).
Laten we nu de wijzigingen opslaan met behulp van de onderstaande knop en pull-aanvraaganalyse inschakelen:
In tegenstelling tot Travis CI hoeven we niet te specificeren .pvs-studio voor caching, aangezien Buddy automatisch alle bestanden in de cache opslaat voor latere lanceringen. Daarom is het laatste wat overblijft het opslaan van de login en het wachtwoord voor PVS-Studio in Buddy. Nadat we de wijzigingen hebben opgeslagen, gaan we terug naar de pijplijn. We moeten naar het instellen van variabelen gaan en login en sleutel toevoegen voor PVS-Studio:
Daarna zal het verschijnen van een nieuw pull-verzoek of commit een controle activeren. Als een commit fouten bevat, zal Buddy dit aangeven op de pull request-pagina.
AppVeyor
Het instellen van AppVeyor is vergelijkbaar met Buddy, omdat alles in de webinterface gebeurt en het niet nodig is om een *.yml-bestand aan de projectrepository toe te voegen.
Laten we naar het tabblad Instellingen in het projectoverzicht gaan:
Laten we naar beneden scrollen op deze pagina en cacheopslag inschakelen voor het bouwen van pull-aanvragen:
Laten we nu naar het tabblad Omgeving gaan, waar we de te bouwen afbeelding en de benodigde omgevingsvariabelen specificeren:
Als je de voorgaande paragrafen hebt gelezen, ben je goed bekend met deze twee variabelen − PVS_KEY и PVS_USERNAME. Zo niet, laat me u er dan aan herinneren dat ze nodig zijn om de licentie van de PVS-Studio-analysator te controleren. In de toekomst zullen we ze weer tegenkomen in Bash-scripts.
Geef op dezelfde pagina hieronder de map voor caching op:
Als we dit niet doen, analyseren we het hele project in plaats van een paar bestanden, maar krijgen we de uitvoer op basis van de opgegeven bestanden. Daarom is het belangrijk om de juiste mapnaam in te voeren.
Nu is het tijd om het script te testen. Open het tabblad Tests en selecteer Script:
Plak de volgende code in dit formulier:
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
Laten we eens kijken naar het volgende deel van de code:
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
De nogal specifieke toewijzing van de waarde van het pwd-commando aan een variabele die deze standaardwaarde zou moeten opslaan, lijkt op het eerste gezicht vreemd, maar ik zal alles zo meteen uitleggen.
Tijdens het instellen van de analysator in AppVeyor kwam ik een buitengewoon vreemd gedrag van de analysator tegen. Aan de ene kant werkte alles correct, maar de analyse kwam niet op gang. Ik heb veel tijd besteed aan het opmerken dat we ons in de /home/appveyor/projects/testcalc/ directory bevinden, en de analysator weet zeker dat we ons in /opt/appveyor/build-agent/ bevinden. Toen besefte ik dat de variabele $PWD een beetje een leugen is. Om deze reden heb ik de waarde handmatig bijgewerkt voordat ik met de analyse begon.
En dan alles, zoals voorheen:
Beschouw nu het volgende 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"`
Daarin krijgen we het verschil tussen de takken waarop het pull-verzoek wordt gedeclareerd. Hiervoor hebben we de volgende omgevingsvariabelen nodig:
- $APPVEYOR_PULL_REQUEST_NUMBER - pull-aanvraagnummer;
- $APPVEYOR_REPO_NAME - gebruikersnaam en projectrepository.
Conclusie
Natuurlijk hebben we niet alle mogelijke continue integratieservices overwogen, maar ze hebben allemaal zeer vergelijkbare werkspecificaties. Met uitzondering van caching maakt elke dienst zijn eigen "fiets", dus alles is altijd anders.
Ergens, zoals in Travis-CI, werken een paar regels code en caching feilloos; ergens, zoals in AppVeyor, hoef je alleen maar de map in de instellingen op te geven; maar ergens moet je unieke sleutels maken en proberen het systeem te overtuigen om je de mogelijkheid te geven het in de cache opgeslagen fragment te overschrijven. Als je daarom een pull-aanvraaganalyse wilt opzetten op een continue integratieservice die hierboven niet is besproken, zorg er dan eerst voor dat je geen problemen krijgt met caching.
Bedankt voor uw aandacht. Als er iets niet lukt, schrijf ons dan gerust op
Als u dit artikel wilt delen met een Engelssprekend publiek, gebruik dan de vertaallink: Maxim Zvyagintsev.
Bron: www.habr.com