Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met behulp van PVS-Studio

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio
In de PVS-Studio-analyzer voor de talen C en C++ op Linux en macOS, sinds versie 7.04, is er een testfunctie toegevoegd om een lijst van opgegeven bestanden te controleren. Met de nieuwe modus kan de analyzer worden ingesteld om commits en pull requests te controleren. In dit artikel wordt uitgelegd hoe je de controle van de lijst met gewijzigde bestanden in een GitHub-project kunt instellen in populaire CI (Continuous Integration) systemen zoals Travis CI, Buddy en AppVeyor.

Bestandenlijst controlemodus

PVS-Studio is een tool voor het opsporen van fouten en potentiële kwetsbaarheden in de broncode van programma's geschreven in de talen C, C++, C# en Java. Het werkt op 64-bits systemen op Windows, Linux en macOS.

In PVS-Studio versie 7.04 voor Linux en macOS is de modus voor het controleren van de lijst met bronbestanden toegevoegd. Dit werkt voor projecten waarvan het bouwsysteem in staat is om een bestand te genereren compile_commands.json. Dit is nodig zodat de analyzer informatie kan extraheren over de compilatie van de opgegeven bestanden. Als je bouwsysteem het genereren van een compile_commands.json bestand niet ondersteunt, kun je proberen zo'n bestand te genereren met de tool Bear.

De bestandenlijst controlemodus kan ook samen met een strace trace-log van de compileruitvoeringen (pvs-studio-analyzer trace) worden gebruikt. Hiervoor moet je eerst een volledige build van het project uitvoeren en deze volgen, zodat de analyzer volledige informatie kan verzamelen over de compilatieparameters van alle gecontroleerde bestanden.

