Analyse des commits et des pull requests dans Travis CI, Buddy et AppVeyor avec PVS-Studio

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Dans l'analyseur PVS-Studio pour les langages C et C++ sur Linux et macOS, à partir de la version 7.04, une nouvelle fonctionnalité a été ajoutée pour vérifier la liste des fichiers spécifiés. Avec ce nouveau mode, vous pouvez configurer l'analyseur pour vérifier les commits et les pull requests. Cet article explique comment configurer la vérification de la liste des fichiers modifiés d'un projet GitHub dans des systèmes CI (Intégration Continue) populaires tels que Travis CI, Buddy et AppVeyor.

Mode de vérification de liste de fichiers

PVS-Studio est un outil visant à détecter les erreurs et les vulnérabilités potentielles dans le code source de programmes écrits en C, C++, C# et Java. Il fonctionne sur des systèmes 64 bits sous Windows, Linux et macOS.

Dans la version PVS-Studio 7.04 pour Linux et macOS, un mode de vérification de la liste des fichiers sources a été introduit. Cela fonctionne pour les projets dont le système de construction permet de générer un fichier compile_commands.json. Il est nécessaire afin que l'analyseur puisse extraire des informations sur la compilation des fichiers spécifiés. Si votre système de construction ne prend pas en charge la génération du fichier compile_commands.json, vous pouvez essayer de générer ce fichier à l'aide de l'utilitaire Bear.

Ce mode de vérification de la liste des fichiers peut également être utilisé avec le journal de traçage strace lors des lancements du compilateur (pvs-studio-analyzer trace). Pour cela, vous devrez d'abord effectuer une construction complète du projet et la suivre afin que l'analyseur puisse collecter toutes les informations sur les paramètres de compilation de tous les fichiers analysés.

