Ejemplo n.º 1
0
def generate(changeset, path):
    '''
    This function generates a report containing the coverage information for a given file
    at a given revision.
    '''
    # If the file is not a source file, we can return early (as we already know
    # we have no coverage information for it).
    if not coverage_supported(path):
        return {}

    _, build_changeset, _ = get_coverage_build(changeset)

    coverage = coverage_service.get_file_coverage(build_changeset, path)

    return coverage if coverage is not None else {}
def generate(changeset):
    '''
    This function generates a report containing the coverage information of the diff
    introduced by a changeset.
    '''
    build_changeset, overall = get_coverage_build(changeset)

    r = requests.get('https://hg.mozilla.org/mozilla-central/raw-rev/%s' % changeset)
    patch = r.text

    diffs = []

    def parse_diff(diff):
        # Get old and new path, for files that have been renamed.
        new_path = diff.header.new_path[2:] if diff.header.new_path.startswith('b/') else diff.header.new_path

        # If the diff doesn't contain any changes, we skip it.
        if diff.changes is None:
            return None

        # If the file is not a source file, we skip it (as we already know
        # we have no coverage information for it).
        if not coverage_supported(new_path):
            return None

        # Retrieve coverage of added lines.
        coverage = coverage_service.get_file_coverage(build_changeset, new_path)

        # If we don't have coverage for this file, we skip it.
        if coverage is None:
            return None

        changes = []
        for old_line, new_line, _ in diff.changes:
            # Only consider added lines.
            if old_line is not None or new_line is None:
                continue

            if new_line not in coverage or coverage[new_line] is None:
                # We have no coverage information for this line (e.g. a definition, like
                # a variable in a header file).
                covered = '?'
            elif coverage[new_line] > 0:
                covered = 'Y'
            else:
                covered = 'N'

            changes.append({
                'coverage': covered,
                'line': new_line,
            })

        return {
          'name': new_path,
          'changes': changes,
        }

    def parse_diff_task(diff):
        return lambda: parse_diff(diff)

    with ThreadPoolExecutor(max_workers=4) as executor:
        futures = []

        for diff in whatthepatch.parse_patch(patch):
            futures.append(executor.submit(parse_diff_task(diff)))

        for future in concurrent.futures.as_completed(futures):
            res = future.result()
            if res is not None:
                diffs.append(res)

    return {
        'build_changeset': build_changeset,
        'git_build_changeset': get_github_commit(build_changeset),
        'overall_cur': overall['cur'],
        'overall_prev': overall['prev'],
        'diffs': diffs,
    }
Ejemplo n.º 3
0
def generate(changeset):
    '''
    This function generates a report containing the coverage information of the diff
    introduced by a changeset.
    '''
    changeset_data, build_changeset, overall = get_coverage_build(changeset)
    if 'merge' in changeset_data:
        raise Exception(
            'Retrieving coverage for merge commits is not supported.')

    diffs = []

    def retrieve_coverage(path):
        # If the file is not a source file, we skip it (as we already know
        # we have no coverage information for it).
        if not coverage_supported(path):
            return None

        # Use hg annotate to report lines in their correct positions and to avoid
        # reporting lines that have been modified by a successive patch in the same push.
        r = requests.get(
            'https://hg.mozilla.org/mozilla-central/json-annotate/{}/{}'.
            format(build_changeset, path))
        data = r.json()
        if 'not found in manifest' in data:
            # The file was removed.
            return None
        annotate = r.json()['annotate']

        # Retrieve coverage of added lines.
        coverage = coverage_service.get_file_coverage(build_changeset, path)

        # If we don't have coverage for this file, we skip it.
        if coverage is None:
            return None

        changes = []
        for data in annotate:
            # Skip lines that were not added by this changeset or were overwritten by
            # another changeset.
            if data['node'][:len(changeset)] != changeset:
                continue

            new_line = data['lineno']

            if new_line not in coverage or coverage[new_line] is None:
                # We have no coverage information for this line (e.g. a definition, like
                # a variable in a header file).
                covered = '?'
            elif coverage[new_line] > 0:
                covered = 'Y'
            else:
                covered = 'N'

            changes.append({
                'coverage': covered,
                'line': data['targetline'],
            })

        return {
            'name': path,
            'changes': changes,
        }

    def retrieve_coverage_task(path):
        return lambda: retrieve_coverage(path)

    with ThreadPoolExecutor(max_workers=4) as executor:
        futures = []

        for path in changeset_data['files']:
            futures.append(executor.submit(retrieve_coverage_task(path)))

        for future in concurrent.futures.as_completed(futures):
            res = future.result()
            if res is not None:
                diffs.append(res)

    return {
        'build_changeset': build_changeset,
        'git_build_changeset': get_github_commit(build_changeset),
        'overall_cur': overall['cur'],
        'overall_prev': overall['prev'],
        'diffs': diffs,
    }
Ejemplo n.º 4
0
def generate(changeset):
    '''
    This function generates a report containing the coverage information of the diff
    introduced by a changeset.
    '''
    desc, build_changeset, overall = get_coverage_build(changeset)
    if any(text in desc for text in ['r=merge', 'a=merge']):
        raise Exception('Retrieving coverage for merge commits is not supported.')

    r = requests.get('https://hg.mozilla.org/mozilla-central/raw-rev/%s' % changeset)
    patch = r.text

    diffs = []

    def parse_diff(diff):
        # Get old and new path, for files that have been renamed.
        new_path = diff.header.new_path[2:] if diff.header.new_path.startswith('b/') else diff.header.new_path

        # If the diff doesn't contain any changes, we skip it.
        if diff.changes is None:
            return None

        # If the file is not a source file, we skip it (as we already know
        # we have no coverage information for it).
        if not coverage_supported(new_path):
            return None

        # Retrieve coverage of added lines.
        coverage = coverage_service.get_file_coverage(build_changeset, new_path)

        # If we don't have coverage for this file, we skip it.
        if coverage is None:
            return None

        # Use hg annotate to report lines in their correct positions and to avoid
        # reporting lines that have been modified by a successive patch in the same push.
        r = requests.get('https://hg.mozilla.org/mozilla-central/json-annotate/%s/%s' % (build_changeset, new_path))
        annotate = r.json()['annotate']

        changes = []
        for data in annotate:
            # Skip lines that were not added by this changeset or were overwritten by
            # another changeset.
            if data['node'][:len(changeset)] != changeset:
                continue

            new_line = data['lineno']

            if new_line not in coverage or coverage[new_line] is None:
                # We have no coverage information for this line (e.g. a definition, like
                # a variable in a header file).
                covered = '?'
            elif coverage[new_line] > 0:
                covered = 'Y'
            else:
                covered = 'N'

            changes.append({
                'coverage': covered,
                'line': data['targetline'],
            })

        return {
          'name': new_path,
          'changes': changes,
        }

    def parse_diff_task(diff):
        return lambda: parse_diff(diff)

    with ThreadPoolExecutor(max_workers=4) as executor:
        futures = []

        for diff in whatthepatch.parse_patch(patch):
            futures.append(executor.submit(parse_diff_task(diff)))

        for future in concurrent.futures.as_completed(futures):
            res = future.result()
            if res is not None:
                diffs.append(res)

    return {
        'build_changeset': build_changeset,
        'git_build_changeset': get_github_commit(build_changeset),
        'overall_cur': overall['cur'],
        'overall_prev': overall['prev'],
        'diffs': diffs,
    }