How to integrate Sonar with TFS (part 2)

In a recent post of mine, I introduced quickly Sonar, and how we can integrate it with TFS. I gave a few tips for its installation. Now it is time to dive in the build process and add the logic we need to make TFS builds use Sonar conveniently.

Are your really sure?

Using Sonar as I’m proposing will deport some processing from TFS to Sonar, which means TFS loses control over a certain things: unit tests are no longer launched by TFS. You *have* to use Gallio Test runner because other test reports format are not *yet* supported. The best bet is then to let Sonar launch tests through Gallio, which may have side effects!

Code analysis can no longer be configured from your projects settings, nor from the build settings (I mean you don’t want to launch it twice), so deactivate it in your builds (pick the Never option), and let Sonar launch FxCop instead.

The tooling is not always up to date, MsTest with VS 2012 was not working when it came out, which means you can be stuck if you upgrade too early. We are in the open source world, we have no guarantee it will work seamlessly with other technologies, unless you contract for a commercial support with SonarSource.

You’re still reading? Ok, you’re a pioneer now, you’ll need a good army knife and some will to make things work in your environment. Hopefully you won’t regret because it will pay off.

Build server tooling

Some tools and scripts need to be deployed onto every build server. We aim at xcopy deployment, I advise to opt for a similar folder structure that you copy from server to server. I pompously named the parent folder “Soner.Net”, and here is its contents:

SNAGHTML2a0d4c9

I cheated a bit with some products, took their installation from the “Program Files” folder on my local machine and copied them in this structure. It just worked for me.

I prefer having a private version of Java running then Sonar analysis. For this, you can just customize the sonar-runner.cmd file and update the PATH, and JAVA_HOME to point to the subfolder where you uncompressed your JDK (not JRE). Be aware of using absolute paths here!

The sonar properties

All your project parameters for the sonar analysis are in a sonar.properties file. You should place this file next to the solution file you want to analyze. I see two options for managing those files:

  1. Create a sonar.properties file for each .NET solution and add it in the source controller
    • Sounds reasonable if you don’t have too many projects
  2. Generate them automatically!
    • But this requires some build customization

The good news is that I’ve written a build Workflow Sonar activity that will generate the properties for you, or at least, help you to generate them. It is very simple, it takes a template file and replaces a few values for you. The path to the template file must be configured in the build process workflow.

Here is the template I’ve set up for using with TFS, a sample sonar-properties.template file:

# Project identification
sonar.projectKey=myCompany:%BUILD_DEFINITION_UNDERSCORE%
sonar.projectVersion=%BUILD_NUMBER_DEFAULT_SUFFIX%
sonar.projectName=%BUILD_DEFINITION%

# Info required for Sonar
sonar.sources=.
sonar.language=cs

# If multiple solutions in folder, use the following line to disambiguate
sonar.dotnet.visualstudio.solution.file=%SOLUTION_FILE%
sonar.dotnet.assemblies=$(SolutionDir)/../Binaries/$(AssemblyName).$(OutputType)
sonar.dotnet.test.assemblies=$(SolutionDir)/../Binaries/$(AssemblyName).$(OutputType)
sonar.dotnet.visualstudio.testProjectPattern=*.Tests

sonar.fxcop.mode=active
sonar.gendarme.mode=active
sonar.gallio.mode=active
sonar.ndeps.mode=active
sonar.squid.mode=active
sonar.stylecop.mode=active

sonar.fxcop.installDirectory=D:/Sonar.Net/Microsoft Fxcop 10.0
sonar.fxcop.assemblyDependencyDirectories=$(SolutionDir)/../Binaries

sonar.gallio.filter=exclude Type:/\.Integration\./
sonar.gallio.it.mode=skip
sonar.gallio.installDirectory=D:/Sonar.Net/Gallio
sonar.gallio.coverage.tool=OpenCover
sonar.gallio.runner=IsolatedProcess
sonar.gallio.timeoutMinutes=10
sonar.gallio.coverage.excludes=Microsoft.Practices.*

sonar.opencover.installDirectory=D:/Sonar.Net/OpenCover

As you can see, there are values that will be replaced at run time. You can see their description on the activity documentation page. The trick with TFS builds is that the output folder for projects is forced to a “Binaries” folder outside the scope of your sources! This template assumes it is running from a TFS build.

It should work locally

To test all these tools, fortunately, you don’t have to run builds. First, create such a properties file based on your values for a project you want to test. Make sure you comment the sonar.dotnet.assemblies and sonar.dotnet.test.assemblies properties since Sonar C# Ecosystem guess them right when TFS is not overriding the output paths. Then, in a command prompt, after having compiled the project, move to your project folder. From there, invoke the sonar.net-runner.cmd file. It should work.

Once this works for you, you are close to make it running into TFS builds, because all we need now is to launch this command line from our builds, and eventually generate the properties dynamically.

Modifying your build template

For this, you need to get the latest Community TFS Build Extensions, and deploy them into your build controller custom assemblies source control folder. See my guide here if you’re not at ease with setting up the solution for editing build templates. You may clone the DefaultTemplate.xaml and start editing it. Once your ready to inject the Sonar activity in your build template, locate the Run On Agent => Try Compile, Test, and Associate Changesets and Work Items activity, it contains the Sequence as illustrated below. You should be able to drag the “Sonar” activity as indicated.

SNAGHTML2db3042

A nice and very simple idea is to add a boolean workflow Argument named “RunSonarAnalysis”.

SNAGHTML2e95f3e

Then encapsulate the Sonar activity into an If activity.

image

If you add the proper Metadata (locate the Metadata Argument, edit it, and add the RunSonarAnalysis argument in the list) for this parameter, you’ll be able to control the Sonar execution from your build definition! That is the start of a real integration.

Finally, edit the Sonar activity properties, and you’re all set!

image

 

Now you can decide to run Sonar from your build definitions!

You may add to your workflow custom parameters (with Metadata), and pass them directly to the Sonar activity. This would allow you to pass values such as “active” or “skip” to enable or disable the plugins of your choice, on a per project basis.

It is not as complicated as it sounds to run Sonar from TFS builds. There are things that can be done better, so stay tuned for future improvements with this activity!