Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Nell'analizzatore PVS-Studio per i linguaggi C e C++ su Linux e macOS, a partire dalla versione 7.04, è stata introdotta la funzione di verifica dell'elenco dei file specificati. Con la nuova modalità, è possibile configurare l'analizzatore per controllare i commit e le pull request. In questo articolo, spiegheremo come impostare il controllo dell'elenco dei file modificati nel progetto GitHub in popolari sistemi CI (Continuous Integration) come Travis CI, Buddy e AppVeyor.

Modalità di controllo dell'elenco dei file

PVS-Studio è uno strumento per identificare errori e vulnerabilità potenziali nel codice sorgente di programmi scritti nei linguaggi C, C++, C# e Java. Funziona su sistemi a 64 bit su Windows, Linux e macOS.

Nella versione 7.04 di PVS-Studio per Linux e macOS è stata introdotta la modalità di controllo dell'elenco dei file sorgenti. Funziona per i progetti la cui sistema di build consente di generare un file compile_commands.json. Serve a permettere all'analizzatore di estrarre informazioni sulla compilazione dei file specificati. Se il tuo sistema di build non supporta la generazione del file compile_commands.json, puoi provare a generare tale file utilizzando l'utility Bear.

Il modo di controllo della lista dei file può essere utilizzato insieme al log di tracciamento degli avvii del compilatore strace (pvs-studio-analyzer trace). Per farlo, dovrai prima eseguire una build completa del progetto e tracciarla, affinché l'analizzatore raccolga tutte le informazioni sui parametri di compilazione di tutti i file controllati.

Tuttavia, questa opzione presenta un notevole svantaggio: sarà necessario eseguire una tracciatura completa della build dell'intero progetto ad ogni avvio, il che contraddice l'idea di un controllo rapido del commit. Oppure, se si memorizza nella cache il risultato stesso della tracciatura, le esecuzioni successive dell'analizzatore potrebbero risultare incomplete se la struttura delle dipendenze dei file sorgente cambia dopo la tracciatura (ad esempio, se in uno dei file sorgente viene aggiunto un nuovo #include).

Pertanto, non raccomandiamo di utilizzare il modo di controllo della lista dei file con il log di tracciamento per la verifica dei commit o delle pull request. Se puoi effettuare una build incrementale durante il controllo del commit, considera l'opzione di utilizzare il modo di analisi incrementale.

L'elenco dei file sorgente da analizzare viene salvato in un file di testo e passato all'analizzatore tramite il parametro -S:

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

In questo file vengono indicati i percorsi relativi o assoluti ai file, con ogni nuovo file su una nuova riga. È possibile specificare non solo i nomi dei file da analizzare, ma anche diverso testo. L'analizzatore vedrà che non si tratta di un file e ignorerà la riga. Questo può essere utile per commenti, nel caso in cui i file vengano specificati manualmente. Tuttavia, spesso l'elenco dei file sarà generato durante l'analisi nella CI, ad esempio, possono essere file da un commit o una pull request.

Ora, con questa modalità, è possibile controllare rapidamente il nuovo codice prima che venga integrato nel ramo principale di sviluppo. Perché il sistema di verifica reagisca alla presenza di avvisi dell'analizzatore, nella utility plog-converter è stato aggiunto il flag —indicate-warnings:

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

Con questo flag, il convertitore restituirà un codice non nullo se nel rapporto dell'analizzatore sono presenti avvisi. In base al codice di ritorno, è possibile bloccare l'hook pre-commit, il commit o la pull request e visualizzare, condividere o inviare via email il rapporto generato dall'analizzatore.

Nota. Al primo avvio dell'analisi, verrà analizzato l'intero progetto, poiché l'analizzatore deve generare un file di dipendenze dei file sorgente del progetto dai file header. Questa è una caratteristica dell'analisi dei file C e C++. In seguito, il file di dipendenze può essere memorizzato nella cache e sarà aggiornato automaticamente dall'analizzatore. Il vantaggio della verifica dei commit utilizzando la modalità di controllo dell'elenco dei file, rispetto all'uso della modalità di analisi incrementale, è che è necessario memorizzare nella cache solo questo file e non i file oggetto.

Principi generali dell'analisi della pull request

Analizzare l'intero progetto richiede molto tempo, quindi ha senso controllare solo una sua parte. Il problema è separare i nuovi file dagli altri file del progetto.

Consideriamo un esempio di albero dei commit con due rami:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio

Immaginiamo che il commit A1 contenga una quantità considerevole di codice che è già stato revisionato. Poco prima abbiamo creato un ramo dal commit A1 e modificato alcuni file.

Ovviamente avrete notato che dopo A1 ci sono stati altri due commit, ma sono stati anche fusioni di altri rami, dato che non stiamo effettuando commit in master. È giunto il momento in cui hotfix è pronto. Perciò è stato creato un pull request per unire B3 e A3.

Naturalmente, si potrebbe controllare l'intero risultato della fusione, ma richiederebbe troppo tempo e sarebbe ingiustificato, dato che sono stati modificati solo alcuni file. Pertanto, è più efficace analizzare solo quelli cambiati.

