Issue and metric API 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. The demosthenes sample project is only available when the entire Klocwork Server package is installed; it is not included with the Validate Server package. 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.

For additional information on request parameters, you can visit http(s)://<klocwork_server_host>:<klocwork_server_port>/review/api.

For most of the examples below, with the exception of printing the project list, you can specify a stream by including the full path in the project field. For example: project = "myProj/myStream1/subVariant"

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 that the Python examples in this topic provide simplified error handling, for example:

Copy
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:

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

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.

Copy
import os.path


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

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.

Copy
import getpass
import json
import time
import urllib.parse
import urllib.request

import kwutil


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.supportLevel = attrs["supportLevel"]
        self.supportLevelCode = attrs["supportLevelCode"]
        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) | Support Level: %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.supportLevel,
            self.supportLevelCode, 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"}

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

values["query"] = "severity:1-3"
data = urllib.parse.urlencode(values)
data = data.encode('utf-8')
req = urllib.request.Request(url, data)
response = urllib.request.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 component, grouped by state.

Copy
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import kwutil


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"}
    login_token = kwutil.get_token(host, port, user)
    if x is not None:
        values["x"] = x
    if y is not None:
        values["y"] = y
    if login_token is not None:
        values["ltoken"] = login_token
    if view is not None:
        values["view"] = view
    if xDrilldown != -1:
        values["xDrilldown"] = xDrilldown
    if yDrilldown != -1:
        values["yDrilldown"] = yDrilldown
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.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)

try:
    reports = report(url, project, user, "Component", "State")
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print(reports)

Example: Retrieve issue details

This example shows how to get details about a specified issue ID.

Copy
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import kwutil


class Details(object):
    def __init__(self, attrs):
        self.id = attrs["id"]
        self.code = attrs["code"]
        self.name = attrs["name"]
        self.location = attrs["location"]
        self.build = attrs["build"]
        self.severity = attrs["severity"]
        self.supportLevel = attrs["supportLevel"]
        self.owner = attrs["owner"]
        self.state = attrs["state"]
        self.status = attrs["status"]
        if "history" in attrs:
            self.history = attrs["history"]
        else:
            self.history = None
        if "xSync" in attrs:
            self.xsync = attrs["xsync"]
        else:
            self.xsync = None


    def __str__(self):
        result = "Id:%s, Code:%s, Name:%s, Location:%s, Build:%s, Severity:%s, Support Level%s, Owner:%s, State:%s, Status:%s, History:%s" % (
            self.id, self.code, self.name, self.location, self.build, self.severity, self.supportLevel, self.owner,
            self.state,
            self.status, self.history)
        if self.xsync is not None:
            result = result + ", XSyncInfo:%s" % self.xsync
        return result


def from_json(json_object):
    # print json_object
    return Details(json_object)


def report(url, user, action, project, id, xsync=None):
    values = {"user": user, "action": action, "project": project, "id": id}
    if xsync is not None:
        values['include_xsync'] = xsync
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.urlopen(req)
    result = []
    for record in response:
        # print "R:" ,record
        result.append(from_json(json.loads(record)))
    return result


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

try:
    issue_details = report(url, user, action, project, id, xsync)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Issue Details:")
    for details in issue_details:
        print(details)

Example: Retrieve CI issue details

This example shows how to get details about a specified CI issue ID.

Copy
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import kwutil


class Details(object):
    def __init__(self, attrs):
        self.id = attrs["id"]
        self.code = attrs["code"]
        self.name = attrs["name"]
        self.location = attrs["location"]
        self.build = attrs["build"]
        self.severity = attrs["severity"]
        self.supportLevel = attrs["supportLevel"]
        self.owner = attrs["owner"]
        self.status = attrs["status"]
        if "history" in attrs:
            self.history = attrs["history"]
        else:
            self.history = None
        if "xSync" in attrs:
            self.xsync = attrs["xsync"]
        else:
            self.xsync = None


    def __str__(self):
        result = "Id:%s, Code:%s, Name:%s, Location:%s, Build:%s, Severity:%s, Support Level%s, Owner:%s, State:%s, Status:%s, History:%s" % (
            self.id, self.code, self.name, self.location, self.build, self.severity, self.supportLevel, self.owner,
            self.state,
            self.status, self.history)
        if self.xsync is not None:
            result = result + ", XSyncInfo:%s" % self.xsync
        return result


def from_json(json_object):
    # print json_object
    return Details(json_object)


def report(url, user, action, project, id, ci_build_name):
    values = {"user": user, "action": action, "project": project, "id": id, "ci_build_name": ci_build_name}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.urlopen(req)
    result = []
    for record in response:
        # print "R:" ,record
        result.append(from_json(json.loads(record)))
    return result


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

try:
    ci_issue_details = report(url, user, action, project, id, ci_build_name)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Issue Details:")
    for details in ci_issue_details:
        print(details)

Example: Update issue status

This example shows how to change issue status, comment(s), owner(s), and bug tracker ID for any specified issues.

If you specify bug tracker ID, all other issue status values are ignored.
Copy
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import kwutil


class Status(object):
    def __init__(self, attrs):
        self.status_message = attrs["status_message"]

    def __str__(self):
        result = "Status message:%s" % self.status_message
        return result


def from_json(json_object):
    return Status(json_object)


def update_status(url, user, project, ids, status=None, comment=None, owner=None, bug_tracker_id=None):
    values = {'action': 'update_status', 'project': project, 'user': user, 'ids': ids}
    if status is not None:
        values['status'] = status
    if comment is not None:
        values['comment'] = comment
    if owner is not None:
        values['owner'] = owner
    if bug_tracker_id is not None:
        values['bug_tracker_id'] = bug_tracker_id
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.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()
url = "http://%s:%d/review/api" % (host, port)
project = "demosthenes"
id = "1"
status = "Fix"
comment = "Making a status change"
owner = "jsmith" # pass "unowned" to clear the owner

try:
    status_messages = update_status(url, user, project, id, status, comment, owner)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Update Status:")
    for message in status_messages:
        print(message)

Example: Print the project list

This example shows how to print the list of projects.

By default, the query returns a list of base projects only. You can also have the query show all base projects and streams by specifying the include_streams flag with a value of true (default is false). For example, include a query with the following values:

  • action=projects

  • user=someone

  • include_streams=true

...returns the following aggregate results:

{"id":"project1","name":"project1","creator":"someone","description":""}

{"id":"project1_sub1","name":"project1/sub1","creator":"someone","description":"","tags":["s"]}

{"id":"project1_sub2","name":"project1/sub1/sub2","creator":"someone","description":""}

Copy
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import kwutil


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}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.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)

try:
    projects = report(url, user, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Existing projects:")
    for project in projects:
        print(project)

Example: Update projects

This example shows how to update the name and description for a specified project.

Copy
import getpass
import urllib.error
import urllib.parse
import urllib.request

import kwutil


def update_project(url, name, user, action, description, new_name):
    values = {"name": name, "user": user, "action": action, "description": description, "new_name": new_name}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
name = "demosthenes"
action = "update_project"
description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
new_name = "demosthenes2"
url = "http://%s:%d/review/api" % (host, port)

try:
    update_project(url, name, user, action, description, new_name)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Project updated!")

You can also use this action to turn on auto-deletion of builds and set how many you would like to keep with the threshold parameter.

Copy
import getpass
import urllib.error
import urllib.parse
import urllib.request

import kwutil


def update_project(url, name, user, action, auto_delete_builds, auto_delete_threshold):
    values = {"name": name, "user": user, "action": action, "auto_delete_builds": auto_delete_builds,
              "auto_delete_threshold": auto_delete_threshold}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
name = "demosthenes"
action = "update_project"
auto_delete_builds = "true"
auto_delete_threshold = "30"
url = "http://%s:%d/review/api" % (host, port)

try:
    update_project(url, name, user, action, auto_delete_builds, auto_delete_threshold)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Project updated!")

Example: Create a project

This example shows how to create a new project.

Copy
import getpass
import urllib.error
import urllib.parse
import urllib.request

import kwutil


def create_project(url, name, user, action):
    values = {"name": name, "user": user, "action": action}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


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

try:
    create_project(url, name, user, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Project created!")

Example: Delete a project

This example shows how to delete a specified project.

Copy
import getpass
import urllib.error
import urllib.parse
import urllib.request

import kwutil


def delete_project(url, name, force, user, action):
    values = {"name": name, "force": force, "user": user, "action": action}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


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

try:
    delete_project(url, name, force, user, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Project and its streams deleted!")

Example: Generate a Project Configuration report

This example shows how to generate a project configuration report for a specified project. The report displays project information such as creation date, Klocwork version and basic code metrics.
Copy
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import kwutil


class Config(object):
    def __init__(self, attrs):
        self.build = attrs["build"]
        self.creationDate = attrs["creationDate"]
        self.version = attrs["version"]
        self.numberOfFiles = attrs["numberOfFiles"]
        self.cFilesAnalyzed = attrs["cFilesAnalyzed"]
        self.systemFilesAnalyzed = attrs["systemFilesAnalyzed"]
        self.linesOfCode = attrs["linesOfCode"]
        self.linesOfComments = attrs["linesOfComments"]
        self.numberOfEntities = attrs["numberOfEntities"]
        self.numberOfFunctions = attrs["numberOfFunctions"]
        self.numberOfClasses = attrs["numberOfClasses"]
        self.taxonomies = attrs["taxonomies"]

    def __str__(self):
        result = "Build:%s, Creation Date:%s, Version:%s, Number of Files:%s, C Files Analyzed:%s, System Files Analyzed:%s, Lines of Code:%s, Lines of Comments:%s. Number of Entities:%s, Number of Functions:%s, Number of Classes:%s, Taxonomies:%s" % (
            self.build, self.creationDate, self.version, self.numberOfFiles, self.cFilesAnalyzed,
            self.systemFilesAnalyzed,
            self.linesOfCode, self.linesOfComments, self.numberOfEntities, self.numberOfFunctions, self.numberOfClasses,
            self.taxonomies)
        return result


def from_json(json_object):
    return Config(json_object)


def report(url, user, action, project, build=None):
    values = {"user": user, "action": action, "project": project}
    if build is not None:
        values['build'] = build
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.urlopen(req)
    result = json.loads(response.read(), object_hook=from_json)
    return result


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

try:
    result = report(url, user, action, project, build)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Project Configuration:")
    print(result)

Example: Print the list of views

This example shows how to print the list of views.

Copy
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import kwutil


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"}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.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)

try:
    views = report(url, project, user)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    for view in views:
        print(view)

Example: Create a view

This example shows how to create views.

Copy
import getpass
import urllib.error
import urllib.parse
import urllib.request

import kwutil


def create_view(url, user, project, name, action, query, tags):
    values = {"project": project, "user": user, "name": name, "action": action, "query": query, "tags": tags}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.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)
try:
    create_view(url, user, project, name, action, query, tags)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("View created!")

Example: Update views

This example shows how to update views.

Copy
import getpass
import urllib.error
import urllib.parse
import urllib.request

import kwutil


def update_view(url, user, project, name, newname, action, query, is_public, tags):
    values = {"project": project,
              "user": user,
              "name": name,
              "new_name": newname,
              "action": action,
              "query": query,
              "is_public": is_public,
              "tags": tags}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.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"
is_public = "true"
url = "http://%s:%d/review/api" % (host, port)
try:
    update_view(url, user, project, name, newname, action, query, is_public, tags)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("View updated!")

Example: Delete a view

This example shows how to delete views.

Copy
import getpass
import urllib.error
import urllib.parse
import urllib.request

import kwutil


def delete_view(url, user, name, project, action):
    values = {"project": project, "name": name, "user": user, "action": action}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.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)
try:
    delete_view(url, user, name, project, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("View deleted!")

Example: Print the list of modules

This example shows how to print the list of modules.

Copy
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import kwutil


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 list_modules(url, project, user, action):
    values = {"project": project, "user": user, "action": action}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.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)

try:
    modules = list_modules(url, project, user, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Existing modules:")
    for module in modules:
        print(module)

Example: Create a module

This example shows how to create modules.

If an access control method has been set, you must have the Project admin role or have the 'manage modules' permission 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).

Copy
import getpass
import urllib.error
import urllib.parse
import urllib.request

import kwutil


def create_module(url, user, project, name, action, allow_all, paths):
    values = {"project": project, "user": user, "name": name, "action": action, "allow_all": allow_all, "paths": paths}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.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)
try:
    create_module(url, user, project, name, action, allow_all, paths)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Module created!")

Example: Update a module

This example shows how to update a module.

If an access control method has been set, you must have the Project admin role or have the 'manage modules' permission 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).

Copy
import getpass
import urllib.error
import urllib.parse
import urllib.request

import kwutil


def update_module(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}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.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)
try:
    update_module(url, user, project, name, new_name, action, allow_all)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Module updated!")

Example: Delete a module

This example shows how to delete modules.

If an access control method has been set, you must have the Project admin role or have the 'manage modules' permission 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).

Copy
import getpass
import urllib.error
import urllib.parse
import urllib.request

import kwutil


def delete_module(url, user, name, project, action):
    values = {"project": project, "name": name, "user": user, "action": action}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
name = "mymodule"
project = "demosthenes"
action = "delete_module"
url = "http://%s:%d/review/api" % (host, port)
try:
    delete_module(url, user, name, project, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    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.

Copy
import getpass
import json
import time
import urllib.error
import urllib.parse
import urllib.request

import kwutil


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}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.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)

try:
    builds = report(url, project, user, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    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.

This action also allows you to toggle whether a specific build should be kept by specifying the 'keepit' option.

Copy
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import kwutil


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, login_token):
    print("retain " + build_name)
    values = {"project": project, "user": user, "action": "update_build", "name": build_name, "keepit": "true"}
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


def retain(url, project, user):
    values = {"project": project, "user": user, "action": "builds"}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.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, login_token)


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.

Copy
import getpass
import urllib.error
import urllib.parse
import urllib.request

import kwutil


def delete_build(url, user, project, build, action):
    values = {"project": project, "name": build, "user": user, "action": action}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
build = "demosthenes_3"
action = "delete_build"
url = "http://%s:%d/review/api" % (host, port)
try:
    delete_build(url, user, project, build, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Build deleted!")

Example: Create a CI build

This example shows how to create a CI build.

Copy
import getpass
import json
import time
import urllib.error
import urllib.parse
import urllib.request

import kwutil


class CiBuild(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

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


def from_json(json_object):
    return CiBuild(json_object)


def report(url, project, user, action):
    values = {"project": project, "user": user, "action": action}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.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 = "ci_builds"
url = "http://%s:%d/review/api" % (host, port)

try:
    ci_builds = report(url, project, user, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Existing Ci Builds:")
    for ci_build in ci_builds:
        print(ci_build)

Example: Update a CI build

This example shows how to update a CI build.

Copy
import getpass
import urllib.error
import urllib.parse
import urllib.request

import kwutil


def rename(url, user, action, project, old_ci_build_name, new_ci_build_name):
    values = {"user": user, "action": action, "project": project, "name": old_ci_build_name, "new_name": new_ci_build_name}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
url = "http://%s:%d/review/api" % (host, port)
action = "update_ci_build"
old_ci_build_name = "ci_build_1"
new_ci_build_name = "win-ci_build_1"


try:
    rename(url, user, action, project, old_ci_build_name, new_ci_build_name)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Ci Build successfully renamed")

Example: Delete a CI build

This example shows how to delete CI builds.

Copy
import getpass
import urllib.error
import urllib.parse
import urllib.request

import kwutil


def delete_build(url, user, project, build, action):
    values = {"project": project, "name": build, "user": user, "action": action}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
build = "ci_build_1"
action = "delete_ci_build"
url = "http://%s:%d/review/api" % (host, port)
try:
    delete_build(url, user, project, build, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Build deleted!")

Example: Print a list of enabled checkers

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

Copy
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import kwutil


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

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


def from_json(json_object):
    return View(json_object)


def report(url, project, user, action):
    values = {"project": project, "user": user, "action": action}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.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"
taxonomy = "C and C++"
url = "http://%s:%d/review/api" % (host, port)

try:
    defects = report(url, project, user, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Defect types:")
    for defect in defects:
        print(defect)

Example: Print a list of taxonomies

This example shows how to print a list of taxonomies.

Copy
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import kwutil


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

    def __str__(self):
        result = "Name: %s\nIs Custom: %s\n" % (self.name, self.is_custom)
        return result


def from_json(json_object):
    return View(json_object)


def report(url, project, user, action):
    values = {"project": project, "user": user, "action": action}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.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 = "taxonomies"
url = "http://%s:%d/review/api" % (host, port)

try:
    taxonomies = report(url, project, user, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Taxonomies:")
    for taxonomy in taxonomies:
        print(taxonomy)

Example: Enable and disable checkers

This example shows how to enable and disable checkers.

Copy
import getpass
import urllib.error
import urllib.parse
import urllib.request

import kwutil


def set_defect(url, project, user, action, code, enabled, severity):
    values = {"project": project, "user": user, "action": action, "code": code, "enabled": enabled,
              "severity": severity}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.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)

try:
    set_defect(url, project, user, action, code, enabled, severity)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    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.

Copy
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import kwutil


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 = "demosthenes"
url = "http://%s:%d/review/api" % (host, port)
values = {"project": project, "user": user, "action": "metrics"}

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

values["query"] = "metric:+RNOEXSTAT,+LINESCOMM,+NCNBLOC_FILE,+RMAXLEVEL,+RCYCLOMATIC"
data = urllib.parse.urlencode(values)
data = data.encode('utf-8')
req = urllib.request.Request(url, data)
try:
    response = urllib.request.urlopen(req)
    for record in response:
        print(json.loads(record, object_hook=from_json))
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.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 aggregate results:

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

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.

Excluding system files from search results

By default, the metrics API generates results based on all files. You can have the query omit system files by specifying the exclude_system_files flag with a value of true (default is false), for example:

A query with the following values:

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

Example curl request:

curl --data "action=metrics&user=someone&project=demosthenes&exclude_system_files=true&query=metric:%2bLOC_FILE&aggregate=true" http://localhost:8080/review/api

...returns the following results:

{"tag":"LOC_FILE","sum":322.0,"min":3.0,"max":68.0,"entries":13}

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.

Copy
import getpass
import urllib.error
import urllib.parse
import urllib.request

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
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.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 urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())

To import a project

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

Copy
import getpass
import urllib.error
import urllib.parse
import urllib.request

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
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.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 urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())

To check import status

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

Copy
import getpass
import json
import sys
import time
import urllib.error
import urllib.parse
import urllib.request

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}
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.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
    login_token = kwutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


def wait_for_import(url, user, project):
    is_timeout = 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:
                is_timeout = time.time() > TIME_OUT

            if status.complete or status.failed:
                print(status.stage)
                incomplete.pop(incomplete.index(status.project))
                break
            elif is_timeout:
                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 urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())

To check 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 }

To list 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