20. Sep 2021
Lesedauer 9 Min.
SonarQube mit Azure DevOps
Schritt für Schritt zu Continuous Inspection mit Azure Pipelines
Die Vorteile der statischen Codeanalyse sind hinlänglich bekannt. Doch was ist zu tun, um SonarQube in eine CI/CD-Umgebung zu integrieren?

In der professionellen Softwareentwicklung ist die statische Codeanalyse ein Baustein unter vielen, die dazu beitragen können, die Qualität der zu entwickelnden Software anzuheben. Es gibt verschiedene Wege, eine solche anzustoßen. IDEs wie Visual Studio oder JetBrains Rider verfügen über eine statische Codeanalyse mit konfigurierbaren Regeln. Sie werden wahlweise manuell oder automatisch ausgeführt und geben Hinweise zu potenziellen Problemstellen direkt in der IDE. Der Entwickler kann anschließend den Code anpassen, damit die Analyseregeln eingehalten werden.SonarQube geht einen anderen Weg und sieht sich als zentrales Analysetool. Es kommt mit eigenem User Interface, das viele Informationen für die quantitative Analyse eines Softwareprojekts bereitstellt.Dieser Artikel bietet einen praktischen Leitfaden für die Integration von SonarQube in Azure DevOps und beschreibt, welche Schritte für eine solide zentrale Qualitätsüberwachung erforderlich sind.
SonarQube versus SonarSource
Während SonarQube die installierbare On-Premises-Variante darstellt, ist SonarSource ein SonarQube-Software-as-a-Service-Produkt der gleichnamigen Firma SonarSource. Grundsätzlich sind die Schritte zur Integration in Azure DevOps bei SonarQube und SonarSource identisch. Lediglich hier und da gibt es kleine Unterschiede in der Weboberfläche.Die installierbare On-Premises-Variante wird in unterschiedlichen Editionen angeboten [1]. Bei der Community-Edition müssen relevante Einschnitte bei der Branch-Analyse hingenommen werden, da hier nur der Default-Branch analysiert wird. Das Feedback für Entwickler im Rahmen von Pull Requests bleibt leider aus.Azure DevOps -> SonarQube
Die Integration von SonarQube in Azure DevOps setzt zwei Dinge voraus: den SonarQube-URL und ein Token für die Authentifizierung am SonarQube-Server. Um dieses Authentifizierungstoken zu erzeugen, melden Sie sich zunächst mit einem Account bei der SonarQube-Weboberfläche an, der über die Berechtigung Execute Analysis verfügt. Anschließend wechseln Sie in die Account-Einstellungen und generieren unter dem Tab Security ein neues Token. Hier geben Sie dem Token noch einen aussagekräftigen Namen, damit Sie es später seinem Verwendungszweck zuordnen können (Bild 1). An dieser Stelle ist es sinnvoll, den Namen des Azure-DevOps-Projekts in der Token-Bezeichnung zu berücksichtigen, da in Azure DevOps die Authentifizierungsinformationen je Projekt hinterlegt werden. Das Token selbst notieren Sie sich kurzzeitig oder kopieren es für den nächsten Schritt in die Zwischenablage.
SonarQube: Nutzer-Tokengenerieren(Bild 1)
Autor
In Azure DevOps werden die Verbindungsinformationen zum SonarQube-Server in den Einstellungen des Azure-DevOps-Projektes hinterlegt. Hierfür gibt es im linken Bereich den Eintrag Dienstverbindungen. Navigiert man dorthin und wählt anschließend Neue Dienstverbindung aus, wird eine Liste bekannter Dienste eingeblendet, die auch den Eintrag SonarQube enthalten sollte. Ist der Eintrag nicht vorhanden, fehlt mit hoher Wahrscheinlichkeit die SonarQube-Erweiterung (siehe Kasten Azure-DevOps-SonarQube-Extension). Nach Auswahl von SonarQube und einem Klick auf Weiter werden Sie um die Eingabe von Verbindungsinformationen gebeten. Server-URL,Token und ein Bezeichner sind obligatorisch. Im Standard akzeptiert SonarQube Verbindungen über Port 9000 (HTTP), daher muss der Port im URL mit angegeben werden, sofern hier nicht eigene Einstellungen getroffen wurden, was durchaus empfehlenswert ist (Bild 2).
Azure-DevOps-SonarQube-Extension
Damit Azure DevOps mit einem SonarQube-Server kommunizieren kann, muss die kostenfreie SonarQube-Erweiterung aus dem Azure DevOps Marketplace installiert werden. Sie enthält beispielsweise die erforderlichen Build-Tasks zum Auslösen der Codeanalyse sowie die Scanner für die jeweilige Zielplattform.

Erstellen einer Dienstverbindungzu SonarQube(Bild 2)
Autor
Die Option Allen Pipelines die Zugriffsberechtigungen gewähren ist zunächst aktiv und kann deaktiviert werden, wenn nicht jede Azure Pipeline die SonarQube-Verbindung nutzen darf. In diesem Fall wird beim Ausführen der Pipeline eine Abfrage initiiert, bei der die Verwendung der Serviceverbindung nochmals bestätigt werden muss.
SonarQube -> Azure DevOps
Nachdem Azure DevOps Verbindungsinformationen für den SonarQube-Server erhalten hat, muss nun die entgegengesetzte Kommunikationsbeziehung eingerichtet werden. Hierfür ist ein Azure DevOps Account erforderlich, der von SonarQube genutzt werden kann, um Zugriff auf den Sourcecode zu erhalten und Pull Requests mit Kommentaren zu dekorieren. Der Account muss also über die entsprechenden Berechtigungen verfügen. Das Zugriffstoken erstellen Sie ähnlich wie in SonarQube. Nachdem Sie sich mit dem passenden Account an der Azure-DevOps-Weboberfläche angemeldet haben, klicken Sie rechts oben auf das Icon für die Benutzereinstellungen und wählen den Eintrag Persönliche Zugriffstoken aus. Nach einem Klick auf Neues Token wird ein Dialog eingeblendet, der auf den ersten Blick viele Sicherheitsinformationen abfragt. Hier geben Sie dem neu zu erstellenden Token einen Bezeichner, eine Gültigkeitsdauer und vor allem einen Gültigkeitsbereich (Scope) mit. Mittels des Scopes legen Sie fest, ob Zugriff auf alle Azure-Ressourcen gewährt werden soll oder nur auf bestimmte Bereiche. Letztere Auswahl ist hier sinnvoll, da einzig der Lese- und Schreibzugriff auf den Code erforderlich ist. Nach einem Klick auf Erstellen wird das Zugriffstoken angezeigt, welches für die spätere Verwendung notiert werden sollte. Eingetragen wird das Token in der Weboberfläche von SonarQube. Hierfür wechseln Sie in den globalen Administrationsbereich von SonarQube und selektieren im linken Bereich ALM integrations. Wird SonarSource anstelle von SonarQube verwendet, befindet sich diese Option in den Projekteinstellungen. Derzeit werden hier vier Application-Lifecycle-Management-Lösungen unterstützt: GitHub, Bitbucket, Azure DevOps und GitLab. Selbstredend ist in diesem Fall Azure DevOps die richtige Wahl, und nach einem Klick auf Create configurationwird ein entsprechender Konfigurationsdialog eingeblendet. In diesen geben Sie nun den Azure-DevOps-URL, das Zugriffstoken und einen Konfigurationsbezeichner ein und speichern die Einstellungen mit einem Klick auf Save configuration(Bild 3).
Azure-DevOps-Konfigurationin SonarQube(Bild 3)
Autor
Wichtig: Der Azure-DevOps-URL muss den Sammlungsnamen enthalten. Die Gültigkeit der eingegebenen Informationen wird im Anschluss automatisch verifiziert.
Erweitern der Build-Pipeline
Die Analyse des Sourcecodes erfolgt durch die Build-Pipeline. Hierfür enthält die SonarQube-Erweiterung die drei folgenden Build-Tasks:- Prepare Analysis Configuration,
- Run Code Analysis,
- Publish Quality Gate Result.
Analyse der Testabdeckung
Die Testabdeckung (auf Englisch Code Coverage) ist eine der häufigsten Metriken für Softwareprojekte und gleichzeitig eine immer häufiger diskutierte. Sie hilft Entwicklern bei der Überprüfung ihrer Arbeit und zeigt Lücken bei den automatisierten Tests auf, wenngleich eine qualitative Analyse von automatisierten Tests damit nicht möglich ist.SonarQube wertet bei der Analyse zwei Informationen separat aus: die Code Coverage und die Testergebnisse selbst. Je nachdem, welche Tools für die Testausführung und die Coverage-Analyse eingesetzt werden, müssen zusätzliche Schritte durchgeführt werden, damit alle vom SonarQube-Scanner gelieferten Daten berücksichtigt werden. Hier versteckt sich mitunter ein größerer Konfigurationsaufwand, je nachdem, wie gut die eingesetzten Tools vom Scanner unterstützt werden. Zum Zeitpunkt des Schreibens dieses Artikels kann der SonarQube-Scanner für .NET mit folgenden Coverage-Report-Formaten umgehen:- VSTest,
- dotCover,
- OpenCover,
- Coverlet,
- NCover 3.
--collect "Code Coverage"
Dies bewirkt, dass zusätzlich eine *.coverage-Datei erzeugt wird. Damit sind beide Informationen in einem von SonarQube unterstützten Format verfügbar. Beide Dateien werden vom Build-Task (sofern nicht anders konfiguriert) in einem temporären Build-Ordner abgelegt, welcher über die Build-Variable Agent.TempDirectory angesprochen werden kann. Damit beide Dateien nun bei der Analyse durch SonarQube gefunden werden, muss der Build-Task Prepare Analysis Configuration um die folgenden Einstellungen erweitert werden:
sonar.cs.vstest.reportsPaths=
$(Agent.TempDirectory)/**/*.trx
sonar.cs.vscoveragexml.reportsPaths=
$(Agent.TempDirectory)/**/*.coveragexml
Die Angabe *.coveragexml dient nur der Veranschaulichung und wäre in diesem Fall nicht notwendig, da der SonarQube-Scanner im temporären Build-Ordner nach dieser Datei sucht. Leider tut er das nicht für die Test-Results-Datei.Nachdem die Build-Pipeline mit diesen Einstellungen für eine Codebasis mit Unit-Tests ausgeführt wurde, werden auf der Weboberfläche von SonarQube Code Coverage und Testergebnisse in unterschiedlichen Ansichten dargestellt. Zu Auswertungszwecken finden Sie unter dem Menüpunkt Measures den Detailbereich Coverage, der einen Überblick über die Unit-Tests und die Testabdeckung der gesamten Codebasis liefert. Unter dem Menüpunkt Code haben Sie die Möglichkeit, den Quellcode zu durchsuchen, und bekommen dabei farbig dargestellt, ob eine Codezeile durch Unit-Tests abgedeckt ist oder nicht.
Listing 1: Grundlegende Pipeline-Beschreibung
trigger: <br/>- master <br/>pool: <br/> name: 'Default' <br/>variables: <br/> solution: '**/*.sln' <br/> buildPlatform: 'Any CPU' <br/> buildConfiguration: 'Release' <br/>steps: <br/>- task: NuGetToolInstaller@1 <br/>- task: NuGetCommand@2 <br/> inputs: <br/> restoreSolution: '$(solution)' <br/>- task: SonarQubePrepare@4 <br/> inputs: <br/> SonarQube: 'SonarQube' <br/> scannerMode: 'MSBuild' <br/> projectKey: 'Playground' <br/> projectName: 'Playground' <br/>- task: DotNetCoreCLI@2 <br/> displayName: Build Solution <br/> inputs: <br/> command: 'build' <br/> projects: '$(solution)' <br/> arguments: <br/> '--configuration $(BuildConfiguration)' <br/>- task: DotNetCoreCLI@2 <br/> displayName: Run Unit-Tests <br/> inputs: <br/> command: 'test' <br/> projects: '**/*.sln' <br/> arguments: <br/> '--configuration $(buildConfiguration)' <br/> publishTestResults: true- task: <br/> SonarQubeAnalyze@4 <br/>- task: SonarQubePublish@4 <br/> inputs: <br/> pollingTimeoutSec: '300'
Pull Requests und Quality Gates
Nachdem beide Systeme eingerichtet sind und zudem die Build-Pipeline erweitert wurde, fehlt noch die Integration der Analyse in die Pull Requests. Erst mit diesem Schritt wird SonarQube zu einem verbindlichen Tool in der Build-Kette und stellt sicher, dass in den Hauptentwicklungszweig ausschließlich Code gelangt, der den festgelegten Qualitätsanforderungen entspricht (Bild 4).
Pull-Request-Kommentarbei mangelnder SW-Qualität(Bild 4)
Autor
Umgesetzt wird das über sogenannte Branch-Richtlinien. Sofern noch keine Richtlinie für den Ziel-Branch existiert, muss eine neue Richtlinie konfiguriert werden. Damit nun automatisch eine SonarQube-Analyse im Rahmen eines Pull Request ausgeführt wird, muss in der Richtlinie unter Build-Überprüfung zunächst eine Build-Pipeline ausgewählt werden, die eine SonarQube-Analyse enthält. Diese wird später für jeden neuen Pull Request gestartet.Des Weiteren sollte unter Status Checks ein weiterer Eintrag hinzugefügt werden. Er hat das Ziel, Pull Requests mit dem ermittelten Quality-Gate-Status zu dekorieren. Ist im Auswahlfeld Zu überprüfenderStatus kein Eintrag der Art SonarQube/quality gate zu finden, muss die Build-Pipeline erstmalig erfolgreich durchlaufen werden, damit Azure DevOps vom SonarQube-Status Kenntnis erlangt.Eine knifflige Frage ist, ob der SonarQube-Quality-Gate-Status eine erforderliche oder optionale Bedingung für Pull Requests ist. Für neue Softwareprojekte spricht wenig gegen eine erforderliche Bedingung. Bei umfangreichen Projekten mit einer veralteten Codebasis kann eine optionale Bedingung der bessere Einstieg in Continuous Inspection sein.
Fazit
Continuous Inspection ist mit SonarQube schon länger möglich, auch wenn die nahtlose Integration in Azure DevOps erst in den letzten Jahren deutlich nutzerfreundlicher geworden ist. Einzig die Integration von Testergebnissen und Code Coverage gehen mitunter nicht so leicht von der Hand. Die Community ist recht groß und man findet online zu vielen Problemen auch schnell eine Lösung.Die fehlende Branch-Analyse macht die Community-Edition zu einem zahnlosen Tiger. Läuft Continuous Inspection nur nebenher mit, ohne dass Entwickler direktes Feedback bekommen, können diese weder aus den gemachten Fehlern lernen noch Korrekturen bereitstellen. Es macht einen großen Unterschied, ob Entwickler proaktiv über die SonarQube-Weboberfläche nach Problemen im Sourcecode suchen oder reaktiv die Probleme beseitigen, die sie am Abschluss eines Pull Request hindern.Fussnoten
- Download SonarQube, http://www.sonarqube.org/downloads/