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

Analyse des commits et des pull request dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Dans l'analyseur PVS-Studio pour les langages C et C++ sous Linux et macOS, à partir de la version 7.04, une option de test est apparue pour vérifier la liste des fichiers spécifiés. En utilisant le nouveau mode, vous pouvez configurer l'analyseur pour vérifier les validations et les demandes d'extraction. Cet article vous expliquera comment configurer la vérification de la liste des fichiers modifiés d'un projet GitHub dans des systèmes CI (intégration continue) aussi populaires que Travis CI, Buddy et AppVeyor.

Mode de vérification de la liste de fichiers

PVS-Studio est un outil permettant d'identifier les erreurs et les vulnérabilités potentielles dans le code source des programmes écrits en C, C++, C# et Java. Fonctionne sur les 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 est apparu. Cela fonctionne pour les projets dont le système de build vous permet de générer un fichier compile_commands.json. Il est nécessaire que l'analyseur extraie des informations sur la compilation des fichiers spécifiés. Si votre système de build ne prend pas en charge la génération du fichier compile_commands.json, vous pouvez essayer de générer un tel fichier à l'aide de l'utilitaire Gardez.

En outre, le mode de vérification de la liste de fichiers peut être utilisé avec le journal de trace strace des lancements du compilateur (trace pvs-studio-analyzer). Pour ce faire, vous devrez d'abord effectuer une construction complète du projet et le suivre afin que l'analyseur collecte des informations complètes sur les paramètres de compilation de tous les fichiers en cours de vérification.

Cependant, cette option présente un inconvénient important : soit vous devrez effectuer une trace de construction complète de l'ensemble du projet à chaque fois que vous l'exécutez, ce qui en soi contredit l'idée de vérifier rapidement un commit. Ou, si vous mettez en cache le résultat de la trace lui-même, les exécutions ultérieures de l'analyseur peuvent être incomplètes si la structure de dépendance des fichiers source change après la trace (par exemple, un nouveau #include est ajouté à l'un des fichiers source).

Par conséquent, nous ne recommandons pas d'utiliser le mode de vérification de la liste de fichiers avec le journal de trace pour vérifier les validations ou les demandes d'extraction. Si vous pouvez effectuer une construction incrémentielle lors de la vérification d'un commit, envisagez d'utiliser le mode 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 spécifie les chemins relatifs ou absolus vers les fichiers, et chaque nouveau fichier doit se trouver sur une nouvelle ligne. Il est acceptable de spécifier non seulement les noms de fichiers à analyser, mais également divers textes. L'analyseur verra qu'il ne s'agit pas d'un fichier et ignorera la ligne. Cela peut être utile pour commenter si les fichiers sont spécifiés manuellement. Cependant, une liste de fichiers est souvent générée lors de l'analyse dans CI, par exemple, il peut s'agir de fichiers issus d'une validation ou d'une pull request.

Désormais, en utilisant ce mode, vous pouvez vérifier rapidement le nouveau code avant qu'il n'entre dans la branche de développement principale. Pour garantir que le système d'analyse répond aux avertissements de l'analyseur, l'utilitaire plog-convertisseur drapeau ajouté --indiquer les avertissements:

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

Avec cet indicateur, le convertisseur renverra un code différent de zéro s'il y a des avertissements dans le rapport de l'analyseur. À l'aide du code retour, vous pouvez bloquer un hook de pré-validation, une validation ou une demande d'extraction, et le rapport de l'analyseur généré peut être affiché, partagé ou envoyé par e-mail.

Note. Lorsque vous commencez à analyser une liste de fichiers, l'ensemble du projet sera analysé, car l'analyseur doit générer un fichier de dépendances des fichiers sources du projet sur les fichiers d'en-tête. Il s'agit d'une fonctionnalité d'analyse des fichiers C et C++. À l'avenir, le fichier de dépendances pourra être mis en cache et il sera automatiquement mis à jour par l'analyseur. L'avantage de la vérification des validations lors de l'utilisation du mode de vérification de la liste de fichiers par rapport au mode d'analyse incrémentielle est que vous devez uniquement mettre en cache ce fichier et non les fichiers objets.

Principes généraux de l’analyse des pull request

L'analyse de l'ensemble du projet prend beaucoup de temps, il est donc logique d'en vérifier seulement une certaine partie. Le problème est que vous devez séparer les nouveaux fichiers du reste des fichiers du projet.

Regardons un exemple d'arbre de validation avec deux branches :

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

Imaginons ce commit A1 contient une assez grande quantité de code déjà testé. Un peu plus tôt nous avons fait une branche à partir du commit A1 et modifié certains fichiers.

Bien sûr, vous avez remarqué qu'après A1 deux autres commits ont eu lieu, mais il s'agissait également de fusions d'autres branches, car nous ne nous engageons pas à maître. Et maintenant le moment est venu où correctif prêt. C'est pourquoi une pull request pour la fusion est apparue B3 и A3.

Bien sûr, il serait possible de vérifier l'intégralité du résultat de leur fusion, mais cela prendrait trop de temps et serait injustifié, puisque seuls quelques dossiers ont été modifiés. Par conséquent, il est plus efficace d’analyser uniquement ceux qui ont été modifiés.

Pour ce faire, on obtient la différence entre les branches, en étant dans le HEAD de la branche à partir de laquelle on veut fusionner en master :

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

$MERGE_BASE nous l'examinerons en détail plus tard. Le fait est que tous les services CI ne fournissent pas les informations nécessaires sur la base de données pour la fusion, vous devez donc à chaque fois trouver de nouvelles façons d'obtenir ces données. Ceci sera décrit en détail ci-dessous dans chacun des services Web décrits.

Nous avons donc obtenu la différence entre les branches, ou plus précisément, une liste de noms de fichiers qui ont été modifiés. Maintenant, nous devons donner le fichier .pvs-pr.list (nous avons redirigé la sortie ci-dessus vers celui-ci) vers 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 facile à lire :

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

Cette commande listera les erreurs dans stderr (sortie de message d'erreur standard).

Ce n'est que maintenant que nous devons non seulement afficher les erreurs, mais également informer notre service de montage et de test de la présence de problèmes. A cet effet, un drapeau a été ajouté au convertisseur -W (--indiquer les avertissements). S'il y a au moins un avertissement de l'analyseur, le code retour de l'utilitaire plog-convertisseur passera à 2, ce qui à son tour informera le service CI de la présence d'erreurs potentielles dans les fichiers de demande d'extraction.

Travis CI

La configuration se fait sous forme de fichier .travis.yml. Pour plus de commodité, je vous conseille de tout mettre dans un script bash séparé avec des fonctions qui seront appelées depuis le fichier .travis.yml (bash nom_script.sh nom_fonction).

Nous ajouterons le code nécessaire au script à bash, de cette façon, nous obtiendrons plus de fonctionnalités. Dans la section installer écrivons ce qui suit :

install:
  - bash .travis.sh travis_install

Si vous aviez des instructions, vous pouvez les transférer dans le script en supprimant les traits d'union.

Ouvrons le fichier .travis.sh et ajoutez le paramètre de l'analyseur à 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 
}

Ajoutons maintenant à la section scénario exécuter une 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 aviez une construction sur CMake :

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

Cela se passera comme ceci :

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é ces variables d'environnement $TRAVIS_PULL_REQUEST и $TRAVIS_BRANCH. Travis CI les déclare indépendamment :

  • $TRAVIS_PULL_REQUEST stocke le numéro de demande d'extraction ou non, s'il s'agit d'une branche régulière ;
  • $TRAVIS_REPO_SLUG stocke le nom du référentiel du projet.

L'algorithme de cette fonction est le suivant :

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

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

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

Le fait est que Travis CI fusionne automatiquement les branches lors de l'analyse d'une pull request :

Analyse des commits et des pull request dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Nous analysons donc A4Et ce n'est pas B3->A3. En raison de cette fonctionnalité, nous devons calculer la différence avec A3, qui est précisément le sommet de la branche de origine.

Il reste un détail important : la mise en cache des dépendances des fichiers d'en-tête sur les unités de traduction compilées (*.c, *.cc, *.cpp, etc.). L'analyseur calcule ces dépendances lors de son premier lancement en mode vérification d'une liste de fichiers puis les enregistre dans le répertoire .PVS-Studio. Travis CI vous permet de mettre en cache des dossiers, nous enregistrerons donc les données du répertoire .PVS-Studio/:

cache:
  directories:
    - .PVS-Studio/

Ce code doit être ajouté au fichier .travis.yml. Ce répertoire stocke diverses données collectées après analyse, ce qui accélérera considérablement les exécutions ultérieures d'analyse de liste de fichiers ou d'analyse incrémentielle. Si cela n'est pas fait, l'analyseur analysera tous les fichiers à chaque fois.

Copain

Comme Travis CI, Copain offre la possibilité de créer et de tester automatiquement des projets stockés sur GitHub. Contrairement à Travis CI, il est configuré dans l'interface Web (le support bash est disponible), il n'est donc pas nécessaire de stocker les fichiers de configuration dans le projet.

Tout d’abord, nous devons ajouter une nouvelle action à la chaîne d’assemblage :

Analyse des commits et des pull request dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Indiquons le compilateur qui a été utilisé pour construire le projet. Notez le conteneur Docker installé dans cette action. Par exemple, il existe un conteneur spécial pour GCC :

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

Analyse des commits et des pull request dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Ajoutons les lignes suivantes à 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

Passons maintenant à l'onglet Exécuter (première icône) et ajoutons le code suivant dans le champ de l'éditeur correspondant :

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 lisez la section sur Travs-CI, alors ce code vous est déjà familier, cependant, il y a maintenant une nouvelle étape :

Analyse des commits et des pull request dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Le fait est que maintenant nous analysons non pas le résultat de la fusion, mais le HEAD de la branche à partir de laquelle la pull request est faite :

Analyse des commits et des pull request dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Nous sommes donc dans un commit conditionnel B3 et nous devons faire la différence entre 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 Utilisons 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 — numéro de demande d'extraction ;
  • $BUDDY_REPO_SLUG — une combinaison de nom d'utilisateur et de référentiel (par exemple max/test).

Enregistrons maintenant les modifications à l'aide du bouton ci-dessous et activons l'analyse de la pull request :

Analyse des commits et des pull request dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Contrairement à Travis CI, nous n'avons pas besoin de préciser .pvs-studio pour la mise en cache, puisque Buddy met automatiquement en cache tous les fichiers pour les lancements ultérieurs. Par conséquent, la dernière chose qui reste est d'enregistrer le login et le mot de passe de PVS-Studio dans Buddy. Après avoir enregistré les modifications, nous serons ramenés à Pipeline. Nous devons passer à la configuration des variables et à l'ajout d'un identifiant et d'une clé pour PVS-Studio :

Analyse des commits et des pull request dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Après cela, l’apparition d’une nouvelle pull request ou d’un commit déclenchera la révision. Si un commit contient des erreurs, Buddy l'indiquera sur la page de demande d'extraction.

AppVeyor

La configuration d'AppVeyor est similaire à celle de Buddy, puisque tout se passe dans l'interface Web et qu'il n'est pas nécessaire d'ajouter un fichier *.yml au référentiel du projet.

Passons à l'onglet Paramètres dans l'aperçu du projet :

Analyse des commits et des pull request 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 collecte des demandes d'extraction :

Analyse des commits et des pull request dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Passons maintenant à l'onglet Environnement, où nous spécifions l'image à assembler et les variables d'environnement nécessaires :

Analyse des commits et des pull request dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Si vous avez lu les sections précédentes, vous connaissez très bien ces deux variables - PVS_KEY и PVS_USERNAME. Sinon, je vous rappelle qu'ils sont nécessaires pour vérifier la licence de l'analyseur PVS-Studio. Nous les reverrons dans les scripts Bash à l'avenir.

Sur la même page ci-dessous, nous indiquons le dossier de mise en cache :

Analyse des commits et des pull request 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 nous obtiendrons le résultat des fichiers spécifiés. Il est donc important de saisir le nom correct du répertoire.

Il est maintenant temps de tester le script. Ouvrez l'onglet Tests et sélectionnez Script :

Analyse des commits et des pull request dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Vous devez coller 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

Faisons attention à la partie suivante 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

L'affectation assez spécifique de la valeur de la commande pwd à une variable qui devrait stocker cette valeur par défaut semble étrange à première vue, cependant, je vais tout expliquer maintenant.

Lors de la configuration de l'analyseur dans AppVeyor, j'ai rencontré un comportement extrêmement étrange de l'analyseur. D’une part, tout a fonctionné correctement, mais l’analyse n’a pas démarré. J'ai passé beaucoup de temps à remarquer que nous sommes dans le répertoire /home/appveyor/projects/testcalc/, et l'analyseur est sûr que nous sommes dans /opt/appveyor/build-agent/. Puis j'ai réalisé que la variable $PWD mentait un peu. Pour cette raison, j'ai mis à jour manuellement sa valeur avant de commencer l'analyse.

Et puis tout est comme avant :

Analyse des commits et des pull request dans Travis CI, Buddy et AppVeyor à l'aide de PVS-Studio
Considérons 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"`

Nous y obtenons la différence entre les branches sur lesquelles la pull request est déclarée. Pour ce faire, nous avons besoin des variables d'environnement suivantes :

  • $APPVEYOR_PULL_REQUEST_NUMBER — numéro de demande d'extraction ;
  • $APPVEYOR_REPO_NAME - nom d'utilisateur et référentiel du projet.

Conclusion

Bien entendu, nous n’avons pas considéré tous les services d’intégration continue possibles, cependant, ils ont tous des spécificités de fonctionnement extrêmement similaires les uns aux autres. À l'exception de la mise en cache, chaque service fabrique son propre « vélo », donc tout est toujours différent.

Quelque part, comme dans Travis-CI, quelques lignes de code et la mise en cache fonctionnent parfaitement ; quelque part, comme dans AppVeyor, il suffit de préciser le dossier dans les paramètres ; mais quelque part, vous devez créer des clés uniques et essayer de convaincre le système de vous donner la possibilité d'écraser le fragment mis en cache. Par conséquent, si vous souhaitez configurer une analyse des demandes d'extraction sur un service d'intégration continue qui n'a pas été évoquée ci-dessus, assurez-vous d'abord que vous n'aurez pas de problèmes de mise en cache.

Merci pour votre attention. Si quelque chose ne fonctionne pas, n'hésitez pas à nous écrire à soutenir. Nous vous conseillerons et vous aiderons.

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

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

Source: habr.com

Ajouter un commentaire