Ab Version 7.04 bietet der PVS-Studio Analyzer für C- und C ++ - Sprachen unter Linux und MacOS die Testfunktion zum Überprüfen der Liste der angegebenen Dateien. Im neuen Modus können Sie den Analysator so konfigurieren, dass Commits überprüft und Anforderungen abgerufen werden. Dieser Artikel behandelt das Einrichten der Überprüfung bestimmter geänderter Dateien aus einem GitHub-Projekt in so beliebten CI-Systemen (Continuous Integration) wie Travis CI, Buddy und AppVeyor.
Modus zum Überprüfen der Liste der Dateien
PVS-Studio ist ein Tool zum Erkennen von Fehlern und potenziellen Schwachstellen im Quellcode von Programmen, die in C, C ++, C # und Java geschrieben wurden. Funktioniert in 64-Bit-Systemen unter Windows, Linux und MacOS.
In der PVS-Studio 7.04-Version für Linux und MacOS gibt es jetzt die Möglichkeit, die Liste der Dateien zu überprüfen. Es funktioniert für Projekte, deren Build-System das Generieren der Datei
compile_commands.json ermöglicht . Es wird benötigt, damit der Analysator Informationen über die Kompilierung bestimmter Dateien erhält. Wenn Ihr Build-System die Generierung der Datei compile_commands.json nicht unterstützt, können Sie versuchen, eine solche Datei mit dem Dienstprogramm
Bear zu generieren.
Diese Art der Überprüfung der Dateiliste kann auch mit dem von strace generierten Compiler-Ablaufverfolgungsprotokoll (pvs-studio-analyzer trace) verwendet werden. Dazu müssen Sie zunächst einen vollständigen Projektaufbau abschließen und verfolgen, damit der Analysator vollständige Informationen zu den Kompilierungsparametern aller überprüften Dateien sammelt.
Diese Option hat jedoch einen erheblichen Nachteil: Sie müssen entweder bei jedem Lauf eine vollständige Build-Ablaufverfolgung des gesamten Projekts durchführen, was der Idee einer schnellen Commit-Überprüfung widerspricht. Wenn Sie das Ablaufverfolgungsergebnis selbst zwischenspeichern, sind nachfolgende Analysatorläufe möglicherweise unvollständig, wenn sich nach dem Verfolgen der Struktur der Quelldateien die Abhängigkeiten ändern (z. B. wird in einer der Quelldateien ein neues #include hinzugefügt).
Daher empfehlen wir nicht, den Modus zum Überprüfen der Dateiliste mit einem Ablaufverfolgungsprotokoll zu verwenden, um Commits oder Pull-Anforderungen zu überprüfen. Wenn Sie beim Überprüfen eines Commits einen inkrementellen Build ausführen können, sollten Sie den
inkrementellen Analysemodus verwenden .
Die Liste der Quelldateien für die Analyse wird in der Textdatei gespeichert und mit dem Parameter
-S an den Analysator übergeben:
pvs-studio-analyzer analyze ... -f build/compile_commands.json -S check-list.txt
Diese Datei enthält relative und absolute Pfade zu Dateien, in denen jede neue Datei in einer neuen Zeile steht. Sie können sowohl Dateinamen für die Analyse als auch unterschiedlichen Text angeben. Der Analysator erkennt, dass es sich nicht um einen Dateinamen handelt, und ignoriert die Zeile. Dies kann zum Kommentieren hilfreich sein, wenn Dateien manuell angegeben werden. Häufig wird die Liste der Dateien jedoch während der CI-Analyse generiert. Dies können beispielsweise Dateien aus einem Commit oder einer Pull-Anforderung sein.
In diesem Modus können Sie jetzt schnell neuen Code überprüfen, bevor er in den Hauptentwicklungszweig gelangt. Das
Flag --indicate-warnings wurde im Dienstprogramm
plog-converter hinzugefügt, damit das
Prüfsystem auf das Vorhandensein von Warnungen des Analysators reagiert.
plog-converter ... --indicate-warnings ... -o /path/to/report.tasks ...
Mit diesem Flag gibt der Konverter einen Code ungleich Null zurück, wenn der Analysatorbericht Warnungen enthält. Sie können den Pre-Commit-Hook, die Commit- oder Pull-Anforderung blockieren und den generierten Analysatorbericht anzeigen, freigeben oder per E-Mail senden.
Hinweis Während der ersten Analyse der Dateiliste wird das gesamte Projekt überprüft, da der Analysator die Datei mit Abhängigkeiten von Projektquelldateien aus Headerdateien generieren muss. Dies ist eine Besonderheit der Analyse von C- und C ++ - Dateien. In Zukunft kann diese Abhängigkeitsdatei zwischengespeichert werden und wird vom Analysator automatisch aktualisiert. Der Vorteil der Überprüfung von Commits im Modus zum Überprüfen der Dateiliste gegenüber dem inkrementellen Analysemodus besteht darin, dass Sie nur diese Datei und nicht die Objektdateien zwischenspeichern müssen.Allgemeine Prinzipien der Pull-Request-Analyse
Die gesamte Projektanalyse nimmt viel Zeit in Anspruch, daher ist es sinnvoll, nur einen Teil davon zu überprüfen. Das Problem ist, dass Sie neue Dateien von den übrigen Projektdateien trennen müssen.
Schauen wir uns das Beispiel eines Commit-Baums mit zwei Zweigen an:
Stellen Sie sich vor, das
A1- Commit enthält ziemlich viel Code, der bereits überprüft wurde. Zuvor haben wir einen Zweig aus dem
A1- Commit erstellt und einige Dateien geändert.
Natürlich haben Sie bemerkt, dass nach
A1 zwei weitere Commits stattgefunden haben und zwei weitere Zweige zusammengeführt wurden, da wir im
Master keine Commits durchführen. Hier kommt der Moment, in dem der
Hotfix bereit ist. Aus diesem Grund haben wir eine Pull-Anfrage für die Zusammenführung von
B3 und
A3 erhalten .
Wir könnten das Ergebnis ihrer Zusammenführung überprüfen, aber es wäre zu lang und unvernünftig, da nur wenige Dateien geändert wurden. Daher ist es effizienter, nur die geänderten zu analysieren.
Dazu erhalten wir den Unterschied zwischen Zweigen, die sich im KOPF des Zweigs befinden, von dem wir in den Master übergehen möchten:
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
Wir werden
$ MERGE_BASE später im Detail betrachten. Tatsache ist, dass nicht jeder CI-Service die erforderlichen Informationen auf der Zusammenführungsbasis bereitstellt. Daher müssen wir jedes Mal über neue Wege nachdenken, um diese Daten abzurufen. Dies wird nachstehend für jeden der beschriebenen Webdienste im Detail betrachtet.
Wir haben also einen Unterschied zwischen Zweigen, dh der Liste der geänderten Dateinamen. Jetzt müssen wir diese
.pvs-pr.list- Datei dem Analysator
zuführen . Wir haben die Ausgabe früher darauf umgeleitet.
pvs-studio-analyzer analyze -j8 \ -o PVS-Studio.log \ -S .pvs-pr.list
Nach der Analyse müssen wir die Protokolldatei (PVS-Studio.log) in ein benutzerfreundliches Format konvertieren:
plog-converter -t errorfile PVS-Studio.log --cerr -w
Dieser Befehl gibt die Fehlerliste in
stderr (Standardfehlerstrom) aus.
Der Haken ist, dass wir nicht nur die Fehler ausgeben müssen, sondern auch unseren Build- und Test-Service über die Probleme informieren müssen. Zu diesem
Zweck wurde im Konverter das Flag
-W (
--indicate-warnings ) hinzugefügt. Wenn mindestens eine Analysatorwarnung
vorliegt , ändert sich der Rückkehrcode des
Plog-Converter- Dienstprogramms in 2, wodurch der CI-Dienst über mögliche Fehler in den Dateien der Pull-Anforderung
informiert wird.
Travis ci
Die Konfiguration erfolgt in Form der Datei
.travis.yml . Der
Einfachheit halber empfehle ich Ihnen, alle Befehle, die sich auf PVS-Studio beziehen, in einem separaten Bash-Skript mit Funktionen zu isolieren, die aus der Datei
.travis.yml (
Bash-Skriptname.sh Funktionsname )
aufgerufen werden .
Durch Erweitern des Skripts erhalten Sie mehr Funktionen. Schreiben Sie im
Installationsabschnitt Folgendes:
install: - bash .travis.sh travis_install
Wenn Sie einige Anweisungen hatten, können Sie diese im Skript verschieben, nachdem Sie Bindestriche entfernt haben.
Öffnen Sie die Datei
.travis.sh und fügen Sie die Analyzer-Installation in die Funktion
travis_install () ein :
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 }
Fügen wir nun den im Skriptabschnitt ausgeführten Analysator hinzu:
script: - bash .travis.sh travis_script
Und im Bash-Skript:
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 }
Sie müssen diesen Code nach dem Erstellen des Projekts ausführen, wenn Sie beispielsweise CMake erstellt haben:
travis_script() { CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}" cmake $CMAKE_ARGS CMakeLists.txt make -j8 }
Sie erhalten Folgendes:
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 }
Höchstwahrscheinlich haben Sie die Umgebungsvariablen
$ TRAVIS_PULL_REQUEST und
$ TRAVIS_BRANCH bereits bemerkt. Travis CI erklärt sie selbst:
- $ TRAVIS_PULL_REQUEST speichert die Pull-Anforderungsnummer oder false, wenn es sich um eine reguläre Verzweigung handelt.
- $ TRAVIS_REPO_SLUG speichert den Namen des Projekt-Repositorys.
Hier ist der Betriebsalgorithmus dieser Funktion:
Travis CI reagiert auf Rückkehrcodes, sodass das Vorhandensein von Warnungen den Dienst meldet, um das Commit als fehlerhaft zu markieren.
Schauen wir uns nun diese Codezeile genauer an:
git diff --name-only origin/HEAD > .pvs-pr.list
Tatsache ist, dass Travis CI bei der Analyse einer Pull-Anforderung automatisch Zweige zusammenführt:
Deshalb analysieren wir
A4 , nicht
B3-> A3 . Aufgrund dieser Besonderheit müssen wir den Unterschied zu
A3 bewerten, dem Kopf des Zweigs vom
Ursprung .
Ein wichtiges Detail bleibt - das Zwischenspeichern der Abhängigkeiten von Header-Dateien von kompilierten Übersetzungseinheiten (* .c, * .cc, * .cpp und andere). Der Analysator wertet diese Abhängigkeiten während des ersten Durchlaufs aus, indem er die Liste der Dateien überprüft und sie dann im Verzeichnis .PVS-Studio speichert. Travis CI ermöglicht das Zwischenspeichern von Repositorys, daher speichern wir Daten im
Verzeichnis .PVS-Studio / :
cache: directories: - .PVS-Studio/
Dieser Code muss in die Datei
.travis.yml eingefügt werden: In diesem Verzeichnis werden verschiedene Daten gespeichert, die nach der Analyse erfasst wurden. Diese Daten beschleunigen nachfolgende Durchläufe der Dateilistenanalyse oder der inkrementellen Analyse erheblich. Wenn Sie dies nicht tun, analysiert der Analysator jedes Mal alle Dateien.
Kumpel
Mit
Buddy können Sie wie mit Travis CI automatisch Projekte aus GitHub erstellen und testen. Im Gegensatz zu Travis CI wird es über die Weboberfläche konfiguriert (Bash-Unterstützung ist verfügbar), sodass keine Konfigurationsdateien im Projekt gespeichert werden müssen.
Zuerst müssen wir der Pipeline einen neuen Schritt hinzufügen:
Geben Sie den Compiler an, der zum Erstellen des Projekts verwendet wird. Achten Sie auf den Docker-Container, der in diesem Schritt installiert wurde. Zum Beispiel gibt es einen speziellen Container für GCC:
Installieren wir nun PVS-Studio und die erforderlichen Dienstprogramme:
Fügen Sie dem Editor die folgenden Zeilen hinzu:
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
Fahren wir mit der Registerkarte Ausführen (erstes Symbol) fort und fügen dem folgenden Editorfeld den folgenden Code hinzu:
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
Wenn Sie den Abschnitt über Travs-CI lesen, ist Ihnen dieser Code bekannt. Aber hier gibt es einen neuen Schritt:
Tatsache ist, dass wir jetzt nicht das Ergebnis der Zusammenführung analysieren, sondern den HEAD des Zweigs mit der aktivierten Pull-Anforderung:
Wir sind also in einem
B3- Commit und müssen den Unterschied zu
A3 herausfinden :
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
Um
A3 zu definieren, verwenden wir die GitHub-API:
https://api.github.com/repos/${USERNAME}/${REPO}/pulls/${PULL_REQUEST_ID}
Wir haben die folgenden Variablen verwendet, die Buddy uns zur Verfügung stellt:
- $ BUDDY_EXECUTION_PULL_REQEUST_NO - Nummer einer Pull-Anfrage;
- $ BUDDY_REPO_SLUG - Kombination aus Benutzername und Repository (z. B. max / test).
Speichern Sie nun die Änderungen mithilfe der folgenden Schaltfläche und aktivieren Sie die Pull-Anforderungsanalyse:
Im Gegensatz zu Travis CI müssen wir für das Caching nicht
.pvs-studio angeben, da Buddy automatisch alle Dateien für nachfolgende Läufe zwischenspeichert. Als letztes müssen Sie also den Login und das Passwort für PVS-Studio in Buddy speichern. Nach dem Speichern der Änderungen kehren wir in die Pipeline zurück. Wir müssen mit dem Einrichten der Variablen fortfahren und den Login und den Schlüssel für PVS-Studio einfügen:
Danach beginnt eine Überprüfung mit jeder neuen Pull-Anforderung oder jedem neuen Commit. Wenn ein Commit Fehler enthält, weist Buddy auf der Pull-Anforderungsseite darauf hin.
Förderer
Die AppVeyor-Einstellung ist ähnlich wie bei Buddy, da dies alles in der Weboberfläche geschieht und die Datei * .yml nicht im Projekt-Repository hinzugefügt werden muss.
Gehen wir in der Projektübersicht zur Registerkarte Einstellungen:
Scrollen Sie auf dieser Seite nach unten und aktivieren Sie das Speichern des Cache für die Erstellung von Pull-Anforderungen:
Fahren wir nun mit der Registerkarte Umgebung fort, auf der wir das Image für den Build und die benötigten Umgebungsvariablen angeben:
Wenn Sie die vorherigen Abschnitte gelesen haben, sind Sie bereits mit diesen beiden Variablen vertraut -
PVS_KEY und
PVS_USERNAME . Wenn nicht, möchte ich Sie daran erinnern, dass sie zur Überprüfung der PVS-Studio Analyzer-Lizenz benötigt werden. In Zukunft werden wir sie in Bash-Skripten wieder sehen.
Geben Sie auf derselben Seite unten den Cache-Ordner an:
Wenn wir dies nicht tun, analysieren wir das gesamte Projekt anstelle einiger Dateien, erhalten jedoch die Ausgabe für die angegebenen Dateien. Daher ist es wichtig, den richtigen Namen des Repositorys einzugeben.
Jetzt ist die Zeit für das Überprüfungsskript gekommen. Öffnen Sie die Registerkarte Tests und wählen Sie Skript:
Der folgende Code sollte in dieses Formular eingefügt werden:
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
Beachten wir den folgenden Teil des Codes:
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
Es ist eine ganz bestimmte Zuordnung des Ausgabewerts des Befehls pwd zur Variablen, die diesen Wert standardmäßig speichern muss. Zunächst scheint es seltsam, aber lassen Sie mich alles erklären.
Beim Einrichten des Analysators in AppVeyor bin ich auf ein sehr seltsames Verhalten des Analysators gestoßen. Einerseits hat alles richtig funktioniert, aber die Analyse hat nicht begonnen. Es hat viel Zeit gekostet zu bemerken, dass wir uns im Verzeichnis / home / appveyor / projects / testcalc / befanden, während der Analysator sicher war, dass wir uns in / opt / appveyor / build-agent / befanden. In diesem Moment wurde mir klar, dass die Variable $ PWD trügerisch ist. Aus diesem Grund habe ich den Wert vor dem Ausführen der Analyse manuell erneuert.
Die weitere Reihenfolge der Aktionen war dieselbe wie zuvor:
Schauen Sie sich nun dieses Fragment an:
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"`
Darin erhalten wir den Unterschied zwischen Zweigen, bezogen auf die überprüfte Pull-Anforderung. Dazu benötigen wir folgende Umgebungsvariablen:
- $ APPVEYOR_PULL_REQUEST_NUMBER - Anforderungsnummer ziehen;
- $ APPVEYOR_REPO_NAME - Benutzername und Projekt-Repository.
Fazit
Nun, wir haben nicht alle möglichen kontinuierlichen Integrationsdienste in Betracht gezogen, sie haben jedoch alle ähnliche betriebliche Besonderheiten. Beim Caching erfindet jeder Dienst sein eigenes Rad neu, sodass es immer anders ist.
In einigen Fällen (wie in Travis-CI) sind einige Codezeilen erforderlich - und das Caching funktioniert einwandfrei. In anderen Fällen (wie in AppVeyor) müssen Sie nur das Verzeichnis in den Einstellungen angeben. Es gibt jedoch einige Dienste, bei denen Sie spezielle Schlüssel erstellen und versuchen müssen, das System davon zu überzeugen, dass Sie die Möglichkeit haben, ein zwischengespeichertes Fragment neu zu schreiben. Wenn Sie die Pull-Anforderungsanalyse für einen kontinuierlichen Integrationsdienst konfigurieren möchten, der oben nicht berücksichtigt wurde, stellen Sie zunächst sicher, dass Sie keine Probleme mit dem Caching haben.
Vielen Dank für Ihre Aufmerksamkeit. Wenn etwas nicht funktioniert, können Sie sicher an unseren
Support schreiben. Wir geben Ihnen einen Hinweis und helfen Ihnen.