mirror of https://github.com/ansible/ansible.git
Add coverage filtering to ansible-test. (#68158)
* Relocate expand_indexes so it can be reused. * Add generate_indexes function. * Simplify type annotations. * Add `coverage analyze targets filter` command. * Add changelog entry.pull/68182/head
parent
c03cb09c3d
commit
8f4f5193a2
@ -0,0 +1,2 @@
|
|||||||
|
minor_changes:
|
||||||
|
- "ansible-test - Added a ``ansible-test coverage analyze targets filter`` command to filter aggregated coverage reports by path and/or target name."
|
@ -0,0 +1,104 @@
|
|||||||
|
"""Filter an aggregated coverage file, keeping only the specified targets."""
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from .... import types as t
|
||||||
|
|
||||||
|
from . import (
|
||||||
|
CoverageAnalyzeTargetsConfig,
|
||||||
|
expand_indexes,
|
||||||
|
generate_indexes,
|
||||||
|
make_report,
|
||||||
|
read_report,
|
||||||
|
write_report,
|
||||||
|
)
|
||||||
|
|
||||||
|
if t.TYPE_CHECKING:
|
||||||
|
from . import (
|
||||||
|
NamedPoints,
|
||||||
|
TargetIndexes,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def command_coverage_analyze_targets_filter(args): # type: (CoverageAnalyzeTargetsFilterConfig) -> None
|
||||||
|
"""Filter target names in an aggregated coverage file."""
|
||||||
|
covered_targets, covered_path_arcs, covered_path_lines = read_report(args.input_file)
|
||||||
|
|
||||||
|
filtered_path_arcs = expand_indexes(covered_path_arcs, covered_targets, lambda v: v)
|
||||||
|
filtered_path_lines = expand_indexes(covered_path_lines, covered_targets, lambda v: v)
|
||||||
|
|
||||||
|
include_targets = set(args.include_targets) if args.include_targets else None
|
||||||
|
exclude_targets = set(args.exclude_targets) if args.exclude_targets else None
|
||||||
|
|
||||||
|
include_path = re.compile(args.include_path) if args.include_path else None
|
||||||
|
exclude_path = re.compile(args.exclude_path) if args.exclude_path else None
|
||||||
|
|
||||||
|
def path_filter_func(path):
|
||||||
|
if include_path and not re.search(include_path, path):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if exclude_path and re.search(exclude_path, path):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def target_filter_func(targets):
|
||||||
|
if include_targets:
|
||||||
|
targets &= include_targets
|
||||||
|
|
||||||
|
if exclude_targets:
|
||||||
|
targets -= exclude_targets
|
||||||
|
|
||||||
|
return targets
|
||||||
|
|
||||||
|
filtered_path_arcs = filter_data(filtered_path_arcs, path_filter_func, target_filter_func)
|
||||||
|
filtered_path_lines = filter_data(filtered_path_lines, path_filter_func, target_filter_func)
|
||||||
|
|
||||||
|
target_indexes = {} # type: TargetIndexes
|
||||||
|
indexed_path_arcs = generate_indexes(target_indexes, filtered_path_arcs)
|
||||||
|
indexed_path_lines = generate_indexes(target_indexes, filtered_path_lines)
|
||||||
|
|
||||||
|
report = make_report(target_indexes, indexed_path_arcs, indexed_path_lines)
|
||||||
|
|
||||||
|
write_report(args, report, args.output_file)
|
||||||
|
|
||||||
|
|
||||||
|
def filter_data(
|
||||||
|
data, # type: NamedPoints
|
||||||
|
path_filter_func, # type: t.Callable[[str], bool]
|
||||||
|
target_filter_func, # type: t.Callable[[t.Set[str]], t.Set[str]]
|
||||||
|
): # type: (...) -> NamedPoints
|
||||||
|
"""Filter the data set using the specified filter function."""
|
||||||
|
result = {} # type: NamedPoints
|
||||||
|
|
||||||
|
for src_path, src_points in data.items():
|
||||||
|
if not path_filter_func(src_path):
|
||||||
|
continue
|
||||||
|
|
||||||
|
dst_points = {}
|
||||||
|
|
||||||
|
for src_point, src_targets in src_points.items():
|
||||||
|
dst_targets = target_filter_func(src_targets)
|
||||||
|
|
||||||
|
if dst_targets:
|
||||||
|
dst_points[src_point] = dst_targets
|
||||||
|
|
||||||
|
if dst_points:
|
||||||
|
result[src_path] = dst_points
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class CoverageAnalyzeTargetsFilterConfig(CoverageAnalyzeTargetsConfig):
|
||||||
|
"""Configuration for the `coverage analyze targets filter` command."""
|
||||||
|
def __init__(self, args): # type: (t.Any) -> None
|
||||||
|
super(CoverageAnalyzeTargetsFilterConfig, self).__init__(args)
|
||||||
|
|
||||||
|
self.input_file = args.input_file # type: str
|
||||||
|
self.output_file = args.output_file # type: str
|
||||||
|
self.include_targets = args.include_targets # type: t.List[str]
|
||||||
|
self.exclude_targets = args.exclude_targets # type: t.List[str]
|
||||||
|
self.include_path = args.include_path # type: t.Optional[str]
|
||||||
|
self.exclude_path = args.exclude_path # type: t.Optional[str]
|
Loading…
Reference in New Issue