예제 #1
0
    def test_failed_review_status__job_config(self):
        config = build_review_config(review_ini, app_config)
        self.assertEqual('success', config.failed_review_status())

        ini = "[review]\nfail_on_comments = true"
        config = build_review_config(ini, app_config)
        self.assertEqual('failure', config.failed_review_status())
예제 #2
0
    def test_failed_review_status__job_config(self):
        config = build_review_config(review_ini, app_config)
        self.assertEqual('success', config.failed_review_status())

        ini = "[review]\nfail_on_comments = true"
        config = build_review_config(ini, app_config)
        self.assertEqual('failure', config.failed_review_status())
예제 #3
0
    def test_publish_pull_review_remove_ok_label(self):
        problems = Problems()

        filename_1 = 'Console/Command/Task/AssetBuildTask.php'
        errors = (
            Comment(filename_1, 117, 117, 'Something bad'),
            Comment(filename_1, 119, 119, 'Something bad'),
        )
        problems.add_many(errors)
        tst_config = build_review_config(fixer_ini, {'OK_LABEL': 'No lint'})

        review = Review(self.repo, self.pr, tst_config)
        sha = 'abc123'
        review.publish_pull_review(problems, sha)

        assert self.pr.remove_label.called, 'Label should be removed'
        assert self.pr.create_review.called, 'Review should be added'
        self.assertEqual(1, self.pr.create_review.call_count)

        self.pr.remove_label.assert_called_with(tst_config['OK_LABEL'])
        assert_review(
            self,
            self.pr.create_review.call_args,
            errors,
            sha)
예제 #4
0
    def test_run_tools__no_changes(self):
        pull = self.get_pull_request()
        repo = Mock()

        config = build_review_config('', app_config)
        subject = Processor(repo, pull, './tests', config)
        subject.run_tools()
예제 #5
0
    def test_run_tools__execute_fixers(self, fixer_stub, tool_stub):
        pull = self.get_pull_request()
        repo = Mock()

        tool_stub.factory.return_value = sentinel.tools

        fixer_stub.create_context.return_value = sentinel.context
        fixer_stub.run_fixers.return_value = sentinel.diff

        config = build_review_config(fixer_ini, app_config)
        subject = Processor(repo, pull, './tests', config)
        subject.load_changes()
        subject.run_tools()

        file_path = 'View/Helper/AssetCompressHelper.php'
        fixer_stub.create_context.assert_called_with(
            config,
            './tests',
            repo,
            pull)
        fixer_stub.run_fixers.assert_called_with(
            sentinel.tools,
            './tests',
            [file_path])
        fixer_stub.apply_fixer_diff.assert_called_with(
            subject._changes,
            sentinel.diff,
            sentinel.context)
        assert tool_stub.run.called, 'Should have ran'
예제 #6
0
    def test_publish_checkrun(self):
        self.repo.create_checkrun = Mock()
        config = build_review_config(fixer_ini,
                                     {'PULLREQUEST_STATUS': True})
        problems = Problems()

        filename_1 = 'Console/Command/Task/AssetBuildTask.php'
        errors = (
            Comment(filename_1, 117, 8, 'Something bad'),
            Comment(filename_1, 119, 9, 'Something worse'),
        )
        problems.add_many(errors)
        run_id = 42

        review = Review(self.repo, self.pr, config)
        review.publish_checkrun(problems, run_id)

        assert self.repo.update_checkrun.called
        eq_(1, self.repo.update_checkrun.call_count)

        assert_checkrun(
            self.repo.update_checkrun.call_args,
            errors,
            run_id)
        assert self.repo.create_status.called is False, 'no status required'
예제 #7
0
def test_run():
    config = build_review_config(simple_ini)
    problems = Problems()
    files = ['./tests/fixtures/pep8/has_errors.py']
    tool_list = tools.factory(config, problems, root_dir)
    tools.run(tool_list, files, [])
    eq_(7, len(problems))
예제 #8
0
    def test_publish_review_no_count_change(self):
        fixture = load_fixture('comments_current.json')
        self.pr.review_comments.return_value = [
            GhIssueComment(f) for f in json.loads(fixture)
        ]
        problems = Problems()

        # Match the line/positions in comments_current.json
        filename_1 = 'Console/Command/Task/AssetBuildTask.php'
        errors = (
            Comment(filename_1, 40, 40, '2. Something bad'),
            Comment(filename_1, 87, 87, '1. Something bad'),
            Comment(filename_1, 89, 89, '2. Something bad'),
        )
        problems.add_many(errors)
        problems.set_changes([1])
        sha = 'abc123'

        config = build_review_config(fixer_ini, {'SUMMARY_THRESHOLD': 1})
        review = Review(self.repo, self.pr, config)
        review.publish_summary = Mock()
        review.publish_status = Mock()

        review.publish_review(problems, sha)
        # Ensure publish_status(True) means the status=failed
        review.publish_status.assert_called_with(True)
예제 #9
0
    def test_run_tools__execute_fixers(self):
        pull = self.get_pull_request()
        repo = Mock()

        self.tool_stub.factory.return_value = sentinel.tools

        self.fixer_stub.create_context.return_value = sentinel.context
        self.fixer_stub.run_fixers.return_value = sentinel.diff

        config = build_review_config(fixer_ini, app_config)
        subject = Processor(repo, pull, './tests', config)
        subject.load_changes()
        subject.run_tools()

        file_path = 'View/Helper/AssetCompressHelper.php'
        self.fixer_stub.create_context.assert_called_with(
            config,
            './tests',
            repo,
            pull
        )
        self.fixer_stub.run_fixers.assert_called_with(
            sentinel.tools,
            './tests',
            [file_path]
        )
        self.fixer_stub.apply_fixer_diff.assert_called_with(
            subject._changes,
            sentinel.diff,
            sentinel.context
        )
        self.tool_stub.run.assert_called()
예제 #10
0
def test_factory_generates_tools():
    gh = Mock(spec=github3.GitHub)
    config = build_review_config(sample_ini)
    linters = tools.factory(Review(gh, None), config, '')
    eq_(2, len(linters))
    assert isinstance(linters[0], tools.pep8.Pep8)
    assert isinstance(linters[1], tools.jshint.Jshint)
예제 #11
0
    def _test_run_tools_fixer_error_scenario(self, error):
        pull = self.get_pull_request()
        repo = Mock()

        self.tool_stub.factory.return_value = sentinel.tools

        self.fixer_stub.create_context.return_value = sentinel.context
        self.fixer_stub.apply_fixer_diff.side_effect = error

        config = build_review_config(fixer_ini, app_config)
        subject = Processor(repo, pull, './tests', config)
        subject.load_changes()
        subject.run_tools()

        self.fixer_stub.create_context.assert_called()
        self.fixer_stub.run_fixers.assert_called()
        self.tool_stub.run.assert_called()
        self.fixer_stub.rollback_changes.assert_called_with(
            './tests', pull.head)
        assert 1 == len(subject.problems), 'strategy error adds pull comment'
        assert 0 == subject.problems.error_count(
        ), 'fixer failure should be info level'
        assert 'Unable to apply fixers. ' + str(error) == subject.problems.all(
        )[0].body
        assert 1 == len(subject.problems), 'strategy error adds pull comment'
예제 #12
0
def test_create_context__missing_key_raises():
    config = build_review_config(fixer_ini)
    with assert_raises(KeyError):
        empty = {}
        fixers.create_context(
            config, empty, clone_path,
            sentinel.repo, sentinel.pull_request)
예제 #13
0
 def test_factory_generates_tools(self):
     gh = Mock(spec=github3.GitHub)
     config = build_review_config(sample_ini)
     linters = tools.factory(config, Review(gh, None, config), '')
     self.assertEqual(2, len(linters))
     self.assertIsInstance(linters[0], pep8.Pep8)
     self.assertIsInstance(linters[1], jshint.Jshint)
예제 #14
0
 def test_factory_generates_tools(self):
     gh = Mock(spec=github3.GitHub)
     config = build_review_config(sample_ini)
     linters = tools.factory(config, Review(gh, None, config), '')
     self.assertEqual(2, len(linters))
     self.assertIsInstance(linters[0], pep8.Pep8)
     self.assertIsInstance(linters[1], jshint.Jshint)
예제 #15
0
    def test_publish_pull_review_remove_ok_label(self):
        problems = Problems()

        filename_1 = 'Console/Command/Task/AssetBuildTask.php'
        errors = (
            Comment(filename_1, 117, 117, 'Something bad'),
            Comment(filename_1, 119, 119, 'Something bad'),
        )
        problems.add_many(errors)
        sha = 'abc123'
        config = build_review_config(fixer_ini, {'OK_LABEL': 'No lint'})

        review = Review(self.repo, self.pr, config)
        sha = 'abc123'
        review.publish_pull_review(problems, sha)

        assert self.pr.remove_label.called, 'Label should be removed'
        assert self.pr.create_review.called, 'Review should be added'
        eq_(1, self.pr.create_review.call_count)

        self.pr.remove_label.assert_called_with(config['OK_LABEL'])
        assert_review(
            self.pr.create_review.call_args,
            errors,
            sha)
예제 #16
0
 def test_run(self):
     config = build_review_config(simple_ini)
     problems = Problems()
     files = ['./tests/fixtures/pep8/has_errors.py']
     tool_list = tools.factory(config, problems, root_dir)
     tools.run(tool_list, files, [])
     self.assertEqual(7, len(problems))
예제 #17
0
def test_factory_generates_tools():
    gh = Mock(spec=github3.GitHub)
    config = build_review_config(sample_ini)
    linters = tools.factory(Review(gh, None), config, '')
    eq_(2, len(linters))
    assert isinstance(linters[0], tools.pep8.Pep8)
    assert isinstance(linters[1], tools.jshint.Jshint)
예제 #18
0
    def test_publish_checkrun(self):
        self.repo.create_checkrun = Mock()
        tst_config = build_review_config(fixer_ini,
                                         {'PULLREQUEST_STATUS': True})
        problems = Problems()
        filename_1 = 'Console/Command/Task/AssetBuildTask.php'
        errors = (
            Comment(filename_1, 117, 8, 'Something bad'),
            Comment(filename_1, 119, 9, 'Something worse'),
        )
        problems.add_many(errors)
        run_id = 42

        review = Review(self.repo, self.pr, tst_config)
        review.publish_checkrun(problems, run_id)

        assert self.repo.update_checkrun.called
        self.assertEqual(1, self.repo.update_checkrun.call_count)

        assert_checkrun(
            self,
            self.repo.update_checkrun.call_args,
            errors,
            run_id)
        assert self.repo.create_status.called is False, 'no status required'
예제 #19
0
파일: tasks.py 프로젝트: jpos15/lint-review
def process_pull_request(self, user, repo_name, number, lintrc):
    """
    Starts processing a pull request and running the various
    lint tools against it.
    """
    log.info('Starting to process lint for %s/%s/%s', user, repo_name, number)
    log.debug("lintrc contents '%s'", lintrc)
    review_config = build_review_config(lintrc, deepcopy(config))

    if len(review_config.linters()) == 0:
        log.info('No configured linters, skipping processing.')
        return

    try:
        log.info(
            'Loading pull request data from github. user=%s '
            'repo=%s number=%s', user, repo_name, number)
        repo = GithubRepository(config, user, repo_name)
        pull_request = repo.pull_request(number)

        clone_url = pull_request.clone_url

        pr_head = pull_request.head
        target_branch = pull_request.target_branch

        if target_branch in review_config.ignore_branches():
            log.info('Pull request into ignored branch %s, skipping review.',
                     target_branch)
            return

        repo.create_status(pr_head, 'pending', 'Lintreview processing')

        # Clone/Update repository
        target_path = git.get_repo_path(user, repo_name, number, config)
        git.clone_or_update(config, clone_url, target_path, pr_head)

        processor = Processor(repo, pull_request, target_path, review_config)
        processor.load_changes()
        processor.run_tools()
        processor.publish()

        log.info('Completed lint processing for %s/%s/%s' %
                 (user, repo_name, number))

    except Exception as e:
        log.exception(e)
    except TimeoutError as e:
        log.exception(e)
        raise self.retry(
            countdown=5,  # Pause for 5 seconds to clear things out
            max_retries=2,  # only give it one more shot
        )
    finally:
        try:
            git.destroy(target_path)
            log.info('Cleaned up pull request %s/%s/%s', user, repo_name,
                     number)
        except Exception as e:
            log.exception(e)
예제 #20
0
    def test_run_tools__no_changes(self):
        pull = self.get_pull_request()
        repo = Mock()

        config = build_review_config('', app_config)
        subject = Processor(repo, pull, './tests', config)
        self.assertRaises(RuntimeError,
                          subject.run_tools)
예제 #21
0
 def test_create_context__missing_key_raises(self):
     config = build_review_config(fixer_ini)
     self.assertRaises(KeyError,
                       fixers.create_context,
                       config,
                       clone_path,
                       sentinel.repo,
                       sentinel.pull_request)
예제 #22
0
def process_pull_request(self, user, repo_name, number, lintrc):
    """
    Starts processing a pull request and running the various
    lint tools against it.
    """
    log.info('Starting to process lint for %s/%s/%s', user, repo_name, number)
    log.debug("lintrc contents '%s'", lintrc)
    review_config = build_review_config(lintrc, deepcopy(config))

    if len(review_config.linters()) == 0:
        log.info('No configured linters, skipping processing.')
        return

    try:
        log.info('Loading pull request data from github. user=%s '
                 'repo=%s number=%s', user, repo_name, number)
        repo = GithubRepository(config, user, repo_name)
        pull_request = repo.pull_request(number)

        clone_url = pull_request.clone_url

        pr_head = pull_request.head
        target_branch = pull_request.target_branch

        if target_branch in review_config.ignore_branches():
            log.info('Pull request into ignored branch %s, skipping review.',
                     target_branch)
            return

        repo.create_status(pr_head, 'pending', 'Lintreview processing')

        # Clone/Update repository
        target_path = git.get_repo_path(user, repo_name, number, config)
        git.clone_or_update(config, clone_url, target_path, pr_head)

        processor = Processor(repo, pull_request, target_path, review_config)
        processor.load_changes()
        processor.run_tools()
        processor.publish()

        log.info('Completed lint processing for %s/%s/%s' % (
            user, repo_name, number))

    except Exception as e:
        log.exception(e)
    except TimeoutError as e:
        log.exception(e)
        raise self.retry(
            countdown=5,  # Pause for 5 seconds to clear things out
            max_retries=2,  # only give it one more shot
        )
    finally:
        try:
            git.destroy(target_path)
            log.info('Cleaned up pull request %s/%s/%s',
                     user, repo_name, number)
        except Exception as e:
            log.exception(e)
예제 #23
0
def test_run__filter_files():
    config = build_review_config(simple_ini)
    problems = Problems()
    files = [
        './tests/fixtures/pep8/has_errors.py',
        './tests/fixtures/phpcs/has_errors.php'
    ]
    tools.run(config, problems, files, [], '')
    eq_(6, len(problems))
