Forcing build failures with simple thresholds
Automated build systems (like NAnt or Ant) are excellent mechanisms with which to incorporate quality gates. An obvious quality gate is a successful test run (i.e. did all developer tests pass?); however, with the incorporation of software inspectors, you can introduce additional quality gates that verify specific code metrics or even combinations of metrics. Some software inspectors, in fact, already have built in mechanisms to cause build failures if specific thresholds are exceed, like Cobertura, which has a cobertura-check task that checks specific coverage values.
If a particular tool doesn’t provide an automatic failure hook, you can easily build one– in fact, combining Groovy’s expressive scripting power with Ant makes this process quite easy. For example, you can audit a JavaNCSS (a software inspector that reports code size and complexity) report and fail a build if the maximum complexity (which is reported for individual methods) is exceeded.
Imagine that as an organization, your team has set a goal that no method will have a cyclomatic complexity greater than 15. If for some reason, a method’s ccn (cyclomatic complexity number) is found to exceed 15, then a quality gate is tripped and a build is failed. This process is actually quite easy to script via Groovy in an Ant task. A number of things need to be in place for this to work:
- A threshold value needs to be defined, preferably via an Ant property
- JavaNCSS needs to be run as a prerequisite as the threshold task will parse the resulting XML report
If the defined threshold value is exceeded, then Ant’s fail task will be invoked. Watch how easy this is with Groovy:
<property name="maxccn" value="15" />
<target name="threshold-check" depends="groovy-init,javancss">
<groovy classpathref="build.classpath">
def fullpath = "${properties.basedir}/${properties.defaulttargetdir}"
def jncssPath = "${fullpath}/javancss_metrics.xml"
def jdoc = new XmlSlurper().parse(jncssPath)
int maxccn = 0
if(jdoc != null){
jdoc.functions.function.each{ mthd ->
int ccn = Integer.parseInt(mthd.ccn.text())
if (ccn > maxccn){
maxccn = ccn
}
}
}
if(maxccn > Integer.parseInt(properties.maxccn)){
ant.fail(message:
"Maximum CCN for a method was exceeded, value was ${maxccn}")
}
</groovy>
</target>
Running this task against a code base containing a method with a ccn greater than 15 will yield the following result:
$ ./run-ant.bat -Dnoget=true threshold-check
Buildfile: build.xml
init:
get-deps:
groovy-init:
javancss-init:
javancss:
[javancss] Generating report
threshold-check:
BUILD FAILED
: Maximum CCN for a method was exceeded, value was 16
Total time: 3 seconds
This example, while useful, can be enhanced by comparing coverage as well as complexity– for instance, if the coverage dropped and complexity increased, this would be a far more adequate quality gate.
Software builds are excellent mechanisms to introduce automated quality gates– and as I’ve shown you, they’re easy to implement. As your build process matures, just remember to think through these quality gates so as to avoid false negatives. Simply failing a build because of a specific metric’s value has tripped a threshold could be dangerous. In the example above, if a method’s ccn value did exceed 15, one could argue that if that method also had high coverage, then some degree of risk has been avoided.

March 10th, 2007 at 4:17 pm
Nice post. Wouldn’t it be better to put this in an Ant task, instead of inline in Ant? Speaking of which, is it possible to *only* use Groovy code in an Ant task. Have you tried this before?
March 12th, 2007 at 9:44 am
Yes, you can easily write an Ant task in Groovy– just use groovyc to compile the code into normal Java class files and you are good to go! I agree, this code probably should be task-ed, especially if you were to add more logic.
March 19th, 2008 at 8:22 pm
[…] Reports are hip, but in truth, reports by tools like CPD are essentially read once– the first time they are generated. After that, it’s anyone’s guess when someone will actively read the report again. Hence, I find it particularly helpful to essentially throw the report out and let the build itself proactively tell me when a particular metric gets out of hand. This essentially means that my build has to monitor a particular metric– and in the case of the CPLOC ratio, my build has to gather data from two sources– JavaNCSS’s report and CPD’s. […]