mirror of
https://github.com/saymrwulf/uhd.git
synced 2026-05-14 20:58:09 +00:00
tools: Add changeset analyzer
This tool compares two git branches of UHD and produces a list of tests required to verify the changeset. The intended use case is to be able to verify branches that are being created for pull requests. For example, say a pull requests is based on a branch that only modifies files in host/lib/usrp/x300. Then it is only necessary to run hardware tests on X300, running tests on other USRPs would be a waste of time. This commit contains two files: The utility itself (a Python script), and a rule file (a YAML file). The former uses the latter to map a changeset to a list of tests.
This commit is contained in:
parent
ac0f3014b6
commit
3b5f89ee72
2 changed files with 320 additions and 0 deletions
145
tools/changeset_testlist.py
Normal file
145
tools/changeset_testlist.py
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright 2023 Ettus Research, a National Instruments Brand
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""
|
||||
Changeset analyzer: Reads changes made on a particular branch compared to
|
||||
another and computes a list of tests that need to be run to validate this branch.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import sys
|
||||
import subprocess
|
||||
import shutil
|
||||
import argparse
|
||||
from ruamel import yaml
|
||||
|
||||
def parse_args():
|
||||
"""
|
||||
Parse and return args.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description=__doc__,
|
||||
)
|
||||
parser.add_argument(
|
||||
'--source-branch',
|
||||
help="Source branch off diff. Defaults to the current branch.")
|
||||
parser.add_argument(
|
||||
'--target-branch', default='master',
|
||||
help="Target branch off diff. Defaults to 'master'.")
|
||||
parser.add_argument(
|
||||
'--repo-path', default='.',
|
||||
help="Path to the UHD git repository. Defaults to the current directory.")
|
||||
parser.add_argument(
|
||||
'--rule-file',
|
||||
help="Path to rules file.")
|
||||
parser.add_argument(
|
||||
'--set-azdo-var',
|
||||
help="Generate output to set an AzDO variable")
|
||||
parser.add_argument(
|
||||
'--list-tests', action='store_true',
|
||||
help="Show the generated test-list.")
|
||||
parser.add_argument(
|
||||
'--include-target', action='store_true',
|
||||
help="Include changes that originate from the target branch.")
|
||||
parser.add_argument(
|
||||
'-v', '--verbose', action='store_true',
|
||||
help="Verbose output")
|
||||
return parser.parse_args()
|
||||
|
||||
def get_changed_files(repo_path, target_branch, source_branch, include_target):
|
||||
"""
|
||||
Returns a list of paths in the UHD repository that have are different between
|
||||
two branches.
|
||||
"""
|
||||
assert target_branch
|
||||
# If include_target is false, then current (unstaged/uncommited) changes are
|
||||
# not included. If we want to change this, then couple this with
|
||||
# git diff --name-only (no further arguments)
|
||||
if not include_target:
|
||||
target_branch += '...'
|
||||
git_cmd = shutil.which('git')
|
||||
get_diff_args = [
|
||||
git_cmd,
|
||||
'diff',
|
||||
'--name-only',
|
||||
target_branch]
|
||||
if source_branch:
|
||||
get_diff_args.append(source_branch)
|
||||
files = subprocess.check_output(get_diff_args, cwd=repo_path, encoding='utf-8')
|
||||
return files.strip().split("\n")
|
||||
|
||||
def load_rules(rule_file):
|
||||
"""
|
||||
Return the rules as a Python list.
|
||||
"""
|
||||
with open(rule_file, 'r', encoding='utf-8') as rfd:
|
||||
return yaml.safe_load(rfd)
|
||||
|
||||
class RuleApplier:
|
||||
"""
|
||||
Helper class to update an internal test list based on a set of rules.
|
||||
"""
|
||||
def __init__(self, rules):
|
||||
self.rules = rules
|
||||
self.test_list = set()
|
||||
|
||||
def apply(self, filename, verbose=False):
|
||||
"""
|
||||
Apply rules against a file.
|
||||
"""
|
||||
for rule in self.rules:
|
||||
if self._apply_rule(rule, filename, verbose):
|
||||
break
|
||||
|
||||
def _apply_rule(self, rule, filename, verbose=False):
|
||||
"""
|
||||
Helper: Apply a single rule.
|
||||
|
||||
Returns True if you can stop applying rules against this filename.
|
||||
"""
|
||||
# First: Check if this rule even applies to this file
|
||||
if 're' in rule and not re.search(rule['re'], filename) \
|
||||
or 'name' in rule and rule['name'] != filename:
|
||||
return False
|
||||
if verbose:
|
||||
sys.stderr.write(f"Filename {filename} matches rule: {rule}\n")
|
||||
if 'add' in rule:
|
||||
self.test_list.update(rule['add'])
|
||||
# If stop is specified as False, then we can still apply more rules.
|
||||
if 'stop' in rule and not rule['stop']:
|
||||
return False
|
||||
return True
|
||||
|
||||
def main():
|
||||
"""
|
||||
Gogogo!
|
||||
"""
|
||||
args = parse_args()
|
||||
rule_file = args.rule_file
|
||||
if not rule_file:
|
||||
rule_file = os.path.join(pathlib.Path(__file__).parent.resolve(), 'changeset_testlist.yaml')
|
||||
file_list = get_changed_files(
|
||||
args.repo_path,
|
||||
args.target_branch,
|
||||
args.source_branch,
|
||||
args.include_target,
|
||||
)
|
||||
rule_applier = RuleApplier(load_rules(rule_file))
|
||||
for filename in file_list:
|
||||
rule_applier.apply(filename, args.verbose)
|
||||
if args.set_azdo_var:
|
||||
print(
|
||||
f"##vso[task.setvariable variable={args.set_azdo_var};isoutput=true]" + \
|
||||
';'.join(rule_applier.test_list))
|
||||
if args.list_tests:
|
||||
print("Required tests:")
|
||||
print("---------------", end='')
|
||||
print('\n* '.join(sorted([''] + list(rule_applier.test_list))))
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
175
tools/changeset_testlist.yaml
Normal file
175
tools/changeset_testlist.yaml
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
# Test targets:
|
||||
# - uhd.build.$PLATFORM: Build UHD on given platforms. This includes running unit tests.
|
||||
# Valid values for $PLATFORM are: all, linux, windows, mac.
|
||||
# - hw.streaming.$DEVICE: Run streaming tests for $DEVICE.
|
||||
# - hw.rf.$DEVICE: Run RF tests for $DEVICE.
|
||||
# - devtest.$DEVICE: Run devtests for $DEVICE.
|
||||
|
||||
|
||||
###############################################################################
|
||||
# HOST CHANGES (UHD)
|
||||
###############################################################################
|
||||
# If only a unit test changed, then we need to re-run unit tests, but no HW tests
|
||||
- re: ^host/tests/[^/]+(cpp|py)$|^host/tests/CMakeLists.txt
|
||||
add:
|
||||
- uhd.build.all
|
||||
- uhd.utest.all
|
||||
# Documentation changes
|
||||
- re: ^host/docs/
|
||||
add:
|
||||
- uhd.docs
|
||||
# Device-specific changes. These should trigger HW tests only on those devices
|
||||
# they affect. We start with daughterboard rules, then motherboard rules.
|
||||
- re: host/lib/usrp/dboard/zbx/
|
||||
add:
|
||||
- uhd.build.all
|
||||
- hw.rf.x410
|
||||
- hw.streaming.x410
|
||||
- devtest.x410
|
||||
- re: host/lib/usrp/dboard/e3xx
|
||||
add:
|
||||
- uhd.build.all
|
||||
- hw.rf.e3xx
|
||||
- hw.streaming.e3xx
|
||||
- devtest.e3xx
|
||||
- re: host/lib/usrp/dboard/magnesium
|
||||
add:
|
||||
- uhd.build.all
|
||||
- hw.rf.n310
|
||||
- devtest.n310
|
||||
- re: host/lib/usrp/dboard/rhodium
|
||||
add:
|
||||
- uhd.build.all
|
||||
- hw.rf.n320
|
||||
- devtest.n320
|
||||
- re: host/lib/usrp/dboard/twinrx/
|
||||
name: host/lib/usrp/dboard/db_twinrx.cpp
|
||||
add:
|
||||
- uhd.build.all
|
||||
- hw.rf.x310.twinrx
|
||||
- hw.rf.x300.twinrx
|
||||
- re: host/lib/usrp/dboard/.*CMakeLists.txt
|
||||
add:
|
||||
- uhd.build.all
|
||||
- re: host/lib/usrp/dboard/db_.+pp$
|
||||
add:
|
||||
- uhd.build.all
|
||||
- hw.rf.x3xx
|
||||
- hw.rf.n2xx
|
||||
- re: host/lib/usrp/b200/
|
||||
add:
|
||||
- uhd.build.all
|
||||
- hw.rf.b2xx
|
||||
- hw.streaming.b2xx
|
||||
- devtest.b2xx
|
||||
- re: host/lib/usrp/b100/
|
||||
add:
|
||||
- uhd.build.all
|
||||
- hw.rf.b1xx
|
||||
- hw.streaming.b1xx
|
||||
- devtest.b1xx
|
||||
- re: host/lib/usrp/x300/
|
||||
add:
|
||||
- uhd.build.all
|
||||
- hw.rf.x3xx
|
||||
- hw.streaming.x3xx
|
||||
- devtest.x3xx.all
|
||||
- re: host/lib/usrp/x400/
|
||||
add:
|
||||
- uhd.build.all
|
||||
- hw.rf.x4xx
|
||||
- hw.rf.n3xx
|
||||
- hw.streaming.x4xx
|
||||
- devtest.x4xx
|
||||
- re: host/lib/usrp/mpmd/
|
||||
add:
|
||||
- uhd.build.all
|
||||
- hw.rf.x4xx
|
||||
- hw.rf.n3xx
|
||||
- hw.rf.e3xx
|
||||
- hw.streaming.x4xx
|
||||
- hw.streaming.n3xx
|
||||
- hw.streaming.e3xx
|
||||
- devtest.x4xx
|
||||
- devtest.e3xx
|
||||
- devtest.n3xx
|
||||
- re: host/lib/usrp/usrp2
|
||||
add:
|
||||
- uhd.build.all
|
||||
- hw.rf.n2xx
|
||||
# Catchall rule for UHD changes
|
||||
- re: host/.+cpp$|host/.+CMakeLists.txt|host/.+hpp$|host/.+ipp$|host/.+c$|host/.+h$|host/.+py$
|
||||
add:
|
||||
- uhd.build.all
|
||||
- uhd.utest.all
|
||||
- hw.streaming.all
|
||||
- hw.rf.all
|
||||
- devtest.all
|
||||
|
||||
###############################################################################
|
||||
# MPM CHANGES
|
||||
###############################################################################
|
||||
# When any code file changes, we want to run the unit tests, but run the
|
||||
# other tests, too
|
||||
- re: ^mpm/.+hpp$|^mpm/.+cpp$|^mpm/.+py$|^mpm/.+/tests/|^mpm/.+CMakeLists.txt$
|
||||
add:
|
||||
- mpm.utest.all
|
||||
stop: False
|
||||
- re: ^mpm/.+/ad9361|^mpm/.+catalina$|^mpm/.+/dboard_manager/ad936x_db.py
|
||||
add:
|
||||
- mpm.build.e3xx
|
||||
- hw.rf.e3xx
|
||||
- devtest.e3xx
|
||||
- re: ^mpm/.+/periph_manager/n3xx
|
||||
add:
|
||||
- mpm.build.n3xx
|
||||
- hw.rf.n3xx
|
||||
- hw.streaming.n3xx
|
||||
- devtest.n3xx
|
||||
- re: ^mpm/.+/ad937x|^mpm/.+/mykonos|^mpm/.+/dboard_manager/mg_|magnesium_manager..pp$
|
||||
add:
|
||||
- mpm.build.n310
|
||||
- hw.rf.n310
|
||||
- devtest.n310
|
||||
- re: ^mpm/.+/dboard_manager/rh_|^mpm/.+/dboard_manager/..._rh.py
|
||||
add:
|
||||
- mpm.build.n320
|
||||
- hw.rf.n320
|
||||
- devtest.n320
|
||||
- re: ^mpm/.+periph_manager/x4xx
|
||||
add:
|
||||
- hw.streaming.x4xx
|
||||
stop: False
|
||||
- re: ^mpm/.+/rfdc|^mpm/.+_manager/x4xx
|
||||
add:
|
||||
- mpm.build.x4xx
|
||||
- hw.rf.x4xx
|
||||
- devtest.x4xx
|
||||
- re: fbx.py$
|
||||
add:
|
||||
- mpm.build.x4xx
|
||||
- hw.rf.x440
|
||||
- devtest.x440
|
||||
- re: zbx.py
|
||||
add:
|
||||
- mpm.build.x4xx
|
||||
- hw.rf.x410
|
||||
- devtest.x410
|
||||
- re: e31x_db_manager..pp$|^mpm/.+/periph_manager/e31x|e31x_db.py$
|
||||
add:
|
||||
- mpm.build.e310
|
||||
- hw.rf.e310
|
||||
- devtest.e310
|
||||
- re: neon_manager..pp$|^mpm/.+/periph_manager/e320
|
||||
add:
|
||||
- mpm.build.e320
|
||||
- hw.rf.e320
|
||||
- devtest.e320
|
||||
# Catchall rule for MPM changes
|
||||
- re: ^mpm/
|
||||
add:
|
||||
- mpm.build.all
|
||||
- mpm.utest.all
|
||||
- hw.streaming.all
|
||||
- hw.rf.all
|
||||
- devtest.all
|
||||
Loading…
Reference in a new issue