Skip to content

Instantly share code, notes, and snippets.

@Tattoo
Created October 27, 2022 09:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Tattoo/509fc564207fa99916fa6e6997bab838 to your computer and use it in GitHub Desktop.
Save Tattoo/509fc564207fa99916fa6e6997bab838 to your computer and use it in GitHub Desktop.
Script to parse changed Robot Framework tests from git diff
'''
$ git diff --unified=0 path/to/robot | python differ.py
'''
import re
import sys
from collections import defaultdict
from pathlib import Path
from robot.api import SuiteVisitor, TestSuiteBuilder
CURDIR = Path.cwd()
def get_absolute_filepath(fp):
return CURDIR / fp
def parse(gitdiff):
changed_files = defaultdict(set)
current_suite_file = ''
test_case_name = ''
for line in gitdiff:
if line.startswith('+++'):
_, current_suite_file = line.split('b/', 1)
current_suite_file = get_absolute_filepath(current_suite_file.strip())
continue
if line.startswith('@@'):
_, test_case_name = line.rsplit('@@', 1)
if re.match('^\+\w', line) != None:
test_case_name = line[1:]
changed_files[current_suite_file].add(test_case_name.strip())
# if there is an entry where they key is empty string, remove it
changed_files.pop('')
return changed_files
def get_actual_tcs(filepaths):
class TestCaseExtractor(SuiteVisitor):
def __init__(self):
self.data = defaultdict(list)
def start_test(self, test):
self.data[Path(test.parent.source)].append(test.name)
extractor = TestCaseExtractor()
suites = [TestSuiteBuilder().build(fp) for fp in filepaths]
for s in suites:
s.visit(extractor)
return extractor.data
def filter_out_non_testcases(changed_files, actual_test_cases):
retval = {}
for suitepath, tests in changed_files.items():
retval[suitepath] = [t for t in tests if t in actual_test_cases[suitepath]]
return retval
def format_(changed_files):
retval = []
for changed_file, changed_tests in changed_files.items():
suite_name = str(changed_file).replace(f'{CURDIR}/', '')
# needs to end in slash, otherwise suite_name is '/foo/bar' instead
# of 'foo/bar'
suite_name = suite_name.replace('/', '.')
suite_name, _ = suite_name.rsplit('.robot', 1)
for test in changed_tests:
t = test.replace(' ', '')
retval.append(f'--suite {suite_name} --test {t}')
return retval
def main(gitdiff):
changed_files = parse(gitdiff)
actual_test_cases = get_actual_tcs(changed_files.keys())
changed_files = filter_out_non_testcases(changed_files, actual_test_cases)
robot_args = format_(changed_files)
print('\n'.join(robot_args))
if __name__ == '__main__':
main(sys.stdin.readlines())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment