Package tlib :: Package base :: Module JiraModerator
[hide private]
[frames] | no frames]

Source Code for Module tlib.base.JiraModerator

  1  from jira.client import JIRA 
  2  from jira.exceptions import JIRAError 
  3  from requests import ConnectionError, HTTPError 
  4   
  5   
6 -class JiraModerator(object):
7 """ 8 Helper class to connect and manipulate the data in Jira 9 """ 10 11 client = None 12 clientOptions = {'server': 'https://issues.ypg.com'} #: conneciton options for Jira 13 username = "ypgAutoTester" #: Automation User username (QA Lead access to Jira) 14 password = "@ut0t3$t3r" #: Automation User password 15 logger = None #: logger to send loggin information to. 16 project = None 17
18 - def __init__(self, logger):
19 """ 20 Constructor for class 21 22 Args : 23 logger : (logger) instance of a logging object configured in testing project 24 25 """ 26 self.logger = logger
27
28 - def connect(self):
29 """ 30 Establishes a connection to our YPG Jira instance and assignes it to self.client 31 32 Returns : (bool) True if we are connected to Jira and False if we are not 33 34 """ 35 36 try: 37 self.client = JIRA(self.clientOptions, basic_auth=(self.username, self.password)) 38 self.client.session() 39 success = True 40 41 except ConnectionError, e: 42 self.logger.error("Error Connection to Jira :") 43 self.logger.error(e) 44 self.client = None 45 success = False 46 except HTTPError, e: 47 self.logger.error("Error Connection to Jira :") 48 self.logger.error(e) 49 self.client = None 50 success = False 51 52 return success
53
54 - def search_for_issue(self, query):
55 """ 56 Returns a list of issues that were returned by Jira given the query you specified 57 58 Args : (str) A string representation of a JQL query. anything you can enter in Jira advanced search can be 59 entered here. 60 61 Returns : (ResultList) a list of jira issues 62 """ 63 result_list = None 64 try: 65 result_list = self.client.search_issues(query) 66 67 except JIRAError, e: 68 self.logger.error("Could not search what you are looking for because " + str(e)) 69 70 if len(result_list) < 1: 71 issues = None 72 elif len(result_list) > 1: 73 self.logger.warn( 74 '''Jira found more than one issue with the search %s . You may want to manually verify 75 the automated process updated the correct issue." % query)''') 76 issues = result_list[0] 77 else: 78 issues = result_list[0] 79 return issues
80
81 - def confirm_version(self, proj_key, build_version):
82 """ 83 Confirms that the project version supplied actually exists in Jira for the specified project 84 85 Args : 86 projKey: (str) the Jira project acronym 87 buildVersion : (str) the version of the application you are testing 88 89 Returns : (bool) True if the version was found in Jira. False if the version was not found 90 """ 91 92 try: 93 # get all the versions for the specified project from Jira 94 project = self.client.project(proj_key) 95 proj_versions = project.versions 96 97 # search for the version we are testing. Is it in Jira? 98 for version in proj_versions: 99 100 if str(version.name) == str(build_version): 101 self.logger.debug("Matched the specidied buildVersion runtime parameter to version in Jira") 102 if not version.released and not version.archived: 103 self.logger.debug( 104 "We are going to start to test build version " + version.name + " for project " + proj_key) 105 return True 106 else: 107 self.logger.warn( 108 '''The buildVersion you are searching for has been released or archived in Jira 109 and is not a valid testable build version''') 110 return False 111 except JIRAError: 112 self.logger.error( 113 "Could not retrieve the projects versions. Check that the project exists or that Jira is not down") 114 return False
115
116 - def get_required_fields(self, project_key):
117 """ 118 Fetches a list of fields that require values to open a new issue in a specified project 119 120 Args : (str) The Jira project acronym for the project you are querying 121 122 Returns : (dict) a dictionary containing the required fields and None values for each. Returns empty dict if 123 search failed. 124 """ 125 126 req_fields = {} 127 128 try: 129 # Get a list of fields that are required to supply values for so that an issue can be created 130 meta = self.client.createmeta(projectKeys=project_key, expand='projects.issuetypes.fields') 131 132 fields = meta['projects'][0]['issuetypes'][0]['fields'] 133 134 for field in fields: 135 if fields[field]['required']: 136 req_fields[field] = None 137 138 except JIRAError, e: 139 self.logger.error("Could not get required fields for Jira project " + project_key + " because " + str(e)) 140 except IndexError, e: 141 self.logger.error("Could not get required fields for Jira project " + project_key + " because " + str(e)) 142 143 return req_fields
144
145 - def create_issue(self, data):
146 """ 147 Creates an issue in Jira with the dictionary of data supplied. Be sure that data contains all required 148 fields before using this. 149 150 Args : (dict) dictionary of required fields and valid values 151 152 Returns : (bool) returns True if issues was created and False if there was a failure 153 """ 154 155 try: 156 self.client.create_issue(fields=data) 157 success = True 158 159 except JIRAError, e: 160 success = False 161 self.logger.error("Issue was not created :" + str(e)) 162 163 return success
164
165 - def reopen_bug(self, issue, proj_key, version):
166 """ 167 Transitions a specified jira Bug from any resolved state back to In Review and assigns it to the 168 project lead with comments 169 170 Args : 171 issue : (issue) an issue object that came from Jira. Use searchForIssue first before reopening issues 172 proj_key : (str) the Jira project acronym from Jira 173 version : (str) the build number currently under test where the bug was rediscovered 174 175 Returns : (bool) returns False if we could not reopen issue and True if we could 176 """ 177 cur_state = issue.fields.status.name 178 179 transitions = self.client.transitions(issue) 180 181 project = self.client.project(proj_key) 182 proj_lead = project.lead.name 183 184 version = version 185 186 comment = "This issue has reoccured in the latest version %s" % version 187 188 try: 189 if cur_state == "Closed": 190 self.client.transition_issue(issue, self.get_transition_id(transitions, "Re-Open"), 191 assignee={'name': proj_lead}) 192 self.client.add_comment(issue, comment) 193 elif cur_state == "Ready for QA": 194 self.client.transition_issue(issue, self.get_transition_id(transitions, "Back to In Development"), 195 assignee={'name': proj_lead}) 196 self.client.add_comment(issue, comment) 197 elif cur_state == "In Testing": 198 self.client.transition_issue(issue, self.get_transition_id(transitions, "Fail"), 199 assignee={'name': proj_lead}) 200 self.client.add_comment(issue, comment) 201 elif cur_state == "Ready to Deploy": 202 self.client.transition_issue(issue, self.get_transition_id(transitions, "Back to In Testing")) 203 transitions = self.client.transitions(issue) 204 self.client.transition_issue(issue, self.get_transition_id(transitions, "Fail"), 205 assignee={'name': proj_lead}) 206 self.client.add_comment(issue, comment) 207 except IndexError: 208 self.logger.error("Could not find a transition to reopen the issue '" + issue.key + "'") 209 return False 210 except JIRAError, e: 211 self.logger.error("Jira returned error when modifying issue '" + issue.key + "' because " + str(e)) 212 return False 213 214 return True
215 216 #noinspection PyMethodMayBeStatic
217 - def get_transition_id(self, trans_dict, trans_name):
218 """ 219 Fetch the id for a transition's name 220 221 Args : 222 trans_dict : (dict) a dictionary of transitions fetched from Jira for a given issue 223 trans_name : (str) name of the Jira transition you would like the id for 224 225 Returns : (str) a numeric id associtated to the transition name 226 """ 227 228 id_dict = [element['id'] for element in trans_dict if element['name'] == trans_name] 229 return id_dict[0]
230 231 #noinspection PyMethodMayBeStatic
232 - def prepare_issue_data(self, req_fields, test_id, project, summary, description, component, severity, version):
233 """ 234 Constructs a properly formatted dictionary of data to supply to Jira for opening an issue. Creates a bug 235 in the specified project After construction, it will validate the dictionary by checking if all required 236 fields are filled 237 238 Args : 239 req_fields : (dict) dictionary of jira project required fields. Construct the dict with getRequiredFields 240 test_id : (str)the name of the test cases found in the test case's decoreator in python or the name in Spiratest 241 project : (str) the Jira project acronym for the project you wish to open a bug inspect 242 summary : (str) the summary of the bug you wish to open 243 description : (str) the description of the bug you wish to open 244 component : (str) the component of the bug you wish to open 245 severity : (str) the severity of the bug you wish to open 246 version : (str) the affected version of the bug you wish to open 247 248 Returns : (dict) if the dictionary properly complies to all the required fields. 249 Returns emtpy dict if it does not. 250 251 """ 252 desc = '''This issue was created by YPG automated Test Case : %(test_id)s. \n \n The error is caused when 253 sending the following parameters to the API method in question : \n %(description)s''' % \ 254 {'description': description, 'test_id': test_id} 255 256 req_fields['project'] = {'key': project} 257 req_fields['summary'] = summary 258 req_fields['description'] = desc 259 req_fields['issuetype'] = {'name': 'Bug'} 260 req_fields['customfield_10411'] = {'value': severity} 261 req_fields['components'] = [{'name': component}] 262 req_fields['versions'] = [{'name': version}] 263 264 # if any of the required fields are not filled erase the dict 265 if None in req_fields.values(): 266 req_fields = {} 267 268 return req_fields
269