|
| 1 | +#!/usr/bin/env python3 |
| 2 | + |
| 3 | +import json |
| 4 | +import os |
| 5 | +import re |
| 6 | +import sys |
| 7 | +from pathlib import Path |
| 8 | +from collections import defaultdict |
| 9 | +import argparse |
| 10 | + |
| 11 | +if "ZEPHYR_BASE" not in os.environ: |
| 12 | + exit("$ZEPHYR_BASE environment variable undefined.") |
| 13 | + |
| 14 | +# These are globally used variables. They are assigned in __main__ and are visible in further methods |
| 15 | +# however, pylint complains that it doesn't recognize them when used (used-before-assignment). |
| 16 | +zephyr_base = Path(os.environ['ZEPHYR_BASE']) |
| 17 | + |
| 18 | +sys.path.insert(0, os.path.join(zephyr_base / "scripts")) |
| 19 | +from get_maintainer import Maintainers |
| 20 | + |
| 21 | +def load_database(database_path): |
| 22 | + with open(database_path, 'r') as file: |
| 23 | + return json.load(file) |
| 24 | + |
| 25 | +def find_areas(files): |
| 26 | + maintf = zephyr_base / "MAINTAINERS.yml" |
| 27 | + maintainer_file = Maintainers(maintf) |
| 28 | + |
| 29 | + num_files = 0 |
| 30 | + all_areas = set() |
| 31 | + |
| 32 | + for changed_file in files: |
| 33 | + num_files += 1 |
| 34 | + print(f"file: {changed_file}") |
| 35 | + areas = maintainer_file.path2areas(changed_file) |
| 36 | + |
| 37 | + if not areas: |
| 38 | + continue |
| 39 | + all_areas.update(areas) |
| 40 | + tests = [] |
| 41 | + for area in all_areas: |
| 42 | + for suite in area.tests: |
| 43 | + tests.append(f"{suite}.*") |
| 44 | + return tests |
| 45 | + |
| 46 | +def find_best_coverage(database, changed_files, tests): |
| 47 | + coverage = defaultdict(lambda: defaultdict(int)) |
| 48 | + |
| 49 | + for file in changed_files: |
| 50 | + if file in database: |
| 51 | + for entry in database[file]: |
| 52 | + if not any(re.search(f"^{test}", entry["testsuite_id"]) for test in tests): |
| 53 | + print("skip") |
| 54 | + continue |
| 55 | + testsuite_id = entry["testsuite_id"] |
| 56 | + platform = entry["platform"] |
| 57 | + coverage[testsuite_id][platform] += 1 |
| 58 | + |
| 59 | + best_coverage = [] |
| 60 | + for testsuite_id, platforms in coverage.items(): |
| 61 | + for platform, count in platforms.items(): |
| 62 | + best_coverage.append((testsuite_id, platform, count)) |
| 63 | + |
| 64 | + best_coverage.sort(key=lambda x: x[2], reverse=True) |
| 65 | + return best_coverage |
| 66 | + |
| 67 | +def main(database_path, changed_files): |
| 68 | + tests = find_areas(changed_files) |
| 69 | + database = load_database(database_path) |
| 70 | + best_coverage = find_best_coverage(database, changed_files, tests) |
| 71 | + |
| 72 | + if best_coverage: |
| 73 | + print("Best coverage testsuites and platforms:") |
| 74 | + for testsuite_id, platform, count in best_coverage: |
| 75 | + print(f"Testsuite: {testsuite_id}, Platform: {platform}, Coverage: {count}") |
| 76 | + else: |
| 77 | + print("No matching testsuites found for the provided files.") |
| 78 | + |
| 79 | + |
| 80 | +if __name__ == "__main__": |
| 81 | + parser = argparse.ArgumentParser(description="Find the best coverage testsuites and platforms for changed files.") |
| 82 | + parser.add_argument("--database", help="Path to the testsuite database JSON file") |
| 83 | + parser.add_argument("--changed-files", action="append", help="List of changed files") |
| 84 | + |
| 85 | + args = parser.parse_args() |
| 86 | + |
| 87 | + main(args.database, args.changed_files) |
0 commit comments