Tuesday, June 25, 2013

Automatic Static Code Analysis of Branches

Hey. Let's setup the scenario - let's say you are in a c/c++/java shop, and you also use Coverity, and you have your main source line setup with a nightly Coverity static analysis run. Awesome, you are way ahead of most places.
Let's say development uses branches - either a home-grown solution, or an older model of trunk-branch-tag or maybe even something newish like git-flow - and the benefits of static code analysis is starting to show returns. So maybe some of the development time for the release is being allocated for clearing some of the backlog of defects discovered from prior static code analysis runs, or you want static code analysis done on the feature/development branch in near-real time and eliminating new defects found by static code analysis during the development process is now what the doctor ordered, but it's very time expensive for you to either be setting up new Coverity projects & builds, or maybe you're modifying the single Coverity build you have in place to point to different branches endlessly.
That's no fun for anyone - you're now a gateway (i.e. bottleneck) and if you have multiple branches in development, this can be a serious time sink.
So you've probably already said to yourself, "Self, I sure wish it was easy for Coverity and our build system to auto-create new Coverity runs when a branch is created!"  Well luckfully for you, there is a solution! Atlassian Bamboo 5 has excellent automatic plan cloning tied to branch detection, combine that with Coverity 6.5's project & stream management at the command line, and you get automatic Coverity builds as branches are detected, all using the same triage store so when one defect is triaged, it's reflected across all branches.

Rough workflow:

  1. Set your project name, stream name, triage store, and code branch. 
  2. Attempt to make the Coverity project with the branch name. 
  3. Attempt to make the project stream with the branch name.
  4. Link the project stream with the Coverity project. 
  5. Run the Coverity static analysis. 
  6. Upload the results to your Coverity server. 

Pre-reqs:
In your Bamboo project, enable Branch Detection.
Note: Bamboo does not automatically go back and setup builds for older branches; it only detects new branches going forward. If you need to  have it detect a branch created prior to you enabling branch detection, just go to the "Manual" branch creation and select the existing branch.
If you want every branch going forward to be used, leave the regex expression field blank. If you use something like the git-flow model, then you only want branches prefixed with "feature-", "release-", or "hotfix-" to be considered; in that event, you would use something like this:
(feature|hotfix|release)/.*

In Coverity, the "dummy" user you use for static analysis will need enough privileges to create projects and streams.

I use a separate Bamboo build from the normal continuous integration build for Coverity runs; usually Coverity takes 3X to 10X longer than your CI build, so while the CI build runs every commit, Coverity analysis only runs with a 3AM SCM polling trigger - if there wasn't any changes that day, Coverity analysis doesn't run. There's little point in re-analyzing code that hasn't changed since the prior run.

Since we have branch detection enabled, our Coverity static analysis user is now above to create projects & streams, here's an actual Bamboo task (inline script) to do a branch-named Coverity run. This is for a Java application being built on a Linux build server. The comments are extra - currently Bamboo doesn't like comments in its scripts, but I added them here make it clear what is going on.
The setup:
The application is called App-X, and the jar build we're following here is the CoreComponent.jar.

 PATH=~/cov-analysis-linux64/bin:$PATH  
 # setup vars  
 proj=AppX  
 stream=CoreComponent  
 covlang=java  
 covtriage=Common-Java  
 covproj=$proj-${bamboo.repository.branch.name}  
 covstream=$proj-$stream-${bamboo.repository.branch.name}  
 # create project, create stream, associate stream with project.  
 cov-manage-im --mode projects --add --set name:$covproj  
 cov-manage-im --mode streams --add --set name:$covstream --set lang:$covlang --set triage:$covtriage  
 cov-manage-im --mode projects --update --name $covproj --insert stream:$covstream  
 # finally do actual analysis  
 rm -rf imed  
 cov-build --dir imed ant -buildfile build-ci.xml  
 cwd=$(pwd)  
 cov-analyze-java --dir imed -j auto --strip-path $(pwd)  
 cov-commit-defects --dir imed --stream $covstream --user username --password password --host coverity.yourcompany.com  

Assuming you're using git, and this is the master branch (default), this makes a project called "AppX-master", and a stream under it called "AppX-CoreComponent-master".
Let's say they create a branch called "develop", meant for the next major release of App-X. Bamboo will detect the branch, clone the trigger, and that night it will run a copy of your main Coverity plan and it will create a Coverity project called "AppX-develop", and a stream under it called "AppX-CoreComponent-develop", using the same triage store the -master streams are using.

Eventually branches go silent; Bamboo will clean it up the branch copy of the plan 30 days after the last detected commit, and Coverity 6.5 will clean up detailed snapshot results (at the code level) in its database within ~120 days by default, I believe, so no worries about exploding disk usage and long term database growth.

This should give your company an advantage by being able to get immediate (within 24 hours at least) static analysis results on branches which should translate to a higher quality of code before you release, which should mean a better release.

-Kelly Schoenhofen

No comments:

Post a Comment