Start here

Home
About Klocwork
What's new
Fixed issues
Release notes
Installation

Reference

C/C++ checkers
Java checkers
C# checkers
MISRA C 2004 checkers
MISRA C++ 2008 checkers
MISRA C 2012 checkers
MISRA C 2012 checkers with Amendment 1
Commands
Metrics
Troubleshooting
Reference

Product components

C/C++ Integration build analysis
Java Integration build analysis
Desktop analysis
Refactoring
Klocwork Static Code Analysis
Klocwork Code Review
Structure101
Tuning
Custom checkers

Coding environments

Visual Studio
Eclipse for C/C++
Eclipse for Java
IntelliJ IDEA
Other

Administration

Project configuration
Build configuration
Administration
Analysis performance
Server performance
Security/permissions
Licensing
Klocwork Static Code Analysis Web API
Klocwork Code Review Web API

Community

View help online
Visit RogueWave.com
Klocwork Support
Rogue Wave Videos

Legal

Legal information

Using the search API

Code Review search allows users to generate lists of revisions, comments and actions based on search criteria. It also allows you to generate report-like summaries optionally filtered by search criteria.

Output is in JSON format with one record per line. The last line of all search requests will be a 'summary' JSON object:

For example, if you request a summary object for plain search, the summary line contains:

1 {"summary":{"query":"reviews:pending","item_count":28,"warnings":[]}}

Where

  • query - the query used to perform the search
  • item_count - the number of records returned
  • warnings - a list of warnings (parameter issues, search syntax)

Summary object for summary search:

1 {"summary" {"query":"reviews:pending","rows":1,"columns":1,"entity":"commits","x":"","sum":"","warnings":[]}}

Where

  • query - search query as above
  • rows, columns - the number of rows and columns returned in the table data
  • entity, x and sum - lists the selected entity type, x and sum values
  • warnings - list of warnings (parameter issues, search syntax, etc.)

Search results consist of one record per line. The record will be a JSON representation of a commit, comment or action.

Search summary results consist of tabular data (a JSON dictionary of dictionaries). You can only summarize on one of commits, comments, actions or reviews per request. For example:

  • entity=commits
1{"commits":{"commits":8}}
  • entity=commits&x=reviewer
1{"commits":{"reviewer":{"test1":2,"rsherk":1,"test4":2,"Nancy Jones":1,"test2":4,"test3":2}}}
  • entity=commits&x=committer&sum=reviewer
1{"reviewer":{"Nancy Jones":{"committer":{"adhocuser":0,"vzakaznikov":0,"Fred Smith":1}}}}

Usage:

  • Simple serach returning all entitites matching search query: action=search&query=*
  • Simple summary of commits: action=search&entity=commits
  • Summary of items matching search: action=search&query=reviews:pending&entity=commits
  • Summary of actions by author and state: action=search&entity=actions&x=author&sum=state

About the following examples

You can copy and paste and run 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 cut 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

Example: Assign tags

This example shows how to assign tags for selected revisions.

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

import kwutil


def assign_tags(url, user, tags, query):
    values = {"action": "assign_tags",
              "user": user,
              "tags": tags,
              "query": query}
    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()

tags = "tag1,tag2"
query = "revision:54321"

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

try:
    assign_tags(url, user, tags, query)
    print "Assigned tags!"
except urllib2.HTTPError, error:
    sys.stderr.write('ERROR: %s\n' % str(error))
    sys.stderr.write('%s\n' % error.read())

Example: List tags

This example shows how to list all tags associated with revisions.

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

import kwutil


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

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


def from_json(json_object):
    return Tag(json_object)


def list_tags(url, user):
    values = {"action": "list_tags",
              "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)
    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/codereview/api" % (host, port)

try:
    tags = list_tags(url, user)

    print "Listing tags:"
    for tag in tags:
        print tag
except urllib2.HTTPError, error:
    sys.stderr.write('ERROR: %s\n' % str(error))
    sys.stderr.write('%s\n' % error.read())

Example: Remove tags

This example shows how to remove a tag.

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

import kwutil

def remove_tag(url, user, tag_name):
    values = {"action": "remove_tag",
              "user": user,
              "name": tag_name}
    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()

tag = "tag1"

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

try:
    remove_tag(url, user, tag)
    print "Removed tag!"
except urllib2.HTTPError, error:
    sys.stderr.write('ERROR: %s\n' % str(error))
    sys.stderr.write('%s\n' % error.read())

Example: Rename a tag

This example shows how to rename a tag.

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


def rename_tag(url, user, name, new_name):
    values = {"action": "rename_tag",
              "user": user,
              "name": name,
              "new_name": new_name}
    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()

name = "tag1"
new_name = "tag2"

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

try:
    rename_tag(url, user, name, new_name)
    print "Renamed tag!"
except urllib2.HTTPError, error:
    sys.stderr.write('ERROR: %s\n' % str(error))
    sys.stderr.write('%s\n' % error.read())

Example: Unassign tags

This example shows how to unassign tags for selected revisions.

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

import kwutil


def unassign_tags(url, user, tags, query):
    values = {"action": "unassign_tags",
              "user": user,
              "tags": tags,
              "query": query}
    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()
tags = "tag1,tag2"
query = "revision:54321"

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

try:
    unassign_tags(url, user, tags, query)
    print "Unassigned tags!"
except urllib2.HTTPError, error:
    sys.stderr.write('ERROR: %s\n' % str(error))
    sys.stderr.write('%s\n' % error.read())

Example: Search for revisions, comments and actions

This example shows how to generate a list of revisions, comments and actions based on search criteria. You can also use it to generate report-like summaries optionally filtered by search criteria.

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

import kwutil


def search(url, user, query):
    values = {"action": "search",
              "user": user,
              "query": query}
    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)
    result = []
    for record in response:
        result.append(json.loads(record))
    return result

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

query = "type:commit commit_type:pre user:userA"

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

try: 
     results = search(url, user, query)
     for result in results:
         print result
except urllib2.HTTPError, error:
    sys.stderr.write('ERROR: %s\n' % str(error))
    sys.stderr.write('%s\n' % error.read())

To import a code review

The following example imports data collected by Code Review specified by projects and/or tag(s).

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

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_codereview(url, user, projects, sourceURL, sourceAdmin, sourcePassword, tagMapping, tags, untaggedProject):
    values = {"user": user,
              "action": "import_codereview",
              "projects": projects,
              "sourceURL": sourceURL,
              "sourceAdmin": sourceAdmin}

    if tags is not None:
        values["tags"] = tags

    if tagMapping is not None:
        values["tagMapping"] = tagMapping

    if untaggedProject is not None:
        values["untaggedProject"] = untaggedProject

    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)
    response = urllib2.urlopen(req)
    result = []
    for record in response:
        result.append(json.loads(record))

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 projects 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()

projects = "projectA"
sourceURL = "http://oldhost:8080"
sourceAdmin = "old admin user name"
sourcePassword = None
tagMapping = None
tags = None
untaggedProject = None

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

try:
    import_codereview(url, user, projects, sourceURL, sourceAdmin, sourcePassword, tagMapping, tags, untaggedProject)
    #Code review imports have a special project key: @codereview_sync
    wait_for_import(url, user, '@codereview_sync')
    print "Imported codereview!"
except urllib2.HTTPError, error:
    sys.stderr.write('ERROR: %s\n' % str(error))
    sys.stderr.write('%s\n' % error.read())

To get a revision ID

The following example shows you how to obtain a list of revision IDs from commits in your search results. These revision IDs are used when using the 'review', 'review_override', 'add_reviewers' and 'commit_details' actions below.

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

import kwutil

'''Get a list of <keyword keyref="shortCRprod"/> revision ids from commits in search results.
   Revision ids can be used with these API methods:
   review, review_override, add_reviewers and commit_details
'''
def get_revision_ids(url, user, query):
    values = {"action": "search",
              "user": user,
              "query": query}
    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)
    revision_ids = []
    for record in response:
        r = json.loads(record)
        print r['type']
        if 'type' in r and r['type'] == 'commit':
            revision_ids.append(r['item']['revision_id'])
    return revision_ids

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

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

try: 
    rids = get_revision_ids(url, user, "revision:111643")
    print str(rids)
except urllib2.HTTPError, error:
    sys.stderr.write('ERROR: %s\n' % str(error))
    sys.stderr.write('%s\n' % error.read())

To update a review state

The following example updates the review state for the specified revision(s).

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

import kwutil

def review(url, user, revision_id, state):
    values = {"action": "review",
              "user": user,
              "revision_id": revision_id,
              "state": state}
    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)
    result = []
    for record in response:
        result.append(json.loads(record))
    return result

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

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

'''Code Review revision id (as opposed to the SCM revision name)
   See get_revision_ids to see how to obtain revision_ids from search results'''
revision_id = 99650
state = "approve" #Can be either "approve" or "reject"

try: 
     results = review(url, user, revision_id, state)
     for result in results:
         print result
except urllib2.HTTPError, error:
    sys.stderr.write('ERROR: %s\n' % str(error))
    sys.stderr.write('%s\n' % error.read())

To override a review state

The following example overrides the review state for the specified revision(s).

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

import kwutil

def review(url, user, revision_id, state):
    values = {"action": "review_override",
              "user": user,
              "revision_id": revision_id,
              "state": state}
    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)
    result = []
    for record in response:
        result.append(json.loads(record))
    return result

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

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

'''Code Review revision id (as opposed to the SCM revision name)
   See get_revision_ids to see how to obtain revision_ids from search results'''
revision_id = 99650
state = "approve" #Can be, "approve", "reject" or "clear"

try: 
     results = review(url, user, revision_id, state)
     for result in results:
         print result
except urllib2.HTTPError, error:
    sys.stderr.write('ERROR: %s\n' % str(error))
    sys.stderr.write('%s\n' % error.read())

To add a reviewer to a code review

The following example adds a reviewer to the specified revision(s).

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

import kwutil

def review(url, user, revision_id, users):
    values = {"action": "add_reviewers",
              "user": user,
              "revision_id": revision_id,
              "users": ",".join(users)}
    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)
    result = []
    for record in response:
        result.append(json.loads(record))
    return result

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

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

'''Code Review revision id (as opposed to the SCM revision name)
   See get_revision_ids to see how to obtain revision_ids from search results'''
revision_id = 99650
users = ["jsmith", "epresly"] #a list of reviewer names

try: 
     results = review(url, user, revision_id, users)
     for result in results:
         print result
except urllib2.HTTPError, error:
    sys.stderr.write('ERROR: %s\n' % str(error))
    sys.stderr.write('%s\n' % error.read())

To check the details of a commit

The following example outputs a detailed view of a specified commit.

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

import kwutil

def review(url, user, revision_id, review_report):
    values = {"action": "commit_details",
              "user": user,
              "revision_id": revision_id,
              "review_report": review_report}
    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)
    result = []
    for record in response:
        result.append(json.loads(record))
    return result

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

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

'''Code Review revision id (as opposed to the SCM revision name)
   See get_revision_ids to see how to obtain revision_ids from search results'''
revision_id = 99650
review_report = False #Set to True to display related file revisions and reviews for each file

try: 
     results = review(url, user, revision_id, review_report)
     for result in results:
         print result
except urllib2.HTTPError, error:
    sys.stderr.write('ERROR: %s\n' % str(error))
    sys.stderr.write('%s\n' % error.read())