Creating the Python script
The Python script for bug system integration is called review_action.py. This script needs to
- identify your bug tracking system
- define the actions that need to take place for the integration
- specify the issue information you want to send to the bug tracker
Optionally, you can also
- customize the text for the 'Create a ticket' button to appear on the issue details page
- display a hyperlink on the issue details page to the bug entry in your bug tracking system, as well as showing comments from the bug tracker
- include diagnostic messages in your script
Example: Creating a connection to Bugzilla
Requirement: In order to fully run this example, you will need to include an external Python JSON library in order to de-serialize and parse the JSON object. You can find a working implementation of the library used in our example here: http://sourceforge.net/projects/json-py/ Alternatively, you can use a different third-party Python JSON library.
In this example, the Python script specifies a connection to the open-source bug tracking system Bugzilla when the user clicks the 'Send to Bugzilla' button in Static Code Analysis. As is typical for the review_action.py script, it defines the issue data that should be sent to Bugzilla, such as the issue ID, the checker that found the issue, the checker message, and the issue's URL. (For a list of the predefined variables for the script, see Using predefined variables.)
The script also includes definition #ui.name to define the custom name for the button, Send to Bugzilla, instead of the default value (Create a ticket). The set_bug_id method specifies a link to Bugzilla, which will become a hyperlink to the issue's corresponding Bugzilla bug, and the success_msg method defines a diagnostic message.
The variable below for current_path is dependent on where you unpack your Python library.
import os.path, urllib, urllib2, getpass, sys, inspect, os, re import sys current_path = "<path to unpacked json script>" sys.path.append(current_path) import json #Button name #ui.name:Send to Bugzilla # Parse the project name based on the issue URL def getProjectName(): #Retrieve project name m = re.search('project=(\w*),', issue.url) project_name = m.group(1) return project_name # Send a request to Bugzilla REST API def bugzillaAPIRequest(proj_name): # URL with authentication information host = "https://api-dev.bugzilla.mozilla.org/test/latest/bug?username=prezioso@gmail.com&password=klocwork" # Bugzilla attributes product = "FoodReplicator" component = "Salt" version = "1.0" target = "---" summary = "%s | %s | %s | %s | %s | %s | %s" % (issue.id, issue.code, issue.severity, issue.severityCode, issue.status, issue.url, proj_name) op_sys = "Linux" platform = "All" # JSON object jdata = '''{"product": "%s", "component": "%s", "version": "%s", "target": "%s", "summary": "%s", "opsys": "%s", "platform": "%s"}''' % (product, component, version, target, summary, op_sys, platform) clen = len(jdata) # HTTP Request req = urllib2.Request(host, jdata, {'Content-Type': 'application/json', 'Accept': 'application/json', 'Content-Length': clen}) try: resp = urllib2.urlopen(req) except urllib2.URLError, e: success(e.code) # Expecting 201, resource created status code if (e.code is 201): content = e.read() string = str(content) obj = json.read(string) # Retrieving ref URL and the id ref=obj['ref'] id=obj['id'] set_bug_id(id) return "%s" % (ref) return "fail" proj_name = getProjectName() successmsg = bugzillaAPIRequest(proj_name) if (successmsg is "fail"): fail("\nERROR - HTTP POST REQUEST") successmsg = successmsg.decode('string_escape') success(successmsg)
After the script has been installed, the issue window looks like the following display, with the BUG ID field showing the hyperlink to the issue's Bugzilla entry.
Example: Integrating with Rational Team Concert
The following example provides a walkthrough of the steps you need to do in order to integrate your Klocwork environment with Rational Team Concert.
How to navigate RTC xml documents
To create a work item in RTC you must first identify the relevant URL and project key by requesting a series of xml documents from the RTC server . The steps will be similar to:
- Fetch the xml root services document from the RTC REST API: http(s)://yourRTCserver:port/ccm/rootservices
- Extract the Services Catalog URL which is the "rdf:resource" attribute in "oslc_cm:cmServiceProviders"
<oslc_cm:cmServiceProviders xmlns:oslc_cm="http://open-services.net/xmlns/cm/1.0/" rdf:resource="http(s):// yourRTCserver:port /ccm/oslc/workitems/catalog" />
- Find the relevant project’s service provider URL (attribute "rdf:resource" of element "oslc_disc:services") in the Service Catalog by identifying the project’s title (element dc:title of element oslc_disc:ServiceProvider). The URL contains a unique project key (e.g. _Day3sOHaEeO1tdkD6QbZUQ).
- Extract the appropriate service factory (<dc:title>Location for creation of change requests</dc:title> of element “oslc_cm:factory” of element “oslc_cm:changeRequests oslc” ) URL ("oslc_cm:url") from the service provider URL
<oslc_cm:changeRequests oslc_cm:version="1.0"> … <oslc_cm:factory> >dc:title<Location for creation of change requests>/dc:title< >oslc_cm:url< http(s):// yourRTCserver:port /ccm/oslc/contexts/_Day3sOHaEeO1tdkD6QbZUQ/workitems</oslc_cm:url> </oslc_cm:factory> … </oslc_cm:changeRequests>
- Post the work item to the factory URL. For example a JSON encoded work item could be:
{ "dc:title":"Klocwork ID 42: Suspicious dereference of pointer in function call before NULL check: cvs\\src\\checkin.c", "dc:description":"This issue was detected by Klocwork static code analysis. \n \t\t\nId: 42 URL: http(s)://yourKlocworkServer:port/review/kw-review.htm#issuedetails_goto:problemid=42,project=CVS,view_id=1 \nExported to RTC by: jchapman \n \nFile: cvs\\src\\checkin.c \n \nChecker: RNPD.CALL \nType: Suspicious dereference of pointer in function call before NULL check \nMessage: Suspicious dereference of pointer 'options' by passing argument 1 to function 'strcmp' at line 63 before NULL check at line 76 \nSeverity: Critical(1) \nStatus: Analyze \nState: Existing \nOwner: azukich \nLast Update: No Updates \nHistory: \n", "dc:type": "task", "oslc_cm:priority": " http(s):// yourRTCserver:port /ccm/oslc/enumerations/_Day3sOHaEeO1tdkD6QbZUQ/priority/priority.literal.l4" }
- If successful, the URL to the work item will in “Location” within the response header and the work item ID will be in the “dc:identifier” element of the response.
How to handle authentication
By default the RTC server is setup to use forms based authentication so it is necessary to look for an authentication response request when posting anything to the RTC server. For example:
req = urllib2.Request(targetUrl, data,{'Content-Type': 'application/json', 'Accept' : "application/xml"}) try : response = urllib2.urlopen(req) if 'X-com-ibm-team-repository-web-auth-msg' in response.info() and response.info()['X-com-ibm-team-repository-web-auth-msg'] == 'authrequired' : reqLogon = urllib2.Request(hostbase+"/j_security_check",urllib.urlencode({'j_username': str(rtc_username), 'j_password': str(rtc_password)}), {'Content-Type': 'application/x-www-form-urlencoded', 'Accept' : "application/json"}) response = urllib2.urlopen(reqLogon) if 'X-com-ibm-team-repository-web-auth-msg' in response.info() and response.info()['X-com-ibm-team-repository-web-auth-msg'] == 'authfailed' : fail("RTC logon failed") else : if data is not None: # if we posted data then we need to repost it response = urllib2.urlopen(req) except HTTPError, e: eData = str(e.read()) if hasattr(e, 'code'): if e.code == 201 :# 201 indicates success with a RTC response # process response elif e.code == 400 : # 400 indicated RTC rejected the request # process error message
How to handle field values
Field value enumerators (e.g. “oslc_cm:priority”) are defined on a per project basis and can be customized by the RTC administrator. To discover the configured values for a particular project, use your browser and the project’s unique project key to query the server. For example:
http(s):// yourRTCserver:port/ccm/oslc/enumerations/_Day3sOHaEeO1tdkD6QbZUQ/priority
Need help? Contact the Static Code Analysis Professional Services Team.
The Static Code Analysis Professional Services Team has experience creating basic scripts for Bugzilla, JIRA, and IBM Rational Team Concert. The scripts can be customized for your installation. Contact the Static Code Analysis Professional Services Team for help.
Customizing the 'Create a ticket' button
Placing the review_action.py script in the projects_root/config directory causes Static Code Analysis to display the 'Create a ticket' button on the issue details pages in Static Code Analysis for the project. (You may need to refresh the browser to see the link.) If you want to specify a different name for the button, add the following line to your script:
#ui.name:<my custom button>
For example:
#ui.name:Send to Bugzilla
After the script has been installed, the issue window shows the new button:
You can put Japanese characters in the button name by including UTF-8 encoding in the review_action.py script.
Including diagnostic messages
If the bug report is filed successfully when the 'Create a ticket' button is clicked, the 'Ticket created' message pops up on the Static Code Analysis window. If it fails, 'Bug reporting failed' appears. To provide custom diagnostic messages for success and failure, use these methods in the Python script:
- success(custom_message)
- fail(custom_message)
If you call the fail() method in the script, it will interrupt further script execution.
Placing the script in projects_root
When you've completed your review_action.py script, place it in the projects_root/config directory for the project.
Using predefined variables
For the review_action.py script, the following variables have been predefined:
variable.field | Usage |
---|---|
username | the name of the user who activated the script with the Create a ticket button |
issue | a Python object of class Issue containing information about the script in the following fields: |
issue.id | the identifier of the issue in Static Code Analysis |
issue.groupId | the identifier of the group that an issue belongs to in Static Code Analysis. A zero value indicates that group calculations are turned off and this variable should not be used. |
issue.name | the name of the issue from the Static Code Analysis issue details page |
issue.message | the checker message for the issue in Static Code Analysis |
issue.file | the file in which the issue occurs |
issue.code | the name of the checker that found that issue |
issue.severity | the severity of the issue in textual form (not numeric) |
issue.severityCode | the severity of the issue in numeric form |
issue.state | the state of the issue - Existing or Fixed |
issue.status | the status of the issue, such as Fix or Analyze |
issue.lastUpdateDate | the time of the last update in milliseconds |
issue.owner | the owner of the issue |
issue.project | the name of the Klocwork project |
issue.url | the URL of the issue in Static Code Analysis |
issue.history | an array with citing history events. Each event is an object of class StatusHistoryEvent with the following fields:
|
issue.bugTrackerId | the bug tracker ID of the issue in Static Code Analysis |