Per fare ciò, otteniamo la differenza tra i rami, trovandoci nel ramo HEAD da cui vogliamo unire nel master:

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

$MERGE_BASE lo esamineremo con attenzione più avanti. Sta di fatto che non tutti i servizi CI forniscono le informazioni necessarie sulla base per la fusione, quindi ogni volta è necessario inventare nuovi modi per ottenere questi dati. Questo sarà descritto in dettaglio di seguito in ciascuno dei servizi web descritti.

Quindi, abbiamo ottenuto la differenza tra i rami, ovvero un elenco dei nomi dei file che sono stati modificati. Adesso dobbiamo passare il file .pvs-pr.list (dove abbiamo reindirizzato l'output sopra) all'analizzatore:

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

Dopo l'analisi, dobbiamo convertire il file di log (PVS-Studio.log) in un formato più leggibile:

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

Questo comando genererà un elenco di errori in stderr (stream standard di output dei messaggi di errore).

Ma abbiamo bisogno non solo di visualizzare gli errori, ma anche di comunicare al nostro servizio di build e test la presenza di problemi. A tal fine, è stato aggiunto un flag al convertitore -W (—indicate-warnings). In caso di almeno un avviso dell'analizzatore, il codice di ritorno dell'utilità plog-converter cambierà in 2, il che, a sua volta, comunicherà al servizio CI la presenza di potenziali errori nei file della pull request.

Travis CI

La configurazione è realizzata sotto forma di file .travis.yml. Per comodità, consiglio di estrarre tutto in uno script bash separato con funzioni che verranno chiamate dal file .travis.yml (bash nome_script.sh nome_funzione).

Aggiungeremo il codice necessario allo script su bash, in questo modo otterremo una funzionalità maggiore. Nella sezione install scriveremo il seguente:

install:
  - bash .travis.sh travis_install

Se hai avuto istruzioni, puoi trasferirle nello script rimuovendo i trattini.

Apriremo il file .travis.sh e aggiungeremo l'installazione dell'analizzatore nella funzione 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 
}

Ora aggiungiamo alla sezione script lanciare l'analisi:

script:
  - bash .travis.sh travis_script

E nello script bash:

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
}

Questo codice deve essere eseguito dopo la costruzione del progetto, per esempio, se hai avuto una costruzione su CMake:

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

Risulterà così:

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
}

Probabilmente hai già notato le variabili d'ambiente indicate. $TRAVIS_PULL_REQUEST e $TRAVIS_BRANCH. Travis CI le autodichiara:

  • $TRAVIS_PULL_REQUEST memorizza il numero della pull request oppure false, se si tratta di un branch normale;
  • $TRAVIS_REPO_SLUG memorizza il nome del repository del progetto.

Il funzionamento di questa funzione è il seguente:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Travis CI reagisce ai codici di ritorno, quindi la presenza di avvisi indicherà al servizio di contrassegnare il commit come contenente errori.

Adesso consideriamo in dettaglio questa riga di codice:

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

Infatti, Travis CI esegue automaticamente il merge dei branch durante l'analisi della pull request:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Pertanto, analizziamo A4, e non B3->A3. A causa di questa particolarità dobbiamo calcolare la differenza con A3, che è proprio la cima del branch di origin.

C'è un'ultima importante questione: la memorizzazione nella cache delle dipendenze dei file di intestazione delle unità di traduzione compilate (*.c, *.cc, *.cpp, ecc.). Queste dipendenze sono calcolate dall'analizzatore al primo avvio in modalità verifica dell'elenco dei file e vengono poi salvate nella directory .PVS-Studio. Travis CI consente di memorizzare nella cache le cartelle, quindi salveremo i dati della directory. .PVS-Studio/:

cache:
  directories:
    - .PVS-Studio/

Questo codice deve essere aggiunto al file .travis.yml. Questa directory conserva i vari dati raccolti dopo l'analisi, che accelerano notevolmente le analisi successive dell'elenco dei file o dell'analisi incrementale. Se non lo si fa, l'analizzatore decoderà effettivamente ogni volta tutti i file.

Buddy

Come Travis CI, Buddy offre la possibilità di compilarli e testarli automaticamente per i progetti memorizzati su GitHub. A differenza di Travis CI, si configura tramite l'interfaccia web (c'è supporto per bash), quindi non è necessario mantenere file di configurazione nel progetto.

In primo luogo, dobbiamo aggiungere una nuova azione alla pipeline di build:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Indichiamo il compilatore utilizzato per costruire il progetto. Fate attenzione al contenitore docker installato in questa operazione. Ad esempio, per GCC esiste un contenitore specifico:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Ora installeremo PVS-Studio e le utilità necessarie:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Aggiungiamo nel nostro editor le seguenti righe:

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

Ora passiamo alla scheda Esegui (prima icona) e nell'apposito campo dell'editor aggiungiamo il seguente codice:

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

Se avete letto la sezione dedicata a Travs-CI, questo codice vi sarà già familiare, ma ora è emerso un nuovo stadio:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Il fatto è che ora analizziamo non il risultato della fusione, ma l'HEAD del ramo da cui viene effettuata la pull request:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Pertanto, siamo in un commit condizionale B3 e dobbiamo ottenere la differenza con 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

Per determinare A3 utilizzeremo l'API di GitHub:

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

Abbiamo utilizzato le seguenti variabili fornite da Buddy:

  • $BUDDY_EXECUTION_PULL_REQEUST_NO — numero della pull request;
  • $BUDDY_REPO_SLUG — combinazione del nome utente e del repository (ad esempio max/test).

Ora salveremo le modifiche utilizzando il pulsante qui sotto e attiveremo l'analisi della pull request:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
A differenza di Travis CI, non abbiamo bisogno di specificare .pvs-studio per la memorizzazione nella cache, poiché Buddy memorizza automaticamente tutti i file per le esecuzioni successive. Quindi resta solo l'ultimo — salvare il login e la password per PVS-Studio in Buddy. Dopo aver salvato le modifiche, torneremo nel Pipeline. Dobbiamo andare alla configurazione delle variabili e aggiungere il login e la chiave per PVS-Studio:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Dopo di ciò, la comparsa di una nuova pull request o di un commit attiverà il controllo. Se il commit contiene errori, Buddy lo segnalerà nella pagina della pull request.

AppVeyor

La configurazione di AppVeyor è simile a quella di Buddy, poiché avviene tutto tramite l'interfaccia web e non è necessario aggiungere un file *.yml nel repository del progetto.

Passiamo alla scheda Impostazioni nel riepilogo del progetto:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Scorriamo verso il basso in questa pagina e abilitiamo il salvataggio della cache per le build delle pull request:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Ora passiamo alla scheda Ambiente, dove specificheremo l'immagine per la build e le necessarie variabili d'ambiente:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Se hai letto le sezioni precedenti, dovresti essere già familiare con queste due variabili — PVS_KEY e PVS_USERNAME. Se non lo sei, ricorda che sono necessarie per la verifica della licenza dell'analizzatore PVS-Studio. In seguito le incontreremo di nuovo negli script Bash.

Nella stessa pagina, in fondo, specificheremo la cartella per la cache:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Se non lo faremo, analizzeremo anziché un paio di file l'intero progetto, ma l'output sarà relativo ai file specificati. Pertanto, è importante inserire il nome corretto della directory.

Ora è il momento dello script per il controllo. Apriamo la scheda Test e selezioniamo Script:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
In questo modulo devi incollare il seguente codice:

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

Guardiamo la seguente parte del codice:

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

L'assegnazione del valore del comando pwd a una variabile, che dovrebbe conservarne il valore per impostazione predefinita, sembra strana a prima vista, ma ora spiegherò tutto.

Durante la configurazione dell'analizzatore in AppVeyor, mi sono imbattuto in un comportamento estremamente strano dell'analizzatore. Da un lato, tutto funzionava correttamente, ma l'analisi non si avviava. Ho speso molto tempo a notare che ci trovavamo nella directory /home/appveyor/projects/testcalc/, mentre l'analizzatore era convinto che fossimo in /opt/appveyor/build-agent/. Allora ho capito che la variabile $PWD sta dicendo un po' di bugie. Per questo motivo, ho aggiornato manualmente il suo valore prima di avviare l'analisi.

E poi il tutto, come prima:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Ora consideriamo il seguente frammento:

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

In esso otteniamo la differenza tra i rami per cui è stato dichiarato il pull request. A tal fine, abbiamo bisogno delle seguenti variabili d'ambiente:

  • $APPVEYOR_PULL_REQUEST_NUMBER — numero del pull request;
  • $APPVEYOR_REPO_NAME — nome utente e repository del progetto.

Conclusione

Certamente, non abbiamo esaminato tutti i possibili servizi di integrazione continua, ma hanno tutte caratteristiche di funzionamento molto simili. A parte la cache, ogni servizio costruisce il proprio "veicolo", quindi ci sono sempre differenze.

In alcuni casi, come in Travis-CI, basta un paio di righe di codice e la cache funziona perfettamente; in altri, come in AppVeyor, è sufficiente indicare una cartella nelle impostazioni; ma in alcuni è necessario creare chiavi uniche e cercare di convincere il sistema a permetterti di sovrascrivere un frammento memorizzato. Pertanto, se desideri configurare l'analisi delle pull request in un servizio di integrazione continua non menzionato sopra, assicurati prima che non ci siano problemi con la cache.

Grazie per l'attenzione. Se hai bisogno di aiuto, non esitare a scriverci a assistenza. Ti daremo indicazioni e supporto.

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio

Se desideri condividere questo articolo con un pubblico anglofono, ti prego di utilizzare il link alla traduzione: Maxim Zvyagintsev. Analisi di commit e pull request in Travis CI, Buddy e AppVeyor usando PVS-Studio.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster