Example #1
0
def parse(contents: str) -> Set[Problem]:
    result = set()  # type: Set[Problem]
    for line in contents.splitlines():
        match = SWIFTLINT_LINE_REGEX.match(line)
        if match:
            groups = match.groupdict()
            result.add(
                Problem(os.path.relpath(groups['path']), groups['line'],
                        groups['message']))
    return result
Example #2
0
def parse(contents: str) -> Set[Problem]:
    result = set()  # type: Set[Problem]
    for line in contents.splitlines():
        match = PYLINT_LINE_REGEX.match(line)
        if match:
            groups = match.groupdict()
            path = groups['path']
            if path.startswith('./'):
                path = path[2:]
            result.add(Problem(path, groups['line'], groups['message']))
    return result
Example #3
0
def parse(contents: str) -> Set[Problem]:
    result = set()  # type: Set[Problem]
    for line in contents.splitlines():
        match = MYPY_LINE_REGEX.match(line)
        if match:
            groups = match.groupdict()
            if groups['code'] != 'note':
                result.add(
                    Problem(groups['path'], groups['line'],
                            '{}: {}'.format(groups['code'],
                                            groups['message'])))
    return result
Example #4
0
def parse(contents: str) -> Set[Problem]:
    result = set()  # type: Set[Problem]
    try:
        root = ElementTree.fromstring(contents)
    except ElementTree.ParseError:
        return result
    for file in root.findall('file'):
        file_name = file.get('name')
        for error in file.findall('error'):
            result.add(
                Problem(
                    file_name,
                    error.get('line'), '{}: {}'.format(error.get('source'),
                                                       error.get('message'))))
    return result
    async def get_existing_problems(self) -> Set[Problem]:
        note_ref = ''
        result = set()
        if self.remote:
            fetch_notes = await asyncio.create_subprocess_exec(
                'git', 'fetch', self.remote, '{0}:{0}'.format(NOTES_REF),
                **GIT_SUBPROCESS_KWARGS)
            await fetch_notes.wait()

        last_n_revisions_proc = await asyncio.create_subprocess_exec(
            'git', 'log', '--skip=1', '-{}'.format(MAX_REVISIONS),
            '--pretty=%H',
            **GIT_SUBPROCESS_KWARGS)
        async for line in last_n_revisions_proc.stdout:
            notes_ref_proc = await asyncio.create_subprocess_exec(
                'git', 'notes', 'list', line.decode().strip(),
                **GIT_SUBPROCESS_KWARGS)
            await notes_ref_proc.wait()
            if notes_ref_proc.returncode == 0:
                note_ref = (
                    await notes_ref_proc.stdout.readline()).decode().strip()
                if note_ref:
                    break
        await last_n_revisions_proc.wait()
        if note_ref:
            notes_proc = await asyncio.create_subprocess_exec(
                'git', 'show', note_ref,
                **GIT_SUBPROCESS_KWARGS)
            async for line in notes_proc.stdout:
                try:
                    problems = json.loads(line.decode())
                    for problem in problems:
                        result.add(Problem.from_json(problem))
                except Exception:
                    pass
            await notes_proc.wait()
        return result
Example #6
0
    async def report(self, problems: List[Problem]) -> None:
        grouped_problems = Problem.group_by_path_and_line(problems)

        headers = {
            'Authorization': 'token {}'.format(self.auth_token),
        }
        with aiohttp.ClientSession(headers=headers) as client_session:
            (line_map, existing_messages) = await asyncio.gather(
                self.create_line_to_position_map(client_session),
                self.get_existing_messages(client_session))
            lint_errors = 0
            review_comment_awaitable = []
            pr_url = self._get_pr_url()
            no_matching_line_number = []

            for location, problems_for_line in grouped_problems:
                message_for_line = [
                    COMMENT_HEADER and '{}:'.format(COMMENT_HEADER) or '', '']

                reported_problems_for_line = set()

                path = location[0]
                line_number = location[1]
                position = line_map.get(path, {}).get(line_number, None)

                if position is None and path in line_map and REPORT_CLOSEST:
                    file_map = line_map[path]
                    closest_line = min(file_map.keys(),
                                       key=lambda x: abs(x - line_number))
                    position = file_map[closest_line]
                    message_for_line.append('(From line {})'.format(
                        line_number))
                message_for_line.append('```')

                if position is not None:
                    for problem in problems_for_line:
                        if problem.message not in reported_problems_for_line:
                            message_for_line.append(problem.message)
                            reported_problems_for_line.add(problem.message)
                    message_for_line.append('```')
                    message = '\n'.join(message_for_line)
                    if (path, position, message) not in existing_messages:
                        lint_errors += 1
                        if lint_errors <= MAX_LINT_ERROR_REPORTS:
                            data = json.dumps({
                                'body': message,
                                'commit_id': self.commit,
                                'path': path,
                                'position': position,
                            }, sort_keys=True)
                            review_comment_awaitable.append(
                                client_session.post(pr_url, data=data))
                else:
                    no_matching_line_number.append((location,
                                                    problems_for_line))
            if lint_errors > MAX_LINT_ERROR_REPORTS:
                message = '''{0}

Too many lint errors to report inline!  {1} lines have a problem.
Only reporting the first {2}.'''.format(
    COMMENT_HEADER and '{}:'.format(COMMENT_HEADER) or '',
    lint_errors, MAX_LINT_ERROR_REPORTS)
                data = json.dumps({
                    'body': message
                })
                review_comment_awaitable.append(
                    asyncio.ensure_future(client_session.post(
                        self._get_issue_url(),
                        data=data)))
            if no_matching_line_number and REPORT_NO_MATCHING:
                no_matching_line_messages = []
                for location, problems_for_line in no_matching_line_number:
                    path = location[0]
                    line_number = location[1]
                    no_matching_line_messages.append(
                        '{0}:{1}:'.format(path, line_number))
                    for problem in problems_for_line:
                        no_matching_line_messages.append('\t{0}'.format(
                            problem.message))
                message = ('Linters found some problems with lines not '
                           'modified by this commit:\n```\n{0}\n```'.format(
                               '\n'.join(no_matching_line_messages)))
                data = json.dumps({
                    'body': message
                })
                review_comment_awaitable.append(
                    asyncio.ensure_future(client_session.post(
                        self._get_issue_url(), data=data)))

            responses = await asyncio.gather(
                *review_comment_awaitable
            )  # type: List[aiohttp.ClientResponse]
            for response in responses:
                response.close()
Example #7
0
    async def report(self, problems: List[Problem]) -> None:
        grouped_problems = Problem.group_by_path_and_line(problems)

        headers = {
            'Authorization': 'token {}'.format(self.auth_token),
        }
        with aiohttp.ClientSession(headers=headers) as client_session:
            (line_map, existing_messages) = await asyncio.gather(
                self.create_line_to_position_map(client_session),
                self.get_existing_messages(client_session))
            lint_errors = 0
            review_comment_awaitable = []
            pr_url = self._get_pr_url()
            no_matching_line_number = []

            for location, problems_for_line in grouped_problems:
                message_for_line = [
                    COMMENT_HEADER and '{}:'.format(COMMENT_HEADER) or '', ''
                ]

                reported_problems_for_line = set()

                path = location[0]
                line_number = location[1]
                position = line_map.get(path, {}).get(line_number, None)

                if position is None and path in line_map and REPORT_CLOSEST:
                    file_map = line_map[path]
                    closest_line = min(file_map.keys(),
                                       key=lambda x: abs(x - line_number))
                    position = file_map[closest_line]
                    message_for_line.append(
                        '(From line {})'.format(line_number))
                message_for_line.append('```')

                if position is not None:
                    for problem in problems_for_line:
                        if problem.message not in reported_problems_for_line:
                            message_for_line.append(problem.message)
                            reported_problems_for_line.add(problem.message)
                    message_for_line.append('```')
                    message = '\n'.join(message_for_line)
                    if (path, position, message) not in existing_messages:
                        lint_errors += 1
                        if lint_errors <= MAX_LINT_ERROR_REPORTS:
                            data = json.dumps(
                                {
                                    'body': message,
                                    'commit_id': self.commit,
                                    'path': path,
                                    'position': position,
                                },
                                sort_keys=True)
                            review_comment_awaitable.append(
                                client_session.post(pr_url, data=data))
                else:
                    no_matching_line_number.append(
                        (location, problems_for_line))
            if lint_errors > MAX_LINT_ERROR_REPORTS:
                message = '''{0}

Too many lint errors to report inline!  {1} lines have a problem.
Only reporting the first {2}.'''.format(
                    COMMENT_HEADER and '{}:'.format(COMMENT_HEADER) or '',
                    lint_errors, MAX_LINT_ERROR_REPORTS)
                data = json.dumps({'body': message})
                review_comment_awaitable.append(
                    asyncio.ensure_future(
                        client_session.post(self._get_issue_url(), data=data)))
            if no_matching_line_number and REPORT_NO_MATCHING:
                no_matching_line_messages = []
                for location, problems_for_line in no_matching_line_number:
                    path = location[0]
                    line_number = location[1]
                    no_matching_line_messages.append('{0}:{1}:'.format(
                        path, line_number))
                    for problem in problems_for_line:
                        no_matching_line_messages.append('\t{0}'.format(
                            problem.message))
                message = ('Linters found some problems with lines not '
                           'modified by this commit:\n```\n{0}\n```'.format(
                               '\n'.join(no_matching_line_messages)))
                data = json.dumps({'body': message})
                review_comment_awaitable.append(
                    asyncio.ensure_future(
                        client_session.post(self._get_issue_url(), data=data)))

            responses = await asyncio.gather(
                *review_comment_awaitable
            )  # type: List[aiohttp.ClientResponse]
            for response in responses:
                response.close()