コード例 #1
0
def add_shell_result(report: Report, name: str, exit_code: int) -> CheckResult:
    logging.info(f'"{name}" exited with {exit_code}')
    z = CheckResult.SUCCESS
    if exit_code != 0:
        z = CheckResult.FAILURE
    report.add_step(name, z, '')
    return z
コード例 #2
0
def ninja_check_all_report(report: Report) -> CheckResult:
    # TODO: merge running ninja check all and analysing results in one step?
    print('Full will be available in Artifacts "ninja-check-all.log"')
    r = subprocess.run(
        f'ninja check-all | tee {artifacts_dir}/ninja-check-all.log | '
        f'grep -vE "^\\[.*] (Building|Linking)" | '
        f'grep -vE "^(PASS|XFAIL|UNSUPPORTED):"',
        shell=True,
        cwd=build_dir)
    z = add_shell_result(report, 'ninja check all', r.returncode)
    # TODO: check if test-results are present.
    report.add_artifact(build_dir, 'test-results.xml', 'test results')
    test_results_report.run(os.path.join(build_dir, 'test-results.xml'),
                            report)
    return z
コード例 #3
0
def run(base_commit, ignore_config, step: Optional[Step],
        report: Optional[Report]):
    """Apply clang-format and return if no issues were found."""
    if report is None:
        report = Report()  # For debugging.
    if step is None:
        step = Step()  # For debugging.
    r, patch = get_diff(base_commit)
    if not r:
        step.success = False
        return
    add_artifact = False
    patches = unidiff.PatchSet(patch)
    ignore_lines = []
    if ignore_config is not None and os.path.exists(ignore_config):
        ignore_lines = open(ignore_config, 'r').readlines()
    ignore = pathspec.PathSpec.from_lines(
        pathspec.patterns.GitWildMatchPattern, ignore_lines)
    patched_file: unidiff.PatchedFile
    success = True
    for patched_file in patches:
        add_artifact = True
        if ignore.match_file(patched_file.source_file) or ignore.match_file(
                patched_file.target_file):
            logging.info(f'patch of {patched_file.patch_info} is ignored')
            continue
        hunk: unidiff.Hunk
        for hunk in patched_file:
            lines = [str(x) for x in hunk]
            success = False
            m = 10  # max number of lines to report.
            description = 'please reformat the code\n```\n'
            n = len(lines)
            cut = n > m + 1
            if cut:
                lines = lines[:m]
            description += ''.join(lines) + '\n```'
            if cut:
                description += f'\n{n - m} diff lines are omitted. See full path.'
            report.add_lint({
                'name': 'clang-format',
                'severity': 'autofix',
                'code': 'clang-format',
                'path': patched_file.source_file,
                'line': hunk.source_start,
                'char': 1,
                'description': description,
            })
    if add_artifact:
        patch_file = 'clang-format.patch'
        with open(patch_file, 'w') as f:
            f.write(patch)
        report.add_artifact(os.getcwd(), patch_file, 'clang-format')
    if not success:
        step.success = False
        step.messages.append(
            'Please format your changes with clang-format by running `git-clang-format HEAD^` or applying patch.'
        )
    logging.debug(f'report: {report}')
    logging.debug(f'step: {step}')
コード例 #4
0
def run(working_dir: str, test_results: str, step: Optional[Step],
        report: Optional[Report]):
    if report is None:
        report = Report()  # For debugging.
    if step is None:
        step = Step()
    path = os.path.join(working_dir, test_results)
    if not os.path.exists(path):
        logging.warning(f'{path} is not found')
        step.success = False
        step.messages.append(f'test report "{path}" is not found')
        return
    report.add_artifact(working_dir, test_results, 'test results')
    try:
        success = True
        root_node = etree.parse(path)
        for test_case in root_node.xpath('//testcase'):
            test_result = 'pass'
            if test_case.find('failure') is not None:
                test_result = 'fail'
            if test_case.find('skipped') is not None:
                test_result = 'skip'
            report.test_stats[test_result] += 1
            if test_result == 'fail':
                success = False
                failure = test_case.find('failure')
                test_result = {
                    'name': test_case.attrib['name'],
                    'namespace': test_case.attrib['classname'],
                    'result': test_result,
                    'duration': float(test_case.attrib['time']),
                    'details': failure.text
                }
                report.unit.append(test_result)

        msg = f'{report.test_stats["pass"]} tests passed, {report.test_stats["fail"]} failed and ' \
              f'{report.test_stats["skip"]} were skipped.\n'
        if not success:
            step.success = False
            for test_case in report.unit:
                if test_case['result'] == 'fail':
                    msg += f'{test_case["namespace"]}/{test_case["name"]}\n'
    except Exception as e:
        logging.error(e)
        step.messages.append('Parsing of test results failed')
        step.success = False

    logging.debug(f'report: {report}')
    logging.debug(f'step: {step}')
コード例 #5
0
def run(test_results, report: Optional[Report]):
    """Apply clang-format and return if no issues were found."""
    if report is None:
        report = Report()  # For debugging.
    if not os.path.exists(test_results):
        logging.warning(f'{test_results} not found')
        report.add_step('clang-format', CheckResult.UNKNOWN, 'test report is not found')
        return
    success = True
    root_node = etree.parse(test_results)
    for test_case in root_node.xpath('//testcase'):
        test_result = 'pass'
        if test_case.find('failure') is not None:
            test_result = 'fail'
        if test_case.find('skipped') is not None:
            test_result = 'skip'
        report.test_stats[test_result] += 1
        if test_result == 'fail':
            success = False
            failure = test_case.find('failure')
            test_result = {
                'name': test_case.attrib['name'],
                'namespace': test_case.attrib['classname'],
                'result': test_result,
                'duration': float(test_case.attrib['time']),
                'details': failure.text
            }
            report.unit.append(test_result)

    msg = f'{report.test_stats["pass"]} tests passed, {report.test_stats["fail"]} failed and' \
          f'{report.test_stats["skip"]} were skipped.\n'
    if success:
        report.add_step('test results', CheckResult.SUCCESS, msg)
    else:
        for test_case in report.unit:
            if test_case['result'] == 'fail':
                msg += f'{test_case["namespace"]}/{test_case["name"]}\n'
        report.add_step('unit tests', CheckResult.FAILURE, msg)
コード例 #6
0
def run(base_commit, ignore_config, step: Optional[Step],
        report: Optional[Report]):
    """Apply clang-format and return if no issues were found."""
    if report is None:
        report = Report()  # For debugging.
    if step is None:
        step = Step()  # For debugging.
    r = subprocess.run(f'git diff -U0 --no-prefix {base_commit}',
                       shell=True,
                       capture_output=True)
    logging.debug(f'git diff {r}')
    diff = r.stdout.decode()
    if ignore_config is not None and os.path.exists(ignore_config):
        ignore = pathspec.PathSpec.from_lines(
            pathspec.patterns.GitWildMatchPattern,
            open(ignore_config, 'r').readlines())
        diff = ignore_diff.remove_ignored(diff.splitlines(keepends=True),
                                          open(ignore_config, 'r'))
        logging.debug(f'filtered diff: {diff}')
    else:
        ignore = pathspec.PathSpec.from_lines(
            pathspec.patterns.GitWildMatchPattern, [])
    p = subprocess.Popen(['clang-tidy-diff', '-p0', '-quiet'],
                         stdout=subprocess.PIPE,
                         stdin=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    step.reproduce_commands.append(
        f'git diff -U0 --no-prefix {base_commit} | clang-tidy-diff -p0')
    a = ''.join(diff)
    logging.info(f'clang-tidy input: {a}')
    out = p.communicate(input=a.encode())[0].decode()
    logging.debug(f'clang-tidy-diff {p}: {out}')
    # Typical finding looks like:
    # [cwd/]clang/include/clang/AST/DeclCXX.h:3058:20: error: ... [clang-diagnostic-error]
    pattern = '^([^:]*):(\\d+):(\\d+): (.*): (.*)'
    add_artifact = False
    logging.debug("cwd", os.getcwd())
    errors_count = 0
    warn_count = 0
    inline_comments = 0
    for line in out.splitlines(keepends=False):
        line = line.strip()
        line = line.replace(os.getcwd() + os.sep, '')
        logging.debug(line)
        if len(line) == 0 or line == 'No relevant changes found.':
            continue
        add_artifact = True
        match = re.search(pattern, line)
        if match:
            file_name = match.group(1)
            line_pos = match.group(2)
            char_pos = match.group(3)
            severity = match.group(4)
            text = match.group(5)
            text += '\n[[{} | not useful]] '.format(
                'https://github.com/google/llvm-premerge-checks/blob/master/docs/clang_tidy.md#warning-is-not-useful'
            )
            if severity in ['warning', 'error']:
                if severity == 'warning':
                    warn_count += 1
                if severity == 'error':
                    errors_count += 1
                if ignore.match_file(file_name):
                    print(
                        '{} is ignored by pattern and no comment will be added'
                        .format(file_name))
                else:
                    inline_comments += 1
                    report.add_lint({
                        'name':
                        'clang-tidy',
                        'severity':
                        'warning',
                        'code':
                        'clang-tidy',
                        'path':
                        file_name,
                        'line':
                        int(line_pos),
                        'char':
                        int(char_pos),
                        'description':
                        '{}: {}'.format(severity, text),
                    })
        else:
            logging.debug('does not match pattern')
    if add_artifact:
        p = 'clang-tidy.txt'
        with open(p, 'w') as f:
            f.write(out)
        report.add_artifact(os.getcwd(), p, 'clang-tidy')
    if errors_count + warn_count != 0:
        step.success = False
        url = format_url(
            "https://github.com/google/llvm-premerge-checks/blob/master/docs/clang_tidy.md"
            "#review-comments.", "why?")
        step.messages.append(
            f'clang-tidy found {errors_count} errors and {warn_count} warnings. {inline_comments} of them are added '
            f'as review comments {url}')
    logging.debug(f'report: {report}')
    logging.debug(f'step: {step}')
コード例 #7
0
        name = url
    return f"\033]1339;url='{url}';content='{name}'\a\n"


if __name__ == '__main__':
    build_dir = ''
    logging.basicConfig(level=logging.WARNING,
                        format='%(levelname)-7s %(message)s')
    scripts_dir = pathlib.Path(__file__).parent.absolute()
    phab = PhabTalk(os.getenv('CONDUIT_TOKEN'),
                    'https://reviews.llvm.org/api/', False)
    maybe_add_url_artifact(phab, os.getenv('BUILDKITE_BUILD_URL'),
                           'Buildkite build')
    artifacts_dir = os.path.join(os.getcwd(), 'artifacts')
    os.makedirs(artifacts_dir, exist_ok=True)
    report = Report()
    timings = {}
    cmake_result = run_step('cmake', report, cmake_report)
    if cmake_result == CheckResult.SUCCESS:
        compile_result = run_step('ninja all', report, ninja_all_report)
        if compile_result == CheckResult.SUCCESS:
            run_step('ninja check all', report, ninja_check_all_report)
        run_step(
            'clang-tidy', report, lambda x: clang_tidy_report.run(
                'HEAD~1', os.path.join(scripts_dir, 'clang-tidy.ignore'), x))
    run_step(
        'clang-format', report, lambda x: clang_format_report.run(
            'HEAD~1', os.path.join(scripts_dir, 'clang-format.ignore'), x))
    print('+++ summary')
    print(
        f'Branch {os.getenv("BUILDKITE_BRANCH")} at {os.getenv("BUILDKITE_REPO")}'
コード例 #8
0
     type=str,
     default='detect',
     help=
     "Projects to select, either a list or projects like 'clang;libc', or "
     "'detect' to automatically infer proejcts from the diff, or "
     "'default' to add all enabled projects")
 args = parser.parse_args()
 logging.basicConfig(level=args.log_level,
                     format='%(levelname)-7s %(message)s')
 build_dir = ''
 step_key = os.getenv("BUILDKITE_STEP_KEY")
 scripts_dir = pathlib.Path(__file__).parent.absolute()
 artifacts_dir = os.path.join(os.getcwd(), 'artifacts')
 os.makedirs(artifacts_dir, exist_ok=True)
 report_path = f'{step_key}_result.json'
 report = Report()
 report.os = f'{os.getenv("BUILDKITE_AGENT_META_DATA_OS")}'
 report.name = step_key
 report.success = False
 # Create report with failure in case something below fails.
 with open(report_path, 'w') as f:
     json.dump(report.__dict__, f, default=as_dict)
 report.success = True
 cmake = run_step('cmake', report,
                  lambda s, r: cmake_report(args.projects, s, r))
 if cmake.success:
     ninja_all = run_step(
         'ninja all', report,
         partial(ninja_all_report, filter_output=args.filter_output))
     if ninja_all.success:
         run_step(