-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathcreateTestFailureJIRA.py
142 lines (116 loc) · 7.42 KB
/
createTestFailureJIRA.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
from jira import JIRA
import magic, ast, urllib, requests, re
from xml.dom import minidom
from optparse import OptionParser
from requests.auth import HTTPBasicAuth
# Requires jira (`pip install jira python-magic`), not jira-python - https://stackoverflow.com/questions/30915236/jira-python-package-in-pip-has-gone
# If connection to JIRA server fails with error: "The error message is __init__() got an unexpected keyword argument 'mime'"
# Then go edit /usr/lib/python2.7/site-packages/jira/client.py
# replace
# self._magic = magic.Magic(mime=True)
# with
# self._magic = magic
#
# ref: http://stackoverflow.com/questions/12609402/init-got-an-unexpected-keyword-argument-mime-in-python-django
usage = "Usage: %prog --affected <jbide version> --component <jbide component> --jira <JIRA server> --jirauser <JIRA user> --jirapwd <JIRA pwd> \
--test https://dev-platform-jenkins.rhev-ci-vms.eng.rdu2.redhat.com/job/<job_name>/<build_num>/testReport/ --testuser <user for test server> --testpwd <pwd for test server> \n\n\
This script will create 1 JBIDE JIRA for the specified component, reporting the test failure from the Test Server testReport URL"
parser = OptionParser(usage)
parser.add_option("-a", "--affected", dest="jbideversion", help="JBIDE Affected Version, eg., 4.1.1.Alpha1")
parser.add_option("-c", "--component", dest="component", help="JBIDE component, eg., server, seam2, openshift")
parser.add_option("-j", "--jira", dest="jiraserver", help="JIRA server, eg., https://issues.stage.redhat.com or https://issues.redhat.com")
parser.add_option("-k", "--jirauser", dest="usernameJIRA", help="JIRA Username")
parser.add_option("-l", "--jirapwd", dest="passwordJIRA", help="JIRA Password")
parser.add_option("-t", "--test", dest="testurl", help="URL of the test failure(s), eg., https://dev-platform-jenkins.rhev-ci-vms.eng.rdu2.redhat.com/job/jbosstools-server_41/113/testReport/")
parser.add_option("-u", "--testuser", dest="usernameTestServer", help="Test Server Username, eg., shortname")
parser.add_option("-v", "--testpwd", dest="passwordTestServer", help="Test Server Password, eg., kerberos pwd")
(options, args) = parser.parse_args()
if not options.jbideversion or not options.component or \
not options.jiraserver or not options.usernameJIRA or not options.passwordJIRA or \
not options.testurl or not options.usernameTestServer or not options.passwordTestServer:
parser.error("Must to specify ALL commandline flags")
jiraserver = options.jiraserver
jbide_affectedversion = options.jbideversion
from components import checkFixVersionsExist, queryComponentLead
if checkFixVersionsExist(jbide_affectedversion, None, jiraserver, options.usernameJIRA, options.passwordJIRA) == True:
component = options.component
testurl = options.testurl
## The jql query across for all testfailure issues
testfailuresearchquery = 'labels IN ("testfailure") AND project IN (JBIDE) AND affectedVersion IN ("' + jbide_affectedversion + '") AND component IN ("' + component + '")'
testfailuresearch = jiraserver + '/issues/?jql=' + urllib.quote_plus(testfailuresearchquery)
testfailuresearchlabel = 'Search for Test Failure JIRAs in JBIDE ' + jbide_affectedversion + ' for ' + component + ' component'
# result here is pretty-printed XML
def prettyXML(xml):
uglyXml = xml.toprettyxml(indent=' ')
text_re = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL)
out = text_re.sub('>\g<1></', uglyXml)
return out
def findChildNodeByName(parent, name):
for node in parent.childNodes:
if node.nodeType == node.ELEMENT_NODE and node.localName == name:
return node
return None
def getText(nodelist):
rc = []
for node in nodelist:
if node.nodeType == node.TEXT_NODE:
rc.append(node.data)
return ''.join(rc)
print "\n" + testfailuresearchlabel + ":\n\n * " + testfailuresearch + "\n"
# query JIRA for existing issues, or else find "No issues were found to match your search"
# https://issues.stage.jboss.org/sr/jira.issueviews:searchrequest-xml/temp/SearchRequest.xml?jqlQuery=labels+%3D+testfailure&tempMax=1000
q = requests.get(jiraserver + '/sr/jira.issueviews:searchrequest-xml/temp/SearchRequest.xml?tempMax=1000&jqlQuery=' + urllib.quote_plus(testfailuresearchquery), auth=HTTPBasicAuth(options.usernameJIRA, options.passwordJIRA), verify=False)
#print q.text
xml = minidom.parseString(q.text)
issuelist = xml.getElementsByTagName('item')
numExistingIssues = len(issuelist)
if numExistingIssues > 0 :
print "Found " + str(numExistingIssues) + " existing JIRAs:\n"
for s in issuelist :
print " * " + getText(findChildNodeByName(s, 'link').childNodes) + ": " + getText(findChildNodeByName(s, 'summary').childNodes).strip() + "\n"
accept = raw_input("Create new JIRA? [Y/n] ")
if accept.capitalize() not in ["N"] :
## get the XML or JSON content from the Jenkins test report page
payload = {'wrapper': 'failures', 'xpath': "//case[status='FAILED']"}
# print testurl
r = requests.get(testurl + "api/xml", auth=HTTPBasicAuth(options.usernameTestServer, options.passwordTestServer), params=payload, verify=False)
# print r.text
xml = minidom.parseString(r.text)
testcaselist = xml.getElementsByTagName('case')
failureSummary = '*' + str(len(testcaselist)) + ' Test Failure(s) in JBIDE ' + jbide_affectedversion + ' for ' + component + ' component:*\n\n' + testurl.strip() + '\n\n'
failureDetails = '\n\n[' + testfailuresearchlabel + '|' + testfailuresearch + ']\n\n-----\n'
for s in testcaselist :
className = getText(findChildNodeByName(s, 'className').childNodes)
className_re = re.sub(r'\.([a-zA-Z0-9_]+$)',"/\g<1>",className.strip())
name = getText(findChildNodeByName(s, 'name').childNodes)
name_re = re.sub(r'[\[\]]+',"_",name)
age = getText(findChildNodeByName(s, 'age').childNodes)
failureSummary = failureSummary + '# [' + className + '|' + testurl + '' + className_re + '/' + name_re + '] (failing for ' + age + ' builds)\n'
failureDetails = failureDetails + '* {color:red}' + className + " : " + name + '{color} (failing for ' + age + ' builds) \n \n '
failureDetails = failureDetails + '{code:title=' + testurl + '' + className_re + '/' + name_re + '}\n'
failureDetails = failureDetails + prettyXML(s)
failureDetails = failureDetails + '\n{code}\n\n'
#print failureDetails
rootJBIDE_dict = {
'project' : { 'key': 'JBIDE' },
'summary' : str(len(testcaselist)) + ' Test Failure(s) in JBIDE ' + jbide_affectedversion + ' for ' + component + ' component',
'description' : failureSummary + failureDetails,
'issuetype' : { 'name' : 'Task' },
'priority' : { 'name' :'Critical'},
'versions' : [{ "name" : jbide_affectedversion }],
'components' : [{ "name" : component }],
'labels' : [ "testfailure" ]
}
jira = JIRA(options={'server':jiraserver}, basic_auth=(options.usernameJIRA, options.passwordJIRA))
CLJBIDE = jira.project_components(jira.project('JBIDE')) # full list of components in JBIDE
rootJBIDE = jira.create_issue(fields=rootJBIDE_dict)
componentLead = queryComponentLead(CLJBIDE, component, 0)
try:
jira.assign_issue(rootJBIDE, componentLead)
except:
print "[WARNING] Unexpected error! User {0} tried to assign {1} to {2}: {3}".format(options.usernameJIRA, rootJBIDE, componentLead, sys.exc_info()[0])
accept = raw_input("\nAccept new JIRA " + jiraserver + '/browse/' + rootJBIDE.key + " => " + componentLead + " ? [Y/n] ")
if accept.capitalize() in ["N"] :
rootJBIDE.delete()
# see JIRA_components listing in components.py
# Sample usage: see createTestFailureJIRA.py.examples.txt