Thursday, July 21, 2011

working with the sonar web services API

Sonar does an amazing job at presenting code quality information in different levels of details and different views all of which catering to particular user (Architect, Managers, Developers etc.) It was natural to quickly fire up there documentation on how to write sonar plugins when I started working on making the emails that sonar sends a bit more informative. However, and to my habit of quickly jumping to the complicated way of doing this :-), I realized I could use the web services API to create a simpler solution. So, here's an example on how you can utilize the web services API that exposes violations for a project to create a quick summary of sorts. I used ruby for this (and I confess I have started liking it the most for writing these helper scripts around a development process), but it can be done equally well in Java, Python or the like. And if you don't like XML there's JSON too.

1. a helper method to build URL for fetching violations in the project
def build_violations_url(sonar_url,resource,*optional)
    if resource.nil?
      raise(ArgumentError.new("Project Key/Id for fetching violations cannot be nil."))
    end
    if sonar_url.nil?
      raise(ArgumentError.new("Sonar Host URL for fetching violations cannot be nil."))
    end
    #build URL to query
    query_url = sonar_url + "/api/violations?resource=#{resource}"
    #add all optional arguments
    optional.each do |opt_arg|
      query_url = query_url + "&#{opt_arg}"
    end
    return query_url
  end
So a call like
query_url = s.build_violations_url("http://sonarhost
/sonar","com.foo:bar","depth=-1","format=xml")
will give you the correct URL to hit

2. extract number of occurrences of all the priorities

def generate_violations_table(query_url)
    critical_ctr = 0
    major_ctr = 0
    minor_ctr = 0
    blocker_ctr = 0
    download(query_url,"./violations.xml")
    f = File.open("violations.xml","r")
    violations = Nokogiri::XML(f)
    f.close()
    # collect all criticals
    violations.xpath("//violation/priority").each do |priority|
      if priority.xpath("text()").to_s == "BLOCKER"
        blocker_ctr += 1
      end
      if priority.xpath("text()").to_s == "CRITICAL"
        critical_ctr += 1
      end
      if priority.xpath("text()").to_s == "MAJOR"
        major_ctr += 1
      end
      if priority.xpath("text()").to_s == "MINOR"
        minor_ctr += 1
      end            
    end
  hash = Hash.new
  hash["BLOCKER"] = blocker_ctr
  hash["CRITICAL"] = critical_ctr
  hash["MAJOR"] = major_ctr
  hash["MINOR"] = minor_ctr
  return hash
  end


You can then just transform the hash to a string object and send it in a mail or use the ruport gem to create a more formatted report out of it.

here's my output ( a mail sent using net/smtp)
Mr. Build Manager says you have a look at this:
Summary of nightly Sonar analysis

Violation    Occurrences
BLOCKER    0
CRITICAL    0
MAJOR     1
MINOR     8


 You can view the detailed dashboard here:
http://sonarhost/dashboard/index/1


Happy Coding!
Mr. Build Manager