Beispiel #1
0
 def __init__(self, cal, fallback, team_name, people=None):
     super(Calendar, self).__init__()
     self.cal = cal
     self.people = People() if people is None else people
     self.fallback = fallback
     self.fb_bzmail = self.people.get_bzmail_from_name(self.fallback)
     self.fb_mozmail = self.people.get_moz_mail(self.fb_bzmail)
     self.team_name = team_name
     self.cache = {}
 def __init__(self):
     super(Nag, self).__init__()
     self.people = People()
     self.send_nag_mail = True
     self.data = {}
     self.nag_date = None
     self.white_list = []
     self.black_list = []
     self.escalation = Escalation(self.people)
     self.triage_owners = {}
     self.all_owners = None
     self.query_params = {}
Beispiel #3
0
 def __init__(self, rr=None, people=None, teams=None):
     self.people = People.get_instance() if people is None else people
     self.components_by_triager = {}
     self.all_calendars = []
     self.feed(teams, rr=rr)
     self.nicks = {}
     self.erroneous_bzmail = {}
     utils.init_random()
 def __init__(self, cal, fallback, team_name, people=None):
     super(Calendar, self).__init__()
     self.cal = cal
     self.people = People() if people is None else people
     self.fallback = fallback
     self.fb_bzmail = self.people.get_bzmail_from_name(self.fallback)
     self.fb_mozmail = self.people.get_moz_mail(self.fb_bzmail)
     self.team_name = team_name
     self.cache = {}
Beispiel #5
0
    def __init__(self):
        super(CodeFreezeWeek, self).__init__()
        self.versions = utils.get_checked_versions()
        if not self.versions:
            return

        self.people = People()
        self.nightly = self.versions['central']
        self.beta = self.versions['beta']
        self.release = self.versions['release']
        self.status_nightly = utils.get_flag(self.nightly, 'status', 'central')
        self.status_beta = utils.get_flag(self.beta, 'status', 'beta')
        self.status_release = utils.get_flag(self.release, 'status', 'release')
        self.tracking_nightly = utils.get_flag(self.nightly, 'tracking',
                                               'central')
        self.tracking_beta = utils.get_flag(self.beta, 'tracking', 'beta')
        self.tracking_release = utils.get_flag(self.release, 'tracking',
                                               'release')
class LeaveOpenNoActivity(BzCleaner):
    def __init__(self):
        super(LeaveOpenNoActivity, self).__init__()
        self.people = People()
        self.nmonths = utils.get_config(self.name(), 'months_lookup')
        self.max_ni = utils.get_config(self.name(), 'max_ni')
        self.blacklist = set(utils.get_config(self.name(), 'blacklist', []))

    def description(self):
        return 'Bugs with leave-open keyword and no activity for the last {} months'.format(
            self.nmonths
        )

    def get_extra_for_needinfo_template(self):
        return self.get_extra_for_template()

    def get_extra_for_template(self):
        return {'nmonths': self.nmonths}

    def get_auto_ni_blacklist(self):
        return self.blacklist

    def get_max_ni(self):
        return self.max_ni

    def get_mail_to_auto_ni(self, bug):
        for f in ['assigned_to', 'triage_owner']:
            person = bug.get(f, '')
            if person and self.people.is_mozilla(person):
                return {'mail': person, 'nickname': bug[f + '_detail']['nick']}

        return None

    def get_bz_params(self, date):
        fields = ['assigned_to', 'triage_owner']
        params = {
            'include_fields': fields,
            'resolution': '---',
            'f1': 'keywords',
            'o1': 'casesubstring',
            'v1': 'leave-open',
            'f2': 'keywords',
            'o2': 'notsubstring',
            'v2': 'intermittent',
            'f3': 'status_whiteboard',
            'o3': 'notregexp',
            'v3': r'\[(test|stockwell) disabled.*\]',
            'f4': 'days_elapsed',
            'o4': 'greaterthan',
            'v4': self.nmonths * 30,
        }

        return params
Beispiel #7
0
 def __init__(self):
     super(Nag, self).__init__()
     self.people = People()
     self.send_nag_mail = True
     self.data = {}
     self.nag_date = None
     self.white_list = []
     self.black_list = []
     self.escalation = Escalation(self.people)
     self.triage_owners = {}
     self.all_owners = None
     self.query_params = {}
Beispiel #8
0
class LeaveOpenNoActivity(BzCleaner):
    def __init__(self):
        super(LeaveOpenNoActivity, self).__init__()
        self.people = People()
        self.nmonths = utils.get_config(self.name(), 'months_lookup')
        self.max_ni = utils.get_config(self.name(), 'max_ni')
        self.skiplist = set(utils.get_config(self.name(), 'skiplist', []))

    def description(self):
        return 'Bugs with leave-open keyword and no activity for the last {} months'.format(
            self.nmonths)

    def get_extra_for_needinfo_template(self):
        return self.get_extra_for_template()

    def get_extra_for_template(self):
        return {'nmonths': self.nmonths}

    def get_auto_ni_skiplist(self):
        return self.skiplist

    def get_max_ni(self):
        return self.max_ni

    def get_mail_to_auto_ni(self, bug):
        for f in ['assigned_to', 'triage_owner']:
            person = bug.get(f, '')
            if person and self.people.is_mozilla(person):
                return {'mail': person, 'nickname': bug[f + '_detail']['nick']}

        return None

    def get_bz_params(self, date):
        fields = ['assigned_to', 'triage_owner']
        params = {
            'include_fields': fields,
            'resolution': '---',
            'f1': 'keywords',
            'o1': 'casesubstring',
            'v1': 'leave-open',
            'f2': 'keywords',
            'o2': 'notsubstring',
            'v2': 'intermittent',
            'f3': 'status_whiteboard',
            'o3': 'notregexp',
            'v3': r'\[(test|stockwell) disabled.*\]',
            'f4': 'days_elapsed',
            'o4': 'greaterthan',
            'v4': self.nmonths * 30,
        }

        return params
class MetaNoDepsNoActivity(BzCleaner):
    def __init__(self):
        super(MetaNoDepsNoActivity, self).__init__()
        self.people = People()
        self.nmonths = utils.get_config(self.name(), 'months_lookup')
        self.max_ni = utils.get_config(self.name(), 'max_ni')
        self.blacklist = set(utils.get_config(self.name(), 'blacklist', []))

    def description(self):
        return 'Bugs with meta keyword, not depending on bugs and no activity for the last {} months'.format(
            self.nmonths
        )

    def get_extra_for_needinfo_template(self):
        return self.get_extra_for_template()

    def get_extra_for_template(self):
        return {'nmonths': self.nmonths}

    def get_auto_ni_blacklist(self):
        return self.blacklist

    def get_max_ni(self):
        return self.max_ni

    def get_mail_to_auto_ni(self, bug):
        for f in ['assigned_to', 'triage_owner']:
            person = bug.get(f, '')
            if person and self.people.is_mozilla(person):
                return {'mail': person, 'nickname': bug[f + '_detail']['nick']}

        return None

    def get_bz_params(self, date):
        fields = ['assigned_to', 'triage_owner']
        params = {
            'include_fields': fields,
            'resolution': '---',
            'f1': 'keywords',
            'o1': 'casesubstring',
            'v1': 'meta',
            'f2': 'days_elapsed',
            'o2': 'greaterthan',
            'v2': self.nmonths * 30,
            'f3': 'dependson',
            'o3': 'isempty',
        }

        return params
class MetaNoDepsNoActivity(BzCleaner):
    def __init__(self):
        super(MetaNoDepsNoActivity, self).__init__()
        self.people = People()
        self.nmonths = utils.get_config(self.name(), 'months_lookup')
        self.max_ni = utils.get_config(self.name(), 'max_ni')
        self.skiplist = set(utils.get_config(self.name(), 'skiplist', []))

    def description(self):
        return 'Bugs with meta keyword, not depending on bugs and no activity for the last {} months'.format(
            self.nmonths)

    def get_extra_for_needinfo_template(self):
        return self.get_extra_for_template()

    def get_extra_for_template(self):
        return {'nmonths': self.nmonths}

    def get_auto_ni_skiplist(self):
        return self.skiplist

    def get_max_ni(self):
        return self.max_ni

    def get_mail_to_auto_ni(self, bug):
        for f in ['assigned_to', 'triage_owner']:
            person = bug.get(f, '')
            if person and self.people.is_mozilla(person):
                return {'mail': person, 'nickname': bug[f + '_detail']['nick']}

        return None

    def get_bz_params(self, date):
        fields = ['assigned_to', 'triage_owner']
        params = {
            'include_fields': fields,
            'resolution': '---',
            'f1': 'keywords',
            'o1': 'casesubstring',
            'v1': 'meta',
            'f2': 'days_elapsed',
            'o2': 'greaterthan',
            'v2': self.nmonths * 30,
            'f3': 'dependson',
            'o3': 'isempty',
        }

        return params
    def __init__(self):
        super(CodeFreezeWeek, self).__init__()
        self.versions = utils.get_checked_versions()
        if not self.versions:
            return

        self.people = People()
        self.nightly = self.versions['central']
        self.beta = self.versions['beta']
        self.release = self.versions['release']
        self.status_nightly = utils.get_flag(self.nightly, 'status', 'central')
        self.status_beta = utils.get_flag(self.beta, 'status', 'beta')
        self.status_release = utils.get_flag(self.release, 'status', 'release')
        self.tracking_nightly = utils.get_flag(self.nightly, 'tracking', 'central')
        self.tracking_beta = utils.get_flag(self.beta, 'tracking', 'beta')
        self.tracking_release = utils.get_flag(self.release, 'tracking', 'release')
Beispiel #12
0
    def __init__(self):
        super(CodeFreezeWeek, self).__init__()
        if not self.init_versions():
            return

        self.people = People.get_instance()
        self.nightly = self.versions["central"]
        self.beta = self.versions["beta"]
        self.release = self.versions["release"]
        self.status_nightly = utils.get_flag(self.nightly, "status", "central")
        self.status_beta = utils.get_flag(self.beta, "status", "beta")
        self.status_release = utils.get_flag(self.release, "status", "release")
        self.tracking_nightly = utils.get_flag(self.nightly, "tracking",
                                               "central")
        self.tracking_beta = utils.get_flag(self.beta, "tracking", "beta")
        self.tracking_release = utils.get_flag(self.release, "tracking",
                                               "release")
Beispiel #13
0
class Nag(object):
    def __init__(self):
        super(Nag, self).__init__()
        self.people = People()
        self.send_nag_mail = True
        self.data = {}
        self.nag_date = None
        self.white_list = []
        self.black_list = []
        self.escalation = Escalation(self.people)
        self.triage_owners = {}
        self.all_owners = None
        self.query_params = {}

    @staticmethod
    def get_from():
        return utils.get_config('auto_nag', 'from', '*****@*****.**')

    def get_cc(self):
        cc = self.get_config('cc', None)
        if cc is None:
            cc = utils.get_config('auto_nag', 'cc', [])

        return set(cc)

    def get_priority(self, bug):
        tracking = bug[self.tracking]
        if tracking == 'blocking':
            return 'high'
        return 'normal'

    def filter_bug(self, priority):
        days = (utils.get_next_release_date() - self.nag_date).days
        weekday = self.nag_date.weekday()
        return self.escalation.filter(priority, days, weekday)

    def get_people(self):
        return self.people

    def set_people_to_nag(self, bug, buginfo):
        return bug

    def escalate(self, person, priority, **kwargs):
        days = (utils.get_next_release_date() - self.nag_date).days
        return self.escalation.get_supervisor(priority, days, person, **kwargs)

    def add(self, person, bug_data, priority='default', **kwargs):
        if not self.people.is_mozilla(person):
            return False

        manager = self.escalate(person, priority, **kwargs)
        return self.add_couple(person, manager, bug_data)

    def add_couple(self, person, manager, bug_data):
        person = self.people.get_moz_mail(person)

        if manager in self.data:
            data = self.data[manager]
        else:
            self.data[manager] = data = {}
        if person in data:
            data[person].append(bug_data)
        else:
            data[person] = [bug_data]

        return True

    def nag_template(self):
        return self.name() + '_nag.html'

    def get_extra_for_nag_template(self):
        return {}

    def columns_nag(self):
        return None

    def sort_columns_nag(self):
        return None

    def _is_in_list(self, mail, _list):
        for manager in _list:
            if self.people.is_under(mail, manager):
                return True
        return False

    def is_under(self, mail):
        if not self.white_list:
            if not self.black_list:
                return True
            return not self._is_in_list(mail, self.black_list)
        if not self.black_list:
            return self._is_in_list(mail, self.white_list)
        return self._is_in_list(mail, self.white_list) and not self._is_in_list(
            mail, self.black_list
        )

    def add_triage_owner(self, owner, real_owner=None):
        if owner not in self.triage_owners:
            to = real_owner if real_owner is not None else owner
            self.triage_owners[owner] = self.get_query_url_for_triage_owner(to)

    def get_query_url_for_triage_owner(self, owner):
        if self.all_owners is None:
            self.all_owners = utils.get_triage_owners()
        params = copy.deepcopy(self.query_params)
        if 'include_fields' in params:
            del params['include_fields']

        comps = self.all_owners[owner]
        comps = set(comps)

        params['component'] = sorted(comps)
        url = utils.get_bz_search_url(params)

        return url

    def organize_nag(self, bugs):
        columns = self.columns_nag()
        if columns is None:
            columns = self.columns()
        key = self.sort_columns_nag()
        if key is None:
            key = self.sort_columns()

        return utils.organize(bugs, columns, key=key)

    def send_mails(self, title, dryrun=False):
        if not self.send_nag_mail:
            return

        env = Environment(loader=FileSystemLoader('templates'))
        common = env.get_template('common.html')
        login_info = utils.get_login_info()
        From = Nag.get_from()
        Default_Cc = self.get_cc()
        mails = self.prepare_mails()

        for m in mails:
            Cc = Default_Cc.copy()
            if m['manager']:
                Cc.add(m['manager'])
            body = common.render(message=m['body'], query_url=None)
            receivers = set(m['to']) | set(Cc)
            status = 'Success'
            try:
                mail.send(
                    From,
                    sorted(m['to']),
                    title,
                    body,
                    Cc=sorted(Cc),
                    html=True,
                    login=login_info,
                    dryrun=dryrun,
                )
            except:  # NOQA
                logger.exception('Tool {}'.format(self.name()))
                status = 'Failure'

            db.Email.add(self.name(), receivers, 'individual', status)

    def prepare_mails(self):
        if not self.data:
            return []

        template = self.nag_template()
        if not template:
            return []

        extra = self.get_extra_for_nag_template()
        env = Environment(loader=FileSystemLoader('templates'))
        template = env.get_template(template)
        mails = []
        for manager, info in self.data.items():
            data = []
            To = sorted(info.keys())
            for person in To:
                bug_data = info[person]
                data += bug_data

            if len(To) == 1 and To[0] in self.triage_owners:
                query_url = self.triage_owners[To[0]]
            else:
                query_url = None

            body = template.render(
                date=self.nag_date,
                extra=extra,
                plural=utils.plural,
                enumerate=enumerate,
                data=self.organize_nag(data),
                nag=True,
                query_url_nag=query_url,
                table_attrs=self.get_config('table_attrs'),
            )

            m = {'manager': manager, 'to': set(info.keys()), 'body': body}
            mails.append(m)

        return mails

    def reorganize_to_bag(self, data):
        return data
Beispiel #14
0
class Calendar(object):
    def __init__(self, cal, fallback, team_name, people=None):
        super(Calendar, self).__init__()
        self.cal = cal
        self.people = People() if people is None else people
        self.fallback = fallback
        self.fb_bzmail = self.people.get_bzmail_from_name(self.fallback)
        self.fb_mozmail = self.people.get_moz_mail(self.fb_bzmail)
        self.team_name = team_name
        self.cache = {}

    def get_fallback(self):
        return self.fallback

    def get_fallback_bzmail(self):
        if not self.fb_bzmail:
            raise BadFallback('\'{}\' is an invalid fallback'.format(
                self.fallback))
        return self.fb_bzmail

    def get_fallback_mozmail(self):
        if not self.fb_mozmail:
            raise BadFallback('\'{}\' is an invalid fallback'.format(
                self.fallback))
        return self.fb_mozmail

    def get_team_name(self):
        return self.team_name

    def get_persons(self, date):
        return []

    def set_team(self, team, triagers):
        self.team = []
        for p in team:
            if p in triagers and 'bzmail' in triagers[p]:
                bzmail = triagers[p]['bzmail']
            else:
                bzmail = self.people.get_bzmail_from_name(p)
            self.team.append((p, bzmail))

    @staticmethod
    def get(url, fallback, team_name, people=None):
        data = None
        if url.startswith('private://'):
            name = url.split('//', 1)[1]
            url = utils.get_private()[name]

        if url.startswith('http'):
            r = requests.get(url)
            data = r.text
        elif os.path.isfile(url):
            with open(url, 'r') as In:
                data = In.read()
        else:
            data = url

        if data is None:
            raise InvalidCalendar('Cannot read calendar: {}'.format(url))

        try:
            cal = json.loads(data)
            return JSONCalendar(cal, fallback, team_name, people=people)
        except JSONDecodeError:
            try:
                # there is an issue with dateutil.rrule parser when until doesn't have a tz
                # so a workaround is to add a Z at the end of the string.
                pat = re.compile(r'^RRULE:(.*)UNTIL=([0-9Z]+)',
                                 re.MULTILINE | re.I)

                def sub(m):
                    date = m.group(1)
                    if date.lower().endswith('z'):
                        return date
                    return date + 'Z'

                data = pat.sub(sub, data)

                return ICSCalendar(data, fallback, team_name, people=people)
            except ValueError:
                raise InvalidCalendar('Cannot decode calendar: {}'.format(url))
Beispiel #15
0
 def __init__(self, rr=None, people=None):
     self.feed(rr=rr)
     self.nicks = {}
     self.people = People() if people is None else people
Beispiel #16
0
class RoundRobin(object):
    def __init__(self, rr=None, people=None):
        self.feed(rr=rr)
        self.nicks = {}
        self.people = People() if people is None else people

    def feed(self, rr=None):
        self.data = {}
        filenames = {}
        if rr is None:
            rr = {}
            for team, path in utils.get_config('round-robin',
                                               "teams",
                                               default={}).items():
                with open('./auto_nag/scripts/configs/{}'.format(path),
                          'r') as In:
                    rr[team] = json.load(In)
                    filenames[team] = path

        # rr is dictionary:
        # - doc -> documentation
        # - triagers -> dictionary: Real Name -> {bzmail: bugzilla email, nick: bugzilla nickname}
        # - components -> dictionary: Product::Component -> strategy name
        # - strategies: dictionay: {duty en date -> Real Name}

        # Get all the strategies for each team
        for team, data in rr.items():
            if 'doc' in data:
                del data['doc']
            strategies = {}
            triagers = data['triagers']
            fallback_bzmail = triagers['Fallback']['bzmail']
            path = filenames.get(team, '')

            # collect strategies
            for pc, strategy in data['components'].items():
                strategy_data = data[strategy]
                if strategy not in strategies:
                    strategies[strategy] = strategy_data

            # rewrite strategy to have a sorted list of end dates
            for strat_name, strategy in strategies.items():
                if 'doc' in strategy:
                    del strategy['doc']
                date_name = []

                # end date and real name of the triager
                for date, name in strategy.items():
                    # collect the tuple (end_date, bzmail)
                    date = lmdutils.get_date_ymd(date)
                    bzmail = triagers[name]['bzmail']
                    date_name.append((date, bzmail))

                # we sort the list to use bisection to find the triager
                date_name = sorted(date_name)
                strategies[strat_name] = {
                    'dates': [d for d, _ in date_name],
                    'mails': [m for _, m in date_name],
                    'fallback': fallback_bzmail,
                    'filename': path,
                }

            # finally self.data is a dictionary:
            # - Product::Component -> dictionary {dates: sorted list of end date
            #                                     mails: list
            #                                     fallback: who to nag when we've nobody
            #                                     filename: the file containing strategy}
            for pc, strategy in data['components'].items():
                self.data[pc] = strategies[strategy]

    def get_nick(self, bzmail):
        if bzmail not in self.nicks:

            def handler(user):
                self.nicks[bzmail] = user['nick']

            BugzillaUser(user_names=[bzmail], user_handler=handler).wait()

        return self.nicks[bzmail]

    def is_mozilla(self, bzmail):
        return self.people.is_mozilla(bzmail)

    def get(self, bug, date):
        pc = '{}::{}'.format(bug['product'], bug['component'])
        if pc not in self.data:
            mail = bug['triage_owner']
            nick = bug['triage_owner_detail']['nick']
            return mail, nick

        date = lmdutils.get_date_ymd(date)
        strategy = self.data[pc]
        dates = strategy['dates']
        i = bisect.bisect_left(strategy['dates'], date)
        if i == len(dates):
            bzmail = strategy['fallback']
        else:
            bzmail = strategy['mails'][i]
        nick = self.get_nick(bzmail)

        return bzmail, nick

    def get_who_to_nag(self, date):
        fallbacks = {}
        date = lmdutils.get_date_ymd(date)
        days = utils.get_config('round-robin', 'days_to_nag', 7)
        for pc, strategy in self.data.items():
            last_date = strategy['dates'][-1]
            if (last_date - date
                ).days <= days and strategy['filename'] not in fallbacks:
                fallbacks[strategy['filename']] = strategy['fallback']

        # create a dict: mozmail -> list of filenames to check
        res = {}
        for fn, fb in fallbacks.items():
            if not self.is_mozilla(fb):
                raise BadFallback()
            mozmail = self.people.get_moz_mail(fb)
            if mozmail not in res:
                res[mozmail] = []
            res[mozmail].append(fn)

        res = {fb: sorted(fn) for fb, fn in res.items()}

        return res
class Calendar(object):
    def __init__(self, cal, fallback, team_name, people=None):
        super(Calendar, self).__init__()
        self.cal = cal
        self.people = People() if people is None else people
        self.fallback = fallback
        self.fb_bzmail = self.people.get_bzmail_from_name(self.fallback)
        self.fb_mozmail = self.people.get_moz_mail(self.fb_bzmail)
        self.team_name = team_name
        self.cache = {}

    def get_fallback(self):
        return self.fallback

    def get_fallback_bzmail(self):
        if not self.fb_bzmail:
            raise BadFallback('\'{}\' is an invalid fallback'.format(self.fallback))
        return self.fb_bzmail

    def get_fallback_mozmail(self):
        if not self.fb_mozmail:
            raise BadFallback('\'{}\' is an invalid fallback'.format(self.fallback))
        return self.fb_mozmail

    def get_team_name(self):
        return self.team_name

    def get_persons(self, date):
        return []

    def set_team(self, team, triagers):
        self.team = []
        for p in team:
            if p in triagers and 'bzmail' in triagers[p]:
                bzmail = triagers[p]['bzmail']
            else:
                bzmail = self.people.get_bzmail_from_name(p)
            self.team.append((p, bzmail))

    @staticmethod
    def get(url, fallback, team_name, people=None):
        data = None
        if url.startswith('private://'):
            name = url.split('//', 1)[1]
            url = utils.get_private()[name]

        if url.startswith('http'):
            r = requests.get(url)
            data = r.text
        elif os.path.isfile(url):
            with open(url, 'r') as In:
                data = In.read()
        else:
            data = url

        if data is None:
            raise InvalidCalendar('Cannot read calendar: {}'.format(url))

        try:
            cal = json.loads(data)
            return JSONCalendar(cal, fallback, team_name, people=people)
        except JSONDecodeError:
            try:
                # there is an issue with dateutil.rrule parser when until doesn't have a tz
                # so a workaround is to add a Z at the end of the string.
                pat = re.compile(r'^RRULE:(.*)UNTIL=([0-9Z]+)', re.MULTILINE | re.I)

                def sub(m):
                    date = m.group(1)
                    if date.lower().endswith('z'):
                        return date
                    return date + 'Z'

                data = pat.sub(sub, data)

                return ICSCalendar(data, fallback, team_name, people=people)
            except ValueError:
                raise InvalidCalendar('Cannot decode calendar: {}'.format(url))
 def __init__(self):
     super(NewbieWithNI, self).__init__()
     self.people = People()
     self.ndays = utils.get_config(self.name(), 'number_of_days', 14)
     self.ncomments = utils.get_config(self.name(), 'number_of_comments', 2)
     self.autofix_reporters = {}
Beispiel #19
0
 def __init__(self):
     super(MetaNoDepsNoActivity, self).__init__()
     self.people = People.get_instance()
     self.nmonths = utils.get_config(self.name(), "months_lookup")
     self.max_ni = utils.get_config(self.name(), "max_ni")
     self.skiplist = set(utils.get_config(self.name(), "skiplist", []))
Beispiel #20
0
    def test_escalation(self):
        people = [
            {
                "mail": "*****@*****.**",
                "cn": "A B",
                "ismanager": "FALSE",
                "manager": {
                    "dn": "[email protected],o=org,dc=mozilla"
                },
                "title": "nothing",
            },
            {
                "mail": "*****@*****.**",
                "cn": "C D",
                "ismanager": "TRUE",
                "manager": {
                    "dn": "[email protected],o=org,dc=mozilla"
                },
                "title": "manager",
            },
            {
                "mail": "*****@*****.**",
                "cn": "E F",
                "ismanager": "TRUE",
                "manager": {
                    "dn": "[email protected],o=org,dc=mozilla"
                },
                "title": "super manager",
            },
            {
                "mail": "*****@*****.**",
                "cn": "G H",
                "ismanager": "TRUE",
                "manager": {
                    "dn": "[email protected],o=org,dc=mozilla"
                },
                "title": "super manager",
            },
            {
                "mail": "*****@*****.**",
                "cn": "I J",
                "ismanager": "TRUE",
                "manager": {
                    "dn": "[email protected],o=org,dc=mozilla"
                },
                "title": "director",
            },
            {
                "mail": "*****@*****.**",
                "cn": "K L",
                "ismanager": "TRUE",
                "title": "vice president",
            },
        ]

        e = Escalation(People(people), data=TestEscalation.config)
        assert (e.get_supervisor(
            "high", 35, "*****@*****.**",
            foobar="*****@*****.**") == "*****@*****.**")
        assert e.get_supervisor("high", 25,
                                "*****@*****.**") == "*****@*****.**"
        assert e.get_supervisor("high", 20,
                                "*****@*****.**") == "*****@*****.**"
        assert e.get_supervisor("high", 18,
                                "*****@*****.**") == "*****@*****.**"
        assert e.get_supervisor("high", 7,
                                "*****@*****.**") == "*****@*****.**"
        assert e.get_supervisor("high", 1,
                                "*****@*****.**") == "*****@*****.**"

        assert e.filter("high", 25, 0) is False
        assert e.filter("high", 25, 3) is True
        assert e.filter("high", 18, 0) is True
        assert e.filter("high", 18, 1) is False
        assert e.filter("high", 18, 3) is True
        assert e.filter("high", 18, 5) is False
        assert e.filter("high", 7, 1) is False
        assert e.filter("high", 7, 3) is True
        assert e.filter("high", 7, 5) is False
        assert e.filter("high", 1, 1) is True
        assert e.filter("high", 1, 3) is True
        assert e.filter("high", 1, 4) is True
        assert e.filter("high", 7, 5) is False

        assert e.get_supervisor("normal", 17,
                                "*****@*****.**") == "*****@*****.**"
        assert e.get_supervisor("normal", 15,
                                "*****@*****.**") == "*****@*****.**"
        assert e.get_supervisor("normal", 12,
                                "*****@*****.**") == "*****@*****.**"
        assert e.get_supervisor("normal", 7,
                                "*****@*****.**") == "*****@*****.**"
        assert e.get_supervisor("normal", 1,
                                "*****@*****.**") == "*****@*****.**"

        assert e.get_supervisor("default", 17,
                                "*****@*****.**") == "*****@*****.**"
        assert e.get_supervisor("default", 7,
                                "*****@*****.**") == "*****@*****.**"
        assert e.get_supervisor("default", 1,
                                "*****@*****.**") == "*****@*****.**"
        assert e.get_supervisor("default", 0,
                                "*****@*****.**") == "*****@*****.**"
Beispiel #21
0
class CodeFreezeWeek(BzCleaner):
    def __init__(self):
        super(CodeFreezeWeek, self).__init__()
        self.versions = utils.get_checked_versions()
        if not self.versions:
            return

        self.people = People()
        self.nightly = self.versions['central']
        self.beta = self.versions['beta']
        self.release = self.versions['release']
        self.status_nightly = utils.get_flag(self.nightly, 'status', 'central')
        self.status_beta = utils.get_flag(self.beta, 'status', 'beta')
        self.status_release = utils.get_flag(self.release, 'status', 'release')
        self.tracking_nightly = utils.get_flag(self.nightly, 'tracking',
                                               'central')
        self.tracking_beta = utils.get_flag(self.beta, 'tracking', 'beta')
        self.tracking_release = utils.get_flag(self.release, 'tracking',
                                               'release')

    def description(self):
        return 'Bugs with patches which landed during the soft freeze week'

    def name(self):
        return 'code-freeze-week'

    def template(self):
        return 'code_freeze_week.html'

    def subject(self):
        return self.description()

    def get_extra_for_template(self):
        return {
            'nightly': self.nightly,
            'beta': self.beta,
            'release': self.release,
            'date': lmdutils.get_date_str(self.date),
        }

    def filter_no_nag_keyword(self):
        return False

    def has_enough_data(self):
        return bool(self.versions)

    def must_run(self, date):
        for c in get_calendar():
            # if freeze is the 2019-03-11, then the tool must run the day after
            # until 2019-03-2018 (a week after)
            freeze = c['soft freeze']
            if freeze <= date <= freeze + relativedelta(days=6):
                return True
        return False

    def has_product_component(self):
        return True

    def columns(self):
        return [
            'id',
            'summary',
            'product',
            'component',
            'assignee',
            'landed_patches',
            'addlines',
            'rmlines',
            'size',
            'test_size',
            'priority',
            'severity',
            'tracking',
            'status',
            'status_flags',
            'crash',
            'keywords',
        ]

    def sort_columns(self):
        return lambda p: (p[2], p[3], -p[5], -p[8], -p[9], -int(p[0]))

    def handle_bug(self, bug, data):
        bugid = str(bug['id'])

        assignee = bug.get('assigned_to', '')
        if assignee:
            info = self.people.get_info(assignee)
            if info:
                assignee = info['cn']
            else:
                name = bug.get('assigned_to_detail', {}).get('real_name', '')
                if name:
                    assignee = utils.get_better_name(name)
        else:
            assignee = 'Nobody'

        isacrash = len(utils.get_signatures(bug.get('cf_crash_signature',
                                                    ''))) != 0

        data[bugid] = {
            'land': {},
            'assignee': assignee,
            'crash': 'Yes' if isacrash else 'No',
            'priority': bug['priority'],
            'severity': bug['severity'],
            'tracking': bug[self.tracking_nightly],
            'status': bug['status'].lower(),
            'status_flags': {
                self.nightly: bug[self.status_nightly],
                self.beta: bug[self.status_beta],
                self.release: bug[self.status_release],
            },
            'keywords': ','.join(bug['keywords']),
        }

        return bug

    def filter_bugs(self, bugs):
        invalids = set()

        def comment_handler(bug, bugid, data):
            r = Bugzilla.get_landing_comments(bug['comments'], [], NIGHTLY_PAT)
            if not r:
                invalids.add(bugid)
                return

            data[bugid]['land'] = {
                i['revision']: {
                    'date': None,
                    'backedout': False,
                    'bugid': bugid
                }
                for i in r
            }

        bugids = list(bugs.keys())
        Bugzilla(
            bugids=bugids,
            commenthandler=comment_handler,
            commentdata=bugs,
            comment_include_fields=['text'],
        ).get_data().wait()

        for bugid in invalids:
            del bugs[bugid]

    def patch_analysis(self, patch):
        info = {'size': 0, 'test_size': 0, 'addlines': 0, 'rmlines': 0}

        for diff in whatthepatch.parse_patch(patch):
            if diff.header and diff.changes:
                h = diff.header
                new_path = h.new_path[2:] if h.new_path.startswith(
                    'b/') else h.new_path

                # Calc changes additions & deletions
                counts = [(old is None and new is not None, new is None
                           and old is not None)
                          for old, new, _ in diff.changes]
                counts = list(zip(*counts))  # inverse zip
                info['addlines'] += sum(counts[0])
                info['rmlines'] += sum(counts[1])

                if utils.is_test_file(new_path):
                    info['test_size'] += len(diff.changes)
                else:
                    info['size'] += len(diff.changes)

        return info

    def get_hg_patches(self, bugs):
        url = hgmozilla.RawRevision.get_url('nightly')
        queries = []

        def handler(patch, data):
            info = self.patch_analysis(patch)
            if 'addlines' not in data:
                data.update(info)
            else:
                for k, v in info.items():
                    data[k] += v

        for info in bugs.values():
            for rev, i in info['land'].items():
                if not i['backedout']:
                    queries.append(Query(url, {'node': rev}, handler, info))

        if queries:
            hgmozilla.Revision(queries=queries).wait()

        torm = []
        for bug, info in bugs.items():
            landed_patches = [v['backedout']
                              for v in info['land'].values()].count(False)
            # bug with only backouts
            if landed_patches == 0:

                torm.append(bug)
            else:
                info['landed_patches'] = landed_patches

        # Remove bugs that we don't want to show
        for bug in torm:
            del bugs[bug]

    def get_hg(self, bugs):
        url = hgmozilla.Revision.get_url('nightly')
        queries = []

        def handler_rev(json, data):
            push = json['pushdate'][0]
            push = datetime.datetime.utcfromtimestamp(push)
            push = lmdutils.as_utc(push)
            data['date'] = lmdutils.get_date_str(push)
            data['backedout'] = utils.is_backout(json)
            m = BUG_PAT.search(json['desc'])
            if not m or m.group(1) != data['bugid']:
                data['bugid'] = ''

        for info in bugs.values():
            for rev, i in info['land'].items():
                queries.append(Query(url, {'node': rev}, handler_rev, i))

        if queries:
            hgmozilla.Revision(queries=queries).wait()

        # clean
        bug_torm = []
        for bug, info in bugs.items():
            torm = []
            for rev, i in info['land'].items():
                if not i['bugid'] or not (self.date <= lmdutils.get_date_ymd(
                        i['date']) < self.tomorrow):
                    torm.append(rev)
            for x in torm:
                del info['land'][x]
            if not info['land']:
                bug_torm.append(bug)
        for x in bug_torm:
            del bugs[x]

        self.get_hg_patches(bugs)

    def get_bz_params(self, date):
        self.date = lmdutils.get_date_ymd(date)
        self.tomorrow = self.date + relativedelta(days=1)
        bugs = utils.get_bugs_from_pushlog(self.date, self.tomorrow)
        assignee_blacklist = self.get_config('assignee_blacklist', default=[])
        assignee_blacklist = ','.join(assignee_blacklist)
        fields = [
            'assigned_to',
            'assigned_to_detail',
            'status',
            'resolution',
            'priority',
            'severity',
            'keywords',
            'cf_crash_signature',
        ]
        fields += [self.status_nightly, self.status_beta, self.status_release]
        fields += [self.tracking_nightly]
        params = {
            'include_fields': fields,
            'bug_id': ','.join(bugs),
            'f1': 'assigned_to',
            'o1': 'nowords',
            'v1': assignee_blacklist,
        }

        return params

    def get_bugs(self, date='today', bug_ids=[]):
        bugs = super(CodeFreezeWeek, self).get_bugs(date=date, bug_ids=bug_ids)
        self.filter_bugs(bugs)
        self.get_hg(bugs)

        return bugs
Beispiel #22
0
class TestRoundRobin(unittest.TestCase):

    config = {
        'doc': 'The triagers need to have a \'Fallback\' entry.',
        'triagers': {
            'A B': {
                'bzmail': '*****@*****.**'
            },
            'C D': {
                'bzmail': '*****@*****.**'
            },
            'E F': {
                'bzmail': '*****@*****.**'
            },
            'Fallback': {
                'bzmail': '*****@*****.**'
            },
        },
        'components': {
            'P1::C1': 'default',
            'P2::C2': 'default',
            'P3::C3': 'special'
        },
        'default': {
            'doc': 'All the dates are the duty end dates.',
            '2019-02-21': 'A B',
            '2019-02-28': 'C D',
            '2019-03-07': 'E F',
        },
        'special': {
            'doc': 'All the dates are the duty end dates.',
            '2019-02-21': 'E F',
            '2019-02-28': 'A B',
            '2019-03-07': 'C D',
        },
    }

    people = People([{
        'mail': '*****@*****.**',
        'cn': 'G H',
        'ismanager': 'FALSE',
        'title': 'nothing',
    }])

    def mk_bug(self, pc):
        p, c = pc.split('::')
        return {
            'product': p,
            'component': c,
            'triage_owner': '*****@*****.**',
            'triage_owner_detail': {
                'nick': 'ij'
            },
        }

    @staticmethod
    def _get_nick(x, bzmail):
        return bzmail.split('@')[0]

    def test_get(self):
        with patch.object(RoundRobin, 'get_nick',
                          new=TestRoundRobin._get_nick):
            rr = RoundRobin(rr={'team': TestRoundRobin.config},
                            people=TestRoundRobin.people)

            assert rr.get(self.mk_bug('P1::C1'), '2019-02-17') == (
                '*****@*****.**',
                'ab',
            )
            assert rr.get(self.mk_bug('P2::C2'), '2019-02-17') == (
                '*****@*****.**',
                'ab',
            )
            assert rr.get(self.mk_bug('P3::C3'), '2019-02-17') == (
                '*****@*****.**',
                'ef',
            )

            assert rr.get(self.mk_bug('P1::C1'), '2019-02-24') == (
                '*****@*****.**',
                'cd',
            )
            assert rr.get(self.mk_bug('P2::C2'), '2019-02-24') == (
                '*****@*****.**',
                'cd',
            )
            assert rr.get(self.mk_bug('P3::C3'), '2019-02-24') == (
                '*****@*****.**',
                'ab',
            )

            assert rr.get(self.mk_bug('P1::C1'), '2019-02-28') == (
                '*****@*****.**',
                'cd',
            )
            assert rr.get(self.mk_bug('P2::C2'), '2019-02-28') == (
                '*****@*****.**',
                'cd',
            )
            assert rr.get(self.mk_bug('P3::C3'), '2019-02-28') == (
                '*****@*****.**',
                'ab',
            )

            assert rr.get(self.mk_bug('P1::C1'), '2019-03-05') == (
                '*****@*****.**',
                'ef',
            )
            assert rr.get(self.mk_bug('P2::C2'), '2019-03-05') == (
                '*****@*****.**',
                'ef',
            )
            assert rr.get(self.mk_bug('P3::C3'), '2019-03-05') == (
                '*****@*****.**',
                'cd',
            )

            assert rr.get(self.mk_bug('P1::C1'), '2019-03-08') == (
                '*****@*****.**',
                'gh',
            )
            assert rr.get(self.mk_bug('P2::C2'), '2019-03-08') == (
                '*****@*****.**',
                'gh',
            )
            assert rr.get(self.mk_bug('P3::C3'), '2019-03-08') == (
                '*****@*****.**',
                'gh',
            )

            assert rr.get(self.mk_bug('Foo::Bar'), '2019-03-01') == (
                '*****@*****.**',
                'ij',
            )

    def test_get_who_to_nag(self):
        rr = RoundRobin(rr={'team': TestRoundRobin.config},
                        people=TestRoundRobin.people)

        assert rr.get_who_to_nag('2019-02-25') == {}
        assert rr.get_who_to_nag('2019-02-28') == {'*****@*****.**': ['']}
        assert rr.get_who_to_nag('2019-03-05') == {'*****@*****.**': ['']}
        assert rr.get_who_to_nag('2019-03-07') == {'*****@*****.**': ['']}
        assert rr.get_who_to_nag('2019-03-10') == {'*****@*****.**': ['']}

        with patch.object(RoundRobin, 'is_mozilla', return_value=False):
            rr = RoundRobin(rr={'team': TestRoundRobin.config},
                            people=TestRoundRobin.people)

            self.assertRaises(BadFallback, rr.get_who_to_nag, '2019-03-01')
 def __init__(self):
     super(LeaveOpenNoActivity, self).__init__()
     self.people = People()
     self.nmonths = utils.get_config(self.name(), 'months_lookup')
     self.max_ni = utils.get_config(self.name(), 'max_ni')
     self.blacklist = set(utils.get_config(self.name(), 'blacklist', []))
 def __init__(self, rr=None, people=None, teams=None):
     self.people = People() if people is None else people
     self.all_calendars = []
     self.feed(teams, rr=rr)
     self.nicks = {}
Beispiel #25
0
 def __init__(self):
     super(MetaNoDepsNoActivity, self).__init__()
     self.people = People()
     self.nmonths = utils.get_config(self.name(), 'months_lookup')
     self.max_ni = utils.get_config(self.name(), 'max_ni')
     self.blacklist = set(utils.get_config(self.name(), 'blacklist', []))
class NewbieWithNI(BzCleaner):
    def __init__(self):
        super(NewbieWithNI, self).__init__()
        self.people = People()
        self.ndays = utils.get_config(self.name(), 'number_of_days', 14)
        self.ncomments = utils.get_config(self.name(), 'number_of_comments', 2)
        self.autofix_reporters = {}

    def description(self):
        return 'Bugs where the reporter has a needinfo and no activity for the last {} weeks'.format(
            self.ndays
        )

    def get_extra_for_template(self):
        return {'ndays': self.ndays, 'ncomments': self.ncomments}

    def get_autofix_change(self):
        return self.autofix_reporters

    def set_autofix(self, bugs):
        for bugid, v in bugs.items():
            nick = v['creator_nick']
            self.autofix_reporters[bugid] = {
                'comment': {
                    'body': 'Closing as INCOMPLETE because no answer to the needinfo.\n:{}, feel free to reopen the bug if you\'ve more information to provide.'.format(
                        nick
                    )
                },
                'status': 'RESOLVED',
                'resolution': 'INCOMPLETE',
            }

    def filter_interesting_bugs(self, bugs):
        """Get the bugs with number of comments less than self.ncommments
        """

        def comment_handler(bug, bugid, data):
            if len(bug['comments']) <= self.ncomments:
                data.append(bugid)

        bugids = list(bugs.keys())
        data = []
        Bugzilla(
            bugids=bugids,
            commenthandler=comment_handler,
            commentdata=data,
            comment_include_fields=['count'],
        ).get_data().wait()

        bugs = {bugid: bugs[bugid] for bugid in data}

        return bugs

    def get_bz_params(self, date):
        fields = ['creator', 'flags']
        params = {
            'include_fields': fields,
            'resolution': '---',
            'f1': 'flagtypes.name',
            'o1': 'substring',
            'v1': 'needinfo?',
            'f2': 'days_elapsed',
            'o2': 'greaterthan',
            'v2': self.ndays,
        }

        return params

    def handle_bug(self, bug, data):
        creator = bug['creator']
        if self.people.is_mozilla(creator):
            return None

        for flag in utils.get_needinfo(bug):
            if flag.get('requestee', '') == creator:
                bugid = str(bug['id'])
                nick = bug['creator_detail']['nick']
                data[bugid] = {'creator_nick': nick}
                return bug
        return None

    def get_bugs(self, date='today', bug_ids=[]):
        bugs = super(NewbieWithNI, self).get_bugs(date=date, bug_ids=bug_ids)
        bugs = self.filter_interesting_bugs(bugs)
        self.set_autofix(bugs)

        return bugs
Beispiel #27
0
 def __init__(self):
     super(LeaveOpenNoActivity, self).__init__()
     self.people = People()
     self.nmonths = utils.get_config(self.name(), 'months_lookup')
     self.max_ni = utils.get_config(self.name(), 'max_ni')
     self.skiplist = set(utils.get_config(self.name(), 'skiplist', []))
Beispiel #28
0
class Nag(object):
    def __init__(self):
        super(Nag, self).__init__()
        self.people = People()
        self.send_nag_mail = True
        self.data = {}
        self.nag_date = None
        self.white_list = []
        self.black_list = []
        self.escalation = Escalation(self.people)
        self.triage_owners = {}
        self.all_owners = None
        self.query_params = {}

    @staticmethod
    def get_from():
        return utils.get_config('auto_nag', 'from', '*****@*****.**')

    @staticmethod
    def get_cc():
        return set(utils.get_config('auto_nag', 'cc', []))

    def get_priority(self, bug):
        tracking = bug[self.tracking]
        if tracking == 'blocking':
            return 'high'
        return 'normal'

    def filter_bug(self, priority):
        days = (utils.get_next_release_date() - self.nag_date).days
        weekday = self.nag_date.weekday()
        return self.escalation.filter(priority, days, weekday)

    def get_people(self):
        return self.people

    def set_people_to_nag(self, bug, buginfo):
        return bug

    def escalate(self, person, priority, **kwargs):
        days = (utils.get_next_release_date() - self.nag_date).days
        return self.escalation.get_supervisor(priority, days, person, **kwargs)

    def add(self, person, bug_data, priority='default', **kwargs):
        if not self.people.is_mozilla(person):
            return False

        manager = self.escalate(person, priority, **kwargs)
        return self.add_couple(person, manager, bug_data)

    def add_couple(self, person, manager, bug_data):
        person = self.people.get_moz_mail(person)

        if manager in self.data:
            data = self.data[manager]
        else:
            self.data[manager] = data = {}
        if person in data:
            data[person].append(bug_data)
        else:
            data[person] = [bug_data]

        return True

    def nag_template(self):
        return self.name() + '_nag.html'

    def get_extra_for_nag_template(self):
        return {}

    def columns_nag(self):
        return None

    def sort_columns_nag(self):
        return None

    def _is_in_list(self, mail, _list):
        for manager in _list:
            if self.people.is_under(mail, manager):
                return True
        return False

    def is_under(self, mail):
        if not self.white_list:
            if not self.black_list:
                return True
            return not self._is_in_list(mail, self.black_list)
        if not self.black_list:
            return self._is_in_list(mail, self.white_list)
        return self._is_in_list(mail, self.white_list) and not self._is_in_list(
            mail, self.black_list
        )

    def add_triage_owner(self, owner, real_owner=None):
        if owner not in self.triage_owners:
            to = real_owner if real_owner is not None else owner
            self.triage_owners[owner] = self.get_query_url_for_triage_owner(to)

    def get_query_url_for_triage_owner(self, owner):
        if self.all_owners is None:
            self.all_owners = utils.get_triage_owners()
        params = copy.deepcopy(self.query_params)
        if 'include_fields' in params:
            del params['include_fields']

        comps = self.all_owners[owner]
        comps = set(comps)

        params['component'] = sorted(comps)
        url = utils.get_bz_search_url(params)

        return url

    def organize_nag(self, bugs):
        columns = self.columns_nag()
        if columns is None:
            columns = self.columns()
        key = self.sort_columns_nag()
        if key is None:
            key = self.sort_columns()

        return utils.organize(bugs, columns, key=key)

    def send_mails(self, title, dryrun=False):
        if not self.send_nag_mail:
            return

        env = Environment(loader=FileSystemLoader('templates'))
        common = env.get_template('common.html')
        login_info = utils.get_login_info()
        From = Nag.get_from()
        Default_Cc = Nag.get_cc()
        mails = self.prepare_mails()

        for m in mails:
            Cc = Default_Cc.copy()
            if m['manager']:
                Cc.add(m['manager'])
            body = common.render(message=m['body'], query_url=None)
            receivers = set(m['to']) | set(Cc)
            status = 'Success'
            try:
                mail.send(
                    From,
                    sorted(m['to']),
                    title,
                    body,
                    Cc=sorted(Cc),
                    html=True,
                    login=login_info,
                    dryrun=dryrun,
                )
            except:  # NOQA
                logger.exception('Tool {}'.format(self.name()))
                status = 'Failure'

            db.Email.add(self.name(), receivers, 'individual', status)

    def prepare_mails(self):
        if not self.data:
            return []

        template = self.nag_template()
        if not template:
            return []

        extra = self.get_extra_for_nag_template()
        env = Environment(loader=FileSystemLoader('templates'))
        template = env.get_template(template)
        mails = []
        for manager, info in self.data.items():
            data = []
            To = sorted(info.keys())
            for person in To:
                bug_data = info[person]
                data += bug_data

            if len(To) == 1 and To[0] in self.triage_owners:
                query_url = self.triage_owners[To[0]]
            else:
                query_url = None

            body = template.render(
                date=self.nag_date,
                extra=extra,
                plural=utils.plural,
                enumerate=enumerate,
                data=self.organize_nag(data),
                nag=True,
                query_url_nag=query_url,
                table_attrs=self.get_config('table_attrs'),
            )

            m = {'manager': manager, 'to': set(info.keys()), 'body': body}
            mails.append(m)

        return mails

    def reorganize_to_bag(self, data):
        return data
class CodeFreezeWeek(BzCleaner):
    def __init__(self):
        super(CodeFreezeWeek, self).__init__()
        self.versions = utils.get_checked_versions()
        if not self.versions:
            return

        self.people = People()
        self.nightly = self.versions['central']
        self.beta = self.versions['beta']
        self.release = self.versions['release']
        self.status_nightly = utils.get_flag(self.nightly, 'status', 'central')
        self.status_beta = utils.get_flag(self.beta, 'status', 'beta')
        self.status_release = utils.get_flag(self.release, 'status', 'release')
        self.tracking_nightly = utils.get_flag(self.nightly, 'tracking', 'central')
        self.tracking_beta = utils.get_flag(self.beta, 'tracking', 'beta')
        self.tracking_release = utils.get_flag(self.release, 'tracking', 'release')

    def description(self):
        return 'Bugs with patches which landed during the soft freeze week'

    def get_extra_for_template(self):
        return {
            'nightly': self.nightly,
            'beta': self.beta,
            'release': self.release,
            'date': lmdutils.get_date_str(self.date),
        }

    def filter_no_nag_keyword(self):
        return False

    def has_enough_data(self):
        return bool(self.versions)

    def must_run(self, date):
        for c in get_calendar():
            # if freeze is the 2019-03-11, then the tool must run the day after
            # until 2019-03-2018 (a week after)
            freeze = c['soft freeze']
            if freeze <= date <= freeze + relativedelta(days=6):
                return True
        return False

    def has_product_component(self):
        return True

    def columns(self):
        return [
            'id',
            'summary',
            'product',
            'component',
            'assignee',
            'landed_patches',
            'addlines',
            'rmlines',
            'size',
            'test_size',
            'priority',
            'severity',
            'tracking',
            'status',
            'status_flags',
            'crash',
            'keywords',
        ]

    def sort_columns(self):
        return lambda p: (p[2], p[3], -p[5], -p[8], -p[9], -int(p[0]))

    def handle_bug(self, bug, data):
        bugid = str(bug['id'])

        assignee = bug.get('assigned_to', '')
        if assignee:
            info = self.people.get_info(assignee)
            if info:
                assignee = info['cn']
            else:
                name = bug.get('assigned_to_detail', {}).get('real_name', '')
                if name:
                    assignee = utils.get_better_name(name)
        else:
            assignee = 'Nobody'

        isacrash = len(utils.get_signatures(bug.get('cf_crash_signature', ''))) != 0

        data[bugid] = {
            'land': {},
            'assignee': assignee,
            'crash': 'Yes' if isacrash else 'No',
            'priority': bug['priority'],
            'severity': bug['severity'],
            'tracking': bug[self.tracking_nightly],
            'status': bug['status'].lower(),
            'status_flags': {
                self.nightly: bug[self.status_nightly],
                self.beta: bug[self.status_beta],
                self.release: bug[self.status_release],
            },
            'keywords': ','.join(bug['keywords']),
        }

        return bug

    def filter_bugs(self, bugs):
        invalids = set()

        def comment_handler(bug, bugid, data):
            r = Bugzilla.get_landing_comments(bug['comments'], [], NIGHTLY_PAT)
            if not r:
                invalids.add(bugid)
                return

            data[bugid]['land'] = {
                i['revision']: {'date': None, 'backedout': False, 'bugid': bugid}
                for i in r
            }

        bugids = list(bugs.keys())
        Bugzilla(
            bugids=bugids,
            commenthandler=comment_handler,
            commentdata=bugs,
            comment_include_fields=['text'],
        ).get_data().wait()

        for bugid in invalids:
            del bugs[bugid]

    def patch_analysis(self, patch):
        info = {'size': 0, 'test_size': 0, 'addlines': 0, 'rmlines': 0}

        for diff in whatthepatch.parse_patch(patch):
            if diff.header and diff.changes:
                h = diff.header
                new_path = h.new_path[2:] if h.new_path.startswith('b/') else h.new_path

                # Calc changes additions & deletions
                counts = [
                    (old is None and new is not None, new is None and old is not None)
                    for old, new, _ in diff.changes
                ]
                counts = list(zip(*counts))  # inverse zip
                info['addlines'] += sum(counts[0])
                info['rmlines'] += sum(counts[1])

                if utils.is_test_file(new_path):
                    info['test_size'] += len(diff.changes)
                else:
                    info['size'] += len(diff.changes)

        return info

    def get_hg_patches(self, bugs):
        url = hgmozilla.RawRevision.get_url('nightly')
        queries = []

        def handler(patch, data):
            info = self.patch_analysis(patch)
            if 'addlines' not in data:
                data.update(info)
            else:
                for k, v in info.items():
                    data[k] += v

        for info in bugs.values():
            for rev, i in info['land'].items():
                if not i['backedout']:
                    queries.append(Query(url, {'node': rev}, handler, info))

        if queries:
            hgmozilla.Revision(queries=queries).wait()

        torm = []
        for bug, info in bugs.items():
            landed_patches = [v['backedout'] for v in info['land'].values()].count(
                False
            )
            # bug with only backouts
            if landed_patches == 0:

                torm.append(bug)
            else:
                info['landed_patches'] = landed_patches

        # Remove bugs that we don't want to show
        for bug in torm:
            del bugs[bug]

    def get_hg(self, bugs):
        url = hgmozilla.Revision.get_url('nightly')
        queries = []

        def handler_rev(json, data):
            push = json['pushdate'][0]
            push = datetime.datetime.utcfromtimestamp(push)
            push = lmdutils.as_utc(push)
            data['date'] = lmdutils.get_date_str(push)
            data['backedout'] = utils.is_backout(json)
            m = BUG_PAT.search(json['desc'])
            if not m or m.group(1) != data['bugid']:
                data['bugid'] = ''

        for info in bugs.values():
            for rev, i in info['land'].items():
                queries.append(Query(url, {'node': rev}, handler_rev, i))

        if queries:
            hgmozilla.Revision(queries=queries).wait()

        # clean
        bug_torm = []
        for bug, info in bugs.items():
            torm = []
            for rev, i in info['land'].items():
                if not i['bugid'] or not (
                    self.date <= lmdutils.get_date_ymd(i['date']) < self.tomorrow
                ):
                    torm.append(rev)
            for x in torm:
                del info['land'][x]
            if not info['land']:
                bug_torm.append(bug)
        for x in bug_torm:
            del bugs[x]

        self.get_hg_patches(bugs)

    def get_bz_params(self, date):
        self.date = lmdutils.get_date_ymd(date)
        self.tomorrow = self.date + relativedelta(days=1)
        bugs = utils.get_bugs_from_pushlog(self.date, self.tomorrow)
        assignee_blacklist = self.get_config('assignee_blacklist', default=[])
        assignee_blacklist = ','.join(assignee_blacklist)
        fields = [
            'assigned_to',
            'assigned_to_detail',
            'status',
            'resolution',
            'priority',
            'severity',
            'keywords',
            'cf_crash_signature',
        ]
        fields += [self.status_nightly, self.status_beta, self.status_release]
        fields += [self.tracking_nightly]
        params = {
            'include_fields': fields,
            'bug_id': ','.join(bugs),
            'f1': 'assigned_to',
            'o1': 'nowords',
            'v1': assignee_blacklist,
        }

        return params

    def get_bugs(self, date='today', bug_ids=[]):
        bugs = super(CodeFreezeWeek, self).get_bugs(date=date, bug_ids=bug_ids)
        self.filter_bugs(bugs)
        self.get_hg(bugs)

        return bugs
Beispiel #30
0
class TestRoundRobin(unittest.TestCase):

    default = {
        "duty-start-dates": {
            "2019-02-14": "A B",
            "2019-02-21": "C D",
            "2019-02-28": "E F",
        }
    }

    special = {
        "duty-start-dates": {
            "2019-02-14": "E F",
            "2019-02-21": "A B",
            "2019-02-28": "C D",
        }
    }

    config = {
        "fallback": "G H",
        "components": {"P1::C1": "default", "P2::C2": "default", "P3::C3": "special"},
        "default": {"calendar": json.dumps(default)},
        "special": {"calendar": json.dumps(special)},
    }

    config_ics = {
        "fallback": "G H",
        "components": {"P1::C1": "default", "P2::C2": "default"},
        "default": {"calendar": "auto_nag/tests/calendar.ics"},
    }

    people = People(
        [
            {
                "mail": "{}{}@mozilla.com".format(x, y),
                "cn": "{} {}".format(x.upper(), y.upper()),
                "ismanager": "FALSE",
                "title": "nothing",
            }
            for x, y in zip("aceg", "bdfh")
        ]
    )

    def mk_bug(self, pc):
        p, c = pc.split("::")
        return {
            "product": p,
            "component": c,
            "triage_owner": "*****@*****.**",
            "triage_owner_detail": {"nick": "ij"},
        }

    @staticmethod
    def _get_nick(x, bzmail, pc, cal):
        return bzmail.split("@")[0]

    def test_get(self):
        with patch.object(RoundRobin, "get_nick", new=TestRoundRobin._get_nick):
            rr = RoundRobin(
                rr={"team": TestRoundRobin.config}, people=TestRoundRobin.people
            )

            assert rr.get(self.mk_bug("P1::C1"), "2019-02-17") == (
                "*****@*****.**",
                "ab",
            )
            assert rr.get(self.mk_bug("P2::C2"), "2019-02-17") == (
                "*****@*****.**",
                "ab",
            )
            assert rr.get(self.mk_bug("P3::C3"), "2019-02-17") == (
                "*****@*****.**",
                "ef",
            )

            assert rr.get(self.mk_bug("P1::C1"), "2019-02-24") == (
                "*****@*****.**",
                "cd",
            )
            assert rr.get(self.mk_bug("P2::C2"), "2019-02-24") == (
                "*****@*****.**",
                "cd",
            )
            assert rr.get(self.mk_bug("P3::C3"), "2019-02-24") == (
                "*****@*****.**",
                "ab",
            )

            assert rr.get(self.mk_bug("P1::C1"), "2019-02-28") == (
                "*****@*****.**",
                "ef",
            )
            assert rr.get(self.mk_bug("P2::C2"), "2019-02-28") == (
                "*****@*****.**",
                "ef",
            )
            assert rr.get(self.mk_bug("P3::C3"), "2019-02-28") == (
                "*****@*****.**",
                "cd",
            )

            assert rr.get(self.mk_bug("P1::C1"), "2019-03-05") == (
                "*****@*****.**",
                "ef",
            )
            assert rr.get(self.mk_bug("P2::C2"), "2019-03-05") == (
                "*****@*****.**",
                "ef",
            )
            assert rr.get(self.mk_bug("P3::C3"), "2019-03-05") == (
                "*****@*****.**",
                "cd",
            )

            assert rr.get(self.mk_bug("P1::C1"), "2019-03-08") == (
                "*****@*****.**",
                "gh",
            )
            assert rr.get(self.mk_bug("P2::C2"), "2019-03-08") == (
                "*****@*****.**",
                "gh",
            )
            assert rr.get(self.mk_bug("P3::C3"), "2019-03-08") == (
                "*****@*****.**",
                "gh",
            )

            assert rr.get(self.mk_bug("Foo::Bar"), "2019-03-01") == (
                "*****@*****.**",
                "ij",
            )

    def test_get_ics(self):
        with patch.object(RoundRobin, "get_nick", new=TestRoundRobin._get_nick):
            rr = RoundRobin(
                rr={"team": TestRoundRobin.config_ics}, people=TestRoundRobin.people
            )

            assert rr.get(self.mk_bug("P1::C1"), "2019-02-17") == (
                "*****@*****.**",
                "ab",
            )
            assert rr.get(self.mk_bug("P2::C2"), "2019-02-17") == (
                "*****@*****.**",
                "ab",
            )

            assert rr.get(self.mk_bug("P1::C1"), "2019-02-24") == (
                "*****@*****.**",
                "cd",
            )
            assert rr.get(self.mk_bug("P2::C2"), "2019-02-24") == (
                "*****@*****.**",
                "cd",
            )

            assert rr.get(self.mk_bug("P1::C1"), "2019-02-28") == (
                "*****@*****.**",
                "ef",
            )
            assert rr.get(self.mk_bug("P2::C2"), "2019-02-28") == (
                "*****@*****.**",
                "ef",
            )

            assert rr.get(self.mk_bug("P1::C1"), "2019-03-05") == (
                "*****@*****.**",
                "ef",
            )
            assert rr.get(self.mk_bug("P2::C2"), "2019-03-05") == (
                "*****@*****.**",
                "ef",
            )

            assert rr.get(self.mk_bug("P1::C1"), "2019-03-08") == (
                "*****@*****.**",
                "ab",
            )
            assert rr.get(self.mk_bug("P2::C2"), "2019-03-08") == (
                "*****@*****.**",
                "ab",
            )

            assert rr.get(self.mk_bug("P1::C1"), "2019-03-15") == (
                "*****@*****.**",
                "gh",
            )
            assert rr.get(self.mk_bug("P2::C2"), "2019-03-15") == (
                "*****@*****.**",
                "gh",
            )

            assert rr.get(self.mk_bug("Foo::Bar"), "2019-03-01") == (
                "*****@*****.**",
                "ij",
            )

    def test_get_who_to_nag(self):
        rr = RoundRobin(
            rr={"team": TestRoundRobin.config}, people=TestRoundRobin.people
        )

        empty = {"team": {"nobody": True, "persons": []}}

        assert rr.get_who_to_nag("2019-02-25") == {}
        assert rr.get_who_to_nag("2019-03-01") == {"*****@*****.**": empty}
        assert rr.get_who_to_nag("2019-03-05") == {"*****@*****.**": empty}
        assert rr.get_who_to_nag("2019-03-07") == {"*****@*****.**": empty}
        assert rr.get_who_to_nag("2019-03-10") == {"*****@*****.**": empty}

        with patch.object(People, "get_moz_mail", return_value=None):
            rr = RoundRobin(
                rr={"team": TestRoundRobin.config}, people=TestRoundRobin.people
            )

            self.assertRaises(BadFallback, rr.get_who_to_nag, "2019-03-01")
Beispiel #31
0
class TestRoundRobin(unittest.TestCase):

    default = {
        'duty-start-dates': {
            '2019-02-14': 'A B',
            '2019-02-21': 'C D',
            '2019-02-28': 'E F',
        }
    }

    special = {
        'duty-start-dates': {
            '2019-02-14': 'E F',
            '2019-02-21': 'A B',
            '2019-02-28': 'C D',
        }
    }

    config = {
        'fallback': 'G H',
        'components': {
            'P1::C1': 'default',
            'P2::C2': 'default',
            'P3::C3': 'special'
        },
        'default': {
            'calendar': json.dumps(default)
        },
        'special': {
            'calendar': json.dumps(special)
        },
    }

    config_ics = {
        'fallback': 'G H',
        'components': {
            'P1::C1': 'default',
            'P2::C2': 'default'
        },
        'default': {
            'calendar': 'auto_nag/tests/calendar.ics'
        },
    }

    people = People([{
        'mail': '{}{}@mozilla.com'.format(x, y),
        'cn': '{} {}'.format(x.upper(), y.upper()),
        'ismanager': 'FALSE',
        'title': 'nothing',
    } for x, y in zip('aceg', 'bdfh')])

    def mk_bug(self, pc):
        p, c = pc.split('::')
        return {
            'product': p,
            'component': c,
            'triage_owner': '*****@*****.**',
            'triage_owner_detail': {
                'nick': 'ij'
            },
        }

    @staticmethod
    def _get_nick(x, bzmail):
        return bzmail.split('@')[0]

    def test_get(self):
        with patch.object(RoundRobin, 'get_nick',
                          new=TestRoundRobin._get_nick):
            rr = RoundRobin(rr={'team': TestRoundRobin.config},
                            people=TestRoundRobin.people)

            assert rr.get(self.mk_bug('P1::C1'), '2019-02-17') == (
                '*****@*****.**',
                'ab',
            )
            assert rr.get(self.mk_bug('P2::C2'), '2019-02-17') == (
                '*****@*****.**',
                'ab',
            )
            assert rr.get(self.mk_bug('P3::C3'), '2019-02-17') == (
                '*****@*****.**',
                'ef',
            )

            assert rr.get(self.mk_bug('P1::C1'), '2019-02-24') == (
                '*****@*****.**',
                'cd',
            )
            assert rr.get(self.mk_bug('P2::C2'), '2019-02-24') == (
                '*****@*****.**',
                'cd',
            )
            assert rr.get(self.mk_bug('P3::C3'), '2019-02-24') == (
                '*****@*****.**',
                'ab',
            )

            assert rr.get(self.mk_bug('P1::C1'), '2019-02-28') == (
                '*****@*****.**',
                'ef',
            )
            assert rr.get(self.mk_bug('P2::C2'), '2019-02-28') == (
                '*****@*****.**',
                'ef',
            )
            assert rr.get(self.mk_bug('P3::C3'), '2019-02-28') == (
                '*****@*****.**',
                'cd',
            )

            assert rr.get(self.mk_bug('P1::C1'), '2019-03-05') == (
                '*****@*****.**',
                'ef',
            )
            assert rr.get(self.mk_bug('P2::C2'), '2019-03-05') == (
                '*****@*****.**',
                'ef',
            )
            assert rr.get(self.mk_bug('P3::C3'), '2019-03-05') == (
                '*****@*****.**',
                'cd',
            )

            assert rr.get(self.mk_bug('P1::C1'), '2019-03-08') == (
                '*****@*****.**',
                'gh',
            )
            assert rr.get(self.mk_bug('P2::C2'), '2019-03-08') == (
                '*****@*****.**',
                'gh',
            )
            assert rr.get(self.mk_bug('P3::C3'), '2019-03-08') == (
                '*****@*****.**',
                'gh',
            )

            assert rr.get(self.mk_bug('Foo::Bar'), '2019-03-01') == (
                '*****@*****.**',
                'ij',
            )

    def test_get_ics(self):
        with patch.object(RoundRobin, 'get_nick',
                          new=TestRoundRobin._get_nick):
            rr = RoundRobin(rr={'team': TestRoundRobin.config_ics},
                            people=TestRoundRobin.people)

            assert rr.get(self.mk_bug('P1::C1'), '2019-02-17') == (
                '*****@*****.**',
                'ab',
            )
            assert rr.get(self.mk_bug('P2::C2'), '2019-02-17') == (
                '*****@*****.**',
                'ab',
            )

            assert rr.get(self.mk_bug('P1::C1'), '2019-02-24') == (
                '*****@*****.**',
                'cd',
            )
            assert rr.get(self.mk_bug('P2::C2'), '2019-02-24') == (
                '*****@*****.**',
                'cd',
            )

            assert rr.get(self.mk_bug('P1::C1'), '2019-02-28') == (
                '*****@*****.**',
                'ef',
            )
            assert rr.get(self.mk_bug('P2::C2'), '2019-02-28') == (
                '*****@*****.**',
                'ef',
            )

            assert rr.get(self.mk_bug('P1::C1'), '2019-03-05') == (
                '*****@*****.**',
                'ef',
            )
            assert rr.get(self.mk_bug('P2::C2'), '2019-03-05') == (
                '*****@*****.**',
                'ef',
            )

            assert rr.get(self.mk_bug('P1::C1'), '2019-03-08') == (
                '*****@*****.**',
                'gh',
            )
            assert rr.get(self.mk_bug('P2::C2'), '2019-03-08') == (
                '*****@*****.**',
                'gh',
            )

            assert rr.get(self.mk_bug('Foo::Bar'), '2019-03-01') == (
                '*****@*****.**',
                'ij',
            )

    def test_get_who_to_nag(self):
        rr = RoundRobin(rr={'team': TestRoundRobin.config},
                        people=TestRoundRobin.people)

        empty = {'team': {'nobody': True, 'persons': []}}

        assert rr.get_who_to_nag('2019-02-25') == {}
        assert rr.get_who_to_nag('2019-03-01') == {'*****@*****.**': empty}
        assert rr.get_who_to_nag('2019-03-05') == {'*****@*****.**': empty}
        assert rr.get_who_to_nag('2019-03-07') == {'*****@*****.**': empty}
        assert rr.get_who_to_nag('2019-03-10') == {'*****@*****.**': empty}

        with patch.object(People, 'get_moz_mail', return_value=None):
            rr = RoundRobin(rr={'team': TestRoundRobin.config},
                            people=TestRoundRobin.people)

            self.assertRaises(BadFallback, rr.get_who_to_nag, '2019-03-01')
Beispiel #32
0
 def __init__(self):
     super(HasSTRNoRange, self).__init__()
     self.people = People.get_instance()
     self.autofix_reporters = {}
    def test_escalation(self):
        people = [
            {
                'mail': '*****@*****.**',
                'cn': 'A B',
                'ismanager': 'FALSE',
                'manager': {
                    'dn': '[email protected],o=org,dc=mozilla'
                },
                'title': 'nothing',
            },
            {
                'mail': '*****@*****.**',
                'cn': 'C D',
                'ismanager': 'TRUE',
                'manager': {
                    'dn': '[email protected],o=org,dc=mozilla'
                },
                'title': 'manager',
            },
            {
                'mail': '*****@*****.**',
                'cn': 'E F',
                'ismanager': 'TRUE',
                'manager': {
                    'dn': '[email protected],o=org,dc=mozilla'
                },
                'title': 'super manager',
            },
            {
                'mail': '*****@*****.**',
                'cn': 'G H',
                'ismanager': 'TRUE',
                'manager': {
                    'dn': '[email protected],o=org,dc=mozilla'
                },
                'title': 'super manager',
            },
            {
                'mail': '*****@*****.**',
                'cn': 'I J',
                'ismanager': 'TRUE',
                'manager': {
                    'dn': '[email protected],o=org,dc=mozilla'
                },
                'title': 'director',
            },
            {
                'mail': '*****@*****.**',
                'cn': 'K L',
                'ismanager': 'TRUE',
                'title': 'vice president',
            },
        ]

        e = Escalation(People(people), data=TestEscalation.config)
        assert e.get_supervisor(
            'high', 35, '*****@*****.**',
            foobar='*****@*****.**') == '*****@*****.**'
        assert e.get_supervisor('high', 25,
                                '*****@*****.**') == '*****@*****.**'
        assert e.get_supervisor('high', 20,
                                '*****@*****.**') == '*****@*****.**'
        assert e.get_supervisor('high', 18,
                                '*****@*****.**') == '*****@*****.**'
        assert e.get_supervisor('high', 7,
                                '*****@*****.**') == '*****@*****.**'
        assert e.get_supervisor('high', 1,
                                '*****@*****.**') == '*****@*****.**'

        assert e.filter('high', 25, 0) == False
        assert e.filter('high', 25, 3) == True
        assert e.filter('high', 18, 0) == True
        assert e.filter('high', 18, 1) == False
        assert e.filter('high', 18, 3) == True
        assert e.filter('high', 18, 5) == False
        assert e.filter('high', 7, 1) == False
        assert e.filter('high', 7, 3) == True
        assert e.filter('high', 7, 5) == False
        assert e.filter('high', 1, 1) == True
        assert e.filter('high', 1, 3) == True
        assert e.filter('high', 1, 4) == True
        assert e.filter('high', 7, 5) == False

        assert e.get_supervisor('normal', 17,
                                '*****@*****.**') == '*****@*****.**'
        assert e.get_supervisor('normal', 15,
                                '*****@*****.**') == '*****@*****.**'
        assert e.get_supervisor('normal', 12,
                                '*****@*****.**') == '*****@*****.**'
        assert e.get_supervisor('normal', 7,
                                '*****@*****.**') == '*****@*****.**'
        assert e.get_supervisor('normal', 1,
                                '*****@*****.**') == '*****@*****.**'

        assert e.get_supervisor('default', 17,
                                '*****@*****.**') == '*****@*****.**'
        assert e.get_supervisor('default', 7,
                                '*****@*****.**') == '*****@*****.**'
        assert e.get_supervisor('default', 1,
                                '*****@*****.**') == '*****@*****.**'
        assert e.get_supervisor('default', 0,
                                '*****@*****.**') == '*****@*****.**'