コード例 #1
0
    def update_bug(self, bug, use_db=True):
        """
        Update a bug
        """

        # Skip when it's already processed in instance
        bug_id = bug['id']
        if bug_id in self.bugs:
            logger.warn('Bug {} already processed.'.format(bug_id))
            return self.bugs[bug_id]

        # Compute the hash of the new bug
        bug_hash = compute_dict_hash(bug)

        if use_db:
            # Fetch or create existing bug result
            try:
                br = BugResult.query.filter_by(bugzilla_id=bug_id).one()
                logger.info('Update existing {}'.format(br))

                # Check the bug has changed since last update
                if br.payload_hash == bug_hash:
                    logger.info('Same bug hash, skip bug analysis {}'.format(
                        br))  # noqa
                    return br

            except NoResultFound:
                br = BugResult(bug_id)
                logger.info('Create new {}'.format(br))
        else:
            # Create a new instance
            br = BugResult(bug_id)
            logger.info('Create new {}'.format(br))

        # Do patch analysis
        try:
            analysis = bug_analysis(bug_id)
        except Exception as e:
            logger.error('Patch analysis failed on {} : {}'.format(bug_id, e))
            return

        # Build html version of uplift comment
        if analysis['uplift_comment']:
            analysis['uplift_comment']['html'] = parse_uplift_comment(
                analysis['uplift_comment']['text'], bug_id)

        payload = {
            'url': '{}/{}'.format(self.bugzilla_url, bug['id']),
            'bug': bug,
            'analysis': analysis,
            'users': self.load_users(analysis),
        }
        br.payload = use_db and pickle.dumps(payload, 2) or payload
        br.payload_hash = bug_hash
        logger.info('Updated payload of {}'.format(br))

        # Save in local cache
        self.bugs[bug_id] = br

        return br
コード例 #2
0
    def update(self):
        """
        Update bug used in this sync
        """

        # Skip when it's already processed in instance
        if self.analysis is not None:
            logger.warn('Bug {} already processed.'.format(self.bugzilla_id))
            return True

        # Do patch analysis
        try:
            self.analysis = bug_analysis(self.bugzilla_id, 'release')
        except Exception as e:
            logger.error('Patch analysis failed on {} : {}'.format(
                self.bugzilla_id, e))  # noqa
            # TODO: Add to report
            return False

        # Build html version of uplift comment
        if self.analysis.get('uplift_comment'):
            self.analysis['uplift_comment']['html'] = parse_uplift_comment(
                self.analysis['uplift_comment']['text'], self.bugzilla_id)

        return True
コード例 #3
0
ファイル: workflow.py プロジェクト: garbas/mozilla-releng
    def update_bug(self, bug, use_db=True):
        """
        Update a bug
        """

        # Skip when it's already processed in instance
        bug_id = bug['id']
        if bug_id in self.bugs:
            logger.warn('Bug {} already processed.'.format(bug_id))
            return self.bugs[bug_id]

        # Compute the hash of the new bug
        bug_hash = compute_dict_hash(bug)

        if use_db:
            # Fetch or create existing bug result
            try:
                br = BugResult.query.filter_by(bugzilla_id=bug_id).one()
                logger.info('Update existing {}'.format(br))

                # Check the bug has changed since last update
                if br.payload_hash == bug_hash:
                    logger.info('Same bug hash, skip bug analysis {}'.format(br))  # noqa
                    return br

            except NoResultFound:
                br = BugResult(bug_id)
                logger.info('Create new {}'.format(br))
        else:
            # Create a new instance
            br = BugResult(bug_id)
            logger.info('Create new {}'.format(br))

        # Do patch analysis
        try:
            analysis = bug_analysis(bug_id)
        except Exception as e:
            logger.error('Patch analysis failed on {} : {}'.format(bug_id, e))
            return

        # Build html version of uplift comment
        if analysis['uplift_comment']:
            analysis['uplift_comment']['html'] = parse_uplift_comment(
                analysis['uplift_comment']['text'], bug_id)

        payload = {
            'url': '{}/{}'.format(self.bugzilla_url, bug['id']),
            'bug': bug,
            'analysis': analysis,
            'users': self.load_users(analysis),
        }
        br.payload = use_db and pickle.dumps(payload, 2) or payload
        br.payload_hash = bug_hash
        logger.info('Updated payload of {}'.format(br))

        # Save in local cache
        self.bugs[bug_id] = br

        return br
コード例 #4
0
def analyze_bug(bug):
    sys.stdout = sys.stderr = open('analyze_bugs_' + str(os.getpid()) + ".out",
                                   "a",
                                   buffering=0)

    uplift_channels = utils.uplift_channels(bug)

    try:
        info = patchanalysis.bug_analysis(bug,
                                          author_cache=author_cache,
                                          reviewer_cache=reviewer_cache)

        # Translate sets into lists, as sets are not JSON-serializable.
        info['users']['authors'] = list(info['users']['authors'])
        info['users']['reviewers'] = list(info['users']['reviewers'])

        info['component'] = bug['component']
        info['channels'] = uplift_channels
        info['types'] = utils.get_bug_types(bug)

        for channel in uplift_channels:
            uplift_info = patchanalysis.uplift_info(bug, channel)
            del uplift_info['landings']
            info[channel + '_uplift_info'] = uplift_info
            # Transform timedelta objects to number of seconds (to make them JSON-serializable).
            info[channel + '_uplift_info']['landing_delta'] = int(
                uplift_info['landing_delta'].total_seconds())
            info[channel + '_uplift_info']['response_delta'] = int(
                uplift_info['response_delta'].total_seconds())
            info[channel + '_uplift_info']['release_delta'] = int(
                uplift_info['release_delta'].total_seconds())
            if uplift_info['uplift_accepted']:
                info[channel +
                     '_uplift_info']['uplift_date'] = utils.get_uplift_date(
                         bug, channel).strftime('%Y-%m-%d')
            uplift_reject_date = utils.get_uplift_reject_date(bug, channel)
            if uplift_reject_date is not None:
                info[channel + '_uplift_info'][
                    'uplift_reject_date'] = uplift_reject_date.strftime(
                        '%Y-%m-%d')

        analyzed_bugs_shared[str(bug['id'])] = info
    except Exception as e:
        print('Error with bug ' + str(bug['id']) + ': ' + str(e))
        traceback.print_exc()
コード例 #5
0
ファイル: sync.py プロジェクト: La0/mozilla-relengapi
    def update(self):
        '''
        Update bug used in this sync
        '''

        # Skip when it's already processed in instance
        if self.analysis is not None:
            logger.warn('Bug {} already processed.'.format(self.bugzilla_id))
            return True

        # Do patch analysis
        try:
            self.analysis = bug_analysis(self.bugzilla_id, 'release')
        except Exception as e:
            logger.error('Patch analysis failed on {} : {}'.format(self.bugzilla_id, e))  # noqa
            # TODO: Add to report
            return False

        # Build html version of uplift comment
        if self.analysis.get('uplift_comment'):
            self.analysis['uplift_comment']['html'] = parse_uplift_comment(
                self.analysis['uplift_comment']['text'], self.bugzilla_id)

        return True
    def test_bug_analysis(self):
        # remove previous versions to avoid conflicts from responses
        versions.__dict__['__versions'] = None

        # Weird situation: the mozilla-central commit referenced in the comments is from some other
        # bug and the actual patch from the bug never landed on mozilla-central but directly on
        # other channels.
        with self.assertRaises(Exception) as exc:
            info = patchanalysis.bug_analysis(846986)

        self.assertIn(str(exc.exception), ['Too many matching authors ([email protected], [email protected]) found for [email protected]', 'Too many matching authors ([email protected], [email protected]) found for [email protected]'])

        info = patchanalysis.bug_analysis(846986, author_cache={
            '*****@*****.**': ['*****@*****.**'],
        })

        info = patchanalysis.bug_analysis(547914, uplift_channel='release')
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 1)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 11)
        self.assertEqual(info['patches']['1584ba8c1b86']['changes_size'], 640)
        self.assertEqual(info['patches']['1584ba8c1b86']['test_changes_size'], 0)
        self.assertEqual(info['patches']['1584ba8c1b86']['modules_num'], 1)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['patches']['1584ba8c1b86']['code_churn_overall'], 205)
        self.assertEqual(info['patches']['1584ba8c1b86']['code_churn_last_3_releases'], 36)
        self.assertEqual(info['patches']['1584ba8c1b86']['developer_familiarity_overall'], 13)
        self.assertEqual(info['patches']['1584ba8c1b86']['developer_familiarity_last_3_releases'], 1)
        self.assertEqual(info['patches']['1584ba8c1b86']['reviewer_familiarity_overall'], 0)
        self.assertEqual(info['patches']['1584ba8c1b86']['reviewer_familiarity_last_3_releases'], 0)
        self.assertEqual(info['patches']['1584ba8c1b86']['languages'], ['License', 'Makefile'])
        self.assertIn('*****@*****.**', info['users']['reviewers'])
        self.assertIn('*****@*****.**', info['users']['reviewers'])
        self.assertEqual(info['users']['assignee']['email'], '*****@*****.**')
        self.assertEqual(len(info['patches']), 1)
        self.assertEqual(info['patches']['1584ba8c1b86']['source'], 'mercurial')
        self.assertEqual(info['patches']['1584ba8c1b86']['url'], 'https://hg.mozilla.org/mozilla-central/rev/1584ba8c1b86')
        self.assertEqual(info['landings']['nightly'], datetime(2010, 4, 5, 23, 12, 52, tzinfo=pytz.UTC))
        self.assertIsNone(info['landings']['release'])
        self.assertIsNone(info['landings']['beta'])
        self.assertIsNone(info['landings']['aurora'])
        self.assertIsNone(info['landings']['esr'])

        bug = {}

        def bughandler(found_bug):
            bug.update(found_bug)

        def commenthandler(found_bug, bugid):
            bug['comments'] = found_bug['comments']

        def historyhandler(found_bug):
            bug['history'] = found_bug['history']

        def attachmenthandler(attachments, bugid):
            bug['attachments'] = attachments

        Bugzilla('id=547914', bughandler=bughandler, commenthandler=commenthandler, attachmenthandler=attachmenthandler, historyhandler=historyhandler).get_data().wait()

        info2 = patchanalysis.bug_analysis(bug)
        self.assertEqual(info2, info)

        info = patchanalysis.bug_analysis(647570, uplift_channel='release')
        self.assertEqual(info['backout_num'], 1)
        self.assertEqual(info['blocks'], 3)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 40)
        self.assertEqual(info['patches']['8641afbd20e6']['changes_size'], 486)
        self.assertEqual(info['patches']['8641afbd20e6']['test_changes_size'], 0)
        self.assertEqual(info['patches']['8641afbd20e6']['modules_num'], 3)
        self.assertEqual(info['r-ed_patches'], 3)
        self.assertEqual(info['patches']['8641afbd20e6']['code_churn_overall'], 184)
        self.assertEqual(info['patches']['8641afbd20e6']['code_churn_last_3_releases'], 31)
        self.assertEqual(info['patches']['8641afbd20e6']['developer_familiarity_overall'], 4)
        self.assertEqual(info['patches']['8641afbd20e6']['developer_familiarity_last_3_releases'], 4)
        self.assertEqual(info['patches']['8641afbd20e6']['reviewer_familiarity_overall'], 16)
        self.assertEqual(info['patches']['8641afbd20e6']['reviewer_familiarity_last_3_releases'], 0)
        self.assertEqual(len(info['patches']), 1)
        self.assertEqual(info['patches']['8641afbd20e6']['source'], 'mercurial')
        self.assertEqual(info['patches']['8641afbd20e6']['url'], 'https://hg.mozilla.org/mozilla-central/rev/8641afbd20e6')
        self.assertEqual(info['patches']['8641afbd20e6']['languages'], ['C', 'C++', 'Makefile'])
        self.assertEqual(info['landings']['nightly'], datetime(2011, 5, 26, 6, 40, 11, tzinfo=pytz.UTC))
        self.assertIsNone(info['landings']['release'])
        self.assertIsNone(info['landings']['beta'])
        self.assertIsNone(info['landings']['aurora'])
        self.assertIsNone(info['landings']['esr'])

        # Backed out once (when it was on inbound) with changesets from anther bug.
        # Author of the patch uses a different email in Bugzilla and Mercurial.
        # Reviewer's email doesn't start with his nick, but he's in CC list.
        with warnings.catch_warnings(record=True) as w:
            info = patchanalysis.bug_analysis(1271794, uplift_channel='release')
            self.assertWarnings(w, ['Revision d0ab0d508a24 was not found.', 'Revision 9f4983dfd881 was not found.', 'Bug 1271794 doesn\'t have a uplift request date.'])
            self.assertEqual(info['backout_num'], 1)
            self.assertEqual(info['blocks'], 1)
            self.assertEqual(info['depends_on'], 2)
            self.assertEqual(info['comments'], 24)
            self.assertEqual(info['patches']['154b951082e3']['changes_size'], 76)
            self.assertEqual(info['patches']['154b951082e3']['test_changes_size'], 0)
            self.assertEqual(info['patches']['154b951082e3']['modules_num'], 3)
            self.assertEqual(info['r-ed_patches'], 0)
            self.assertEqual(info['patches']['154b951082e3']['code_churn_overall'], 249)
            self.assertEqual(info['patches']['154b951082e3']['code_churn_last_3_releases'], 245)
            self.assertEqual(info['patches']['154b951082e3']['developer_familiarity_overall'], 2)
            self.assertEqual(info['patches']['154b951082e3']['developer_familiarity_last_3_releases'], 2)
            self.assertEqual(info['patches']['154b951082e3']['reviewer_familiarity_overall'], 158)
            self.assertEqual(info['patches']['154b951082e3']['reviewer_familiarity_last_3_releases'], 157)
            self.assertEqual(info['patches']['154b951082e3']['languages'], ['Makefile'])
            self.assertEqual(len(info['patches']), 1)
            self.assertEqual(info['patches']['154b951082e3']['source'], 'mercurial')
            self.assertEqual(info['patches']['154b951082e3']['url'], 'https://hg.mozilla.org/mozilla-central/rev/154b951082e3')
            self.assertEqual(info['landings']['nightly'], datetime(2016, 5, 19, 16, 54, 30, tzinfo=pytz.UTC))
            self.assertIsNone(info['landings']['release'])
            self.assertIsNone(info['landings']['beta'])
            self.assertIsNone(info['landings']['aurora'])
            self.assertIsNone(info['landings']['esr'])

        # Backed out from central and relanded on central.
        # One of the reviewers email doesn't start with his nick and he isn't in CC list.
        # The author of the patch changed his email on Bugzilla.
        info = patchanalysis.bug_analysis(679352, uplift_channel='release')
        self.assertEqual(info['backout_num'], 1)
        self.assertEqual(info['blocks'], 4)
        self.assertEqual(info['depends_on'], 4)
        self.assertEqual(info['comments'], 19)
        self.assertEqual(info['patches']['b9d0984bdd95']['changes_size'], 312)
        self.assertEqual(info['patches']['f5578fdc50ef']['changes_size'], 8524)
        self.assertEqual(info['patches']['b9d0984bdd95']['test_changes_size'], 0)
        self.assertEqual(info['patches']['f5578fdc50ef']['test_changes_size'], 410)
        self.assertEqual(info['patches']['b9d0984bdd95']['modules_num'], 2)
        self.assertEqual(info['patches']['f5578fdc50ef']['modules_num'], 3)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['patches']['b9d0984bdd95']['code_churn_overall'], 406)
        self.assertEqual(info['patches']['f5578fdc50ef']['code_churn_overall'], 670)
        self.assertEqual(info['patches']['b9d0984bdd95']['code_churn_last_3_releases'], 62)
        self.assertEqual(info['patches']['f5578fdc50ef']['code_churn_last_3_releases'], 121)
        self.assertEqual(info['patches']['b9d0984bdd95']['developer_familiarity_overall'], 5)
        self.assertEqual(info['patches']['f5578fdc50ef']['developer_familiarity_overall'], 5)
        self.assertEqual(info['patches']['b9d0984bdd95']['developer_familiarity_last_3_releases'], 5)
        self.assertEqual(info['patches']['f5578fdc50ef']['developer_familiarity_last_3_releases'], 5)
        self.assertEqual(info['patches']['b9d0984bdd95']['reviewer_familiarity_overall'], 48)
        self.assertEqual(info['patches']['f5578fdc50ef']['reviewer_familiarity_overall'], 9)
        self.assertEqual(info['patches']['b9d0984bdd95']['reviewer_familiarity_last_3_releases'], 1)
        self.assertEqual(info['patches']['f5578fdc50ef']['reviewer_familiarity_last_3_releases'], 2)
        self.assertEqual(info['patches']['b9d0984bdd95']['languages'], ['C', 'C++', 'Windows IDL'])
        self.assertEqual(info['patches']['f5578fdc50ef']['languages'], ['C', 'Makefile', 'Shell'])
        self.assertEqual(len(info['patches']), 2)
        self.assertEqual(info['patches']['b9d0984bdd95']['source'], 'mercurial')
        self.assertIn(info['patches']['b9d0984bdd95']['url'], 'https://hg.mozilla.org/mozilla-central/rev/b9d0984bdd95')
        self.assertEqual(info['patches']['f5578fdc50ef']['source'], 'mercurial')
        self.assertIn(info['patches']['f5578fdc50ef']['url'], 'https://hg.mozilla.org/mozilla-central/rev/f5578fdc50ef')
        self.assertEqual(info['landings']['nightly'], datetime(2011, 12, 11, 4, 15, 3, tzinfo=pytz.UTC))
        self.assertIsNone(info['landings']['release'])
        self.assertIsNone(info['landings']['beta'])
        self.assertIsNone(info['landings']['aurora'])
        self.assertIsNone(info['landings']['esr'])

        # Changeset with multiple unrelated backouts (on fx-team).
        # Landing comment with long revision (Entire hash instead of first 12 characters).
        info = patchanalysis.bug_analysis(384458, uplift_channel='release')
        self.assertEqual(info['backout_num'], 1)
        self.assertEqual(info['blocks'], 6)
        self.assertEqual(info['depends_on'], 64)
        self.assertEqual(info['comments'], 110)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqualPatches(info['patches'], 384458)
        self.assertEqual(info['landings']['nightly'], datetime(2016, 6, 10, 13, 42, 45, tzinfo=pytz.UTC))
        self.assertIsNone(info['landings']['release'])
        self.assertIsNone(info['landings']['beta'])
        self.assertIsNone(info['landings']['aurora'])
        self.assertIsNone(info['landings']['esr'])

        # Custom backout (no reference to revision).
        # Author has a different name on Bugzilla and Mercurial and they don't use the email on Mercurial.
        with warnings.catch_warnings(record=True) as w:
            info = patchanalysis.bug_analysis(1220307, uplift_channel='release')
            if sys.version_info >= (3, 0):
                self.assertWarnings(w, ['da10eecd0e76 looks like a backout, but we couldn\'t find which revision was backed out.', 'Revision da10eecd0e76 is related to another bug (1276850).', 'Bug 1220307 doesn\'t have a uplift request date.'])
            self.assertEqual(info['backout_num'], 2)
            self.assertEqual(info['blocks'], 4)
            self.assertEqual(info['depends_on'], 1)
            self.assertEqual(info['comments'], 43)
            self.assertEqual(info['r-ed_patches'], 0)
            self.assertEqualPatches(info['patches'], 1220307)

        with warnings.catch_warnings(record=True) as w:
            info = patchanalysis.bug_analysis(1276850, uplift_channel='release')
            if sys.version_info >= (3, 0):
                self.assertWarnings(w, ['da10eecd0e76 looks like a backout, but we couldn\'t find which revision was backed out.', 'Author [email protected] is not in the list of authors on Bugzilla ().', 'Bug 1276850 doesn\'t have a uplift request date.'])
            self.assertEqual(info['backout_num'], 0)
            self.assertEqual(info['blocks'], 1)
            self.assertEqual(info['depends_on'], 0)
            self.assertEqual(info['comments'], 24)
            self.assertEqual(info['r-ed_patches'], 0)
            self.assertEqualPatches(info['patches'], 1276850)
            self.assertEqual(info['landings']['nightly'], datetime(2016, 6, 6, 15, 4, 18, tzinfo=pytz.UTC))
            self.assertIsNone(info['landings']['release'])
            self.assertIsNone(info['landings']['beta'])
            self.assertIsNone(info['landings']['aurora'])
            self.assertIsNone(info['landings']['esr'])

        # No landed patches.
        # The author of the patch changed his email on Bugzilla, so past contributions
        # are hard to find.
        info = patchanalysis.bug_analysis(1007402)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 1)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 41)
        self.assertEqual(info['r-ed_patches'], 1)
        self.assertEqualPatches(info['patches'], 1007402)

        # No link between Bugzilla account and Mercurial author.
        # Reviewer uses different email on Bugzilla and Mercurial.
        info = patchanalysis.bug_analysis(901821)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 1)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 11)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqualPatches(info['patches'], 901821)

        # Reviewer has different emails on Bugzilla and Mercurial, and his short name is hard to find.
        info = patchanalysis.bug_analysis(859425)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 0)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 8)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqualPatches(info['patches'], 859425)

        # r=bustage
        info = patchanalysis.bug_analysis(701875)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 3)
        self.assertEqual(info['depends_on'], 1)
        self.assertEqual(info['comments'], 69)
        self.assertEqual(info['r-ed_patches'], 1)
        self.assertEqualPatches(info['patches'], 701875)

        # Reviewer doesn't have his short name in his Bugzilla name.
        with warnings.catch_warnings(record=True) as w:
            info = patchanalysis.bug_analysis(853033)
            self.assertWarnings(w, ['Revision 8de609c5d378 is related to another bug (743252).', 'Reviewer jlebar could not be found.'])
            self.assertEqual(info['backout_num'], 0)
            self.assertEqual(info['blocks'], 2)
            self.assertEqual(info['depends_on'], 0)
            self.assertEqual(info['comments'], 13)
            self.assertEqual(info['r-ed_patches'], 0)
            self.assertEqualPatches(info['patches'], 853033)

        # There are users in the CC list with empty real names.
        info = patchanalysis.bug_analysis(699633)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 0)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 41)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqualPatches(info['patches'], 699633)

        # Reviewer with several IRC names.
        info = patchanalysis.bug_analysis(914034)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 2)
        self.assertEqual(info['depends_on'], 1)
        self.assertEqual(info['comments'], 26)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqualPatches(info['patches'], 914034)

        # IRC handle in the domain of the email ([email protected]).
        info = patchanalysis.bug_analysis(903475)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 1)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 71)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqualPatches(info['patches'], 903475)

        # Backout without the 'changeset' word.
        info = patchanalysis.bug_analysis(829421)
        self.assertEqual(info['backout_num'], 1)
        self.assertEqual(info['blocks'], 0)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 22)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqualPatches(info['patches'], 829421)

        # IRC handle first character is lower case in Mercurial, upper case in Bugzilla.
        info = patchanalysis.bug_analysis(799266)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 0)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 28)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqualPatches(info['patches'], 799266)

        # r=IRC_HANDLE_OF_THE_AUTHOR
        info = patchanalysis.bug_analysis(721760)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 0)
        self.assertEqual(info['depends_on'], 1)
        self.assertEqual(info['comments'], 72)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqualPatches(info['patches'], 721760)

        # IRC handle is ':IRC_HANDLE.SURNAME' and reviewer is not a reviewer of the patch on Bugzilla.
        info = patchanalysis.bug_analysis(1021265)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 3)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 111)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqualPatches(info['patches'], 1021265)

        # IRC handle is the beginning of the real name with a space after.
        info = patchanalysis.bug_analysis(1029098)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 1)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 15)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqualPatches(info['patches'], 1029098)

        # Typo in the reviewer name.
        with warnings.catch_warnings(record=True) as w:
            info = patchanalysis.bug_analysis(843733)
            self.assertWarnings(w, ['Reviewer mjronseb could not be found.'])

        # r=oops
        info = patchanalysis.bug_analysis(843821)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 1)
        self.assertEqual(info['depends_on'], 1)
        self.assertEqual(info['comments'], 21)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqualPatches(info['patches'], 843821)

        # r=backout
        info = patchanalysis.bug_analysis(679509)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 0)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 97)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqualPatches(info['patches'], 679509)

        # Bugzilla user is impossible to find from IRC handle.
        with warnings.catch_warnings(record=True) as w:
            info = patchanalysis.bug_analysis(700583, uplift_channel='release')
            self.assertWarnings(w, ['Reviewer [email protected] is not in the list of reviewers on Bugzilla (' + ', '.join(sorted(['*****@*****.**', '*****@*****.**'])) + ').', 'Bug 700583 doesn\'t have a uplift request date.'])

        # IRC handle is name+surname
        info = patchanalysis.bug_analysis(701262)

        # r=none
        info = patchanalysis.bug_analysis(733614)

        # Reviewer on Bugzilla is a different person than the reviewer in the Mercurial commit.
        with warnings.catch_warnings(record=True) as w:
            info = patchanalysis.bug_analysis(963621)
            self.assertWarnings(w, ['Reviewer doublec could not be found.'])

        # IRC handle is part of the name.
        info = patchanalysis.bug_analysis(829646)

        # Multiple backouts with a commit message of one line.
        info = patchanalysis.bug_analysis(683280)

        # IRC handle on Bugzilla is different than the one used in Mercurial.
        info = patchanalysis.bug_analysis(680802)

        # A comment contains a non-existing revision.
        with warnings.catch_warnings(record=True) as w:
            info = patchanalysis.bug_analysis(1156913)
            self.assertWarnings(w, ['Revision fa8854bd0029 doesn\'t exist.'])

        # Author in mercurial doesn't use the same format as usual ("Full Name email" instead of "Full Name <email>").
        info = patchanalysis.bug_analysis(1277522)

        # Author in mercurial doesn't have email
        # ESR landing too

        info = patchanalysis.bug_analysis(1254980, uplift_channel='release')
        self.assertEqual(info['landings']['nightly'], datetime(2016, 3, 26, 2, 12, 27, tzinfo=pytz.UTC))
        self.assertEqual(info['landings']['aurora'], datetime(2016, 3, 28, 23, 24, 6, tzinfo=pytz.UTC))
        self.assertEqual(info['landings']['beta'], datetime(2016, 3, 31, 19, 48, 30, tzinfo=pytz.UTC))
        self.assertEqual(info['landings']['release'], datetime(2016, 4, 6, 19, 35, 18, tzinfo=pytz.UTC))
        self.assertEqual(info['landings']['esr'], datetime(2016, 4, 7, 18, 41, 3, tzinfo=pytz.UTC))

        # Check uplift request
        info = patchanalysis.bug_analysis(1230065, uplift_channel='release')

        self.assertIsNotNone(info['uplift_comment'])
        self.assertEqual(len(info['uplift_comment']['text'].split('\n')), 11)
        self.assertEqual(info['uplift_comment']['id'], 11222288)
        self.assertIsNotNone(info['uplift_author'])
        self.assertEqual(info['uplift_author']['email'], '*****@*****.**')
        self.assertIsNone(info['uplift_reviewer'])

        # in-testsuite?
        info = patchanalysis.bug_analysis(1190)
        self.assertEqual(info['in-testsuite'], '?')
        # in-testsuite-
        info = patchanalysis.bug_analysis(91)
        self.assertEqual(info['in-testsuite'], '-')
        # in-testsuite+
        info = patchanalysis.bug_analysis(105)
        self.assertEqual(info['in-testsuite'], '+')
        # in-testsuite not set
        info = patchanalysis.bug_analysis(1234567)
        self.assertEqual(info['in-testsuite'], '')

        info = patchanalysis.bug_analysis(712363)
        self.assertEqual(info['backout_num'], 0)
        self.assertIn('e610972755d9', info['patches'])
        self.assertIn('0bcaac9fadf1', info['patches'])
        self.assertIn('efae575a79e4', info['patches'])
        self.assertIn('9576aeb57bd4', info['patches'])
        self.assertIn('d9eab22ce37a', info['patches'])

        # Author email has different upper- and lower-case letters on Mercurial and Bugzilla.
        info = patchanalysis.bug_analysis(772679)
        for h in ['8364cb62506e', '970496fa31dd', '7566f863512b', '1ee6a1ae6cfc', 'b2127fc9bd2b', '6424adfb7ac2', 'e63fd4fc05a0', 'b15fb3603bfe', '14d17919e235', '6efd09dda9e1', '313b5b97e7e3', 'f89ae41eed63']:
            self.assertIn(h, info['patches'])

        # Bugs with patches with no changes.
        info = patchanalysis.bug_analysis(829557, author_cache={
            '*****@*****.**': ['*****@*****.**'],
        })
        info = patchanalysis.bug_analysis(1019595)
        info = patchanalysis.bug_analysis(1264786)
        info = patchanalysis.bug_analysis(1114040)
        info = patchanalysis.bug_analysis(1211871)

        # Reviewer can't be found.
        info = patchanalysis.bug_analysis(1161913, reviewer_cache={
            'mt': '*****@*****.**',
        })

        # Reviewer has a point in the short name.
        info = patchanalysis.bug_analysis(1232113)

        # Reviewer has an underscore in the short name.
        info = patchanalysis.bug_analysis(1281387)
コード例 #7
0
    def test_bug_analysis(self):
        info = patchanalysis.bug_analysis(547914)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 1)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 11)
        self.assertEqual(info['changes_size'], 640)
        self.assertEqual(info['test_changes_size'], 0)
        self.assertEqual(info['modules_num'], 1)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['code_churn_overall'], 205)
        self.assertEqual(info['code_churn_last_3_releases'], 36)
        self.assertEqual(info['developer_familiarity_overall'], 13)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 1)
        self.assertEqual(info['reviewer_familiarity_overall'], 0)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 0)
        self.assertIn('*****@*****.**', info['users']['reviewers'])
        self.assertIn('*****@*****.**', info['users']['reviewers'])
        self.assertEqual(info['users']['assignee']['email'], '*****@*****.**')

        self.assertGreater(info['crashes'], 0)

        bug = {}

        def bughandler(found_bug, data):
            bug.update(found_bug)

        def commenthandler(found_bug, bugid, data):
            bug['comments'] = found_bug['comments']

        def historyhandler(found_bug, data):
            bug['history'] = found_bug['history']

        def attachmenthandler(attachments, bugid, data):
            bug['attachments'] = attachments

        Bugzilla('id=547914', bughandler=bughandler, commenthandler=commenthandler, attachmenthandler=attachmenthandler, historyhandler=historyhandler).get_data().wait()

        info2 = patchanalysis.bug_analysis(bug)
        self.assertEqual(info2, info)

        info = patchanalysis.bug_analysis(647570)
        self.assertEqual(info['backout_num'], 1)
        self.assertEqual(info['blocks'], 3)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 40)
        self.assertEqual(info['changes_size'], 488)
        self.assertEqual(info['test_changes_size'], 0)
        self.assertEqual(info['modules_num'], 3)
        self.assertEqual(info['r-ed_patches'], 3)
        self.assertEqual(info['code_churn_overall'], 184)
        self.assertEqual(info['code_churn_last_3_releases'], 31)
        self.assertEqual(info['developer_familiarity_overall'], 4)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 4)
        self.assertEqual(info['reviewer_familiarity_overall'], 16)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 0)
        self.assertGreater(info['crashes'], 0)

        # Backed out once (when it was on inbound) with changesets from anther bug.
        # Author of the patch uses a different email in Bugzilla and Mercurial.
        # Reviewer's email doesn't start with his nick, but he's in CC list.
        with warnings.catch_warnings(record=True) as w:
            info = patchanalysis.bug_analysis(1271794)
            self.assertWarnings(w, ['Revision d0ab0d508a24 was not found.', 'Revision 9f4983dfd881 was not found.', 'Bug 1271794 doesn\'t have a uplift request date.'])
            self.assertEqual(info['backout_num'], 1)
            self.assertEqual(info['blocks'], 1)
            self.assertEqual(info['depends_on'], 2)
            self.assertEqual(info['comments'], 24)
            self.assertEqual(info['changes_size'], 76)
            self.assertEqual(info['test_changes_size'], 0)
            self.assertEqual(info['modules_num'], 3)
            self.assertEqual(info['r-ed_patches'], 0)
            self.assertEqual(info['code_churn_overall'], 249)
            self.assertEqual(info['code_churn_last_3_releases'], 245)
            self.assertEqual(info['developer_familiarity_overall'], 2)
            self.assertEqual(info['developer_familiarity_last_3_releases'], 2)
            self.assertEqual(info['reviewer_familiarity_overall'], 158)
            self.assertEqual(info['reviewer_familiarity_last_3_releases'], 157)
            self.assertGreaterEqual(info['crashes'], 0)

        # Backed out from central and relanded on central.
        # One of the reviewers email doesn't start with his nick and he isn't in CC list.
        # The author of the patch changed his email on Bugzilla.
        info = patchanalysis.bug_analysis(679352)
        self.assertEqual(info['backout_num'], 1)
        self.assertEqual(info['blocks'], 4)
        self.assertEqual(info['depends_on'], 4)
        self.assertEqual(info['comments'], 19)
        self.assertEqual(info['changes_size'], 8836)
        self.assertEqual(info['test_changes_size'], 410)
        self.assertEqual(info['modules_num'], 5)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['code_churn_overall'], 1076)
        self.assertEqual(info['code_churn_last_3_releases'], 183)
        self.assertEqual(info['developer_familiarity_overall'], 10)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 10)
        self.assertEqual(info['reviewer_familiarity_overall'], 57)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 3)
        self.assertGreater(info['crashes'], 0)

        # Changeset with multiple unrelated backouts (on fx-team).
        # Landing comment with long revision (Entire hash instead of first 12 characters).
        info = patchanalysis.bug_analysis(384458)
        self.assertEqual(info['backout_num'], 1)
        self.assertEqual(info['blocks'], 6)
        self.assertEqual(info['depends_on'], 47)
        self.assertEqual(info['comments'], 106)
        self.assertEqual(info['changes_size'], 2752)
        self.assertEqual(info['test_changes_size'], 462)
        self.assertEqual(info['modules_num'], 11)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['code_churn_overall'], 8191)
        self.assertEqual(info['code_churn_last_3_releases'], 801)
        self.assertEqual(info['developer_familiarity_overall'], 162)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 51)
        self.assertEqual(info['reviewer_familiarity_overall'], 2)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 0)
        self.assertGreater(info['crashes'], 0)

        # Custom backout (no reference to revision).
        # Author has a different name on Bugzilla and Mercurial and they don't use the email on Mercurial.
        with warnings.catch_warnings(record=True) as w:
            info = patchanalysis.bug_analysis(1220307)
            self.assertWarnings(w, ['da10eecd0e76 looks like a backout, but we couldn\'t find which revision was backed out.', 'Revision da10eecd0e76 is related to another bug (1276850).', 'Bug 1220307 doesn\'t have a uplift request date.'])
            self.assertEqual(info['backout_num'], 2)
            self.assertEqual(info['blocks'], 4)
            self.assertEqual(info['depends_on'], 1)
            self.assertEqual(info['comments'], 42)
            self.assertEqual(info['changes_size'], 67)
            self.assertEqual(info['test_changes_size'], 50)
            self.assertEqual(info['modules_num'], 3)
            self.assertEqual(info['r-ed_patches'], 0)
            self.assertEqual(info['code_churn_overall'], 79)
            self.assertEqual(info['code_churn_last_3_releases'], 33)
            self.assertEqual(info['developer_familiarity_overall'], 5)
            self.assertEqual(info['developer_familiarity_last_3_releases'], 5)
            self.assertEqual(info['reviewer_familiarity_overall'], 2)
            self.assertEqual(info['reviewer_familiarity_last_3_releases'], 1)
            self.assertGreater(info['crashes'], 0)

        with warnings.catch_warnings(record=True) as w:
            info = patchanalysis.bug_analysis(1276850)
            self.assertWarnings(w, ['da10eecd0e76 looks like a backout, but we couldn\'t find which revision was backed out.', 'Author [email protected] is not in the list of authors on Bugzilla.', 'Bug 1276850 doesn\'t have a uplift request date.'])
            self.assertEqual(info['backout_num'], 0)
            self.assertEqual(info['blocks'], 1)
            self.assertEqual(info['depends_on'], 0)
            self.assertEqual(info['comments'], 24)
            self.assertEqual(info['changes_size'], 40)
            self.assertEqual(info['test_changes_size'], 0)
            self.assertEqual(info['modules_num'], 1)
            self.assertEqual(info['r-ed_patches'], 0)
            self.assertEqual(info['code_churn_overall'], 26)
            self.assertEqual(info['code_churn_last_3_releases'], 21)
            self.assertEqual(info['developer_familiarity_overall'], 0)
            self.assertEqual(info['developer_familiarity_last_3_releases'], 0)
            self.assertEqual(info['reviewer_familiarity_overall'], 26)
            self.assertEqual(info['reviewer_familiarity_last_3_releases'], 21)
            self.assertGreater(info['crashes'], 0)

        # No landed patches.
        # The author of the patch changed his email on Bugzilla, so past contributions
        # are hard to find.
        info = patchanalysis.bug_analysis(1007402)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 1)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 41)
        self.assertEqual(info['changes_size'], 1035)
        self.assertEqual(info['test_changes_size'], 445)
        self.assertEqual(info['modules_num'], 6)
        self.assertEqual(info['r-ed_patches'], 1)
        self.assertEqual(info['code_churn_overall'], 2465)
        self.assertEqual(info['code_churn_last_3_releases'], 316)
        self.assertEqual(info['developer_familiarity_overall'], 4)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 4)
        self.assertEqual(info['reviewer_familiarity_overall'], 266)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 15)
        self.assertGreaterEqual(info['crashes'], 0)

        # No link between Bugzilla account and Mercurial author.
        # Reviewer uses different email on Bugzilla and Mercurial.
        info = patchanalysis.bug_analysis(901821)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 1)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 11)
        self.assertEqual(info['changes_size'], 18)
        self.assertEqual(info['test_changes_size'], 0)
        self.assertEqual(info['modules_num'], 1)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['code_churn_overall'], 1088)
        self.assertEqual(info['code_churn_last_3_releases'], 152)
        self.assertEqual(info['developer_familiarity_overall'], 115)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 23)
        self.assertEqual(info['reviewer_familiarity_overall'], 0)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 0)
        self.assertGreaterEqual(info['crashes'], 0)

        # Reviewer has different emails on Bugzilla and Mercurial, and his short name is hard to find.
        info = patchanalysis.bug_analysis(859425)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 0)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 8)
        self.assertEqual(info['changes_size'], 31)
        self.assertEqual(info['test_changes_size'], 0)
        self.assertEqual(info['modules_num'], 1)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['code_churn_overall'], 79)
        self.assertEqual(info['code_churn_last_3_releases'], 30)
        self.assertEqual(info['developer_familiarity_overall'], 1)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 1)
        self.assertEqual(info['reviewer_familiarity_overall'], 0)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 0)
        self.assertGreaterEqual(info['crashes'], 0)

        # r=bustage
        info = patchanalysis.bug_analysis(701875)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 3)
        self.assertEqual(info['depends_on'], 1)
        self.assertEqual(info['comments'], 69)
        self.assertEqual(info['changes_size'], 194)
        self.assertEqual(info['test_changes_size'], 0)
        self.assertEqual(info['modules_num'], 5)
        self.assertEqual(info['r-ed_patches'], 1)
        self.assertEqual(info['code_churn_overall'], 3770)
        self.assertEqual(info['code_churn_last_3_releases'], 526)
        self.assertEqual(info['developer_familiarity_overall'], 86)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 12)
        self.assertEqual(info['reviewer_familiarity_overall'], 25)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 5)
        self.assertGreaterEqual(info['crashes'], 0)

        # Reviewer doesn't have his short name in his Bugzilla name.
        with warnings.catch_warnings(record=True) as w:
            info = patchanalysis.bug_analysis(853033)
            self.assertWarnings(w, ['Revision 8de609c5d378 is related to another bug (743252).', 'Reviewer jlebar could not be found.'])
            self.assertEqual(info['backout_num'], 0)
            self.assertEqual(info['blocks'], 2)
            self.assertEqual(info['depends_on'], 0)
            self.assertEqual(info['comments'], 13)
            self.assertEqual(info['changes_size'], 18)
            self.assertEqual(info['test_changes_size'], 0)
            self.assertEqual(info['modules_num'], 1)
            self.assertEqual(info['r-ed_patches'], 0)
            self.assertEqual(info['code_churn_overall'], 4)
            self.assertEqual(info['code_churn_last_3_releases'], 1)
            self.assertEqual(info['developer_familiarity_overall'], 1)
            self.assertEqual(info['developer_familiarity_last_3_releases'], 1)
            self.assertEqual(info['reviewer_familiarity_overall'], 0)
            self.assertEqual(info['reviewer_familiarity_last_3_releases'], 0)
            self.assertGreaterEqual(info['crashes'], 0)

        # There are users in the CC list with empty real names.
        info = patchanalysis.bug_analysis(699633)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 0)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 41)
        self.assertEqual(info['changes_size'], 179)
        self.assertEqual(info['test_changes_size'], 35)
        self.assertEqual(info['modules_num'], 1)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['code_churn_overall'], 66)
        self.assertEqual(info['code_churn_last_3_releases'], 66)
        self.assertEqual(info['developer_familiarity_overall'], 28)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 28)
        self.assertEqual(info['reviewer_familiarity_overall'], 0)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 0)
        self.assertGreaterEqual(info['crashes'], 0)

        # Reviewer with several IRC names.
        info = patchanalysis.bug_analysis(914034)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 2)
        self.assertEqual(info['depends_on'], 1)
        self.assertEqual(info['comments'], 26)
        self.assertEqual(info['changes_size'], 287)
        self.assertEqual(info['test_changes_size'], 0)
        self.assertEqual(info['modules_num'], 1)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['code_churn_overall'], 240)
        self.assertEqual(info['code_churn_last_3_releases'], 27)
        self.assertEqual(info['developer_familiarity_overall'], 7)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 7)
        self.assertEqual(info['reviewer_familiarity_overall'], 3)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 2)
        self.assertGreaterEqual(info['crashes'], 0)

        # IRC handle in the domain of the email ([email protected]).
        info = patchanalysis.bug_analysis(903475)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 1)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 71)
        self.assertEqual(info['changes_size'], 18)
        self.assertEqual(info['test_changes_size'], 0)
        self.assertEqual(info['modules_num'], 1)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['code_churn_overall'], 13)
        self.assertEqual(info['code_churn_last_3_releases'], 3)
        self.assertEqual(info['developer_familiarity_overall'], 0)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 0)
        self.assertEqual(info['reviewer_familiarity_overall'], 0)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 0)
        self.assertGreaterEqual(info['crashes'], 0)

        # Backout without the 'changeset' word.
        info = patchanalysis.bug_analysis(829421)
        self.assertEqual(info['backout_num'], 1)
        self.assertEqual(info['blocks'], 0)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 22)
        self.assertEqual(info['changes_size'], 21)
        self.assertEqual(info['test_changes_size'], 0)
        self.assertEqual(info['modules_num'], 1)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['code_churn_overall'], 110)
        self.assertEqual(info['code_churn_last_3_releases'], 21)
        self.assertEqual(info['developer_familiarity_overall'], 0)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 0)
        self.assertEqual(info['reviewer_familiarity_overall'], 11)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 4)
        self.assertGreaterEqual(info['crashes'], 0)

        # IRC handle first character is lower case in Mercurial, upper case in Bugzilla.
        info = patchanalysis.bug_analysis(799266)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 0)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 28)
        self.assertEqual(info['changes_size'], 104)
        self.assertEqual(info['test_changes_size'], 0)
        self.assertEqual(info['modules_num'], 1)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['code_churn_overall'], 355)
        self.assertEqual(info['code_churn_last_3_releases'], 37)
        self.assertEqual(info['developer_familiarity_overall'], 36)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 5)
        self.assertEqual(info['reviewer_familiarity_overall'], 1)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 0)
        self.assertGreaterEqual(info['crashes'], 0)

        # r=IRC_HANDLE_OF_THE_AUTHOR
        info = patchanalysis.bug_analysis(721760)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 0)
        self.assertEqual(info['depends_on'], 1)
        self.assertEqual(info['comments'], 72)
        self.assertEqual(info['changes_size'], 216)
        self.assertEqual(info['test_changes_size'], 0)
        self.assertEqual(info['modules_num'], 2)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['code_churn_overall'], 38)
        self.assertEqual(info['code_churn_last_3_releases'], 25)
        self.assertEqual(info['developer_familiarity_overall'], 28)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 17)
        self.assertEqual(info['reviewer_familiarity_overall'], 13)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 6)
        self.assertGreaterEqual(info['crashes'], 0)

        # IRC handle is ':IRC_HANDLE.SURNAME' and reviewer is not a reviewer of the patch on Bugzilla.
        info = patchanalysis.bug_analysis(1021265)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 3)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 111)
        self.assertEqual(info['changes_size'], 173)
        self.assertEqual(info['test_changes_size'], 0)
        self.assertEqual(info['modules_num'], 5)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['code_churn_overall'], 1763)
        self.assertEqual(info['code_churn_last_3_releases'], 150)
        self.assertEqual(info['developer_familiarity_overall'], 66)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 17)
        self.assertEqual(info['reviewer_familiarity_overall'], 325)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 36)
        self.assertGreaterEqual(info['crashes'], 0)

        # IRC handle is the beginning of the real name with a space after.
        info = patchanalysis.bug_analysis(1029098)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 1)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 15)
        self.assertEqual(info['changes_size'], 94)
        self.assertEqual(info['test_changes_size'], 97)
        self.assertEqual(info['modules_num'], 1)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['code_churn_overall'], 277)
        self.assertEqual(info['code_churn_last_3_releases'], 15)
        self.assertEqual(info['developer_familiarity_overall'], 81)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 8)
        self.assertEqual(info['reviewer_familiarity_overall'], 9)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 0)
        self.assertGreaterEqual(info['crashes'], 0)

        # Typo in the reviewer name.
        with warnings.catch_warnings(record=True) as w:
            info = patchanalysis.bug_analysis(843733)
            self.assertWarnings(w, ['Reviewer mjronseb could not be found.'])

        # r=oops
        info = patchanalysis.bug_analysis(843821)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 1)
        self.assertEqual(info['depends_on'], 1)
        self.assertEqual(info['comments'], 21)
        self.assertEqual(info['changes_size'], 148)
        self.assertEqual(info['test_changes_size'], 0)
        self.assertEqual(info['modules_num'], 2)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['code_churn_overall'], 887)
        self.assertEqual(info['code_churn_last_3_releases'], 149)
        self.assertEqual(info['developer_familiarity_overall'], 131)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 19)
        self.assertEqual(info['reviewer_familiarity_overall'], 7)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 7)
        self.assertGreaterEqual(info['crashes'], 0)

        # r=backout
        info = patchanalysis.bug_analysis(679509)
        self.assertEqual(info['backout_num'], 0)
        self.assertEqual(info['blocks'], 0)
        self.assertEqual(info['depends_on'], 0)
        self.assertEqual(info['comments'], 97)
        self.assertEqual(info['changes_size'], 347)
        self.assertEqual(info['test_changes_size'], 108)
        self.assertEqual(info['modules_num'], 5)
        self.assertEqual(info['r-ed_patches'], 0)
        self.assertEqual(info['code_churn_overall'], 1874)
        self.assertEqual(info['code_churn_last_3_releases'], 334)
        self.assertEqual(info['developer_familiarity_overall'], 116)
        self.assertEqual(info['developer_familiarity_last_3_releases'], 43)
        self.assertEqual(info['reviewer_familiarity_overall'], 53)
        self.assertEqual(info['reviewer_familiarity_last_3_releases'], 44)
        self.assertGreaterEqual(info['crashes'], 0)

        # Bugzilla user is impossible to find from IRC handle.
        with warnings.catch_warnings(record=True) as w:
            info = patchanalysis.bug_analysis(700583)
            self.assertWarnings(w, ['Reviewer [email protected] is not in the list of reviewers on Bugzilla.', 'Bug 700583 doesn\'t have a uplift request date.'])

        # IRC handle is name+surname
        info = patchanalysis.bug_analysis(701262)

        # r=none
        info = patchanalysis.bug_analysis(733614)

        # Reviewer on Bugzilla is a different person than the reviewer in the Mercurial commit.
        with warnings.catch_warnings(record=True) as w:
            info = patchanalysis.bug_analysis(963621)
            self.assertWarnings(w, ['Reviewer doublec could not be found.'])

        # IRC handle is part of the name.
        info = patchanalysis.bug_analysis(829646)

        # Multiple backouts with a commit message of one line.
        info = patchanalysis.bug_analysis(683280)

        # IRC handle on Bugzilla is different than the one used in Mercurial.
        info = patchanalysis.bug_analysis(680802)

        # Weird situation: the mozilla-central commit referenced in the comments is from some other
        # bug and the actual patch from the bug never landed on mozilla-central but directly on
        # other channels.
        try:
            info = patchanalysis.bug_analysis(846986)
        except Exception as e:
            self.assertTrue(str(e) in ['Too many matching authors ([email protected], [email protected]) found for [email protected]', 'Too many matching authors ([email protected], [email protected]) found for [email protected]'])

        # A comment contains a non-existing revision.
        with warnings.catch_warnings(record=True) as w:
            info = patchanalysis.bug_analysis(1156913)
            self.assertWarnings(w, ['Revision fa8854bd0029 doesn\'t exist.'])

        # Author in mercurial doesn't use the same format as usual ("Full Name email" instead of "Full Name <email>").
        info = patchanalysis.bug_analysis(1277522)

        # Check uplift request
        info = patchanalysis.bug_analysis(1230065)

        self.assertIsNotNone(info['uplift_comment'])
        self.assertEqual(len(info['uplift_comment']['text'].split('\n')), 11)
        self.assertEqual(info['uplift_comment']['id'], 11222288)
        self.assertIsNotNone(info['uplift_author'])
        self.assertEqual(info['uplift_author']['email'], '*****@*****.**')