Using the search APICode 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
Summary object for summary search: 1 {"summary" {"query":"reviews:pending","rows":1,"columns":1,"entity":"commits","x":"","sum":"","warnings":[]}} Where
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:
1{"commits":{"commits":8}}
1{"commits":{"reviewer":{"test1":2,"rsherk":1,"test4":2,"Nancy Jones":1,"test2":4,"test3":2}}}
1{"reviewer":{"Nancy Jones":{"committer":{"adhocuser":0,"vzakaznikov":0,"Fred Smith":1}}}} Usage:
About the following examplesYou 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 tagsThis 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 tagsThis 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 tagsThis 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 tagThis 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 tagsThis 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 actionsThis 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 reviewThe 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 IDThe 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 stateThe 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 stateThe 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 reviewThe 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 commitThe 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())
|