Cependant, cette option présente un inconvénient majeur : il faut soit effectuer une traçage complet de la construction de tout le projet à chaque exécution, ce qui contredit en soi l'idée d'une vérification rapide du commit, soit, si l'on met en cache le résultat de la traçage, les exécutions suivantes de l'analyseur peuvent être incomplètes si, après la traçage, la structure des dépendances des fichiers sources change (par exemple, si un nouveau #include est ajouté à l'un des fichiers sources).

C'est pourquoi nous ne recommandons pas d'utiliser le mode de vérification de la liste des fichiers avec le journal de traçage pour vérifier les commits ou les pull requests. Si vous pouvez effectuer une construction incrémentale lors de la vérification d'un commit, envisagez d'utiliser le mode d'analyse incrémentale.

La liste des fichiers sources à analyser est enregistrée dans un fichier texte et transmise à l'analyseur à l'aide du paramètre -S:

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

Ce fichier indique les chemins relatifs ou absolus vers des fichiers, chaque nouveau fichier devant être sur une nouvelle ligne. Il est permis d’indiquer non seulement des noms de fichiers à analyser, mais aussi divers textes. L'analyseur verra que ce n'est pas un fichier et ignorera la ligne. Cela peut être utile pour commenter si les fichiers sont fournis manuellement. Cependant, dans de nombreux cas, la liste des fichiers sera générée lors de l'analyse dans CI, par exemple, il peut s'agir des fichiers d'un commit ou d'une pull request.

Désormais, avec ce mode, vous pouvez vérifier rapidement le nouveau code avant qu'il n'atteigne la branche principale de développement. Afin que le système de vérification réagisse à la présence d'avertissements de l'analyseur, dans l'outil plog-converter un drapeau a été ajouté —indicate-warnings:

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

Avec ce drapeau, le convertisseur renverra un code non nul si des avertissements sont présents dans le rapport de l'analyseur. Par le code de retour, vous pouvez bloquer le hook de pré-commit, le commit ou la pull request, et le rapport généré par l'analyseur peut être affiché à l'écran, partagé ou envoyé par e-mail.

Remarque. Lors de la première exécution de l'analyse de la liste des fichiers, l'ensemble du projet sera analysé, car l'analyseur doit générer le fichier de dépendances des fichiers sources du projet par rapport aux fichiers d'en-tête. C'est une particularité de l'analyse des fichiers C et C++. Par la suite, le fichier de dépendances peut être mis en cache et il sera mis à jour automatiquement par l'analyseur. L'avantage de la vérification des commits en utilisant le mode de vérification de la liste des fichiers par rapport à l'utilisation du mode d'analyse incrémentale est qu'il suffit de mettre en cache ce fichier, et non les fichiers objets.

Principes généraux de l'analyse des pull requests

L'analyse de l'ensemble du projet prend beaucoup de temps, il est donc judicieux de ne vérifier qu'une partie de celui-ci. Le problème est qu'il faut séparer les nouveaux fichiers des autres fichiers du projet.

Considérons un exemple d'arbre de commits avec deux branches :

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio

Imaginons que le commit A1 contient une quantité suffisante de code qui a déjà été vérifiée. Un peu plus tôt, nous avons créé une branche à partir du commit A1 et avons modifié certains fichiers.

Vous avez probablement remarqué qu'après A1 il y a eu encore deux commits, mais ce n'étaient que des fusions d'autres branches, car nous ne commettons pas dans master. Et voilà, il est venu le moment où hotfix prête. C'est pourquoi une demande de fusion a été créée B3 et A3.

Il aurait évidemment été possible de vérifier l'ensemble du résultat de leur fusion, mais cela aurait été trop long et injustifié, car seuls quelques fichiers ont été modifiés. Il est donc plus efficace d'analyser uniquement les fichiers modifiés.

Pour cela, nous allons récupérer la différence entre les branches, en étant sur la branche HEAD, depuis laquelle nous souhaitons fusionner dans master :

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

$MERGE_BASE nous y reviendrons en détail plus tard. En effet, tous les services CI ne fournissent pas les informations nécessaires concernant la base de la fusion, donc chaque fois, il faut trouver de nouvelles manières d'obtenir ces données. Cela sera expliqué plus en détail ci-dessous dans chacun des services web décrits.

Ainsi, nous avons obtenu la différence entre les branches, plus précisément — la liste des noms de fichiers qui ont été modifiés. Maintenant, nous devons transmettre ce fichier .pvs-pr.list (vers lequel nous avons redirigé la sortie précédemment) à l'analyseur :

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

Après analyse, nous devons convertir le fichier journal (PVS-Studio.log) dans un format plus compréhensible :

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

Cette commande affichera la liste des erreurs dans stderr (flux de sortie standard des messages d'erreur).

Cependant, nous avons besoin non seulement d'afficher les erreurs, mais aussi d'informer notre service de construction et de test de la présence de problèmes. Pour cela, un drapeau a été ajouté au convertisseur -W (—indicate-warnings). En cas de présence d'un avertissement de l'analyseur, le code de retour de l'utilitaire plog-converter changera à 2, ce qui, à son tour, signalera au service CI la présence d'erreurs potentielles dans les fichiers de la demande de tirage.

Travis CI

La configuration est effectuée sous forme de fichier .travis.yml. Pour plus de commodité, je recommande de tout transférer dans un script bash séparé avec des fonctions, qui seront appelées depuis le fichier .travis.yml (bash nom_du_script.sh nom_de_fonction).

Nous allons ajouter le code nécessaire dans le script en bash, ce qui nous donnera plus de fonctionnalités. Dans la section install nous écrirons ce qui suit :

install:
  - bash .travis.sh travis_install

Si vous aviez des instructions, vous pouvez les transférer dans le script en retirant les tirets.

Ouvrons le fichier .travis.sh et ajoutons l'installation de l'analyseur dans la fonction 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 
}

Maintenant, ajoutons à la section script le lancement de l'analyse :

script:
  - bash .travis.sh travis_script

Et dans le 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
}

