diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5cfaf6e6e06..b3fe25c8672 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -753,83 +753,16 @@ Commit Check:
# https://docs.gitlab.com/ee/ci/testing/unit_test_reports.html
# https://www.ibm.com/docs/en/developer-for-zos/14.2?topic=formats-junit-xml-format
#
- # Let's generate a unit test report, even if that means wondering which life choices
- # led us to assemlbing an XML document from fragments in a shell script which is
- # embedded in YAML.
- - FAILURE_COUNT=0
- - TESTCASES=""
- FAILURE_COUNT=$(( FAILURE_COUNT + 1 ))
- else
- TESTCASES+="/>"
- fi
- - PC_EXIT_CODE=0
- - ANALYSIS_MESSAGE=$( ./tools/pre-commit "${CI_COMMIT_SHA}~$NUM_COMMITS" ) || PC_EXIT_CODE=1
- - TESTCASES+=""
- FAILURE_COUNT=$(( FAILURE_COUNT + 1 ))
- else
- TESTCASES+="/>"
- fi
- - VC_EXIT_CODE=0
- - ANALYSIS_MESSAGE=$( tools/validate-commit.py ) || VC_EXIT_CODE=1
- - TESTCASES+=""
- FAILURE_COUNT=$(( FAILURE_COUNT + 1 ))
- else
- TESTCASES+="/>"
- fi
- - LC_EXIT_CODE=0
- - ANALYSIS_MESSAGE=$( python3 tools/checklicenses.py ) || LC_EXIT_CODE=1
- - TESTCASES+=""
- FAILURE_COUNT=$(( FAILURE_COUNT + 1 ))
- else
- TESTCASES+="/>"
- fi
- - HC_EXIT_CODE=0
- - ANALYSIS_MESSAGE=$( python3 tools/check_help_urls.py ) || HC_EXIT_CODE=1
- - TESTCASES+=""
- FAILURE_COUNT=$(( FAILURE_COUNT + 1 ))
- else
- TESTCASES+="/>"
- fi
- - |
- cat > commit_checks.xml <
-
- $TESTCASES
-
- FIN
- # - cat commit_checks.xml
- - grep ' 0) or (args.command is None and len(command_list) == 0):
+ sys.stderr.write('Error: The command must be provided via the --command flag or extra arguments.\n')
+ sys.exit(1)
+
+ try:
+ tree = ET.parse(args.file)
+ testsuites_el = tree.getroot()
+ except FileNotFoundError:
+ testsuites_el = ET.Element('testsuites')
+ tree = ET.ElementTree(testsuites_el)
+ except ET.ParseError:
+ sys.stderr.write(f'Error: {args.file} is invalid.\n')
+ sys.exit(1)
+
+ suites_time = float(testsuites_el.get('time', 0.0))
+ suites_tests = int(testsuites_el.get('tests', 0)) + 1
+ suites_failures = int(testsuites_el.get('failures', 0))
+
+ testsuite_el = testsuites_el.find(f'./testsuite[@name="{args.suite}"]')
+ if testsuite_el is None:
+ testsuite_el = ET.Element('testsuite', attrib={'name': args.suite})
+ testsuites_el.append(testsuite_el)
+
+ suite_time = float(testsuite_el.get('time', 0.0))
+ suite_tests = int(testsuite_el.get('tests', 0)) + 1
+ suite_failures = int(testsuite_el.get('failures', 0))
+
+ testcase_el = ET.Element('testcase', attrib={'name': args.case})
+ testsuite_el.append(testcase_el)
+
+ if args.command:
+ proc_args = args.command
+ in_shell = True
+ else:
+ proc_args = command_list
+ in_shell = False
+
+ start_time = time.perf_counter()
+ proc = subprocess.run(proc_args, shell=in_shell, encoding='UTF-8', errors='replace', capture_output=True)
+ case_time = time.perf_counter() - start_time
+
+ testcase_el.set('time', f'{case_time}')
+ testsuite_el.set('time', f'{suite_time + case_time}')
+ testsuites_el.set('time', f'{suites_time + case_time}')
+
+ # XXX Try to interleave them?
+ sys.stdout.write(proc.stdout)
+ sys.stderr.write(proc.stderr)
+
+ # Remove ANSI control sequences and escape other invalid characters
+ # https://stackoverflow.com/a/14693789/82195
+ ansi_seq_re = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
+ scrubbed_stdout = html.escape(ansi_seq_re.sub('', proc.stdout), quote=False)
+ scrubbed_stderr = html.escape(ansi_seq_re.sub('', proc.stderr), quote=False)
+
+ if proc.returncode != 0:
+ failure_el = ET.Element('failure')
+ failure_el.text = f'{scrubbed_stdout}{scrubbed_stderr}'
+ testcase_el.append(failure_el)
+ testsuite_el.set('failures', f'{suite_failures + 1}')
+ testsuites_el.set('failures', f'{suites_failures + 1}')
+ else:
+ system_out_el = ET.Element('system-out')
+ system_out_el.text = f'{scrubbed_stdout}'
+ testcase_el.append(system_out_el)
+ system_err_el = ET.Element('system-err')
+ system_err_el.text = f'{scrubbed_stderr}'
+ testcase_el.append(system_err_el)
+
+ testsuite_el.set('tests', f'{suite_tests}')
+ testsuites_el.set('tests', f'{suites_tests}')
+
+ tree.write(args.file, encoding='UTF-8', xml_declaration=True)
+
+ return proc.returncode
+
+if __name__ == '__main__':
+ sys.exit(main())