diff --git a/eng/pipelines/templates/steps/build-test.yml b/eng/pipelines/templates/steps/build-test.yml index 539aae602d29..928883868701 100644 --- a/eng/pipelines/templates/steps/build-test.yml +++ b/eng/pipelines/templates/steps/build-test.yml @@ -65,7 +65,7 @@ steps: - pwsh: | if (Test-Path -Path '.\_coverage\') { - Get-ChildItem .\_coverage\ | + Get-ChildItem .\_coverage\ -Recurse | Foreach-Object { Get-Content $_ } diff --git a/scripts/devops_tasks/code_cov_report.py b/scripts/devops_tasks/code_cov_report.py new file mode 100644 index 000000000000..cb9ee141d088 --- /dev/null +++ b/scripts/devops_tasks/code_cov_report.py @@ -0,0 +1,113 @@ +import copy +import logging +import os +import xml.etree.ElementTree as ET + +root_dir = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..")) +coverage_file = os.path.join(root_dir, "coverage.xml") + + +def create_coverage_report(): + if not os.path.exists(coverage_file): + logging.info("No coverage file detected at {}".format(coverage_file)) + return + logging.info("Modifying coverage file at {}".format(coverage_file)) + tree = ET.parse(coverage_file) + root = tree.getroot() + + packages = root[1] + + recursive_set_name(packages) + + packages_to_report = [] + for child in packages: + # Order should be: ['azure', '', 'azure-', ...] + name = child.attrib['name'].split('.') + logging.info("Name: {}".format(name)) + folder, package = name[1], name[2] + if (folder, package) not in packages_to_report: + packages_to_report.append((folder, package)) + logging.info("Found a package: {}".format(package)) + + package_names = [p[1] for p in packages_to_report] + + packages_root = root.find('packages') + packages_root = packages + + packages_nodes = [] + for folder, package_name in packages_to_report: + condense_nodes = [] + for child in packages: + + test_str = "sdk.{}.{}.{}".format( + folder, + package_name, + package_name.replace('-', '.') + ) + + if package_name in child.attrib['name']: + condense_nodes.append(child) + + packages_nodes.append(condense_nodes) + + nodes_to_remove = [] + for nodes in packages_nodes: + if len(nodes) > 1: + first_package = nodes[0] + + first_package_classes = first_package.find('classes') + + for node in nodes[1:]: + temp_classes = node.find('classes') + + for _class in temp_classes: + first_package_classes.append(_class) + nodes_to_remove.append(node) + + for n in nodes_to_remove: + if n not in packages_root: + continue + + packages_root.remove(n) + + # Last thing with root, change the 'name' attrib to be just the package name + packages_to_add = [] + for package in root.find('packages'): + name = package.attrib['name'].split('.') + package.attrib['name'] = name[2] + + packages_to_add.append(copy.deepcopy(package)) + + write_final_xml(packages_to_add) + + +def write_final_xml(packages_to_add): + if not os.path.exists(coverage_file): + logging.info("No coverage file detected at {}".format(coverage_file)) + return + + logging.info("Modifying coverage file at {}".format(coverage_file)) + tree = ET.parse(coverage_file) + root = tree.getroot() + + packages = root[1] + + for p in packages_to_add: + packages.insert(0, p) + + with open(coverage_file, "wb") as f: + data = ET.tostring(root) + f.write(data) + + +def recursive_set_name(root): + # Stopping condition + if 'line' in root.attrib: + return + + # Add file path to the filename + if root.tag == 'class': + root.set('name', root.attrib['filename']) + + for child in root: + recursive_set_name(child) diff --git a/scripts/devops_tasks/create_coverage.py b/scripts/devops_tasks/create_coverage.py index e4f286253d31..7d1294a56a82 100644 --- a/scripts/devops_tasks/create_coverage.py +++ b/scripts/devops_tasks/create_coverage.py @@ -11,6 +11,8 @@ import re from common_tasks import run_check_call +from code_cov_report import create_coverage_report + logging.getLogger().setLevel(logging.INFO) root_dir = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..")) @@ -71,4 +73,5 @@ def fix_dot_coverage_file(coverage_file): if __name__ == "__main__": collect_tox_coverage_files() - generate_coverage_xml() \ No newline at end of file + generate_coverage_xml() + create_coverage_report() \ No newline at end of file