Klocwork Insight Web API cookbook

From current

(Redirected from Klocwork Web API cookbook)
Klocwork Review > Reporting > Advanced reporting > Klocwork Insight Web API cookbook

Contents

The Insight Web API provides administrators with a scriptable interface to the Klocwork database. Currently, the API targets only information on detected issues and metrics.

The API allows you, for example, to generate lists of detected issues and create views.

Use of the API is as simple as posting an HTTP request to the following URL:

http(s)://<klocwork_server_host>:<klocwork_server_port>/review/api

Note: Use https:// if a secure Klocwork Server connection has been configured.

The output is in the form of JSON records. For more information about JSON, see http://www.json.org/.

You can place the HTTP requests with a utility as simple as curl, or with the scripting language of your choice. Running curl will allow you to read the JSON output, but if you want to further process the output, you'll need to use a scripting language such as Python or Ruby. You can write scripts in any language that supports sending POST HTTP requests and that processes JSON output. All of the examples in this article use curl.

Reference information

For details on all supported actions and their parameters with examples, go to:

http(s)://<klocwork_server_host>:<klocwork_server_port>/review/api

Formatting requests to the API

Using curl as an example, here is the format for the API request:

curl --data "action=<action>&user=<username>&project=<project>&<parameters>[&ltoken=<auth_token>]" http(s)://<server>:<port>/review/api

