-
Notifications
You must be signed in to change notification settings - Fork 15
/
checkUnresolvedIssues.py
202 lines (177 loc) · 9.76 KB
/
checkUnresolvedIssues.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
from jira import JIRA
import magic, ast, urllib, requests, re, sys, os
from xml.dom import minidom
from optparse import OptionParser
from requests.auth import HTTPBasicAuth
import components
# 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
# Example usage:
#
# sprint="devex #136 August 2017"
# sprint_NEXT="devex #137 September 2017"
# versionWithRespin_jbt=4.5.1.AM1
# versionWithRespin_jbt_NEXT=4.5.1.AM2
# versionWithRespin_ds=11.2.0.AM1
# versionWithRespin_ds_NEXT=11.2.0.AM2
# python -W ignore checkUnresolvedIssues.py -S --jira https://issues.redhat.com \
# --jbt ${versionWithRespin_jbt} --jbt_NEXT ${versionWithRespin_jbt_NEXT} \
# --ds ${versionWithRespin_ds} --ds_NEXT ${versionWithRespin_ds_NEXT} \
# --sprint "${sprint}" --sprint_NEXT "${sprint_NEXT}"
usage = "Usage: python -W ignore %prog \\ \n\
--jbt <version_jbt> --ds <version_ds> --sprint <sprint> \\ \n\
--jbt_NEXT <version_jbt_NEXT> --ds_NEXT <version_ds_NEXT> --sprint_NEXT <sprint_NEXT> \\ \n\
--jira <JIRA server> --jirauser <JIRA user> --jirapwd <JIRA pwd>\n\
\n\
Optional flags:\n\
-S (skip validation of FixVersion values to save time) \n\
-A (automatically apply suggested changes) \n\
-X (to enable debugging) \n\
\n\
NOTE: rather than passing in --jirauser and --jirapwd, you can `export userpass=jirauser:jirapwd`, \n\
and this script will read those values from the shell\n\
\n\
This script will check for unresolved issues from the specified JBIDE/JBDS fixversions or sprint, \n\
then move them to the next fixversion or to the .x backlog, depending on if they're \n\
already queued for a future sprint or are blocker/critical."
parser = OptionParser(usage)
parser.add_option("--sprint", dest="sprint", help="Current Sprint, eg., 'devex #134 Jun 2017'")
parser.add_option("--sprint_NEXT",dest="sprint_NEXT", help="Future Sprint, eg., 'devex #135 July 2017'")
parser.add_option("--jbt", dest="version_jbt", help="Current JBIDE fix version")
parser.add_option("--jbt_NEXT", dest="version_jbt_NEXT", help="Next JBIDE fix version")
parser.add_option("--ds", dest="version_ds", help="Current JBDS fix version")
parser.add_option("--ds_NEXT", dest="version_ds_NEXT", help="Next JBDS fix version")
parser.add_option("--skipLabels", dest="skipLabels", help="To skip processing if a label is set, list label(s) to skip, eg., 'task, releasework'")
parser.add_option("--jira", dest="jiraserver", help="JIRA server, eg., https://issues.stage.redhat.com or https://issues.redhat.com")
parser.add_option("--jirauser", dest="jirauser", help="JIRA Username")
parser.add_option("--jirapwd", dest="jirapwd", help="JIRA Password")
# NOTE: rather than passing in two flags here, you can `export userpass=jirauser:jirapwd`,
# and this script will read those values from the shell
parser.add_option("-S", dest="skipVersionValidation", action="store_true", help="Skip validation of FixVersion values to save time")
parser.add_option("-A", dest="autoApplyChanges", action="store_true", help="If set, automatically apply proposed changes")
parser.add_option("-D", dest="dryrun", action="store_true", help="If set, just list the affected JIRAs, don't change them")
parser.add_option("-X", dest="debug", action="store_true", help="Debug output")
(options, args) = parser.parse_args()
if (not options.jirauser or not options.jirapwd) and "userpass" in os.environ:
# check if os.environ["userpass"] is set and use that if defined
#sys.exit("Got os.environ[userpass] = " + os.environ["userpass"])
userpass_bits = os.environ["userpass"].split(":")
options.jirauser = userpass_bits[0]
options.jirapwd = userpass_bits[1]
if \
not options.version_jbt or not options.version_jbt_NEXT or \
not options.version_ds or not options.version_ds_NEXT or \
not options.sprint or not options.sprint_NEXT or \
not options.jiraserver or not options.jirauser or not options.jirapwd:
parser.error("Must specify ALL required commandline flags")
jiraserver = options.jiraserver
jirauser = options.jirauser
jirapwd = options.jirapwd
debug = options.debug
components.debug = debug
version_jbt = options.version_jbt
version_jbt_NEXT = options.version_jbt_NEXT
fixversion_bits = version_jbt_NEXT.split(".")
version_jbt_DOTX = fixversion_bits[0]+"."+fixversion_bits[1]+".x"
version_ds = options.version_ds
version_ds_NEXT = options.version_ds_NEXT
fixversion_bits = version_ds_NEXT.split(".")
version_ds_DOTX = fixversion_bits[0]+".x"
sprint = options.sprint
sprint_NEXT = options.sprint_NEXT
sprintId = None # not used other than to verify the sprint exists
sprintId_NEXT = None # used to set a new sprint value
# define list of labels to skip
skipLabels = options.skipLabels.split(",") if options.skipLabels else ""
def missingFixversion(version_jbt, version_ds):
sys.exit("[ERROR] FixVersion does not exist. Go bug " + components.defaultAssignee() + " to get it created.")
sprintId = components.getSprintId(sprint, jiraserver, jirauser, jirapwd)
sprintId_NEXT = components.getSprintId(sprint_NEXT, jiraserver, jirauser, jirapwd)
if not options.skipVersionValidation:
if components.checkFixVersionsExist(version_jbt, version_ds, jiraserver, jirauser, jirapwd) == False:
missingFixversion(version_jbt, version_ds)
if components.checkFixVersionsExist(version_jbt_NEXT, version_ds_NEXT, jiraserver, jirauser, jirapwd) == False:
missingFixversion(version_jbt_NEXT, version_ds_NEXT)
if components.checkFixVersionsExist(version_jbt_DOTX, version_ds_DOTX, jiraserver, jirauser, jirapwd) == False:
missingFixversion(version_jbt_DOTX, version_ds_DOTX)
###################################################
def updateIssues(issuelist, NEXTorDOTX, description):
numExistingIssues = len(issuelist) if not issuelist == None else 0
if numExistingIssues > 0 :
if debug: print("[DEBUG] Move " + str(numExistingIssues) + " " + description)
jira = JIRA(options={'server':jiraserver}, basic_auth=(jirauser, jirapwd))
cnt = 0
for s in issuelist :
key = components.getText(components.findChildNodeByName(s, 'key').childNodes)
issue = jira.issue(key)
cnt += 1
doThisJIRA = True
whichLabelSkipped = ""
for label in issue.fields.labels:
for skipLabel in skipLabels:
if label == skipLabel.strip():
whichLabelSkipped = label
doThisJIRA = False
linkURL = components.getText(components.findChildNodeByName(s, 'link').childNodes)
summary = components.getText(components.findChildNodeByName(s, 'summary').childNodes).strip()
operation = " + [" + str(cnt) + "/" + str(len(issuelist)) + "] Update " + linkURL + " : " + summary
if debug: operation = operation + " :: " + str(issue.fields.labels)
if doThisJIRA == False:
operation = " - [" + str(cnt) + "/" + str(len(issuelist)) + "] -Skip- " + linkURL + " (" + whichLabelSkipped + ") : " + summary
print(operation)
else:
if options.autoApplyChanges or options.dryrun:
print(operation)
yesno = ""
else:
yesno = input(operation + " ? [y/N] ")
if options.autoApplyChanges or yesno.capitalize() in ["Y"]:
# move issue to next fixversion
if components.findChildNodeByName(s, 'project').attributes["key"].value == "JBIDE": # JBIDE or JBDS
fixversion = version_jbt
fixversion_NEXT = version_jbt_NEXT if NEXTorDOTX else version_jbt_DOTX
else:
fixversion = version_ds
fixversion_NEXT = version_ds_NEXT if NEXTorDOTX else version_ds_DOTX
fixVersions = []
# NOTE: if there is more than one fixversion, the others will not be changed
for version in issue.fields.fixVersions:
if version.name != fixversion:
fixVersions.append({'name': version.name})
fixVersions.append({'name': fixversion_NEXT})
issue.update(fields={'fixVersions': fixVersions})
# only for NEXT, not for .x
if NEXTorDOTX:
# move issue to new sprint
jira.add_issues_to_sprint(sprintId_NEXT, [key])
jira.add_comment(key, "[checkUnresolvedIssues.py] Slip to fixversion = *" + fixversion_NEXT + "* and sprint = *" + sprint_NEXT + "*")
else:
jira.add_comment(key, "[checkUnresolvedIssues.py] Slip to fixversion = *" + fixversion_NEXT + "*")
print("\n[INFO] [1] Check " + sprint + " + " + sprint_NEXT + ", JBIDE " + version_jbt + " + JBDS " + version_ds + \
", for unresolved blockers/criticals + issues in NEXT sprint: " + \
"move to NEXT sprint/milestone\n")
query = 'resolution = null AND ( \
( \
( (project = JBIDE AND fixVersion = "' + version_jbt + '") OR (project = JBDS AND fixVersion = "' + version_ds + '") ) \
AND \
sprint = "' + sprint_NEXT + '") OR \
(sprint = "' + sprint + '" AND priority in (blocker,critical)) \
)'
updateIssues(components.getIssuesFromQuery(query, jiraserver, jirauser, jirapwd), True, \
"issues to fixversion = " + version_jbt_NEXT + "/" + version_ds_NEXT + " and sprint = " + sprint_NEXT + " (" + sprintId_NEXT + ")")
# TODO should these be removed from the current sprint?
print("\n[INFO] [2] Check JBIDE " + version_jbt + " + JBDS " + version_ds + \
", for unresolved issues NOT in the next sprint: " + \
"move to .x\n")
query = 'resolution = null AND \
((project = JBIDE AND fixVersion = "' + version_jbt + '") OR (project = JBDS AND fixVersion = "' + version_ds + '")) AND \
(sprint is null OR sprint != "' + sprint_NEXT + '")'
updateIssues(components.getIssuesFromQuery(query, jiraserver, jirauser, jirapwd), False, \
"issues to fixversion = .x")