1#!/usr/bin/env python 2# Copyright (c) 2018 Parsa Amini 3# 4# Distributed under the Boost Software License, Version 1.0. (See accompanying 5# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 7# ## Synopsis 8# ``` 9# usage: inspect_to_junit.py [-h] [source] [destination] 10# 11# Generate JUnit XML report from inspect output 12# 13# positional arguments: 14# source File path to read inspect output from 15# destination File path to write JUnit XML report to 16# 17# optional arguments: 18# -h, --help show this help message and exit 19# ``` 20 21import argparse 22import re 23import sys 24from xml.dom import minidom 25from collections import namedtuple 26 27error_item = namedtuple('error_item', 'filename message') 28 29 30def parse_inspect8_log(fh): 31 line_pattern = re.compile('(.+):\ (\*.+\*.+)') 32 split_pattern = re.compile(',\ (?=\*)') 33 stipper_pattern = re.compile('<\/?\w+[^>]*>') 34 35 errors = [] 36 37 for line in fh: 38 m = line_pattern.match(line) 39 if m: 40 for message in split_pattern.split(m.group(2)): 41 error = error_item(filename=m.group(1), 42 message=stipper_pattern.sub('', message)) 43 errors.append(error) 44 45 return errors 46 47 48def convert(inspect8_log_fh): 49 errors = parse_inspect8_log(inspect8_log_fh) 50 51 doc = minidom.Document() 52 suite = doc.createElement('testsuite') 53 doc.appendChild(suite) 54 suite.setAttribute('name', 'inspect') 55 suite.setAttribute('errors', str(len(errors))) 56 suite.setAttribute('failures', '0') 57 suite.setAttribute('tests', str(len(errors))) 58 59 if len(errors) == 0: 60 case = doc.createElement('testcase') 61 case.setAttribute('name', 'inspect') 62 case.setAttribute('time', '') 63 suite.appendChild(case) 64 65 for error in errors: 66 case = doc.createElement('testcase') 67 case.setAttribute('name', error.filename) 68 case.setAttribute('time', '') 69 suite.appendChild(case) 70 71 failure = doc.createElement('failure') 72 case.appendChild(failure) 73 74 failure.setAttribute('file', error.filename) 75 failure.setAttribute('message', error.message) 76 message = doc.createTextNode(error.message) 77 failure.appendChild(message) 78 79 return doc 80 81 82def main(): 83 parser = argparse.ArgumentParser( 84 description='Generate JUnit XML report from inspect html output') 85 parser.add_argument('source', 86 type=argparse.FileType('r'), 87 nargs='?', 88 default=sys.stdin, 89 help='File path to read inspect html output from') 90 parser.add_argument('destination', 91 type=argparse.FileType('w'), 92 nargs='?', 93 default=sys.stdout, 94 help='File path to write JUnit XML report to') 95 96 args = parser.parse_args() 97 report = convert(args.source) 98 report.writexml(args.destination, 99 addindent=' ', newl='\n', encoding='utf-8') 100 101 102if __name__ == '__main__': 103 main() 104