where

  • <action> is one of the supported actions. See the API reference page for details (http://<klocwork_server_host>:<klocwork_server_port>/review/api).
  • <username> is your user name (required for all requests)
  • <project> is the name of a project on the Klocwork Server
  • <parameters> is option(s) for an action. See the examples below for details.
  • <auth_token> is an authentication token from the ltoken. See the next section on authentication for details.

Note: The API has full internalization support as long as the Content-Type is set correctly. Use curl's add-header command-line option to set the charset to UTF-8. For example:

curl --data "action=search&user=myself&query=アクション&project=a" -H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8" http://localhost:8080/review/api

Authentication

As with any other operation involving the Klocwork Server, API requests must be authenticated. If no access control method has been defined, all that is required is a user name, and that user name can be anything at all. When using access control, however, both a user name and an authentication token must be provided.

Authentication tokens are stored by kwauth and by Klocwork client applications in a special file in the user's home directory. You can find this file, called ltoken, as follows:

  • Windows Vista and Windows 7: C:\Users\<user_name>\.klocwork\ltoken
  • Windows XP: C:\Documents and Settings\<user_name>\.klocwork\ltoken
  • Unix: ~/.klocwork/ltoken
  • Mac: ~/.klocwork/ltoken

If there is no ltoken file in your .klocwork directory, run kwauth to generate the file.

The ltoken file contains one or more text lines, each of which contains four pieces of information, separated by semi-colons:

<server>;<port>;<user_name>;<token>

Use the fourth piece of information as the authentication token in an API request. For example, the ltoken file for user bsmith, accessing server1 on the default port, 8080, might look like this:

server1;8080;bsmith;8244b24fbc50aa75e6f7c882d190616d577914501802ead4009a3e501df79350

The resulting curl request would look like this:

curl --data "action=projects&user=bsmith&ltoken=8244b24fbc50aa75e6f7c882d190616d577914501802ead4009a3e501df79350" http://server1:8080/review/api 

Any script that accesses the API must read the ltoken file and extract the appropriate authentication token to append to its API requests. API applications must not write to the ltoken file. Instead, use kwauth to populate the ltoken file.

Understanding the API response

The result of any request is a (possibly zero-sized) set of JSON records.

The search action response is formatted as one detected issue per line. The reason for formatting them in this way is to support streaming, so that you can read records one at a time rather than having to wait for the whole result set to de-serialize. Note that the search action response does not include line numbers for detected issues.

The report action response is formatted as a JSON object containing, in this order:

  • a list of rows
  • a list of columns
  • a matrix of data, the dimensions of which are bounded by the number of rows and columns

Each row and column item consists of a pair of 'id' and 'name' fields. The 'name' is for display, while the 'id' allows for drilldown.

Note: If you are using an action which generates a time stamp, the encoding of the date is a form of POSIX/UTC time in milliseconds. If you want to convert it to a human readable date, use a python 'time.ctime' function like this:

human_readable_date = time.ctime(attrs["date"] / 1000)

Specifying drilldown for the report action

curl --data "action=report&user=bob&project=demosthenes&x=category&y=state" http://localhost:8080/review/api

This request is asking for a top-level (no drilldown specified) summary of issues in the project demosthenes.

The x-axis of this summary will contain the issue categories, while the y-axis will reflect the issue state (such as new or existing). The response is shown here:

{
	"rows":[{"id":1,"name":"C and C++"}],
	"columns":[{"id":-1,"name":"Existing"},{"id":-1,"name":"New"}],
	"data":[[14,2]],
	"warnings":[]
}

To drill down into this information, or to follow the category tree one level down, we add a drilldown specific to the ID of the item into which we want to drill, on either the x or y axis:

curl --data "action=report&user=bob&project=demosthenes&x=category&y=state&xDrilldown=1" http://localhost:8080/review/api

This request is asking for the next level of the "C and C++" taxonomy to be shown on the x-axis, while the y-axis continues to reflect the issue state:

{
    "rows":[{"id":2, "name":"Attempt to use memory after free"}, {"id":3, "name":"Buffer Overflow"}, ...],
    "columns":[{"id":4, "name":"Existing"}, {"id":3, "name":"Fixed"}], 
    "data":[...],
    "warnings":[]
}

If no such drilldown is possible (for example, asking to drill into state makes no sense), then the top-level summary of that axis will be shown instead.

Examples

These examples are written in Python, but should be simple enough to understand even without an in-depth knowledge of that language.

All of the examples below use demosthenes, a C/C++ sample project installed with the Klocwork Server package at <server_install>/samples/demosthenes. See the README file in that directory for instructions on how to set up the sample project.

You can try out the example scripts on the sample project, or on your own project. If you use them on your own project, you need to change the value for project. You may also need to change the value for host from localhost to your own Klocwork Server host.

About error handling in these examples

When curl calls are made using the Web API, any errors that are encountered are printed to the console automatically. Note however, that the Python examples in this topic provide simplified error handling. For example:

builds = report(url, project, user, action)
print "Existing builds:"
    for build in builds:
        print build

To better handle errors in your own python scripts, use a try block:

try: builds = report(url, project, user, action)
except urllib2.HTTPError as e:
     print "Request failed: " + e.reason + ": " + e.read()
else:
     print "Existing builds:"
     for build in builds:
         print build


Example: Search for all critical issues

This example script searches for all critical issues (with severities 1, 2 and 3) in the latest build of the Demosthenes sample project.

import urllib, urllib2, json, sys, os.path, getpass, time

def getToken(host, port, user) :
   ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
   ltokenFile = open(ltoken, 'r')
   for r in ltokenFile :
      rd = r.strip().split(';')
      if rd[0] == host and rd[1] == str(port) and rd[2] == user :
        ltokenFile.close()
        return rd[3]
   ltokenFile.close()

class Issue(object) :
   def __init__(self, attrs) :
      self.id = attrs["id"]
      self.message = attrs["message"]
      self.file = attrs["file"]
      self.method = attrs["method"]
      self.code = attrs["code"]
      self.severity = attrs["severity"]
      self.severityCode = attrs["severityCode"]
      self.state = attrs["state"]
      self.status = attrs["status"]
      self.taxonomyName = attrs["taxonomyName"]
      self.url = attrs["url"]
      self.created=time.ctime(attrs["dateOriginated"]/1000)

   def __str__(self) :
      return "[%d] %s\n\t%s | %s\n\tCode %s | Severity: %s(%d) | State: %s | Status: %s | Taxonomy: %s | Created: %s\n\t%s" % (
      self.id, self.message, self.file, self.method, self.code, self.severity, self.severityCode, self.state,
      self.status, self.taxonomyName, self.created, self.url
      )

def from_json(json_object) :
   if 'id' in json_object :
      return Issue(json_object)
   return json_object

host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
url = "http://%s:%d/review/api" % (host, port)
values = {"project": project, "user": user, "action": "search"}

loginToken = getToken(host, port, user)
if loginToken is not None :
   values["ltoken"] = loginToken

values["query"] = "severity:1-3"
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req)
for record in response :
   print json.loads(record, object_hook=from_json)

Example: Report detected issues

This example shows the distribution of detected issues by module, grouped by state.

import urllib, urllib2, json, sys, os.path, getpass

def getToken(host, port, user) :
   ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
   ltokenFile = open(ltoken, 'r')
   for r in ltokenFile :
      rd = r.strip().split(';')
      if rd[0] == host and rd[1] == str(port) and rd[2] == user :
        ltokenFile.close()
        return rd[3]
   ltokenFile.close()

class Key(object) :
   def __init__(self, attrs) :
      self.id = attrs["id"]
      self.name = attrs["name"]

   def __str__(self) :
      return "%s (%d)" % (self.name, self.id)

class Report(object) :
   def __init__(self, attrs) :
      self.rows = attrs["rows"]
      self.columns = attrs["columns"]
      self.data = attrs["data"]

   def __str__(self) :
      result = ""
      maxRowName = 0
      for r in self.rows :
        maxRowName = max(len(str(r)), maxRowName)
      maxRowName += 1
      header = ' ' * maxRowName
      colPosition = []
      for c in self.columns :
        colPosition.append(len(header) + len(str(r)))
        header += str(c) + ' '
      result += header + '\n'
      for x in range(len(self.rows)) :
        rHead = ('%-' + str(maxRowName) + 's') % str(self.rows[x])
        for y in range(len(self.columns)) :
           rHead += ('%' + str(len(str(self.columns[y]))) + 's') % str(self.data[x][y]) + ' '
        result += rHead + '\n'
      return result

def from_json(json_object) :
   if 'rows' in json_object :
      return Report(json_object)
   if 'id' in json_object :
      return Key(json_object)
   return json_object

def report(url, project, user, x = None, y = None, view = None, xDrilldown = -1, yDrilldown = -1) :
   values = {"project": project, "user": user, "action": "report"}
   loginToken = getToken(host, port, user)
   if x is not None :
      values["x"] = x
   if y is not None :
      values["y"] = y
   loginToken = getToken(host, port, user)
   if loginToken is not None :
      values["ltoken"] = loginToken
   if view is not None :
      values["view"] = view
   if xDrilldown != -1 :
      values["xDrilldown"] = xDrilldown
   if yDrilldown != -1 :
      values["yDrilldown"] = yDrilldown
   data = urllib.urlencode(values)
   req = urllib2.Request(url, data)
   response = urllib2.urlopen(req)
   for record in response :
      return json.loads(record, object_hook=from_json)

host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
url = "http://%s:%d/review/api" % (host, port)

print report(url, project, user, "Component", "State")

Example: Print the project list

This example shows how to print the list of projects.

import urllib, urllib2, json, sys, os.path, getpass

def getToken(host, port, user):
    ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
    ltokenFile = open(ltoken, 'r')
    for r in ltokenFile:
        rd = r.strip().split(';')
        if rd[0] == host and rd[1] == str(port) and rd[2] == user:
            ltokenFile.close()
            return rd[3]
    ltokenFile.close()


class View(object):
    def __init__(self, attrs):
        self.name = attrs["name"]

    def __str__(self):
        result = "%s" % self.name
        return result


def from_json(json_object):
    return View(json_object)


def report(url, user, action):
    values = {"user": user, "action": action}
    loginToken = getToken(host, port, user)
    if loginToken is not None:
        values["ltoken"] = loginToken
    data = urllib.urlencode(values)
    req = urllib2.Request(url, data)
    response = urllib2.urlopen(req)
    result = []
    for record in response:
        result.append(json.loads(record, object_hook=from_json))
    return result

host = "localhost"
port = 8080
user = getpass.getuser()
action = "projects"
url = "http://%s:%d/review/api" % (host, port)

projects = report(url, user, action)
print "Existing projects:"
for project in projects:
    print project

Example: Print the list of views

This example shows how to print the list of views.

import urllib, urllib2, json, sys, os.path, getpass

def getToken(host, port, user):
    ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
    ltokenFile = open(ltoken, 'r')
    for r in ltokenFile:
        rd = r.strip().split(';')
        if rd[0] == host and rd[1] == str(port) and rd[2] == user:
            ltokenFile.close()
            return rd[3]
    ltokenFile.close()


class View(object):
    def __init__(self, attrs):
        self.name = attrs["name"]
        self.query = attrs["query"]
        self.creator = attrs["creator"]
        if "tags" in attrs:
            self.tags = attrs["tags"]
        else:
            self.tags = ""
        self.is_public = attrs["is_public"]

    def __str__(self):
        result = "Name:%s (Query:%s, Creator:%s, Public:%s) Tags: [" % (
        self.name, self.query, self.creator, self.is_public)
        for x in range(len(self.tags)):
            if not x:
                result = result + self.tags[x]
            else:
                result = result + ',' + self.tags[x]
        result += ']'
        return result


def from_json(json_object):
    return View(json_object)


def report(url, project, user):
    values = {"project": project, "user": user, "action": "views"}
    loginToken = getToken(host, port, user)
    if loginToken is not None:
        values["ltoken"] = loginToken
    data = urllib.urlencode(values)
    req = urllib2.Request(url, data)
    response = urllib2.urlopen(req)
    result = []
    for record in response:
        result.append(json.loads(record, object_hook=from_json))
    return result

host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
url = "http://%s:%d/review/api" % (host, port)

views = report(url, project, user)
for view in views:
    print view

Example: Create a view

This example shows how to create views.

import urllib, urllib2, json, sys, os.path, getpass

def getToken(host, port, user):
    ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
    ltokenFile = open(ltoken, 'r')
    for r in ltokenFile:
        rd = r.strip().split(';')
        if rd[0] == host and rd[1] == str(port) and rd[2] == user:
            ltokenFile.close()
            return rd[3]
    ltokenFile.close()


def createView(url, user, project, name, action, query, tags):
    values = {"project": project, "user": user, "name": name, "action": action, "query": query, "tags": tags}
    loginToken = getToken(host, port, user)
    if loginToken is not None:
        values["ltoken"] = loginToken
    data = urllib.urlencode(values)
    req = urllib2.Request(url, data)
    urllib2.urlopen(req)

host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
name = "Sample View"
action = "create_view"
query = "severity:1-3"
tags = "c,security"
url = "http://%s:%d/review/api" % (host, port)
createView(url, user, project, name, action, query, tags)
print "View created!"

Example: Update views

This example shows how to update views.

import urllib, urllib2, json, sys, os.path, getpass

def getToken(host, port, user):
    ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
    ltokenFile = open(ltoken, 'r')
    for r in ltokenFile:
        rd = r.strip().split(';')
        if rd[0] == host and rd[1] == str(port) and rd[2] == user:
            ltokenFile.close()
            return rd[3]
    ltokenFile.close()


def updateView(url, user, project, name, newname, action, query, ispublic, tags):
    values = {"project": project,
              "user": user,
              "name": name,
              "new_name": newname,
              "action": action,
              "query": query,
              "is_public": ispublic,
              "tags": tags}
    loginToken = getToken(host, port, user)
    if loginToken is not None :
      values["ltoken"] = loginToken
    data = urllib.urlencode(values)
    req = urllib2.Request(url, data)
    urllib2.urlopen(req)

host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
name = "Sample View"
newname = "Updated Sample View"
action = "update_view"
query = "severity:1"
tags = "c,security,important"
ispublic = "true"
url = "http://%s:%d/review/api" % (host, port)
updateView(url, user, project, name, newname, action, query, ispublic, tags)
print "View updated!"

Example: Delete a view

This example shows how to delete views.

import urllib, urllib2, json, sys, os.path, getpass

def getToken(host, port, user):
    ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
    ltokenFile = open(ltoken, 'r')
    for r in ltokenFile:
        rd = r.strip().split(';')
        if rd[0] == host and rd[1] == str(port) and rd[2] == user:
            ltokenFile.close()
            return rd[3]
    ltokenFile.close()


def deleteView(url, user, name, project, action):
    values = {"project": project, "name": name, "user": user, "action": action}
    loginToken = getToken(host, port, user)
    if loginToken is not None:
        values["ltoken"] = loginToken
    data = urllib.urlencode(values)
    req = urllib2.Request(url, data)
    urllib2.urlopen(req)

host = "localhost"
port = 8080
user = getpass.getuser()
name = "Sample View"
project = "demosthenes"
action = "delete_view"
url = "http://%s:%d/review/api" % (host, port)
deleteView(url, user, name, project, action)
print "View deleted!"

Example: Print the list of modules

This example shows how to print the list of modules.

import urllib, urllib2, json, sys, os.path, getpass

def getToken(host, port, user) :
  ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
  ltokenFile = open(ltoken, 'r')
  for r in ltokenFile :
    rd = r.strip().split(';')
    if rd[0] == host and rd[1] == str(port) and rd[2] == user :
      ltokenFile.close()
      return rd[3]
  ltokenFile.close()

class Module(object) :
  def __init__(self, attrs) :
    self.name = attrs["name"]

  def __str__(self) :
    result = "%s" % (self.name)
    return result

def from_json(json_object) :
  return Module(json_object)

def listModules(url, project, user, action) :
  values = {"project": project, "user": user, "action": action}
  loginToken = getToken(host, port, user)
  if loginToken is not None :
    values["ltoken"] = loginToken
  data = urllib.urlencode(values)
  req = urllib2.Request(url, data)
  response = urllib2.urlopen(req)
  result = []
  for record in response :
    result.append(json.loads(record, object_hook=from_json))
  return result

host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
action = "modules"
url = "http://%s:%d/review/api" % (host, port)

modules = listModules(url, project, user, action)
print "Existing modules:"
for module in modules :
  print module

Example: Create a module

This example shows how to create modules.

Note: If an access control method has been set, you must have the Project admin role to create and edit modules. In order to add or change access permissions on a module, you need the 'assign role' permission (which a Project admin has by default).

import urllib, urllib2, json, sys, os.path, getpass

def getToken(host, port, user) :
  ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
  ltokenFile = open(ltoken, 'r')
  for r in ltokenFile :
    rd = r.strip().split(';')
    if rd[0] == host and rd[1] == str(port) and rd[2] == user :
      ltokenFile.close()
      return rd[3]
  ltokenFile.close()

def createModule(url, user, project, name, action, allow_all, paths) :
  values = {"project": project, "user": user, "name": name, "action": action, "allow_all": allow_all, "paths": paths}
  loginToken = getToken(host, port, user)
  if loginToken is not None :
    values["ltoken"] = loginToken
  data = urllib.urlencode(values) 
  req = urllib2.Request(url, data)
  response = urllib2.urlopen(req)

host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
name = "mymodule"
action = "create_module"
allow_all = "true"
paths= "**/test/*"
url = "http://%s:%d/review/api" % (host, port)
createModule(url, user, project, name, action, allow_all, paths)
print "Module created!"

Example: Update a module

This example shows how to update a module.

Note: If an access control method has been set, you must have the Project admin role to create and edit modules. In order to add or change access permissions on a module, you need the 'assign role' permission (which a Project admin has by default).

import urllib, urllib2, json, sys, os.path, getpass

def getToken(host, port, user) :
  ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
  ltokenFile = open(ltoken, 'r')
  for r in ltokenFile :
    rd = r.strip().split(';')
    if rd[0] == host and rd[1] == str(port) and rd[2] == user :
      ltokenFile.close()
      return rd[3]
  ltokenFile.close()

def updateModule(url, user, project, name, new_name, action, allow_all) :
  values = {"project": project, "user": user, "name": name, "new_name": new_name, "action": action, "allow_all": allow_all}
  loginToken = getToken(host, port, user)
  if loginToken is not None :
    values["ltoken"] = loginToken
  data = urllib.urlencode(values)
  req = urllib2.Request(url, data)
  response = urllib2.urlopen(req)

host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
name = "mymodule"
new_name = "mymodule2"
action = "update_module"
allow_all = "false"
url = "http://%s:%d/review/api" % (host, port)
updateModule(url, user, project, name, new_name, action, allow_all)
print "Module updated!"

Example: Delete a module

This example shows how to delete modules.

Note: If an access control method has been set, you must have the Project admin role to create and edit modules. In order to add or change access permissions on a module, you need the 'assign role' permission (which a Project admin has by default).

import urllib, urllib2, json, sys, os.path, getpass

def getToken(host, port, user) :
  ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
  ltokenFile = open(ltoken, 'r')
  for r in ltokenFile :
    rd = r.strip().split(';')
    if rd[0] == host and rd[1] == str(port) and rd[2] == user :
      ltokenFile.close()
      return rd[3]
  ltokenFile.close()

def deleteModule(url, user, name, project, action) :
  values = {"project": project, "name": name, "user": user, "action": action}
  loginToken = getToken(host, port, user)
  if loginToken is not None :
    values["ltoken"] = loginToken
  data = urllib.urlencode(values)
  req = urllib2.Request(url, data)
  response = urllib2.urlopen(req)

host = "localhost"
port = 8080
user = getpass.getuser()
name = "mymodule"
project = "demosthenes"
action = "delete_module"
url = "http://%s:%d/review/api" % (host, port)
deleteModule(url, user, name, project, action)
print "Module deleted!"

Example: Print the list of builds

This example shows how to print the list of builds. For information on build management, see Managing integration builds.

import urllib, urllib2, json, sys, os.path, getpass, time

def getToken(host, port, user):
    ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
    ltokenFile = open(ltoken, 'r')
    for r in ltokenFile:
        rd = r.strip().split(';')
        if rd[0] == host and rd[1] == str(port) and rd[2] == user:
            ltokenFile.close()
            return rd[3]
    ltokenFile.close()


class Build(object):
    def __init__(self, attrs):
        self.id = attrs["id"] # build id
        self.name = attrs["name"] # build name
        self.date = time.ctime(attrs["date"] / 1000) # build date
        self.keepit = attrs["keepit"] # sticky flag

    def __str__(self):
        result = "%s: %s" % (self.name, self.date)
        return result


def from_json(json_object):
    return Build(json_object)


def report(url, project, user, action):
    values = {"project": project, "user": user, "action": action}
    loginToken = getToken(host, port, user)
    if loginToken is not None:
        values["ltoken"] = loginToken
    data = urllib.urlencode(values)
    req = urllib2.Request(url, data)
    response = urllib2.urlopen(req)
    result = []
    for record in response:
        result.append(json.loads(record, object_hook=from_json))
    return result

host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
action = "builds"
url = "http://%s:%d/review/api" % (host, port)

builds = report(url, project, user, action)
print "Existing builds:"
for build in builds:
    print build

Example: Specify which builds to keep

This example specifies that every second build will not be deleted by the auto-delete feature.

import urllib, urllib2, json, sys, os.path, getpass

def getToken(host, port, user) :
   ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
   ltokenFile = open(ltoken, 'r')
   for r in ltokenFile :
      rd = r.strip().split(';')
      if rd[0] == host and rd[1] == str(port) and rd[2] == user :
        ltokenFile.close()
        return rd[3]
   ltokenFile.close()

class Build(object) :
   def __init__(self, attrs) :
      self.id = attrs["id"]
      self.name = attrs["name"]
      self.date = attrs["date"]

   def __str__(self) :
      return "Id: %s Name:%s Date:%i" % (self.id, self.name, self.date)

def from_json(json_object) :
   return Build(json_object)

def keepit(build_name, loginToken):
   print "retain " + build_name
   values = {"project": project, "user": user, "action": "update_build", "name": build_name, "keepit" : "true"}
   if loginToken is not None :
      values["ltoken"] = loginToken
   data = urllib.urlencode(values)
   req = urllib2.Request(url, data)

   urllib2.urlopen(req)

def retain(url, project, user) :
   values = {"project": project, "user": user, "action": "builds"}
   loginToken = getToken(host, port, user)
   if loginToken is not None :
      values["ltoken"] = loginToken
   data = urllib.urlencode(values)
   req = urllib2.Request(url, data)
   response = urllib2.urlopen(req)

   i = 0
   for record in response :
      build = json.loads(record, object_hook=from_json)

      i += 1
      if not i % 2:
        keepit(build.name, loginToken)


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
url = "http://%s:%d/review/api" % (host, port)

retain(url, project, user)

Example: Delete a build

This example shows how to delete builds. For information on build management, see Managing integration builds.

import urllib, urllib2, json, sys, os.path, getpass

def getToken(host, port, user):
    ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
    ltokenFile = open(ltoken, 'r')
    for r in ltokenFile:
        rd = r.strip().split(';')
        if rd[0] == host and rd[1] == str(port) and rd[2] == user:
            ltokenFile.close()
            return rd[3]
    ltokenFile.close()


def deleteBuild(url, user, project, build, action):
    values = {"project": project, "name": build, "user": user, "action": action}
    loginToken = getToken(host, port, user)
    if loginToken is not None:
        values["ltoken"] = loginToken
    data = urllib.urlencode(values)
    req = urllib2.Request(url, data)
    urllib2.urlopen(req)

host = "localhost"
port = 8080
user = getpass.getuser()
build = "Sample Build"
project = "demosthenes"
build = "demosthenes_3"
action = "delete_build"
url = "http://%s:%d/review/api" % (host, port)
deleteBuild(url, user, project, build, action)
print "Build deleted!"

Example: Print a list of enabled checkers

This example shows how to print a list of enabled checkers.

import urllib, urllib2, json, sys, os.path, getpass

def getToken(host, port, user) :
  ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
  ltokenFile = open(ltoken, 'r')
  for r in ltokenFile :
    rd = r.strip().split(';')
    if rd[0] == host and rd[1] == str(port) and rd[2] == user :
      ltokenFile.close()
      return rd[3]
  ltokenFile.close()

class View(object) :
  def __init__(self, attrs) :
	self.code = attrs["code"]
	self.name = attrs["name"]
	self.enabled = attrs["enabled"]
	self.severity = attrs["severity"]

  def __str__(self) :
    result = "Code: %s\nName: %s\nEnabled: %s\nSeverity: %s\n" % (self.code, self.name, self.enabled, self.severity)
    return result

def from_json(json_object) :
  return View(json_object)

def report(url, project, user, action) :
  values = {"project": project, "user": user, "action": action}
  loginToken = getToken(host, port, user)
  if loginToken is not None :
    values["ltoken"] = loginToken
  data = urllib.urlencode(values)
  req = urllib2.Request(url, data)
  response = urllib2.urlopen(req)
  result = []
  for record in response :
    result.append(json.loads(record, object_hook=from_json))
  return result

host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
action = "defect_types"
url = "http://%s:%d/review/api" % (host, port)

defects = report(url, project, user, action)
print "Defect types:"
for defect in defects :
  print defect

Example: Enable and disable checkers

This example shows how to enable and disable checkers.

import urllib, urllib2, json, sys, os.path, getpass

def getToken(host, port, user) :
  ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
  ltokenFile = open(ltoken, 'r')
  for r in ltokenFile :
    rd = r.strip().split(';')
    if rd[0] == host and rd[1] == str(port) and rd[2] == user :
      ltokenFile.close()
      return rd[3]
  ltokenFile.close()

def set_defect(url, project, user, action, code, enabled, severity) :
  values = {"project": project, "user": user, "action": action, "code": code, "enabled": enabled, "severity": severity}
  loginToken = getToken(host, port, user)
  if loginToken is not None :
    values["ltoken"] = loginToken
  data = urllib.urlencode(values)
  req = urllib2.Request(url, data)
  response = urllib2.urlopen(req)

host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
action = "update_defect_type"
code = "VOIDRET"
enabled = "True"
severity = "1"
url = "http://%s:%d/review/api" % (host, port)

set_defect(url, project, user, action, code, enabled, severity)
print "Defect type %s updated!\nEnabled: %s\nSeverity: %s" % (code, enabled, severity)


Example: Report metrics

The following example reports the number of lines of commented and non-commented lines, the number of executable statements, the maximum nesting level, and cyclomatic complexity metrics for each file in project from last build.

See the Klocwork Metrics Reference for a list of valid metric codes.

import urllib, urllib2, json, sys, os.path, getpass

def getToken(host, port, user) :
    ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
    ltokenFile = open(ltoken, 'r')
    for r in ltokenFile :
        rd = r.strip().split(';')
        if rd[0] == host and rd[1] == str(port) and rd[2] == user :
            ltokenFile.close()
            return rd[3]
    ltokenFile.close()
 
class Metric(object) :
    def __init__(self, attrs) :
        self.file = attrs["filePath"]
        self.entity = attrs["entity"]
        self.tag = attrs["tag"]
        self.value = attrs["metricValue"]

    def __str__(self) :
        return "%s;%s;%d" % (self.file, self.tag, self.value)

def from_json(json_object) :
    if 'filePath' in json_object :
        return Metric(json_object)
    return json_object
 
host = "localhost"
port = 8080
user = getpass.getuser()
project = "project"
url = "http://%s:%d/review/api" % (host, port)
values = {"project": project, "user": user, "action": "metrics"}
 
loginToken = getToken(host, port, user)
if loginToken is not None :
    values["ltoken"] = loginToken
 
values["query"] = "metric:+RNOEXSTAT,+LINESCOMM,+NCNBLOC_FILE,+RMAXLEVEL,+RCYCLOMATIC"
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
try:
    response = urllib2.urlopen(req)
    for record in response :
        print json.loads(record, object_hook=from_json)
except urllib2.HTTPError, error:
    sys.stderr.write('ERROR: %s\n' % str(error))
    sys.stderr.write('%s\n' % error.read())

Aggregated search results

By default, the metrics API generates results on a per file basis. To generate aggregated search results for all files in a given query, specify the aggregate flag with a value of true (default is false). The following example shows aggregated search results:

A query with the following values:

  • action=metrics
  • user=someone
  • query=metric:+LOC_FILE
  • project=demosthenes
  • aggregate=true

...returns the following aggregated results:

{"tag":"LOC_FILE","sum":8113.0,"min":3.0,"max":966.0,"entries":47}

Note: The aggregate flag is only really useful for data that has relative meaning. In other words, if a metric can be summed, or if max and min values can be determined.

About the following examples

This module (kwutil), which is used by the examples below, handles reading ltokens from your system. It has been made into a separate module for readability. Be sure to copy and paste the code below to create the kwutil module.

import socket, re, platform, os.path

def getToken(host, port, user):
    if host is "localhost":
        host = socket.gethostname()
    userHomePath = os.path.expanduser("~")
    if re.search("Windows", platform.platform()) != None:
        userHomePath = os.environ['UserProfile']
    ltoken = os.path.normpath(os.path.join(userHomePath, ".klocwork", "ltoken"))
    ltokenFile = open(ltoken, 'r')
    for r in ltokenFile:
        rd = r.strip().split(';')
        if rd[0] == socket.getfqdn(host) and rd[1] == str(port) and rd[2] == user:
            ltokenFile.close()
            return rd[3]
    ltokenFile.close()
    return None

Importing server settings, projects and code review

You can also use the API to import server settings, projects or code reviews via the command line. This can be done for each of these methods as follows:

To import server settings

The following example imports authentication configuration, permissions, custom metrics, reports definitions and e-mail subscription settings.

import urllib, urllib2, json, sys, os.path, getpass, time

import kwutil


def import_server_configuration(url, user, sourceURL, sourceAdmin, sourcePassword):
    values = {"action": "import_server_configuration",
              "user": user,
              "sourceURL": sourceURL,
              "sourceAdmin": sourceAdmin}
    if sourcePassword is not None:
        values["sourcePassword"] = sourcePassword
    loginToken = kwutil.getToken(host, port, user)
    if loginToken is not None:
        values["ltoken"] = loginToken
    data = urllib.urlencode(values)
    req = urllib2.Request(url, data)
    urllib2.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()

sourceURL = "http://oldhost:8080"
sourceAdmin = "old admin user name"
sourcePassword = None

url = "http://%s:%d/review/api" % (host, port)

try:
    import_server_configuration(url, user, sourceURL, sourceAdmin, sourcePassword)
    print "Imported server configuration!"
except urllib2.HTTPError, error:
    sys.stderr.write('ERROR: %s\n' % str(error))
    sys.stderr.write('%s\n' % error.read())

To import a project

The following example imports data collected by Insight for the specified project.

import urllib, urllib2, json, sys, os.path, getpass, time

import kwutil


def import_project(url, user, project, sourceURL, sourceAdmin, sourcePassword):
    values = {"action": "import_project",
              "user": user,
              "project": project,
              "sourceURL": sourceURL,
              "sourceAdmin": sourceAdmin}
    if sourcePassword is not None:
        values["sourcePassword"] = sourcePassword
    loginToken = kwutil.getToken(host, port, user)
    if loginToken is not None:
        values["ltoken"] = loginToken
    data = urllib.urlencode(values)
    req = urllib2.Request(url, data)
    urllib2.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()

project = "projectA"
sourceURL = "http://oldhost:8080"
sourceAdmin = "old admin user name"
sourcePassword = None

url = "http://%s:%d/review/api" % (host, port)

try:
    import_project(url, user, project, sourceURL, sourceAdmin, sourcePassword)
    print "Imported project!"
except urllib2.HTTPError, error:
    sys.stderr.write('ERROR: %s\n' % str(error))
    sys.stderr.write('%s\n' % error.read())

To check import status

You can use this API method to check the status of importing your server settings, project or code review.

import urllib, urllib2, json, time, os.path, getpass, re, platform, sys, socket

import kwutil


class ImportStatus(object):
    def __init__(self, project, attrs):
        self.project = project
        self.stage = attrs["stage"]
        self.progress = attrs["progress"]
        self.failed = attrs["failed"]
        self.hasWarnings = attrs["hasWarnings"]
        self.projectReady = attrs["projectReady"]
        self.complete = attrs["complete"]


    def __str__(self):
        return "Project: %s\n\tStage: %s | Progress: %s%% | Failed: %s | Warnings: %s | Project Ready: %s | Complete: %s" % (
            self.project, self.stage, self.progress, self.failed, self.hasWarnings, self.projectReady, self.complete)


def import_status(url, user):
    values = {"action": "import_status", "user": user}

    loginToken = kwutil.getToken(host, port, user)
    if loginToken is not None:
        values["ltoken"] = loginToken

    data = urllib.urlencode(values)
    req = urllib2.Request(url, data)

    response = urllib2.urlopen(req)
    importStatus = []

    for record in response:
        attrs = json.loads(record)
        for key in attrs.keys():
            importStatus.append(ImportStatus(key, attrs[key]))
    return importStatus


def import_project(url, user, project, sourceURL, sourceAdmin, sourcePassword=None, ):
    values = {"action": "import_project",
              "user": user,
              "project": project,
              "sourceURL": sourceURL,
              "sourceAdmin": sourceAdmin}

    if sourcePassword:
        values["sourcePassword"] = sourcePassword

    loginToken = kwutil.getToken(host, port, user)
    if loginToken is not None:
        values["ltoken"] = loginToken

    data = urllib.urlencode(values)
    req = urllib2.Request(url, data)
    urllib2.urlopen(req)


def wait_for_import(url, user, project):
    isTimeout = False
    TIME_OUT = time.time() + 60 * 20
    incomplete = [project]

    if len(incomplete) == 0:
        return

    while True:
        for status in import_status(url, user):
            if status.project != project:
                continue

            # If all operations are complete then exit the loop
            if len(incomplete) == 0:
                break

            if status.project in incomplete:
                isTimeout = time.time() > TIME_OUT

            if status.complete or status.failed:
                print status.stage
                incomplete.pop(incomplete.index(status.project))
                break
            elif isTimeout:
                print "Import of project '%s' took longer than expected." % status.project
                print "Check if import is still progressing."
                sys.exit(-1)

        # If all projects are complete then exit the loop
        if len(incomplete) == 0:
            break

        time.sleep(10)


host = "localhost"
port = 8080
user = getpass.getuser()

url = "http://%s:%d/review/api" % (host, port)

project = "demosthenes"
sourceURL = "http://oldhost:8080"
sourceAdmin = "old admin user name"

try:
    import_project(url, user, project, sourceURL, sourceAdmin)
    print "Import started"

    wait_for_import(url, user, project)
except urllib2.HTTPError, error:
    sys.stderr.write('ERROR: %s\n' % str(error))
    sys.stderr.write('%s\n' % error.read())

Checking the Klocwork Server version

This action allows you to retrieve the Klocwork Server version. Here is an example curl command for this action:

curl --data "action=version&user=myself&" http://jsmith.klocwork.com:8080/review/api

The follow listing shows sample output from this command:

    1 {
    2 majorVersion: "10.1"
    3 minorVersion: "1"
    4 }

Listing the statuses of all tasks running on the Klocwork Server

This action allows you to list the status of each task running on your Klocwork Server. Here is an example curl command for this action:

curl --data "action=task_status&user=myself&" http://jsmith.klocwork.com:8080/review/api

See also