Пример #1
0
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
Пример #2
0
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())
Пример #3
0
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