class HelpDesk: def __init__(self, domain='jira.fiware.org'): self.base_url = 'https://{}'.format(domain) self.user = JIRA_USER self.password = JIRA_PASSWORD options = {'server': self.base_url, 'verify': False} self.jira = JIRA(options=options, basic_auth=(self.user, self.password)) self.emailer = Emailer(log_level=DEBUG) self.enablersBook = find_enablersbook() self.nodesBook = find_nodesbook() self.chaptersBook = find_chaptersbook() self.n_assignments = 0 self.n_channeled = 0 self.n_removed = 0 self.n_renamed = 0 def _change_channel(self): query = 'project = HELP AND issuetype in (extRequest, Monitor) ' \ 'AND component in (FIWARE-TECH-HELP, FIWARE-LAB-HELP) and updated >= -1d' inrequests = sorted(self.jira.search_issues(query, maxResults=25), key=lambda item: item.key) # issues changed to LAB channel when node has been set up # HD node = issue.fields.customfield_11104 requests = filter( lambda x: x.fields.components[0].name == 'FIWARE-TECH-HELP', inrequests) condition = lambda x: x.fields.customfield_11104 and not \ x.fields.customfield_11103 and not \ x.fields.customfield_11105 and\ x.fields.customfield_11104.value != 'Unknown' for issue in filter(condition, requests): enabler = issue.fields.customfield_11105 if enabler and enabler.value != 'Unknown': continue chapter = issue.fields.customfield_11103 if chapter and chapter.value != 'Unknown': continue issue.update(fields={'components': [{'name': 'FIWARE-LAB-HELP'}]}) logging.info('update issue= {} - change to LAB channel') # issues changed to TECH channel when enabler or chapter has been set up # HD enabler = issue.fields.customfield_11105 requests = filter( lambda x: x.fields.components[0].name == 'FIWARE-LAB-HELP', inrequests) condition = lambda x: x.fields.customfield_11105 and not \ x.fields.customfield_11104 and \ x.fields.customfield_11105.value != 'Unknown' for issue in filter(condition, requests): node = issue.fields.customfield_11104 if node and node.value != 'Unknown': continue issue.update(fields={'components': [{'name': 'FIWARE-TECH-HELP'}]}) logging.info( 'update issue= {} - change to TECH channel'.format(issue)) # HD chapter = issue.fields.customfield_11103 condition = lambda x: x.fields.customfield_11103 and not \ x.fields.customfield_11104 and \ x.fields.customfield_11103.value != 'Unknown' for issue in filter(condition, requests): node = issue.fields.customfield_11104 if node and node.value != 'Unknown': continue issue.update(fields={'components': [{'name': 'FIWARE-TECH-HELP'}]}) logging.info( 'update issue= {} - change to TECH channel'.format(issue)) def _assign_tech_channel(self): query = 'project = HELP AND issuetype in (extRequest, Monitor) ' \ 'AND component = FIWARE-TECH-HELP AND status != Closed AND assignee = EMPTY and updated >= -1d' requests = sorted(self.jira.search_issues(query, maxResults=25), key=lambda item: item.key) # HD chapter = issue.fields.customfield_11103 # HD node = issue.fields.customfield_11104 # HD enabler = issue.fields.customfield_11105 # make fields visible with value 'Unknown' condition = lambda x: not x.fields.customfield_11103 and not \ x.fields.customfield_11104 and not \ x.fields.customfield_11105 for issue in filter(condition, requests): enabler_values = self.jira.editmeta( issue)['fields']['customfield_11105']['allowedValues'] enabler = next( filter(lambda x: x['value'] == 'Unknown', enabler_values)) chapter_values = self.jira.editmeta( issue)['fields']['customfield_11103']['allowedValues'] chapter = next( filter(lambda x: x['value'] == 'Unknown', chapter_values)) node_values = self.jira.editmeta( issue)['fields']['customfield_11104']['allowedValues'] node = next(filter(lambda x: x['value'] == 'Unknown', node_values)) issue.update( fields={ 'customfield_11103': chapter, 'customfield_11104': node, 'customfield_11105': enabler }) logging.info( 'update issue: issue= {} node={}, chapter={}, enabler={}'. format(issue, node['value'], chapter['value'], enabler['value'])) # assign issues whose enabler has been set up, chapter is also filled consistently # HD enabler = issue.fields.customfield_11105 condition = lambda x: x.fields.customfield_11105 and x.fields.customfield_11105.value != 'Unknown' for issue in filter(condition, requests): enabler = issue.fields.customfield_11105.value if enabler in self.enablersBook: chapter_values = self.jira.editmeta( issue)['fields']['customfield_11103']['allowedValues'] chapter = next( filter( lambda x: x['value'] == self.enablersBook[enabler][ 'chapter'], chapter_values)) if chapter: issue.update(fields={'customfield_11103': chapter}) component = self.jira.component( self.enablersBook[enabler]['component']) assignee = component.assignee.name self.jira.assign_issue(issue, assignee=assignee) logging.info( 'assign issue= {} enabler={} chapter={} assignee={}'. format(issue, enabler, chapter['value'], assignee)) else: message = 'Dear Help Desk Caretaker Admin,' +\ "\n\nPlease, have a look at '{}' Enabler " \ "because it wasn't found in the Enablers book.".format(enabler) +\ '\n\nThanks in advance for cooperation!!' +\ '\n\nKind Regards,' +\ '\nFernando' self.emailer.send_adm_msg( 'Unknown Enabler: {}'.format(enabler), message) # assign issues for chapter leaders, enabler field is not assigned # HD enabler = issue.fields.customfield_11105 # HD chapter = issue.fields.customfield_11103 condition = lambda x: x.fields.customfield_11103 and x.fields.customfield_11103.value != 'Unknown' for issue in filter(condition, requests): enabler = issue.fields.customfield_11105 if enabler and enabler.value != 'Unknown': continue chapter = issue.fields.customfield_11103.value if chapter in self.chaptersBook: component = self.jira.component( self.chaptersBook[chapter]['coordination_key']) assignee = component.assignee.name self.jira.assign_issue(issue, assignee=assignee) logging.info('assign issue= {} chapter={} assignee={}'.format( issue, chapter, assignee)) else: message = 'Dear Help Desk Caretaker Admin,' +\ "\n\nPlease, have a look at {} Chapter " \ "because it wasn't found in the Chapters book.".format(chapter) +\ '\n\nThanks in advance for cooperation!!' +\ '\n\nKind Regards,' +\ '\nFernando' self.emailer.send_adm_msg( 'Unknown Chapter: {}'.format(chapter), message) def _assign_lab_channel(self): query = 'project = HELP AND issuetype in (extRequest, Monitor) AND component = FIWARE-LAB-HELP ' \ 'AND status != Closed and assignee = EMPTY and updated >= -1d' requests = sorted(self.jira.search_issues(query, maxResults=25), key=lambda item: item.key) # HD chapter = issue.fields.customfield_11103 # HD node = issue.fields.customfield_11104 # HD enabler = issue.fields.customfield_11105 # make issues visible condition = lambda x: not x.fields.customfield_11103 and not \ x.fields.customfield_11104 and not \ x.fields.customfield_11105 for issue in filter(condition, requests): enabler_values = self.jira.editmeta( issue)['fields']['customfield_11105']['allowedValues'] enabler = next( filter(lambda x: x['value'] == 'Unknown', enabler_values)) node_values = self.jira.editmeta( issue)['fields']['customfield_11104']['allowedValues'] node = next(filter(lambda x: x['value'] == 'Unknown', node_values)) issue.update(fields={ 'customfield_11105': enabler, 'customfield_11104': node }) logging.info('update issue= {} node={} enabler={}'.format( issue, node['value'], enabler['value'])) # assign issues whose node has been set up # HD node = issue.fields.customfield_11104 condition = lambda x: x.fields.customfield_11104 and x.fields.customfield_11104.value != 'Unknown' for issue in filter(condition, requests): node = issue.fields.customfield_11104.value if node in self.nodesBook: assignee = self.nodesBook[node]['support'] self.jira.assign_issue(issue, assignee=assignee) logging.info('assign issue= {} node={} assignee={}'.format( issue, node, assignee)) else: message = 'Dear Help Desk Caretaker Admin,' +\ "\n\nPlease, have a look at {} Node because it wasn't found in the Enablers book.".format(node) +\ '\n\nThanks in advance for cooperation!!' +\ '\n\nKind Regards,' +\ '\nFernando' self.emailer.send_adm_msg('Unknown Node: {}'.format(node), message) def channel_requests(self): query = 'project = HELP AND issuetype = extRequest AND component = EMPTY' requests = sorted(self.jira.search_issues(query, maxResults=25), key=lambda item: item.key) for request in requests: summary = request.fields.summary if re.search(r'\[SPAM\]', summary): request.update(fields={'components': [{'name': 'SPAM'}]}) continue match = re.search(r'\[[^\]]+?\]', summary) if match: channel = match.group(0)[1:-1] if channel not in channels: continue request.update( fields={'components': [{ 'name': channels[channel] }]}) self.n_channeled += 1 if not request.fields.assignee: assignee = None if channel in ('Fiware-tech-help', 'Fiware-lab-help', 'SPAM') else '-1' self.jira.assign_issue(request, assignee) self.n_assignments += 1 logging.info('updated request {}, channel= {}'.format( request, channel)) def assign_requests(self): self._change_channel() self._assign_tech_channel() self._assign_lab_channel() def naming(self): query = 'project = HELP AND issuetype in (extRequest, Monitor) ' \ 'AND status = Closed and updated >= -1d AND component != EMPTY' issues = sorted(self.jira.search_issues(query, maxResults=25), key=lambda item: item.key) # name spam logging.info('====== SPAM =======') condition = lambda x: x.fields.components[0].name == 'SPAM' for issue in filter(condition, issues): if not re.match(r'SPAM\s=>', issue.fields.summary): summary = 'SPAM => ' + re.sub(r'\[[^\]]+?\]', '', issue.fields.summary.strip()) issue.update( fields={ 'summary': summary, 'customfield_11103': None, 'customfield_11104': None, 'customfield_11105': None }) logging.info('update issue:{} {}'.format(issue, summary)) # name othen channels than TECH and LAB _channels = '|'.join( ifilterfalse(lambda x: x in ('Tech', 'Lab'), keywords.values())) logging.info('====== other channels than Tech and Lab =======') condition = lambda x: x.fields.components[0].name in noTechChannels for issue in filter(condition, issues): try: issuetype = issuetypedict[issue.fields.issuetype.name] except Exception as e: logging.warning(e) issuetype = 'Unknown' chkeyword = keywords[issue.fields.components[0].name] pattern = r'FIWARE\.{}\.{}\.'.format(issuetype, chkeyword) # formato correcto if re.match(pattern, issue.fields.summary): continue # en canal equivocado gpattern = r'FIWARE\.{}\.({})\.'.format(issuetype, _channels) if re.match(gpattern, issue.fields.summary.strip()): summary = re.sub(r'\.({})\.'.format(_channels), chkeyword, issue.fields.summary).strip() else: summary = re.sub(r'\[[^\]]+?\]', '', issue.fields.summary.strip()) summary = re.sub(r'\.FIWARE\.(Request|Question)\.\w+\.', '', summary) summary = 'FIWARE.{}.{}.{}'.format(issuetype, chkeyword, summary) issue.update( fields={ 'summary': summary, 'customfield_11103': None, 'customfield_11104': None, 'customfield_11105': None }) logging.info('update issue:{} {}'.format(issue, summary)) self.n_renamed += 1 # name Lab channel # HD chapter = issue.fields.customfield_11103 # HD node = issue.fields.customfield_11104 # HD enabler = issue.fields.customfield_11105 logging.info('===== Lab channel ========') condition = lambda x: x.fields.components[0].name == 'FIWARE-LAB-HELP' # HD node = issue.fields.customfield_11104 for issue in filter(condition, issues): try: issuetype = issuetypedict[issue.fields.issuetype.name] except Exception as e: logging.warning(e) issuetype = 'Unknown' chunks = issue.fields.summary.strip().split('.') node = issue.fields.customfield_11104 nodeValue = node.value if node else 'Unknown' _channels = '|'.join(keywords.values()) if nodeValue != 'Unknown': pattern = r'FIWARE\.{}\.Lab\.{}\.'.format(issuetype, nodeValue) if re.match(pattern, issue.fields.summary): continue pattern = r'FIWARE\.{}\.({})\.{}\.'.format( issuetype, _channels, nodeValue) if re.match(pattern, issue.fields.summary): summary = '.'.join(chunks[0:2]) + '.Lab.' + '.'.join( chunks[3:]) else: summary = re.sub(r'\[[^\]]+?\]', '', issue.fields.summary).strip() summary = re.sub(r'FIWARE\.(Request|Question)\.\w+\.', '', summary) summary = 'FIWARE.{}.Lab.{}.{}'.format( issuetype, nodeValue, summary) issue.update( fields={ 'summary': summary, 'customfield_11103': None, 'customfield_11105': None }) else: pattern = r'FIWARE\.{}\.Lab\.'.format(issuetype) if re.match(pattern, issue.fields.summary): continue pattern = r'FIWARE\.{}\.({})\.'.format(issuetype, _channels) if re.match(pattern, issue.fields.summary): summary = '.'.join(chunks[0:2]) + '.Lab.' + '.'.join( chunks[3:]) else: summary = re.sub(r'\[[^\]]+?\]', '', issue.fields.summary).strip() summary = re.sub(r'FIWARE\.(Request|Question)\.\w+\.', '', summary) summary = 'FIWARE.{}.Lab.{}.'.format(issuetype, summary) issue.update( fields={ 'summary': summary, 'customfield_11103': None, 'customfield_11104': None, 'customfield_11105': None }) logging.info('update issue: {} {}'.format(issue, summary)) self.n_renamed += 1 # name Tech channel # HD chapter = issue.fields.customfield_11103 # HD node = issue.fields.customfield_11104 # HD enabler = issue.fields.customfield_11105 logging.info('===== Tech channel =======') condition = lambda x: x.fields.components[0].name == 'FIWARE-TECH-HELP' for issue in filter(condition, issues): chapter_values = self.jira.editmeta( issue)['fields']['customfield_11103']['allowedValues'] try: issuetype = issuetypedict[issue.fields.issuetype.name] except Exception as e: logging.warning(e) issuetype = 'Unknown' chunks = issue.fields.summary.strip().split('.') chapter = issue.fields.customfield_11103 enabler = issue.fields.customfield_11105 chapter_value = chapter.value if chapter else 'Unknown' enabler_value = enabler.value if enabler else 'Unknown' if enabler_value != 'Unknown': try: enablerkeyword = self.enablersBook[enabler_value][ 'backlog_keyword'] chapterkeyword = self.enablersBook[enabler_value][ 'chapter'] except KeyError: logging.exception( 'Unknown enabler {}'.format(enabler_value)) continue chapter = next( filter(lambda x: x['value'] == chapterkeyword, chapter_values)) pattern = r'FIWARE\.{}\.Tech\.{}\.{}\.'.format( issuetype, chapterkeyword, enablerkeyword) if re.match(pattern, issue.fields.summary): continue pattern = r'FIWARE\.{}\.({})\.{}\.{}\.'.format( issuetype, _channels, chapterkeyword, enablerkeyword) if re.match(pattern, issue.fields.summary): summary = '.'.join(chunks[0:2]) + '.Tech.' + '.'.join( chunks[3:]) else: summary = re.sub(r'\[[^\]]+?\]', '', issue.fields.summary).strip() summary = re.sub(r'FIWARE\.(Request|Question)\.\w+\.', '', summary) summary = 'FIWARE.{}.Tech.{}.{}.{}'.format( issuetype, chapterkeyword, enablerkeyword, summary) issue.update( fields={ 'summary': summary, 'customfield_11103': chapter, 'customfield_11104': None }) elif enabler_value == 'Unknown' and chapter_value != 'Unknown': pattern = r'FIWARE\.{}\.Tech\.{}\.'.format( issuetype, chapter_value) if re.match(pattern, issue.fields.summary): continue pattern = r'FIWARE\.{}\.({})\.{}\.'.format( issuetype, _channels, chapter_value) if re.match(pattern, issue.fields.summary): summary = '.'.join(chunks[0:2]) + '.Tech.' + '.'.join( chunks[3:]) else: summary = re.sub(r'\[[^\]]+?\]', '', issue.fields.summary).strip() summary = re.sub(r'FIWARE\.(Request|Question)\.\w+\.', '', summary) summary = 'FIWARE.{}.Tech.{}.{}'.format( issuetype, chapter_value, summary) issue.update( fields={ 'summary': summary, 'customfield_11104': None, 'customfield_11105': None }) else: pattern = r'FIWARE\.{}\.Tech\.'.format(issuetype) if re.match(pattern, issue.fields.summary): continue pattern = r'FIWARE\.{}\.({})\.'.format(issuetype, _channels) if re.match(pattern, issue.fields.summary): summary = '.'.join(chunks[0:2]) + '.Tech.' + '.'.join( chunks[3:]) else: summary = re.sub(r'\[[^\]]+?\]', '', issue.fields.summary).strip() summary = re.sub(r'FIWARE\.(Request|Question)\.\w+\.', '', summary) summary = 'FIWARE.{}.Tech.{}.'.format(issuetype, summary) issue.update( fields={ 'summary': summary, 'customfield_11103': None, 'customfield_11104': None, 'customfield_11105': None }) logging.info('update issue: {} {}'.format(issue, summary)) self.n_renamed += 1 def remove_spam(self): query = 'project in (HELP, HELC) and component = SPAM and updated <= -7d' # query = 'project in (HELP, HELC) and component = SPAM' requests = sorted(self.jira.search_issues(query, maxResults=25), key=lambda item: item.key) for request in requests: request.delete() logging.info('DELETED SPAM {}'.format(request)) self.n_removed += 1
class Strategy: def __init__(self, account_name, user_name, user_password): self._account = account_name self._user = user_name self._password = user_password self._server = 'https://{}.atlassian.net'.format(self._account) self._jira_connection = JIRA(server=self._server, basic_auth=(self._user, self._password)) self._makelog = makelog.Makelog('output', 'errorlog') def execute(self, key): if key == 1: self._doreporting() elif key == 2: self._domailing() elif key == 3: self._dogenerating() else: return False def _doreporting(self): data_peruser = {} data_percomponent = {} # getting all users users_all = self._jira_connection.search_users('%', maxResults=False, includeInactive=True) for user in users_all: data_peruser[user.name] = { 'time_total': 0, 'time_perissue': {}, 'actual_name': user.displayName, 'components': set() } # getting all components components_all = set() projects_all = self._jira_connection.projects() for project in projects_all: try: comps = self._jira_connection.project_components(project) components_all.update(comps) except: outstr = "Unexpected error with getting components from project: {}\n".format( project.key) self._makelog.putto_console(outstr) self._makelog.putto_errorlog(outstr, traceback.format_exc()) for comp in components_all: try: component_data = self._jira_connection.component(comp.id) data_percomponent[component_data.id] = { 'name': component_data.name, 'projectkey': component_data.project, 'time_total': 0, 'time_perissue': {}, 'lead': '' if not hasattr(component_data, 'lead') else component_data.lead.name } if hasattr(component_data, 'lead'): data_peruser[component_data.lead.name]['components'].add( component_data.id) except: outstr = "Unexpected error with getting data of component id: {}\n".format( comp.id) self._makelog.putto_console(outstr) self._makelog.putto_errorlog(outstr, traceback.format_exc()) # counting hours logic issues_all = self._jira_connection.search_issues('', maxResults=False) for iss in issues_all: try: iss_works = self._jira_connection.worklogs(iss) for work in iss_works: # per user data_peruser[work.author. name]['time_total'] += work.timeSpentSeconds if iss.key not in data_peruser[ work.author.name]['time_perissue']: data_peruser[work.author.name]['time_perissue'][ iss.key] = 0 data_peruser[work.author.name]['time_perissue'][ iss.key] += work.timeSpentSeconds # per valid component (with lead) for comp in iss.fields.components: if data_percomponent[ comp.id]['lead'] == work.author.name: data_percomponent[ comp.id]['time_total'] += work.timeSpentSeconds if iss.key not in data_percomponent[ comp.id]['time_perissue']: data_percomponent[comp.id]['time_perissue'][ iss.key] = 0 data_percomponent[comp.id]['time_perissue'][ iss.key] += work.timeSpentSeconds except: outstr = "Unexpected error counting hours with issue: {}\n".format( iss.key) self._makelog.putto_console(outstr) self._makelog.putto_errorlog(outstr, traceback.format_exc()) # outputting data outstr = "" outstr += "\t\t\tReport on the spent hours:\n" outstr += "\n\t\tPer programmer:\n\n" for user_name, user_dat in data_peruser.iteritems(): outstr += "-> Name: {} ({})\n".format(user_dat['actual_name'], user_name) outstr += " Total time: {} hour(s)\n".format( str(user_dat['time_total'] / 3600)) outstr += " Time per issue:\n" for iss_key, time_val in user_dat['time_perissue'].iteritems(): outstr += "\t{} is: {} hour(s)\n".format( iss_key, str(time_val / 3600)) outstr += "\n" outstr += "\n\t\tPer component (with lead only):\n\n" for comp_id, comp_dat in data_percomponent.iteritems(): outstr += "-> Name: {} ({})\n".format(comp_dat['name'], comp_dat['projectkey']) outstr += " Lead: {}\n".format(comp_dat['lead']) outstr += " Total time: {} hour(s)\n".format( str(comp_dat['time_total'] / 3600)) outstr += " Time per issue:\n" for iss_key, time_val in comp_dat['time_perissue'].iteritems(): outstr += "\t{} is: {} hour(s)\n".format( iss_key, str(time_val / 3600)) outstr += "\n" outstr += "\n-----> END REPORT <-----\n\n" self._makelog.putto_console(outstr, iscln=True) self._makelog.putto_file(outstr) def _domailing(self): issues_tonotify = [] issues_all = self._jira_connection.search_issues('', maxResults=False) for iss in issues_all: try: iss_data = self._jira_connection.issue(iss) if (iss_data.fields.timeestimate is None) or (len( iss_data.fields.components) == 0): issues_tonotify.append({ 'name': iss_data.fields.assignee.name, 'dispname': iss_data.fields.assignee.displayName, 'email': iss_data.fields.assignee.emailAddress, 'isskey': iss.key }) except: outstr = "Unexpected error with getting issue: {}\n".format( iss.key) self._makelog.putto_console(outstr) self._makelog.putto_errorlog(outstr, traceback.format_exc()) for data in issues_tonotify: try: url = "{}/rest/api/2/issue/{}/notify".format( self._server, data['isskey']) notify_data = { "subject": "You have some incomplete fields in issue {}".format( data['isskey']), "textBody": "Your got this notification because have one or couple incomplete fields in {} issue. Note, that 'estimates' \ and 'component' fields are mandatory. Please, check this fields and fill its in if need." .format(data['isskey']), "to": { "users": [{ "name": data['name'] }] }, } requests.post(url, auth=(self._user, self._password), json=notify_data) outstr = "Successfully sending notification to:\n-> {} {} about incomplete fields in {} issue\n".format( data['dispname'], data['email'], data['isskey']) self._makelog.putto_console(outstr) self._makelog.putto_file(outstr) except: outstr = "Unexpected error with sending notification to:\n-> {} {} about: {}\n".format( data['dispname'], data['email'], data['isskey']) self._makelog.putto_console(outstr) self._makelog.putto_errorlog(outstr, traceback.format_exc()) if len(issues_tonotify) == 0: self._makelog.putto_console( "All tested issues were filed in correct") def _dogenerating(self): names_base = namebase.Namebase() maxlen_projname = 10 content_count = { 'project': 1, 'user': 1, 'component': 2, 'issue': 10, 'worklog': 20 } # making projects for i in xrange(content_count['project']): newname = names_base.getname_project() parts = newname.split()[::2] newkey = string.join( (parts[0][:(maxlen_projname - len(parts[1]))], parts[1]), '') try: self._jira_connection.create_project(newkey, name=newname) outstr = "Project {} was successfully created\n".format(newkey) self._makelog.putto_console(outstr) self._makelog.putto_file(outstr) except: outstr = "Some problem with project {} creation\n".format( newkey) self._makelog.putto_console(outstr) self._makelog.putto_errorlog(outstr, traceback.format_exc()) # making users for i in xrange(content_count['user']): newname = names_base.getname_user() try: self._jira_connection.add_user(newname, "{}@mail.net".format(newname),\ fullname="Name {}{}".format(string.upper(newname[:1]), newname[1:])) outstr = "User {} was successfully created\n".format(newname) self._makelog.putto_console(outstr) self._makelog.putto_file(outstr) except: outstr = "Some problem with user {} creation\n".format(newname) self._makelog.putto_console(outstr) self._makelog.putto_errorlog(outstr, traceback.format_exc()) # getting all valid project keys projects_keys = [] projects_all = self._jira_connection.projects() for project in projects_all: projects_keys.append(project.key) # getting all valid user names users_keys = [] users_all = self._jira_connection.search_users('%', maxResults=False, includeInactive=True) for user in users_all: users_keys.append(user.name) # making components for i in xrange(content_count['component']): newname = names_base.getname_component() try: self._jira_connection.create_component( newname, random.choice(projects_keys), leadUserName=random.choice(users_keys)) outstr = "Component {} was successfully created\n".format( newname) self._makelog.putto_console(outstr) self._makelog.putto_file(outstr) except: outstr = "Some problem with component {} creation\n".format( newname) self._makelog.putto_console(outstr) self._makelog.putto_errorlog(outstr, traceback.format_exc()) # making issues for i in xrange(content_count['issue']): newname = names_base.getname_issue() fields = { "project": { "key": random.choice(projects_keys) }, "summary": "Here should be some random text summary for issue {}".format( newname), "description": "Here should be some random text description for issue {}". format(newname), "issuetype": { "name": random.choice( ("Bug", "Improvement", "Task", "Epic", "New Feature")) }, "assignee": { "name": random.choice(users_keys) }, "timetracking": { "originalEstimate": "{}w {}d {}h".format(random.randint(1, 3), random.randint(1, 4), random.randint(1, 7)), "remainingEstimate": "{}d {}h".format(random.randint(1, 4), random.randint(1, 7)) } } try: self._jira_connection.create_issue(fields=fields) outstr = "Issue {} was successfully created\n".format(newname) self._makelog.putto_console(outstr) self._makelog.putto_file(outstr) except: outstr = "Some problem with issue {} creation\n".format( newname) self._makelog.putto_console(outstr) self._makelog.putto_errorlog(outstr, traceback.format_exc()) # making worklogs issues_all = self._jira_connection.search_issues('', maxResults=False) for i in xrange(content_count['worklog']): iss = random.choice(issues_all) try: self._jira_connection.add_worklog(iss, timeSpent="{}h".format(random.randint(1, 3)), user=random.choice(users_keys),\ comment="Here should be some random text about work on this issue") outstr = "Worklog for issue {} was successfully created\n".format( iss.key) self._makelog.putto_console(outstr) self._makelog.putto_file(outstr) except: outstr = "Some problem with worklog creation for issue {}\n".format( iss.key) self._makelog.putto_console(outstr) self._makelog.putto_errorlog(outstr, traceback.format_exc())
class JiraIntegrator: def __init__(self, user, api_token, host): options = {"server": host} self.jira_connection = JIRA(options, basic_auth=(user, api_token)) self.event_handlers = { enums.GitHubAction.OPENED.value: self.create_new_jira_issue, enums.GitHubAction.CREATED.value: self.create_new_jira_issue, enums.GitHubAction.EDITED.value: self.update_jira_issue, enums.GitHubAction.LABELED.value: self.update_jira_label, enums.GitHubAction.UNLABELED.value: self.update_jira_label, enums.GitHubAction.CLOSED.value: self.close_jira_issue, enums.GitHubAction.REOPENED.value: self.reopen_jira_issue, } def handle(self, event): status_code = 500 try: handler = self.event_handlers[event["action"]] handler(event["issue"], event["repository"]) status_code = 200 except (KeyError, ValueError) as err: status_code = 404 logging.exception(f"Can not find: {repr(err)}") except Exception as err: logging.exception(f"Error occurs: {repr(err)}") return { "statusCode": status_code, "headers": {"Access-Control-Allow-Origin": "*"}, } def create_new_jira_issue(self, issue, repository): issuetype = {"name": utils.get_issue_type(issue["labels"])} github_link_field_name = self._get_field_id("GitHub Link") github_author_field_name = self._get_field_id("GitHub Author") github_link = utils.find_github_link(repository["full_name"], issue["number"]) labels = utils.get_jira_labels(issue["labels"]) project = utils.find_project(repository) fields = { "project": project, "summary": issue["title"], "description": issue["body"], "issuetype": issuetype, "labels": labels, github_link_field_name: github_link, github_author_field_name: issue.get("user", {}).get("login"), } component = None try: if "mirumee/saleor-dashboard" in github_link: component = self.jira_connection.component(COMPONENT_ID_DASHBOARD) if "mirumee/saleor-docs" in github_link: component = self.jira_connection.component(COMPONENT_ID_DOCS) except Exception as err: logging.exception(f"Failed to assign component: {repr(err)}") if component: fields["components"] = [{"name": component.name}] self.jira_connection.create_issue(**fields) def update_jira_issue(self, issue, repository): jira_issue = self._find_jira_issue(repository["full_name"], issue["number"]) fields = {"summary": issue["title"], "description": issue["body"]} jira_issue.update(fields=fields) def update_jira_label(self, issue, repository): jira_issue = self._find_jira_issue(repository["full_name"], issue["number"]) issuetype = {"name": utils.get_issue_type(issue["labels"])} labels = utils.get_jira_labels(issue["labels"]) fields = {"issuetype": issuetype, "labels": labels} jira_issue.update(fields=fields) def close_jira_issue(self, issue, repository): jira_issue = self._find_jira_issue(repository["full_name"], issue["number"]) ready_to_test_transition = self._get_ready_to_test_transition(jira_issue) self.jira_connection.transition_issue( jira_issue, ready_to_test_transition["id"] ) def reopen_jira_issue(self, issue, repository): jira_issue = self._find_jira_issue(repository["full_name"], issue["number"]) to_do_transition = self._get_to_do_transition(jira_issue) self.jira_connection.transition_issue(jira_issue, to_do_transition["id"]) def _get_field_id(self, field_name): fields = self.jira_connection.fields() selected_field = filter( lambda field: field["name"].lower() == field_name.lower(), fields ) return next(selected_field)["key"] def _find_jira_issue(self, github_project, issue_number): query = '"GitHub Link" = "{github_link}"'.format( github_link=utils.find_github_link(github_project, issue_number) ) issues = self.jira_connection.search_issues(query) if not issues: raise ValueError(f"Can not find jira issue with number {issue_number}") return issues[0] def _get_to_do_transition(self, issue): return self._get_transition_by_name(issue, enums.JiraTransition.TO_DO.value) def _get_ready_to_test_transition(self, issue): return self._get_transition_by_name( issue, enums.JiraTransition.READY_TO_TEST.value ) def _get_transition_by_name(self, issue, transition): transitions = self.jira_connection.transitions(issue) ready_to_test_transition = next( filter(lambda tr: tr["name"].lower() == transition, transitions) ) return ready_to_test_transition