Echter, deze optie heeft een aanzienlijk nadeel: je moet ofwel een volledige trace van de build van het hele project maken bij elke uitvoering, wat in tegenspraak is met het idee van een snelle commitcontrole. Of, als je het resultaat van de trace opslaat, kunnen toekomstige uitvoeringen van de analyzer incompleet blijken te zijn als de structuur van de afhankelijkheden van de bronbestanden verandert (bijvoorbeeld als er een nieuwe #include aan een van de bronbestanden wordt toegevoegd).

Daarom raden we aan om de bestandenlijst controlemodus met een trace-log niet te gebruiken voor het controleren van commits of pull requests. Als je een incrementele build kunt maken bij het controleren van een commit, overweeg dan om de modus incrementele analyse.

De lijst met bronbestanden voor analyse wordt opgeslagen in een tekstbestand en aan de analyzer doorgegeven met de parameter -S:

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

In dit bestand worden relatieve of absolute paden naar bestanden opgegeven, waarbij elk nieuw bestand op een nieuwe regel moet staan. Het is toegestaan om niet alleen bestandsnamen voor analyse op te geven, maar ook verschillende teksten. De analyser zal zien dat dit geen bestand is en de regel negeren. Dit kan handig zijn voor opmerkingen, als bestanden handmatig worden opgegeven. Vaak zal de lijst met bestanden echter worden gegenereerd tijdens de analyse in CI, bijvoorbeeld dit kunnen bestanden zijn uit een commit of pull request.

Nu kan met deze modus snel nieuwe code worden gecontroleerd voordat deze in de hoofdontwikkelingsbranch terechtkomt. Om het controlesysteem te laten reageren op waarschuwingen van de analyser, is de tool plog-converter een vlag toegevoegd —indicate-warnings:

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

Met deze vlag zal de converter een niet-nul code teruggeven als er waarschuwingsmeldingen in het analyserapport aanwezig zijn. Op basis van de retourcode kan de pre-commit hook, commit of pull request worden geblokkeerd, en het gegenereerde analyserapport kan op het scherm worden weergegeven, gedeeld of per e-mail worden verstuurd.

Opmerking. Bij de eerste запуск van de analyse van de lijst met bestanden zal het hele project worden geanalyseerd, aangezien de analyser een afhankelijkheid van de bronbestanden van het project met de headerbestanden moet genereren. Dit is een kenmerk van de analyse van C- en C++-bestanden. Later kan het afhankelijkheidsbestand in cache worden opgeslagen en zal het automatisch door de analyser worden bijgewerkt. Het voordeel van het controleren van commits met behulp van de modus voor het controleren van de lijst met bestanden in plaats van de modus voor incrementele analyse is dat alleen dit bestand in cache hoeft te worden opgeslagen, en niet de objectbestanden.

Algemene principes voor de analyse van pull requests

De analyse van het hele project kost behoorlijk wat tijd, daarom is het zinvol om alleen een deel ervan te controleren. Het probleem is dat nieuwe bestanden van de rest van de projectbestanden moeten worden gescheiden.

Laten we een voorbeeld bekijken van een boom van commits met twee takken:

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio

Laten we ons voorstellen dat de commit A1 een aanzienlijk aantal code bevat dat al is gecontroleerd. Eerder hebben we een tak gemaakt van de commit A1 en zijn we enkele bestanden gaan wijzigen.

U heeft ongetwijfeld opgemerkt dat er na A1 nog twee commits zijn geweest, maar dit waren ook samenvaltungen van andere takken, aangezien we niet committen in master. En nu is het tijd gekomen dat hotfix klaar. Daarom is er een pull request voor samensmelting verschenen B3 en A3.

Natuurlijk zou je het hele resultaat van hun samensmelting kunnen controleren, maar dat zou te lang en onredelijk zijn, aangezien er maar een paar bestanden zijn gewijzigd. Het is daarom efficiënter om alleen de gewijzigde bestanden te analyseren.

Hiervoor krijgen we het verschil tussen de takken, terwijl we in de HEAD-tak staan waarvan we willen samensmelten naar master:

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

$MERGE_BASE we zullen dit later in detail bespreken. Het punt is dat niet elke CI-service de benodigde informatie over de basis voor samensmelting geeft, dus elke keer moeten we nieuwe manieren bedenken om deze gegevens te verkrijgen. Dit zal hieronder in detail worden beschreven in elk van de beschreven webservices.

Dus, we hebben het verschil tussen de takken verkregen, of beter gezegd, een lijst met bestandsnamen die zijn gewijzigd. Nu moeten we het bestand .pvs-pr.list (waar we de uitvoer hierboven naartoe hebben geleid) aan de analyser geven:

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

Na de analyse moeten we het logbestand (PVS-Studio.log) converteren naar een overzichtelijk formaat:

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

Deze opdracht zal de lijst met fouten in stderr (de standaard uitvoerstroom voor foutmeldingen) weergeven.

Maar we moeten niet alleen de fouten weergeven, maar ook ons bouw- en testservice informeren over eventuele problemen. Hiervoor is er een vlag toegevoegd aan de converter -W (—indicate-warnings). Bij aanwezigheid van zelfs maar één waarschuwing van de analyzer, verandert de exitcode van de tool plog-converter in 2, wat op zijn beurt de CI-service informeert over de aanwezigheid van potentiële fouten in de bestanden van de pull request.

Travis CI

De configuratie is uitgevoerd in de vorm van een bestand .travis.yml. Voor de duidelijkheid raad ik aan om alles in een aparte bash-script met functies te plaatsen, die vanuit het bestand zullen worden aangeroepen .travis.yml (bash naam_script.sh naam_functie).

We zullen de nodige code aan het script toevoegen in bash, zo krijgen we meer functionaliteit. In de sectie install schrijven we het volgende:

install:
  - bash .travis.sh travis_install

Als je instructies hebt, kun je die naar het script verplaatsen en de streepjes weghalen.

We openen het bestand .travis.sh en voegen de installatie van de analyzer 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 de sectie toevoegen script voor het starten van de analyse:

script:
  - bash .travis.sh travis_script

En in de 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 na het bouwen van het project worden uitgevoerd, bijvoorbeeld als je een build met CMake hebt gehad:

travis_script() {
  CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
  cmake $CMAKE_ARGS CMakeLists.txt
  make -j8
}

Het zal zo uitkomen:

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
}