Ce code doit être exécuté après la construction du projet, par exemple, si vous avez utilisé CMake :

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

Cela donnera :

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
}

Vous avez probablement déjà remarqué les variables d'environnement indiquées $TRAVIS_PULL_REQUEST et $TRAVIS_BRANCH. Travis CI les déclare automatiquement :

  • $TRAVIS_PULL_REQUEST il contient le numéro de la pull request ou faux, s'il s'agit d'une branche ordinaire ;
  • $TRAVIS_REPO_SLUG il contient le nom du dépôt du projet.

L'algorithme de cette fonction :

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Travis CI réagit aux codes de retour, donc la présence d'avertissements indiquera au service de marquer le commit comme contenant des erreurs.

Examinons maintenant cette ligne de code de plus près :

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

Le fait est que Travis CI fusionne automatiquement les branches lors de l'analyse des pull requests :

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
C'est pourquoi nous analysons A4, pas B3->A3. En raison de cette particularité, nous devons calculer la différence avec A3, qui est justement le sommet de la branche à partir de origin..

Il reste un détail important — le cache des dépendances des fichiers d'en-tête des unités de compilation (*.c, *.cc, *.cpp, etc.). Ces dépendances sont calculées par l'analiseur lors de la première exécution en mode vérification de la liste des fichiers et sont ensuite enregistrées dans le répertoire .PVS-Studio. Travis CI permet de mettre en cache des dossiers, donc nous allons conserver les données du répertoire .PVS-Studio/:

cache:
  directories:
    - .PVS-Studio/

Ce code doit être ajouté dans le fichier .travis.yml. Ce répertoire contient diverses données collectées après l'analyse, ce qui accélérera considérablement les analyses ultérieures de la liste des fichiers ou des analyses incrémentielles. Si cela n'est pas fait, l'analyseur analysera en fait tous les fichiers à chaque fois.

Buddy

Tout comme Travis CI, Buddy offre la possibilité d'automatiser la construction et les tests des projets stockés sur GitHub. Contrairement à Travis CI, il est configuré via une interface web (le support bash est disponible), il n'est donc pas nécessaire de conserver des fichiers de configuration dans le projet.

Nous devons d'abord ajouter une nouvelle action à la chaîne de construction :

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Indiquons le compilateur utilisé pour construire le projet. Notez le conteneur Docker qui est défini dans cette action. Par exemple, pour GCC, il existe un conteneur spécifique :

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Installez maintenant PVS-Studio et les utilitaires nécessaires :

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Ajoutez les lignes suivantes dans l'éditeur :

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

Maintenant, allons dans l'onglet Run (première icône) et ajoutons le code suivant dans le champ approprié de l'éditeur :

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

Si vous avez lu la section concernant Travs-CI, ce code vous est déjà familier, cependant, une nouvelle étape est maintenant introduite :

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
En effet, nous n'analysons plus le résultat de la fusion, mais HEAD de la branche à partir de laquelle le pull request est fait :

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Nous sommes donc dans un commit conditionnel B3 et nous devons obtenir la différence avec 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

Pour déterminer A3 nous utiliserons l'API GitHub :

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

Nous avons utilisé les variables suivantes fournies par Buddy :

  • $BUDDY_EXECUTION_PULL_REQEUST_NO — le numéro du pull request ;
  • $BUDDY_REPO_SLUG — la combinaison du nom d'utilisateur et du dépôt (par exemple max/test).

Nous allons maintenant enregistrer les modifications en utilisant le bouton ci-dessous et activer l'analyse du pull request :

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Contrairement à Travis CI, nous n'avons pas besoin de spécifier .pvs-studio pour le cache, car Buddy met automatiquement en cache tous les fichiers pour les exécutions suivantes. Il ne reste plus qu'à enregistrer le nom d'utilisateur et le mot de passe pour PVS-Studio dans Buddy. Après avoir enregistré les modifications, nous reviendrons au Pipeline. Nous devons passer à la configuration des variables et ajouter le nom d'utilisateur et la clé pour PVS-Studio :

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Après cela, la création d'un nouveau pull request ou d'un commit déclenchera l'analyse. Si le commit contient des erreurs, Buddy les signalera sur la page du pull request.

AppVeyor

La configuration d'AppVeyor est similaire à celle de Buddy, car tout se fait dans l'interface web et il n'est pas nécessaire d'ajouter un fichier *.yml dans le dépôt du projet.

Accédons à l'onglet Paramètres dans l'aperçu du projet :

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Faisons défiler cette page vers le bas et activons la sauvegarde du cache pour la construction des pull requests :

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Maintenant, passons à l'onglet Environnement, où nous spécifierons l'image de construction et les variables d'environnement nécessaires :

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Si vous avez lu les sections précédentes, vous êtes bien familiarisé avec ces deux variables — PVS_KEY et PVS_USERNAME. Si ce n'est pas le cas, rappelez-vous qu'elles sont nécessaires pour vérifier la licence de l'analyseur PVS-Studio. Nous les rencontrerons à nouveau dans les scripts Bash.

Sur cette même page, en bas, indiquons le dossier pour le cache :

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Si nous ne le faisons pas, nous analyserons l'ensemble du projet au lieu de quelques fichiers, mais les résultats seront obtenus pour les fichiers indiqués. Il est donc important d'entrer le bon nom de répertoire.

Il est maintenant temps de créer le script de vérification. Ouvrons l'onglet Tests et sélectionnons Script :

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Vous devez insérer le code suivant dans ce formulaire :

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

Prenons note de la prochaine partie du 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

Bien que l'attribution d'une valeur de la commande pwd à une variable qui devrait contenir cette valeur par défaut semble étrange au premier abord, je vais tout expliquer.

Lors de la configuration de l'analyseur dans AppVeyor, j'ai rencontré un comportement très étrange de cet analyseur. D'un côté, tout fonctionnait bien, mais l'analyse ne se lançait pas. J'ai passé un certain temps à comprendre que nous étions dans le répertoire /home/appveyor/projects/testcalc/, tandis que l'analyseur était convaincu que nous étions dans /opt/appveyor/build-agent/. J'ai alors réalisé que la variable $PWD mentait légèrement. C'est pourquoi je l'ai mise à jour manuellement avant de lancer l'analyse.

Et ensuite, tout se passe comme avant :

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Examinons maintenant le fragment suivant :

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

Ici, nous obtenons la différence entre les branches sur lesquelles une pull request a été déclarée. Pour cela, nous avons besoin des variables d'environnement suivantes :

  • $APPVEYOR_PULL_REQUEST_NUMBER — le numéro de la pull request ;
  • $APPVEYOR_REPO_NAME — le nom d'utilisateur et le dépôt du projet.

Conclusion

Bien sûr, nous n'avons pas exploré tous les services d'intégration continue possibles, mais tous ont une spécificité de fonctionnement assez similaire. À l'exception du cache, chaque service crée son propre « vélo », c'est pourquoi tout fonctionne différemment.

Parfois, comme dans Travis-CI, quelques lignes de code suffisent et le cache fonctionne à merveille ; d'autres fois, comme dans AppVeyor, il suffit de spécifier le dossier dans les paramètres ; mais parfois, il faut créer des clés uniques et essayer de convaincre le système de te permettre de réécrire un fragment mis en cache. Donc, si tu veux configurer l'analyse des pull requests dans un service d'intégration continue qui n'a pas été abordé ci-dessus, assure-toi d'abord que tu ne rencontreras pas de problèmes avec le cache.

Merci de votre attention. Si quelque chose ne fonctionne pas, n'hésite pas à nous écrire à le support. Nous te conseillerons et t'aiderons.

Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio

Si vous souhaitez partager cet article avec un public anglophone, merci d'utiliser le lien vers la traduction : Maxim Zvyagintsev. Analyse des commits et des demandes de tirage dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio.

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster