def test_transplant_to_mozreview(self):
        local_repo_path = tempfile.mkdtemp()
        mozreview_repo_path = tempfile.mkdtemp()

        shutil.copy(os.path.join(HERE, 'test-data', 'initial.patch'),
                    local_repo_path)
        try:
            cmds = [['hg', 'init'],
                    ['hg', 'import', 'initial.patch'],
                    ['hg', 'phase', '--public', '-r', '.'],
                    ['hg', 'bookmark', 'upstream']]

            for cmd in cmds:
                # Use check_output to suppress the output from hg import
                subprocess.check_output(cmd, stderr=subprocess.STDOUT,
                                        cwd=local_repo_path)
            with open(os.path.join(local_repo_path, '.hg', 'hgrc'), 'w') as f:
                f.write('[extensions]\npurge =\n')
                f.write('[paths]\nmozreview-push = ')
                f.write(mozreview_repo_path)
                f.write('\n')
                f.write('upstream = .\n')

            cmds = [['hg', 'init']]
            for cmd in cmds:
                # Use check_output to suppress the output from hg import
                subprocess.check_output(cmd, stderr=subprocess.STDOUT,
                                        cwd=mozreview_repo_path)

            with open(os.path.join(mozreview_repo_path, '.hg', 'hgrc'), 'w') as f:
                f.write('[phases]\npublish = False\n')

            def get_repo_path(tree):
                return local_repo_path
            transplant.get_repo_path = get_repo_path

            class RetrieveCommits():
                def __init__(self):
                    self.files = [['rename-file.patch'],
                                  ['added-blah.patch']]
                    self.current = 0

                def __call__(self, gh, user, repo, pullrequest, path):
                    if self.current > len(self.files):
                        return []
                    else:
                        files = self.files[self.current]
                        self.current += 1
                        for f in files:
                            shutil.copy(os.path.join(HERE, 'test-data', f),
                                        local_repo_path)
                    return files

            gh = mock.Mock()
            github.retrieve_commits = RetrieveCommits()

            # land a patch with a rename
            landed, result = transplant.transplant_to_mozreview(gh, 'mozilla',
                                                                'cthulhu',
                                                                'repo', 0,
                                                                0, 'cookie', 0)

            # We expect this to not be landed as we're not pushing to a repo
            # with the mozreview extension, but we should not see an error in
            # the result.
            self.assertEqual(landed, False)
            self.assertEqual(result, '')

            # ensure patches are applied independently - this should fail if
            # we still see the rename above.
            cmds = [['hg', 'strip', '--no-backup', '-r', 'draft()']]
            for cmd in cmds:
                subprocess.check_call(cmd, stderr=subprocess.STDOUT,
                                      cwd=mozreview_repo_path)

            landed, result = transplant.transplant_to_mozreview(gh, 'mozilla',
                                                                'cthulhu',
                                                                'repo', 0, 0,
                                                                'cookie', 0)
            self.assertEqual(landed, False)
            self.assertEqual(result, '')
            self.assertTrue(os.path.isfile(os.path.join(local_repo_path,
                            'hello')))

            # simple test of rexp to extract review id
            output = 'review url: http://localhost:55557/r/1 (pending)'
            m = re.search(transplant.REVIEW_REXP, output)
            self.assertIsNotNone(m)
            self.assertEqual(m.groups()[0], 'http://localhost:55557/r/1')

        finally:
            shutil.rmtree(local_repo_path)
            shutil.rmtree(mozreview_repo_path)
def handle_pending_mozreview_pullrequests(logger, dbconn):
    gh = github.connect()
    if not gh:
        return

    bzurl = config.get('bugzilla')['url']

    cursor = dbconn.cursor()

    query = """
        select id,ghuser,repo,pullrequest,destination,bzuserid,bzcookie,bugid,
               pingback_url
        from MozreviewPullRequest
        where landed is null
    """
    cursor.execute(query)

    finished_revisions = []
    mozreview_updates = []
    for row in cursor.fetchall():
        (transplant_id, ghuser, repo, pullrequest, destination, bzuserid,
         bzcookie, bugid, pingback_url) = row

        logger.info('attempting to import pullrequest: %s' % transplant_id)

        # see if we can extract the bug from the commit message
        if bugid is None:
            title, body = github.retrieve_issue(gh, ghuser, repo, pullrequest)
            bugs = parse_bugs(title)
            if bugs:
                bugid = bugs[0]
                logger.info('using bug %s from issue title' % bugid)
                finished_revisions.append([bugid, None, None, transplant_id])

        # still no luck, attempt to autofile a bug on the user's behalf
        if bugid is None:
            logger.info('attempting to autofile bug for: %s' % transplant_id)

            b = bugsy.Bugsy(userid=bzuserid, cookie=bzcookie,
                            bugzilla_url=bzurl)
            if not b:
                logger.info('could not connect to bugzilla instance at %s for '
                            'pullrequest id %s' % (bzurl, transplant_id))
                error = 'could not connect to bugzilla. bad credentials?'
            else:
                bug = bugsy.Bug()

                # Summary is required, the rest have defaults or are optional
                bug.summary = title

                if config.testing():
                    bug.product = 'TestProduct'
                    bug.component = 'TestComponent'
                else:
                    # TODO: determine a better product & component than the
                    # defaults provided by Bugsy
                    pass

                pr_url = github.url_for_pullrequest(ghuser,repo, pullrequest)
                bug.add_comment('%s\n\nImported from: %s' % (body, pr_url))

                try:
                    b.put(bug)
                    bugid = bug.id
                    logger.info('created bug: %s ' % bugid)
                    finished_revisions.append([bugid, None, None, transplant_id])
                except bugsy.BugsyException as e:
                    logger.info('transplant failed: could not create new bug: %s '
                                % e.msg)
                    finished_revisions.append([None, False, e.msg, transplant_id])

                    # set up data to be posted back to mozreview
                    data = {
                        'request_id': transplant_id,
                        'bugid': None,
                        'landed': False,
                        'error_msg': 'could not create new bug: ' + e.msg,
                        'result': ''
                    }

                    mozreview_updates.append([transplant_id, pingback_url,
                                              json.dumps(data)])

        landed, result = transplant.transplant_to_mozreview(gh, destination,
                                                            ghuser, repo,
                                                            pullrequest,
                                                            bzuserid, bzcookie,
                                                            bugid)

        if landed:
            logger.info(('transplanted from'
                         ' https://github.com/%s/%s/pull/%s'
                         ' to destination: %s new revision: %s') %
                        (ghuser, repo, pullrequest, destination, result))
        else:
            logger.info(('transplant failed'
                         ' https://github.com/%s/%s/pull/%s'
                         ' destination: %s error: %s') %
                        (ghuser, repo, pullrequest, destination, result))

        finished_revisions.append([bugid, landed, result, transplant_id])

        # set up data to be posted back to mozreview
        data = {
            'request_id': transplant_id,
            'bugid': bugid,
            'landed': landed,
            'error_msg': '',
            'result': ''
        }

        if landed:
            data['result'] = result
        else:
            data['error_msg'] = result

        mozreview_updates.append([transplant_id, pingback_url, json.dumps(data)])

    if finished_revisions:
        query = """
            update MozreviewPullRequest set bugid=%s,landed=%s,result=%s
            where id=%s
        """
        cursor.executemany(query, finished_revisions)
        dbconn.commit()

    if mozreview_updates:
        query = """
            insert into MozreviewUpdate(request_id,pingback_url,data)
            values(%s,%s,%s)
        """
        cursor.executemany(query, mozreview_updates)
        dbconn.commit()