Je hebt waarschijnlijk al opgemerkt dat de opgegeven omgevingsvariabelen zijn: $TRAVIS_PULL_REQUEST en $TRAVIS_BRANCH. Travis CI declareert ze automatisch:

  • $TRAVIS_PULL_REQUEST bevat het nummer van de pull request of false, als het een normale branch is;
  • $TRAVIS_REPO_SLUG bevat de naam van de projectrepository.

Het werkingsschema van deze functie:

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio
Travis CI reageert op retourcodes, dus de aanwezigheid van waarschuwingen zal de service aangeven het commit als zijnde met fouten te markeren.

Laten we nu deze regel code in detail bekijken:

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

Het punt is dat Travis CI automatisch branches samenvoegt tijdens de analyse van een pull request:

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio
Daarom analyseren we A4, en niet B3->A3. Vanwege deze eigenschap moeten we het verschil berekenen met A3, wat precies de top van de branch is vanuit oorsprong.

Er is nog één belangrijk detail — het cachen van afhankelijkheden van de headerbestanden van de gecompileerde eenheden (*.c, *.cc, *.cpp, enz.). Deze afhankelijkheden worden door de analyzer berekend bij de eerste uitvoering in de controlemodus van de bestandenlijst en vervolgens opgeslagen in de directory .PVS-Studio. Travis CI staat het cachen van mappen toe, dus we zullen de gegevens van de directory opslaan .PVS-Studio/:

cache:
  directories:
    - .PVS-Studio/

Deze code moet aan het bestand worden toegevoegd .travis.yml. Deze directory bevat verschillende gegevens die zijn verzameld na analyse, die de volgende analyses van het bestand of incrementele analyses aanzienlijk versnellen. Als u dit niet doet, zal de analyzer elke keer alle bestanden analyseren.

Buddy

Net als Travis CI, Buddy biedt het de mogelijkheid voor geautomatiseerde builds en tests van projecten die op GitHub zijn opgeslagen. In tegenstelling tot Travis CI, wordt het ingesteld via een webinterface (bash-ondersteuning is beschikbaar), waardoor er geen behoefte is om configuratiebestanden in het project op te slaan.

Allereerst moeten we een nieuwe actie aan de buildlijn toevoegen:

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio
We geven de compiler op die is gebruikt om het project te bouwen. Let op de docker-container die in deze actie is ingesteld. Voor GCC is er bijvoorbeeld een speciale container:

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio
Laten we nu PVS-Studio en de benodigde tools installeren:

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio
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 (de eerste pictogram) en in het bijbehorende veld van de editor de volgende code toevoegen:

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 fase:

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio
Het punt is dat we nu niet het resultaat van de merge analyseren, maar de HEAD van de tak waarvan de pull request wordt gemaakt:

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio
Daarom bevinden we ons in een hypothetische commit B3 en moeten we het verschil krijgen met 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

Voor de identificatie A3 maken we gebruik van de GitHub API:

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

We hebben de volgende variabelen gebruikt die Buddy biedt:

  • $BUDDY_EXECUTION_PULL_REQEUST_NO — het nummer van de pull request;
  • $BUDDY_REPO_SLUG — de combinatie van gebruikersnaam en repository (bijvoorbeeld max/test).

Laten we de wijzigingen opslaan met de knop hieronder en de analyse van de pull request inschakelen:

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio
In tegenstelling tot Travis CI hoeven we niet aan te geven .pvs-studio voor caching, omdat Buddy automatisch alle bestanden cachet voor toekomstige runs. Dus de laatste stap is om de gebruikersnaam en het wachtwoord voor PVS-Studio in Buddy op te slaan. Na het opslaan van de wijzigingen komen we weer terug in de Pipeline. We moeten naar de instellingen van de variabelen gaan en de gebruikersnaam en sleutel voor PVS-Studio toevoegen:

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio
Daarna zal het verschijnen van een nieuwe pull request of commit de controle activeren. Als de commit fouten bevat, zal Buddy dat aangeven op de pagina van de pull request.

