Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor utilizzando 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 possibilità di testare l'elenco dei file specificati. Con la nuova modalità è possibile configurare l'analizzatore per verificare i commit e le pull request. In questo articolo verrà spiegato 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 della lista dei file

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

Nella versione PVS-Studio 7.04 per Linux e macOS è stata introdotta la modalità di controllo dell'elenco dei file sorgente. Questo funziona per i progetti la cui sistema di build consente di generare il file compile_commands.json. È necessario affinché l'analizzatore estragga 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 usando l'utilità Bear.

Inoltre, la modalità di controllo dell'elenco dei file può essere utilizzata insieme al log di tracciamento strace delle esecuzioni del compilatore (pvs-studio-analyzer trace). Per questo dovrai prima effettuare una build completa del progetto e monitorarla, affinché l'analizzatore raccolga informazioni complete sui parametri di compilazione di tutti i file verificati.

Tuttavia, questa opzione presenta uno svantaggio significativo: sarà necessario effettuare una tracciatura completa della build dell'intero progetto ad ogni esecuzione, il che contraddice l'idea di una rapida verifica del commit. Oppure, se si memorizza il risultato della tracciatura, le successive esecuzioni dell'analizzatore potrebbero risultare incomplete se, dopo la tracciatura, cambia la struttura delle dipendenze dei file sorgenti (ad esempio, se a uno dei file sorgenti viene aggiunto un nuovo #include).

Pertanto, non consigliamo di utilizzare la modalità di controllo dell'elenco dei file con il log di tracciamento per la verifica dei commit o delle pull request. Qualora tu possa effettuare una build incrementale durante la verifica del commit, considera la possibilità di utilizzare la modalità 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, dove ogni nuovo file deve essere su una nuova riga. È possibile specificare non solo i nomi dei file da analizzare, ma anche testi vari. L'analizzatore vedrà che non è un file e ignorerà la riga. Questo può essere utile per commentare, se i file vengono specificati manualmente. Tuttavia, spesso l'elenco dei file verrà generato durante l'analisi in CI, ad esempio, potrebbero essere file da un commit o una pull request.

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

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

Con questo flag, il convertitore restituirà un codice non zero se nel report dell'analizzatore ci sono avvisi. In base al codice di ritorno, è possibile bloccare il pre-commit hook, il commit o la pull request, e visualizzare il report generato dall'analizzatore a schermo, condividerlo o inviarlo via email.

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

Principi generali dell'analisi delle pull request

L'analisi dell'intero progetto richiede un tempo considerevole, quindi ha senso controllare solo una parte di esso. Il problema è separare i nuovi file dagli altri file del progetto.

Consideriamo un esempio di albero di 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à stata verificata. Poco prima abbiamo creato un ramo dal commit A1 e modificato alcuni file.

Certamente hai notato che dopo A1 ci sono stati altri due commit, ma erano anche fusioni di altri rami, dato che non stiamo facendo commit in master. E ora è arrivato il momento in cui hotfix è pronto. Quindi è stata aperta una pull request per la fusione B3 e A3.

Naturalmente, si potrebbe controllare l'intero risultato della loro fusione, ma ci vorrebbe troppo tempo e sarebbe ingiustificato, poiché sono stati modificati solo pochi file. Pertanto, è più efficace analizzare solo quelli modificati.

Per questo motivo, otterremo la differenza tra i rami, rimanendo nel ramo HEAD da cui vogliamo unire in master:

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

$MERGE_BASE ne parleremo in dettaglio in seguito. Il fatto è che non tutti i servizi CI forniscono le informazioni necessarie sulla base per la fusione, quindi ogni volta dobbiamo 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, più precisamente — l'elenco dei nomi dei file che sono stati modificati. Ora dobbiamo fornire il file .pvs-pr.list (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ù comprensibile:

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

Questo comando mostrerà l'elenco degli errori in stderr (stream di output standard per i messaggi di errore).

Ma dobbiamo non solo visualizzare gli errori, ma anche 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 presenza di almeno un avviso dell'analizzatore, il codice di ritorno dell'utility plog-converter cambierà a 2, il che, a sua volta, informerà il servizio CI sulla presenza di potenziali errori nei file della pull request.

Travis CI

La configurazione è stata eseguita in formato 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 nello script in bash, in questo modo otterremo una maggiore funzionalità. Nella sezione install scriveremo quanto segue:

install:
  - bash .travis.sh travis_install

Se avete avuto istruzioni, potete trasferirle nello script, rimuovendo i trattini.

Apriamo il file .travis.sh e aggiungiamo 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 nella sezione script di avvio dell'analisi:

script:
  - bash .travis.sh travis_script

E nello script bash:

travis_script() {
  pvs-studio-analyzer credenziali $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 compilazione del progetto, ad esempio, se hai effettuato una compilazione con CMake:

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

Otterrai così:

travis_script() {
  CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
  cmake $CMAKE_ARGS CMakeLists.txt
  make -j8
  
  pvs-studio-analyzer credenziali $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 di ambiente indicate $TRAVIS_PULL_REQUEST e $TRAVIS_BRANCH. Travis CI le dichiara automaticamente:

  • $TRAVIS_PULL_REQUEST memorizza il numero della pull request o false, se si tratta di un ramo 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 farà sì che il servizio contrassegni il commit come contenente errori.

Ora esaminiamo più da vicino questa riga di codice:

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

Il fatto è che Travis CI esegue automaticamente il merge dei rami durante l'analisi della pull request:

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

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

cache:
  directories:
    - .PVS-Studio/

Questo codice deve essere aggiunto al file .travis.yml. Questa directory conserva vari dati raccolti dopo l'analisi, che accelereranno notevolmente le successive esecuzioni dell'analisi della lista di file o dell'analisi incrementale. Se non lo si fa, l'analizzatore analizzerà di fatto ogni volta tutti i file.

Buddy

Come Travis CI, Buddy fornisce la possibilità di costruire e testare automaticamente progetti archiviati su GitHub. A differenza di Travis CI, si configura tramite un'interfaccia web (esiste supporto per bash), quindi non è necessario conservare file di configurazione nel progetto.

Per prima cosa, dobbiamo aggiungere una nuova azione nella linea di costruzione:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Specifichiamo il compilatore utilizzato per costruire il progetto. Nota il contenitore docker che è impostato in questa azione. Ad esempio, per GCC esiste un contenitore speciale:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Ora installiamo PVS-Studio e gli strumenti necessari:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Aggiungiamo al 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 nel campo corrispondente 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 hai letto la sezione dedicata a Travs-CI, allora questo codice ti sarà già familiare, tuttavia, ora è emersa una nuova fase:

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

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Pertanto, ci troviamo 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 definire 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 del pull request;
  • $BUDDY_REPO_SLUG — combinazione del nome utente e del repository (ad esempio max/test).

Ora salviamo le modifiche utilizzando il pulsante qui sotto e attiviamo l'analisi del pull request:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
A differenza di Travis CI, non è necessario specificare .pvs-studio per la memorizzazione nella cache, poiché Buddy memorizza automaticamente nella cache tutti i file per i successivi avvii. Quindi resta solo l'ultimo passaggio: salvare il nome utente e la password per PVS-Studio in Buddy. Dopo aver salvato le modifiche, torneremo a Pipeline. Dobbiamo andare a configurare le variabili e aggiungere il nome utente e la chiave per PVS-Studio:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Dopo di che, l'apparizione di un nuovo pull request o commit avvierà il controllo. Se il commit contiene errori, Buddy lo indicherà nella pagina del pull request.

AppVeyor

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

Andiamo alla scheda Impostazioni nella panoramica del progetto:

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

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

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

Nella stessa pagina, in basso, specifichiamo la cartella per la memorizzazione della cache:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Se non lo faremo, analizzeremo invece di un paio di file l'intero progetto, ma il risultato verrà fornito solo per i file specificati. Quindi è 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 bisogna 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

Poniamo attenzione alla 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 della comando pwd a una variabile, che deve conservare questo valore per impostazione predefinita, può sembrare strana a prima vista, ma ora spiego tutto.

Durante la configurazione dell'analizzatore in AppVeyor, mi sono imbattuto in un comportamento piuttosto strano dell'analizzatore. Da un lato, tutto funzionava correttamente, ma l'analisi non partiva. Ho speso un bel po' di tempo a rendermi conto che ci trovavamo nella directory /home/appveyor/projects/testcalc/, mentre l'analizzatore era sicuro che fossimo in /opt/appveyor/build-agent/. Così ho capito che la variabile $PWD mente un po'. Per questo motivo, ho aggiornato manualmente il suo valore prima di avviare l'analisi.

E poi tutto come al solito:

Analisi dei commit e delle pull request in Travis CI, Buddy e AppVeyor con PVS-Studio
Ora esaminiamo 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 su cui è stata dichiarata la pull request. Per farlo, abbiamo bisogno delle seguenti variabili ambientali:

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

Conclusione

Certo, non abbiamo esaminato tutti i servizi di integrazione continua disponibili, ma tutti hanno caratteristiche operative molto simili. A parte la memorizzazione nella cache, ogni servizio costruisce il proprio "cavallo di battaglia", quindi tutto funziona in modo diverso.

In alcuni casi, come in Travis-CI, basta qualche riga di codice e la cache funziona in modo impeccabile; in altri, come in AppVeyor, è sufficiente specificare una cartella nelle impostazioni; ma in altri ancora è necessario creare chiavi uniche e cercare di convincere il sistema a fornirti la possibilità di sovrascrivere porzioni memorizzate nella cache. Pertanto, se desideri configurare l'analisi delle pull request su un servizio di integrazione continua non considerato sopra, assicurati innanzitutto che non ci siano problemi di caching.

Grazie per l'attenzione. Se hai difficoltà, non esitare a contattarci a supporto. Ti aiuteremo e supporteremo.

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 dei commit e delle pull request in Travis CI, Buddy e AppVeyor utilizzando 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