Code Metrics Statistics with TeamCity

Code metrics can be a very useful tool for monitoring some aspects of code quality. To get the most out of it you need to calculate the metrics on a regular basis in order to find trends. Code quality tend to go down during intense phases of a development project and also when a product is in low-intensity development, a.k.a the maintenance phase. The obvious thing to do for a modern developer is to integrate calculation of code metrics into the Continuous Integration process.

In this post I will demonstrate how you can calculate code metrics and display graphs of the evolution over time as part of your Continuous Integration process. There are a few tools available for calculating code metrics in .NET, the most capable is without doubt NDepend. Here I will use another tool, SourceMonitor, which is free of charge and very lightweight. We use Team City at work, so that is the CI server that I will use here also, but you could probably implement this idea in the CI server you are using.

One of the goals I had when I started experimenting with code metrics statistics was that I wanted it to be easy to add statistics to any project, without changing anything in the project itself. All changes should be in the Team City configuration.

Step 1: Create Metrics project in VCS

The first step is to create a project in your version control system. This project should contain the following artifacts:

The SourceMonitor executable

A SourceMonitor command file, SourceMonitorCommands.xml

A MSBuild script file, SourceMonitor.proj

MSBuild community tasks

I put all the files in a directory called SourceMonitor.

Step 2: Create a SourceMonitor command file

I will not go into the details of working with SourceMonitor. If you are interested, you can read the documentation that is included in the download. Here is the command file that I used:

This command file will create two xml-files: SourceMonitor-details.xml and SourceMonitor-summary.xml. It is from the latter that we will extract the values to publish to Team City.

Step 3: Create a build script

Here I have used MSBuild, but you can of course use NAnt, Rake or whatever. The build script will do the following:

Run SourceMonitor on your source files

Extract the interesting values from the resulting xml-file

Publish these values to Team City

The MSBuild community task XmlRead is used to extract the values from the xml-file. The Team City task TeamCityReportStatsValue is used to publish the values. The community tasks has to be explicitly imported, but the Team City tasks are imported automatically when the script is run by Team City. Here is my MSBuild script:

The build script above will extract the following metrics and publish them:

Number of lines of code

Average number of methods per class

Average number of statements per method

Maximum cyclomatic complexity

Average cyclomatic complexity

Step 4: Create a build configuration in Team City

The next step is to create a new build configuration for the project that you want to analyze and display statistics for.

Attach your VCS project root and the SourceMonitor root as well. Your version control settings will look like the example below.

Version Control Settings in Team City

Configure TeamCity to use the MSBuild runner for your build and specify the path to the build script that will run SourceMonitor. Also specify the target, in my case “Analyze”.

Build runner configuration in Team City

Setup build triggering the way you like it, either as a dependent build or scheduled at some interval, for example every night.

Step 5: Configure Team City to display statistics

TeamCity has built in capablities to display statistics in graphs. You can easily add your own graphs to a project by adding configuration to the file plugin-settings.xml which is located in the folder: (TeamCity path)\.BuildServer\config\(project name). Note that you have to change the buildTypeId value to the Id of your Metrics build configuration. You can find the buildTypeId in the URL as a query parameter. Below is a sample plugin-settings file:

<?xmlversion="1.0"encoding="UTF-8"?><settings><custom-graphs><graphtitle="Number of Lines"defaultFilters=""hideFilters="showFailed"><valueTypekey="NumberOfLines"title="Number Of Lines"buildTypeId="bt61"/></graph><graphtitle="Methods per Class"defaultFilters=""hideFilters="showFailed"><valueTypekey="MethodsPerClass"title="Methods per Class"buildTypeId="bt61"/></graph><graphtitle="Statements per Method"defaultFilters=""hideFilters="showFailed"><valueTypekey="StatementsPerMethod"title="Statements per Method"buildTypeId="bt61"/></graph><graphtitle="Complexity"defaultFilters=""hideFilters="showFailed"><valueTypekey="MaxComplexity"title="Max Complexity"buildTypeId="bt61"/><valueTypekey="AvgComplexity"title="Average Complexity"buildTypeId="bt61"/></graph></custom-graphs></settings>

Whenever the Metrics build is run, the graphs will be updated with the latest values. You will find them on the Statistics tab on the project overview page. It will look something like this after the first successful run:

Sample Metrics graphs

Final remarks

SourceMonitor only supports a few metrics, so if you want some more advanced metrics, like code cohesion, then go for NDepend.

In this post I haven’t explained how to display detailed reports from SourceMonitor in TeamCity. Maybe that will come in a later post.

pwigle

Perry

FYI you have to edit (TeamCity path)\.BuildServer\config\main-config in 6.0 instead of (TeamCity path)\.BuildServer\config\(project name)\plugin-settings.xml. The plugin-settings.xml file is still present in 6.0 but doesn’t appear to do anything anymore. After that all works as expected. Now I just have to edit my SourceMonitorCommands.xml so I get the results I am looking for. Thanks for the write up.

acarum

@Perry if I understood correctly, the graphics in teamcity will always show the same values, because sourcemonitor’s command file is ponting to only one checkpoint: “baseline”.
This checkpoint is the history file of code metrics in a especific date.

@Pwingle Is there any way to automate the process of updating the checkpoint name in the SourceMonitor command file?