AppVeyor

De configuratie van AppVeyor lijkt op die van Buddy, omdat alles in de webinterface gebeurt en er geen behoefte is om een *.yml bestand aan de projectrepository toe te voegen.

Laten we naar het tabblad Instellingen in het projectoverzicht gaan:

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio
Scroll naar beneden op deze pagina en schakel het opslaan van de cache voor het bouwen van pull requests in:

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio
Laten we nu naar het tabblad Omgeving gaan, waar we het image voor de build en de benodigde omgevingsvariabelen opgeven:

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio
Als je de vorige secties hebt gelezen, ben je goed bekend met deze twee variabelen — PVS_KEY en PVS_USERNAME. Als je dat niet bent, laat me je eraan herinneren dat ze nodig zijn voor de licentiecontrole van de PVS-Studio-analyzer. We zullen ze later opnieuw tegenkomen in de Bash-scripts.

Op dezelfde pagina onderaan geven we de map voor caching op:

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio
Als we dit niet doen, zullen we in plaats van een paar bestanden het hele project analyseren, maar de output krijgen voor de opgegeven bestanden. Daarom is het belangrijk om de juiste naam van de map in te voeren.

Nu is het tijd voor het script voor de controle. Laten we het tabblad Tests openen en Script kiezen:

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio
In dit formulier moet de volgende code worden ingevoegd:

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 aandacht besteden aan 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

Het lijkt in eerste instantie vreemd om de waarde van het commando pwd aan een variabele toe te wijzen, die deze waarde standaard zou moeten opslaan, maar ik zal het nu uitleggen.

Tijdens de configuratie van de analyzer in AppVeyor kwam ik een uiterst vreemd gedrag van de analyzer tegen. Enerzijds werkte alles correct, maar de analyse startte niet. Ik heb veel tijd besteed om te realiseren dat we ons in de directory /home/appveyor/projects/testcalc/ bevonden, terwijl de analyzer dacht dat we in /opt/appveyor/build-agent/ waren. Toen realiseerde ik me dat de variabele $PWD een beetje loog. Daarom heb ik de waarde handmatig bijgewerkt voordat ik de analyse startte.

En verder is alles zoals eerder:

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio
Laten we nu de volgende fragment bekijken:

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"`

Hierin krijgen we het verschil tussen de branches waar een pull request op is ingediend. Hiervoor hebben we de volgende omgevingsvariabelen nodig:

  • $APPVEYOR_PULL_REQUEST_NUMBER — het nummer van de pull request;
  • $APPVEYOR_REPO_NAME — de gebruikersnaam en de naam van de projectrepository.

Conclusie

Natuurlijk hebben we niet alle mogelijke continue integratieservices behandeld, maar ze hebben allemaal een zeer vergelijkbare werking. Met uitzondering van caching, elke service maakt zijn 'fiets', dus het is altijd anders.

Sommige, zoals Travis-CI, functioneren met een paar regels code en caching werkt perfect; andere, zoals AppVeyor, vereisen gewoon dat je een map in de instellingen opgeeft; en weer andere vereisen unieke sleutels en proberen het systeem te overtuigen je de mogelijkheid te geven om het gecachte fragment te overschrijven. Daarom, als je pull request-analyse wilt opzetten op een continue integratieservice die hierboven niet is besproken, zorg er dan eerst voor dat caching geen problemen voor je oplevert.

Bedankt voor je aandacht. Als er iets niet lukt, aarzel dan niet om ons te schrijven in de ondersteuning. We helpen en ondersteunen je.

Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met PVS-Studio

Als u dit artikel met een Engelstalig publiek wilt delen, gebruik dan alstublieft de link naar de vertaling: Maxim Zvyagintsev. Analyse van commits en pull requests in Travis CI, Buddy en AppVeyor met behulp van PVS-Studio.

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers 🔥 Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster