integrate sonarqube in a .net project with appveyor
What is SonarQube
From their site:
SonarQube is an open platform to manage code quality. As such, it covers the 7 axes of code quality:
- Architecture & design
- Duplications
- Unit tests
- Complexity
- Potential bugs
- Coding rules
- Comments
So basically with this you can be pretty sure that your code is good. And since it is open source, you can download it and install a copy on your own server. Or you can use the instance dedicated to open source projects.
Add scan to build
SonarQube works with MSBuild for .net projects through the Scanner for MSBuild, which is available on Chocolatey. There is also an unofficial plugin for F# but it isn't available on the public instance of sonarqube.
All following code examples will be in classic command line and in FAKE, which is a build automation system I use in my projects, like for NVika.
Installation
Two ways to install it, either download it from the SonarQube Scanner for MSBuild page or through Chocolatey:
choco install "msbuild-sonarqube-runner" -y
or with FAKE, which have a lot of helpers:
"msbuild-sonarqube-runner" |> Choco.Install id
Scan
The scan must be started before the build then ended after the build:
Begin:
MSBuild.SonarQube.Runner.exe begin /k:"laedit:Vika" /n:"Vika" /v:"0.1.4" /d:sonar.host.url=https://sonarqube.com /d:sonar.login=[SonarToken]
Or with FAKE:
SonarQube Begin (fun p ->
{p with
ToolsPath = "MSBuild.SonarQube.Runner.exe"
Key = "laedit:Vika"
Name = "Vika"
Version = version
Settings = [ "sonar.host.url=https://sonarqube.com"; "sonar.login=" + environVar "SonarQube_Token" ] })
Mandatory parameters:
/k
|Key
: key of the project; Must be unique; Allowed characters are: letters, numbers,-
,_
,.
and:
, with at least one non-digit./n
|Name
: name of the project; Displayed on the web interface./v
|Version
: version of the project./d:sonar.host.url
: SonarQube server url; default:http://localhost:9000
; must be set tohttps://sonarqube.com
to use the SonarQube public instance./d:sonar.login
: your login or authentication token. If login is used, you must use thesonar.password
with your password as well but this is highly unsecure.
SonarQube_Token
is an AppVeyor secure environment variable wich contains the SonarQube token. While not mandatory it is recommended to generate one by project scanned.
There is also a bunch of other parameters available.
Build like usual, with msbuild for example:
"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" /t:Rebuild
Or an helper:
Target "BuildApp" (fun _ ->
!! "src/NVika/NVika.csproj"
|> MSBuildRelease buildResultDir "Build"
|> Log "AppBuild-Output: "
)
Then the end part:
MSBuild.SonarQube.Runner.exe end /d:sonar.login=[SonarToken]
or with FAKE:
SonarQube End (fun p ->
{p with
ToolsPath = "MSBuild.SonarQube.Runner.exe"
Settings = [ "sonar.login=" + environVar "SonarQube_Token" ]
})
Since all security related parameters aren't write to the disk, you have to pass them again to the end part. Meaning that if you have used login
+ password
in begin you have to pass them both again in end.
Note: there is no need to create a project in the web interface, it is automatically created on the first analysis.
Frequency
It's up to you to determine the frequency of the SonarQube scans, but int order to avoid abuse of the SonarQube public instance and because a scan is not needed for every local build I choose to start one only on AppVeyor and for the original repository (not forks) because I use AppVeyor's secure environment variables:
// check if the build is on AppVeyor and for the original repository
let isOriginalRepo = environVar "APPVEYOR_REPO_NAME" = "laedit/vika"
let isAppVeyorBuild = buildServer = AppVeyor
// build dependencies: SonarQube scan will be launched only if the condition is true
"Clean"
==> "RestorePackages"
=?> ("BeginSonarQube", isAppVeyorBuild && isOriginalRepo)
==> "BuildApp"
=?> ("EndSonarQube", isAppVeyorBuild && isOriginalRepo)
Additional settings
You might want to subscribe to notifications in order to be aware of each new issues or changes of the quality gate status.
But if you use the public instance, subscribe only for specific projects if you want to avoid getting spammed with notifications of all projects.
Also, even if SonarQube doesn't propose built-in badges, shields do, so you can add one to your project's ReadMe.
Use SonarQube in Pull Request builds
SonarQube have a GitHub, which can handle the pull request build without pushing the results to SonarQube.
You just have to add several parameters:
sonar.analysis.mode=preview
: avoid to send the results to the SonarQube instancesonar.github.pullRequest=" + environVar "APPVEYOR_PULL_REQUEST_NUMBER"
: pull request number, here from AppVeyorsonar.github.repository=laedit/vika
: identification of the repository with format <organisation/repo>sonar.github.oauth=" + environVar "Sonar_PR_Token"
: GitHub personal access token, with the scopespublic_repo
(orrepo
for private repositories) andrepo:status
in order to update the PR status
In this example, Sonar_PR_Token
is the GitHub token embedded as AppVeyor secure environment variable. They are not accessible from PRs, unless you check the "Enable secure variables in Pull Requests from the same repository only" box in General tab of your AppVeyor's repo settings.
Even if only PRs from the same repository will have access to the content of the secure environment variable, they can still be visible in the logs of your AppVeyor builds, so be careful.
But if you still want to implement it, be sure to add these parameters only on PRs, for example with FAKE:
let isPR = environVar "APPVEYOR_PULL_REQUEST_NUMBER" |> isNull |> not
Target "BeginSonarQube" (fun _ ->
"msbuild-sonarqube-runner" |> Choco.Install id
let sonarSettings = match isPR with
| false -> [ "sonar.host.url=https://sonarqube.com"; "sonar.login=" + environVar "SonarQube_Token" ]
| true -> [
"sonar.host.url=https://sonarqube.com";
"sonar.login=" + environVar "SonarQube_Token";
"sonar.analysis.mode=preview";
"sonar.github.pullRequest=" + environVar "APPVEYOR_PULL_REQUEST_NUMBER";
"sonar.github.repository=laedit/vika";
"sonar.github.oauth=" + environVar "Sonar_PR_Token"
]
SonarQube Begin (fun p ->
{p with
ToolsPath = "MSBuild.SonarQube.Runner.exe"
Key = "laedit:Vika"
Name = "Vika"
Version = version
Settings = sonarSettings })
)
SonarLint
If you want to find issues before committing, you can use SonarLint, either in your favorite IDE or through command line.