There are some examples in Java and C# showing how to interact with RQM in this document. My preference was python. This post is a little example how to use python to interact with RQM server.
Motivation
It would be nice to have a python RQM client working like this.
from jazzclient import JazzClient
jazz = JazzClient('https://servername:9443/jazz','username','password')
workItemXml = jazz.getWorkItem('3934')
jazz.changeProgress('3934', '90')
jazz = JazzClient('https://servername:9443/jazz','username','password')
workItemXml = jazz.getWorkItem('3934')
jazz.changeProgress('3934', '90')
Interacting with the REST interface is easy via the httplib2 python module.
1. Authentication
consists of 3 steps (details on jazz.net here)
- requesting a "restricted resource"
- supplying credintials and getting togetherthe session ID
- requesting the "restricted resource" again, this time we should get it and confirm that our session is authenticated
All the authentication is done during construction, see bellow.
import urllib
import httplib2
from xml.dom.minidom import parse, parseString
from exceptions import Exception
class JazzClient(object):
def __init__(self, server_url, user, password):
self.base_url = server_url
self.http = httplib2.Http()
self.http.follow_redirects = True
self.headers = {'Content-type': 'text/xml'}
#1) before authentification one needs to go first to a "restricted resource"
resp, content = self.http.request( self.base_url + "/oslc/workitems/1.xml", 'GET', headers=self.headers)
#TODO sometimes returns capital X-
#TODO check before if the key is in dictionary, if not something is wrong as well
if resp['x-com-ibm-team-repository-web-auth-msg'] != 'authrequired':
raise Exception("something is wrong seems the server doesn't expect authentication!")
self.headers['Cookie']= resp['set-cookie']
self.headers['Content-type'] = 'application/x-www-form-urlencoded'
#2 now we can start the authentication via j_security_check page
resp, content = self.http.request(self.base_url+'/j_security_check' , 'POST', headers=self.headers,
body=urllib.urlencode({'j_username': user, 'j_password': password}))
#TODO check auth worked fine, if not throw exception
#3 get the requested resource - finish the authentication
resp, content = self.http.request( self.base_url + "/oslc/workitems/1.xml", 'GET', headers=self.headers)
import httplib2
from xml.dom.minidom import parse, parseString
from exceptions import Exception
class JazzClient(object):
def __init__(self, server_url, user, password):
self.base_url = server_url
self.http = httplib2.Http()
self.http.follow_redirects = True
self.headers = {'Content-type': 'text/xml'}
#1) before authentification one needs to go first to a "restricted resource"
resp, content = self.http.request( self.base_url + "/oslc/workitems/1.xml", 'GET', headers=self.headers)
#TODO sometimes returns capital X-
#TODO check before if the key is in dictionary, if not something is wrong as well
if resp['x-com-ibm-team-repository-web-auth-msg'] != 'authrequired':
raise Exception("something is wrong seems the server doesn't expect authentication!")
self.headers['Cookie']= resp['set-cookie']
self.headers['Content-type'] = 'application/x-www-form-urlencoded'
#2 now we can start the authentication via j_security_check page
resp, content = self.http.request(self.base_url+'/j_security_check' , 'POST', headers=self.headers,
body=urllib.urlencode({'j_username': user, 'j_password': password}))
#TODO check auth worked fine, if not throw exception
#3 get the requested resource - finish the authentication
resp, content = self.http.request( self.base_url + "/oslc/workitems/1.xml", 'GET', headers=self.headers)
2. Getting a first "WorkItem" in XML (getWorkItem)
Once we are authenticated it's just simple (follow the API documentation ). getWorkItem is method of JazzClient class.
def getWorkItem(self, itemNumber):
self.headers['Content-type'] = 'text/xml'
resp, content = self.http.request(self.base_url+'/oslc/workitems/'+ itemNumber +'.xml', 'GET', headers=self.headers)
if resp.status != 200:
raise Exception("JazzClient responce status != 200 !!!")
return content
resp, content = self.http.request(self.base_url+'/oslc/workitems/'+ itemNumber +'.xml', 'GET', headers=self.headers)
if resp.status != 200:
raise Exception("JazzClient responce status != 200 !!!")
return content
3. Changing progress field in a WorkItem (changeProgress )
Now a small example showing change of progress field in a WorkItem. Again following method belongs to above JazzClient class.
def changeProgress(self, itemNumber, progress):
changeRequest = """
<oslc_cm:changerequest xmlns:atom="http://www.w3.org/2005/Atom" xmlns:calm="http://jazz.net/xmlns/prod/jazz/calm/1.0/" xmlns:dc="http://purl.org/dc/terms/" xmlns:jd="http://jazz.net/xmlns/prod/jazz/discovery/1.0/" xmlns:jp="http://jazz.net/xmlns/prod/jazz/process/1.0/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:oslc_cm="http://open-services.net/xmlns/cm/1.0/" xmlns:oslc_disc="http://open-services.net/xmlns/discovery/1.0/" xmlns:oslc_qm="http://open-services.net/xmlns/qm/1.0/" xmlns:oslc_rm="http://open-services.net/xmlns/rm/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:rtc_cm="http://jazz.net/xmlns/prod/jazz/rtc/cm/1.0/">
<rtc_cm:progress>%s</rtc_cm:progress>
</oslc_cm:changerequest>"""% (progress)
self.headers['Content-type'] = 'text/xml'
resp, content = self.http.request(self.base_url+'/oslc/workitems/'+ itemNumber +'.xml' , 'PUT', headers=self.headers, body=changeRequest)
if resp.status != 200:
raise Exception("JazzClient.responce status != 200 !!!")
return content
changeRequest = """
<oslc_cm:changerequest xmlns:atom="http://www.w3.org/2005/Atom" xmlns:calm="http://jazz.net/xmlns/prod/jazz/calm/1.0/" xmlns:dc="http://purl.org/dc/terms/" xmlns:jd="http://jazz.net/xmlns/prod/jazz/discovery/1.0/" xmlns:jp="http://jazz.net/xmlns/prod/jazz/process/1.0/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:oslc_cm="http://open-services.net/xmlns/cm/1.0/" xmlns:oslc_disc="http://open-services.net/xmlns/discovery/1.0/" xmlns:oslc_qm="http://open-services.net/xmlns/qm/1.0/" xmlns:oslc_rm="http://open-services.net/xmlns/rm/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:rtc_cm="http://jazz.net/xmlns/prod/jazz/rtc/cm/1.0/">
<rtc_cm:progress>%s</rtc_cm:progress>
</oslc_cm:changerequest>"""% (progress)
self.headers['Content-type'] = 'text/xml'
resp, content = self.http.request(self.base_url+'/oslc/workitems/'+ itemNumber +'.xml' , 'PUT', headers=self.headers, body=changeRequest)
if resp.status != 200:
raise Exception("JazzClient.responce status != 200 !!!")
return content
Conclusion
With the REST api documentation and bit of python it is fun to interact with Jazz servers.
The above code of JazzClient class were tested so just copy&paste to use it.
Links
- RTC REST API v2.0
- RQM API - Data model of RQM
- RQM Using Poster - howto access RQM using Firefox Poster plugin d
- OSLC Workshop - Consumer & Producer labs
- RQMURLUtility - example java client for REST API including source code
Would you mind checking out this forum post about authenticating to Jazz via Python here: https://jazz.net/forums/viewtopic.php?t=20097 ... I updated your code to work with release 3.01...but it doesn't work.
OdpovědětVymazat