예제 #24
0
def test_run__filter_files():
    config = build_review_config(simple_ini)
    problems = Problems()
    files = [
        './tests/fixtures/pep8/has_errors.py',
        './tests/fixtures/phpcs/has_errors.php'
    ]
    tools.run(config, problems, files, [], '')
    eq_(6, len(problems))
예제 #25
0
 def test_run__filter_files(self):
     config = build_review_config(simple_ini)
     problems = Problems()
     files = [
         './tests/fixtures/pep8/has_errors.py',
         './tests/fixtures/phpcs/has_errors.php'
     ]
     tool_list = tools.factory(config, problems, root_dir)
     tools.run(tool_list, files, [])
     self.assertEqual(7, len(problems))
예제 #26
0
    def test_load_changes(self):
        pull = self.get_pull_request()
        repo = Mock()

        config = build_review_config('', app_config)
        subject = Processor(repo, pull, './tests', config)
        subject.load_changes()

        eq_(1, len(subject._changes), 'File count is wrong')
        assert isinstance(subject._changes, DiffCollection)
예제 #27
0
    def setUp(self):
        repo = Mock(spec=GithubRepository)
        pr = Mock(spec=GithubPullRequest,
                  head='abc123',
                  display_name='markstory/lint-review#1',
                  number=2)
        repo.pull_request.return_value = pr

        self.repo, self.pr = repo, pr
        self.config = build_review_config(fixer_ini, config)
예제 #28
0
    def test_load_changes(self):
        pull = self.get_pull_request()
        repo = Mock()

        config = build_review_config('', app_config)
        subject = Processor(repo, pull, './tests', config)
        subject.load_changes()

        self.assertEqual(1, len(subject._changes), 'File count is wrong')
        assert isinstance(subject._changes, DiffCollection)
예제 #29
0
def test_create_context():
    config = build_review_config(fixer_ini, app_config)
    context = fixers.create_context(config, clone_path, sentinel.repo,
                                    sentinel.pull_request)

    eq_('commit', context['strategy'])
    eq_(config['GITHUB_AUTHOR_EMAIL'], context['author_email'])
    eq_(config['GITHUB_AUTHOR_NAME'], context['author_name'])
    eq_(clone_path, context['repo_path'])
    eq_(sentinel.repo, context['repository'])
    eq_(sentinel.pull_request, context['pull_request'])
예제 #30
0
    def test_run_tools__ignore_patterns(self, fixer_stub, tool_stub):
        pull = self.get_pull_request()
        repo = Mock()

        config = build_review_config(fixer_ini, app_config)
        config.ignore_patterns = lambda: ['View/Helper/*']

        subject = Processor(repo, pull, './tests', config)
        subject.load_changes()
        subject.run_tools()
        tool_stub.run.assert_called_with(ANY, [], ANY)
예제 #31
0
    def test_linter_config(self):
        config = build_review_config(sample_ini)
        res = config.linter_config('phpcs')
        expected = {
            'standard': 'test/CodeStandards',
            'config': 'test/phpcs.xml'
        }
        eq_(res, expected)

        res = config.linter_config('not there')
        eq_(res, {})
예제 #32
0
    def setUp(self):
        repo = Mock(spec=GithubRepository)
        pr = Mock(spec=GithubPullRequest,
                  head='abc123',
                  display_name='markstory/lint-review#1',
                  number=2)
        repo.pull_request.return_value = pr

        self.repo, self.pr = repo, pr
        self.config = build_review_config(fixer_ini, config)

        self.session = GitHubSession()
예제 #33
0
    def test_run_timeout_error(self, mock_docker):
        mock_docker.side_effect = TimeoutError("Read timed out. (read timeout=300)")
        config = build_review_config(simple_ini)
        problems = Problems()
        files = ['./tests/fixtures/pep8/has_errors.py']
        tool_list = tools.factory(config, problems, root_dir)
        tools.run(tool_list, files, [])

        errors = problems.all()
        assert 1 == len(errors)
        assert 'timed out during' in errors[0].body
        assert 'run pep8 linter' in errors[0].body
예제 #34
0
    def test_run_timeout_error(self, mock_docker):
        mock_docker.side_effect = TimeoutError(
            "Read timed out. (read timeout=300)")
        config = build_review_config(simple_ini)
        problems = Problems()
        files = ['./tests/fixtures/pep8/has_errors.py']
        tool_list = tools.factory(config, problems, root_dir)
        tools.run(tool_list, files, [])

        errors = problems.all()
        assert 1 == len(errors)
        assert 'timed out during' in errors[0].body
        assert 'run pep8 linter' in errors[0].body
예제 #35
0
    def test_create_context(self):
        config = build_review_config(fixer_ini, app_config)
        context = fixers.create_context(
            config, clone_path,
            sentinel.repo, sentinel.pull_request)

        self.assertEqual('commit', context['strategy'])
        self.assertEqual(config['GITHUB_AUTHOR_EMAIL'],
                         context['author_email'])
        self.assertEqual(config['GITHUB_AUTHOR_NAME'], context['author_name'])
        self.assertEqual(clone_path, context['repo_path'])
        self.assertEqual(sentinel.repo, context['repository'])
        self.assertEqual(sentinel.pull_request, context['pull_request'])
예제 #36
0
    def test_publish_checks_api__no_problems(self):
        self.repo.create_checkrun = Mock()
        config = build_review_config(checks_ini, {'PULLREQUEST_STATUS': True})
        problems = Problems()
        sha = 'abc123'

        review = Review(self.repo, self.pr, config)
        review.publish_checkrun(problems, False, sha)

        assert self.repo.create_checkrun.called
        eq_(1, self.repo.create_checkrun.call_count)

        assert_checkrun(self.repo.create_checkrun.call_args, [], sha)
예제 #37
0
    def test_publish_status__ok_no_comment_or_label(self):
        app_config = {
            'OK_COMMENT': None,
            'OK_LABEL': None,
            'PULLREQUEST_STATUS': False,
        }
        tst_config = build_review_config(fixer_ini, app_config)
        review = Review(self.repo, self.pr, tst_config)
        review.publish_status(False)

        assert self.repo.create_status.called, 'Create status called'
        assert not self.pr.create_comment.called, 'Comment not created'
        assert not self.pr.add_label.called, 'Label added created'
예제 #38
0
    def test_publish_status__ok_no_comment_or_label(self):
        app_config = {
            'OK_COMMENT': None,
            'OK_LABEL': None,
            'PULLREQUEST_STATUS': False,
        }
        config = build_review_config(fixer_ini, app_config)
        review = Review(self.repo, self.pr, config)
        review.publish_status(False)

        assert self.repo.create_status.called, 'Create status called'
        assert not self.pr.create_comment.called, 'Comment not created'
        assert not self.pr.add_label.called, 'Label added created'
예제 #39
0
    def test_publish_checkrun__no_problems(self):
        tst_config = build_review_config(fixer_ini,
                                         {'PULLREQUEST_STATUS': True})
        problems = Problems()
        run_id = 42

        review = Review(self.repo, self.pr, tst_config)
        review.publish_checkrun(problems, run_id)

        assert self.repo.update_checkrun.called
        self.assertEqual(1, self.repo.update_checkrun.call_count)

        assert_checkrun(self.repo.update_checkrun.call_args, [], run_id)
        assert self.repo.create_status.called is False, 'no status required'
예제 #40
0
def process_pull_request(user, repo_name, number, lintrc):
    """
    Starts processing a pull request and running the various
    lint tools against it.
    """
    log.info('Starting to process lint for %s/%s/%s', user, repo_name, number)
    log.debug("lintrc contents '%s'", lintrc)
    review_config = build_review_config(lintrc, config)

    if len(review_config.linters()) == 0:
        log.info('No configured linters, skipping processing.')
        return

    try:
        log.info('Loading pull request data from github. user=%s '
                 'repo=%s number=%s', user, repo_name, number)
        repo = GithubRepository(config, user, repo_name)
        pull_request = repo.pull_request(number)

        clone_url = pull_request.clone_url

        pr_head = pull_request.head
        target_branch = pull_request.target_branch

        if target_branch in review_config.ignore_branches():
            log.info('Pull request into ignored branch %s, skipping review.',
                     target_branch)
            return

        status = config.get('PULLREQUEST_STATUS', True)
        if status:
            repo.create_status(pr_head, 'pending', 'Lintreview processing...')

        # Clone/Update repository
        target_path = git.get_repo_path(user, repo_name, number, config)
        git.clone_or_update(config, clone_url, target_path, pr_head)

        processor = Processor(repo, pull_request,
                              target_path, config)
        processor.load_changes()
        processor.run_tools(review_config)
        processor.publish()

        log.info('Completed lint processing for %s/%s/%s' % (
            user, repo, number))

        git.destroy(target_path)
        log.info('Cleaned up pull request %s/%s/%s', user, repo, number)
    except BaseException as e:
        log.exception(e)
예제 #41
0
def process_pull_request(user, repo_name, number, lintrc):
    """
    Starts processing a pull request and running the various
    lint tools against it.
    """
    log.info('Starting to process lint for %s/%s/%s', user, repo_name, number)
    log.debug("lintrc contents '%s'", lintrc)
    review_config = build_review_config(lintrc, config)

    if len(review_config.linters()) == 0:
        log.info('No configured linters, skipping processing.')
        return

    try:
        log.info('Loading pull request data from github. user=%s '
                 'repo=%s number=%s', user, repo_name, number)
        repo = GithubRepository(config, user, repo_name)
        pull_request = repo.pull_request(number)

        head_repo = pull_request.clone_url

        private_repo = pull_request.is_private
        pr_head = pull_request.head
        target_branch = pull_request.target_branch

        if target_branch in review_config.ignore_branches():
            log.info('Pull request into ignored branch %s, skipping processing.' %
                     target_branch)
            return

        status = config.get('PULLREQUEST_STATUS', True)
        if status:
            repo.create_status(pr_head, 'pending', 'Lintreview processing...')

        # Clone/Update repository
        target_path = git.get_repo_path(user, repo_name, number, config)
        git.clone_or_update(config, head_repo, target_path, pr_head,
                            private_repo)

        processor = Processor(repo, pull_request,
                              target_path, config)
        processor.load_changes()
        processor.run_tools(review_config)
        processor.publish()

        log.info('Completed lint processing for %s/%s/%s' % (
            user, repo, number))
    except BaseException, e:
        log.exception(e)
예제 #42
0
    def test_publish_empty_comment_add_ok_label(self):
        problems = Problems(changes=[])
        config = build_review_config(fixer_ini, {'OK_LABEL': 'No lint'})
        review = Review(self.repo, self.pr, config)

        sha = 'abc123'
        review.publish(problems, sha)

        assert self.pr.create_comment.called, 'ok comment should be added.'
        assert self.pr.remove_label.called, 'label should be removed.'
        self.pr.remove_label.assert_called_with(config['OK_LABEL'])

        msg = ('Could not review pull request. '
               'It may be too large, or contain no reviewable changes.')
        self.pr.create_comment.assert_called_with(msg)
예제 #43
0
    def test_publish_review_empty_comment_add_ok_label(self):
        problems = Problems(changes=DiffCollection([]))
        tst_config = build_review_config(fixer_ini, {'OK_LABEL': 'No lint'})
        review = Review(self.repo, self.pr, tst_config)

        sha = 'abc123'
        review.publish_review(problems, sha)

        assert self.pr.create_comment.called, 'ok comment should be added.'
        assert self.pr.remove_label.called, 'label should be removed.'
        self.pr.remove_label.assert_called_with(tst_config['OK_LABEL'])

        msg = ('Could not review pull request. '
               'It may be too large, or contain no reviewable changes.')
        self.pr.create_comment.assert_called_with(msg)
예제 #44
0
    def test_publish_checkrun(self):
        pull = self.get_pull_request()
        repo = Mock()

        config = build_review_config(fixer_ini, app_config)
        subject = Processor(repo, pull, './tests', config)
        subject.problems = Mock()
        subject._review = Mock()

        subject.publish(check_run_id=9)
        eq_(True, subject.problems.limit_to_changes.called,
            'Problems should be filtered.')
        eq_(True, subject._review.publish_checkrun.called,
            'Review should be published.')
        subject._review.publish_checkrun.assert_called_with(
            subject.problems, 9)
예제 #45
0
def process_pull_request(user, repo, number, lintrc):
    """
    Starts processing a pull request and running the various
    lint tools against it.
    """
    log.info('Starting to process lint for %s/%s/%s', user, repo, number)
    log.debug("lintrc contents '%s'", lintrc)
    review_config = build_review_config(lintrc, config)

    if len(review_config.linters()) == 0:
        log.info('No configured linters, skipping processing.')
        return

    try:
        log.info(
            'Loading pull request data from github. user=%s '
            'repo=%s number=%s', user, repo, number)
        gh = github.get_repository(config, user, repo)
        pull_request = gh.pull_request(number)

        pr_dict = pull_request.as_dict()
        head_repo = pr_dict['head']['repo']['clone_url']
        private_repo = pr_dict['head']['repo']['private']
        pr_head = pr_dict['head']['sha']

        target_branch = pr_dict['base']['ref']
        if target_branch in review_config.ignore_branches():
            log.info(
                'Pull request into ignored branch %s, skipping processing.' %
                target_branch)
            return

        # Clone/Update repository
        target_path = git.get_repo_path(user, repo, number, config)
        git.clone_or_update(config, head_repo, target_path, pr_head,
                            private_repo)

        processor = Processor(gh, number, pr_head, target_path, config)
        processor.load_changes()
        processor.run_tools(review_config)
        processor.publish()

        log.info('Completed lint processing for %s/%s/%s' %
                 (user, repo, number))
    except BaseException as e:
        log.exception(e)
예제 #46
0
    def test_publish_status__has_errors(self):
        app_config = {
            'OK_COMMENT': 'Great job!',
            'OK_LABEL': 'No lint errors',
            'APP_NAME': 'custom-name'
        }
        config = build_review_config(fixer_ini, app_config)
        review = Review(self.repo, self.pr, config)
        review.publish_status(True)

        assert self.repo.create_status.called, 'Create status not called'

        self.repo.create_status.assert_called_with(
            self.pr.head, 'failure',
            'Lint errors found, see pull request comments.')
        assert not self.pr.create_comment.called, 'Comment not created'
        assert not self.pr.add_label.called, 'Label added created'
예제 #47
0
    def test_publish(self):
        pull = self.get_pull_request()
        repo = Mock()

        config = build_review_config(fixer_ini, app_config)
        subject = Processor(repo, pull, './tests', config)
        subject.problems = Mock()
        subject._review = Mock()

        subject.publish()
        self.assertTrue(subject.problems.limit_to_changes.called,
                        'Problems should be filtered.')
        self.assertTrue(subject._review.publish_review.called,
                        'Review should be published.')
        subject._review.publish_review.assert_called_with(
            subject.problems,
            pull.head)
예제 #48
0
    def test_run_tools__ignore_patterns(self):
        pull = self.get_pull_request()
        repo = Mock()

        config = build_review_config(fixer_ini, app_config)
        config.ignore_patterns = lambda: [
            'View/Helper/*']

        subject = Processor(repo, pull, './tests', config)
        subject.load_changes()
        subject.run_tools()

        self.tool_stub.run.assert_called_with(
            ANY,
            [],
            ANY
        )
예제 #49
0
    def test_publish_checkrun__multiple_chunks(self):
        self.repo.create_checkrun = Mock()
        tst_config = build_review_config(fixer_ini,
                                         {'PULLREQUEST_STATUS': True})
        problems = Problems()
        filename_1 = 'Console/Command/Task/AssetBuildTask.php'
        errors = [
            Comment(filename_1, i, i, 'Something worse') for i in range(0, 70)
        ]
        problems.add_many(errors)
        problems.add(IssueComment('In the body'))
        run_id = 42

        review = Review(self.repo, self.pr, tst_config)
        review.publish_checkrun(problems, run_id)

        assert self.repo.update_checkrun.call_count == 2
        assert self.repo.create_status.called is False, 'no status required'

        first_call = self.repo.update_checkrun.call_args_list[0]
        assert run_id == first_call[0][0]

        first_payload = first_call[0][1]
        assert 'failure' == first_payload['conclusion']

        assert 'completed_at' in first_payload
        assert 'title' in first_payload['output']
        assert 'summary' in first_payload['output']
        assert 'annotations' in first_payload['output']

        assert 'In the body' == first_payload['output']['summary']
        assert 50 == len(first_payload['output']['annotations'])

        second_call = self.repo.update_checkrun.call_args_list[1]
        assert run_id == second_call[0][0]

        # The second payload should only contain additional annotations.
        second_payload = second_call[0][1]
        assert 'completed_at' not in second_payload
        assert 'title' in second_payload['output']
        assert 'summary' in second_payload['output']
        assert 'annotations' in second_payload['output']
        assert 'In the body' == second_payload['output']['summary']

        assert 20 == len(second_payload['output']['annotations'])
예제 #50
0
def process_pull_request(user, repo, number, lintrc):
    """
    Starts processing a pull request and running the various
    lint tools against it.
    """
    log.info('Starting to process lint for %s/%s/%s', user, repo, number)
    log.debug("lintrc contents '%s'", lintrc)
    review_config = build_review_config(lintrc, config)

    if len(review_config.linters()) == 0:
        log.info('No configured linters, skipping processing.')
        return

    try:
        log.info('Loading pull request data from github. user=%s '
                 'repo=%s number=%s', user, repo, number)
        gh = github.get_repository(config, user, repo)
        pull_request = gh.pull_request(number)

        pr_dict = pull_request.as_dict()
        head_repo = pr_dict['head']['repo']['clone_url']
        private_repo = pr_dict['head']['repo']['private']
        pr_head = pr_dict['head']['sha']

        target_branch = pr_dict['base']['ref']
        if target_branch in review_config.ignore_branches():
            log.info('Pull request into ignored branch %s, skipping processing.' %
                     target_branch)
            return

        # Clone/Update repository
        target_path = git.get_repo_path(user, repo, number, config)
        git.clone_or_update(config, head_repo, target_path, pr_head,
                            private_repo)

        processor = Processor(gh, number, pr_head,
                              target_path, config)
        processor.load_changes()
        processor.run_tools(review_config)
        processor.publish()

        log.info('Completed lint processing for %s/%s/%s' % (
            user, repo, number))
    except BaseException, e:
        log.exception(e)
예제 #51
0
    def test_publish_empty_comment_with_comment_status(self):
        config = build_review_config(fixer_ini, {'PULLREQUEST_STATUS': True})

        problems = Problems(changes=[])
        review = Review(self.repo, self.pr, config)

        sha = 'abc123'
        review.publish(problems, sha)

        assert self.pr.create_comment.called, 'Should create a comment'

        msg = ('Could not review pull request. '
               'It may be too large, or contain no reviewable changes.')

        self.repo.create_status.assert_called_with(self.pr.head, 'success',
                                                   msg)

        self.pr.create_comment.assert_called_with(msg)
예제 #52
0
    def test_publish_status__has_errors(self):
        app_config = {
            'OK_COMMENT': 'Great job!',
            'OK_LABEL': 'No lint errors',
            'APP_NAME': 'custom-name'
        }
        tst_config = build_review_config(fixer_ini, app_config)
        review = Review(self.repo, self.pr, tst_config)
        review.publish_status(True)

        assert self.repo.create_status.called, 'Create status not called'

        self.repo.create_status.assert_called_with(
            self.pr.head,
            'failure',
            'Lint errors found, see pull request comments.')
        assert not self.pr.create_comment.called, 'Comment not created'
        assert not self.pr.add_label.called, 'Label added created'
예제 #53
0
    def test_run_tools__execute_fixers_fail(self):
        pull = self.get_pull_request()
        repo = Mock()

        self.tool_stub.factory.return_value = sentinel.tools

        self.fixer_stub.create_context.return_value = sentinel.context
        self.fixer_stub.run_fixers.side_effect = RuntimeError

        config = build_review_config(fixer_ini, app_config)
        subject = Processor(repo, pull, './tests', config)
        subject.load_changes()
        subject.run_tools()

        self.fixer_stub.create_context.assert_called()
        self.fixer_stub.run_fixers.assert_called()
        self.fixer_stub.apply_fixer_diff.assert_not_called()
        self.fixer_stub.rollback_changes.assert_called()
        self.tool_stub.run_assert_called()
예제 #54
0
    def test_publish_checkrun__no_problems(self):
        self.repo.create_checkrun = Mock()
        tst_config = build_review_config(fixer_ini,
                                         {'PULLREQUEST_STATUS': True})
        problems = Problems()
        run_id = 42

        review = Review(self.repo, self.pr, tst_config)
        review.publish_checkrun(problems, run_id)

        assert self.repo.update_checkrun.called
        self.assertEqual(1, self.repo.update_checkrun.call_count)

        assert_checkrun(
            self,
            self.repo.update_checkrun.call_args,
            [],
            run_id)
        assert self.repo.create_status.called is False, 'no status required'
예제 #55
0
    def test_publish_review_empty_comment_with_comment_status(self):
        tst_config = build_review_config(fixer_ini,
                                         {'PULLREQUEST_STATUS': True})

        problems = Problems(changes=DiffCollection([]))
        review = Review(self.repo, self.pr, tst_config)

        sha = 'abc123'
        review.publish_review(problems, sha)

        assert self.pr.create_comment.called, 'Should create a comment'

        msg = ('Could not review pull request. '
               'It may be too large, or contain no reviewable changes.')

        self.repo.create_status.assert_called_with(
            self.pr.head,
            'success',
            msg)

        self.pr.create_comment.assert_called_with(msg)
예제 #56
0
    def test_publish_status__has_errors__success_status(self):
        app_config = {
            'PULLREQUEST_STATUS': False,
            'OK_COMMENT': 'Great job!',
            'OK_LABEL': 'No lint errors',
            'APP_NAME': 'custom-name'
        }
        tst_config = build_review_config(fixer_ini, app_config)
        self.assertEqual('success', tst_config.failed_review_status(),
                         'config object changed')

        review = Review(self.repo, self.pr, tst_config)
        review.publish_status(True)

        assert self.repo.create_status.called, 'Create status not called'
        self.repo.create_status.assert_called_with(
            self.pr.head,
            'success',
            'Lint errors found, see pull request comments.')
        assert not self.pr.create_comment.called, 'Comment not created'
        assert not self.pr.add_label.called, 'Label added created'
예제 #57
0
    def test_publish_status__ok_with_comment_label(self):
        app_config = {
            'OK_COMMENT': 'Great job!',
            'OK_LABEL': 'No lint errors',
            'PULLREQUEST_STATUS': True,
        }
        tst_config = build_review_config(fixer_ini, app_config)
        Review(self.repo, self.pr, tst_config)
        review = Review(self.repo, self.pr, tst_config)
        review.publish_status(False)

        assert self.repo.create_status.called, 'Create status not called'
        self.repo.create_status.assert_called_with(
            self.pr.head,
            'success',
            'No lint errors found.')

        assert self.pr.create_comment.called, 'Issue comment created'
        self.pr.create_comment.assert_called_with('Great job!')

        assert self.pr.add_label.called, 'Label added created'
        self.pr.add_label.assert_called_with('No lint errors')
예제 #58
0
    def _test_run_tools_fixer_error_scenario(self, error):
        pull = self.get_pull_request()
        repo = Mock()

        self.tool_stub.factory.return_value = sentinel.tools

        self.fixer_stub.create_context.return_value = sentinel.context
        self.fixer_stub.apply_fixer_diff.side_effect = error

        config = build_review_config(fixer_ini, app_config)
        subject = Processor(repo, pull, './tests', config)
        subject.load_changes()
        subject.run_tools()

        self.fixer_stub.create_context.assert_called()
        self.fixer_stub.run_fixers.assert_called()
        self.tool_stub.run.assert_called()
        self.fixer_stub.rollback_changes.assert_not_called()
        assert 1 == len(subject.problems), 'strategy error adds pull comment'
        assert 0 == subject.problems.error_count(), 'fixer failure should be info level'
        assert 'Unable to apply fixers. ' + str(error) == subject.problems.all()[0].body
        assert 1 == len(subject.problems), 'strategy error adds pull comment'
예제 #59
0
    def test_publish_review_no_count_change(self, pub_status_mock, _):
        fixture = load_fixture('comments_current.json')
        self.pr.review_comments.return_value = [
            GhIssueComment(f, self.session) for f in json.loads(fixture)]
        problems = Problems()

        # Match the line/positions in comments_current.json
        filename_1 = 'Console/Command/Task/AssetBuildTask.php'
        errors = (
            Comment(filename_1, 40, 40, '2. Something bad'),
            Comment(filename_1, 87, 87, '1. Something bad'),
            Comment(filename_1, 89, 89, '2. Something bad'),
        )
        problems.add_many(errors)
        problems.set_changes([1])
        sha = 'abc123'

        tst_config = build_review_config(fixer_ini, {'SUMMARY_THRESHOLD': 1})
        review = Review(self.repo, self.pr, tst_config)

        review.publish_review(problems, sha)
        # Ensure publish_status(True) means the status=failed
        pub_status_mock.assert_called_with(True)