-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refs #20441: Add action to print a simple summary from jUnit reports
Signed-off-by: EduPonz <eduardoponz@eprosima.com>
- Loading branch information
Showing
4 changed files
with
399 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
name: 'junit_summary' | ||
description: 'Generate a summary from a jUnit report. This summary shows in the workflow summary page. Exit code is number of failed tests.' | ||
|
||
inputs: | ||
junit_reports_dir: | ||
description: 'Path to directory containing XML files with the jUnit reports' | ||
required: true | ||
|
||
output_file: | ||
description: 'Path to the file where the summary will be written' | ||
required: true | ||
|
||
print_summary: | ||
description: 'Whether to print the summary (Default: True)' | ||
required: false | ||
default: 'True' | ||
|
||
show_failed: | ||
description: 'Whether to show the list of failed tests (Default: True)' | ||
required: false | ||
default: 'True' | ||
|
||
show_disabled: | ||
description: 'Whether to show the list of disabled tests (Default: False)' | ||
required: false | ||
default: 'False' | ||
|
||
show_skipped: | ||
description: 'Whether to show the list of skipped tests (Default: False)' | ||
required: false | ||
default: 'False' | ||
|
||
runs: | ||
using: composite | ||
steps: | ||
|
||
- name: Run in ubuntu | ||
if: runner.os == 'Linux' | ||
uses: eProsima/eProsima-CI/ubuntu/junit_summary@feature/ctest2junit_translation | ||
with: | ||
junit_reports_dir: ${{ inputs.junit_reports_dir }} | ||
output_file: ${{ inputs.output_file }} | ||
print_summary: ${{ inputs.print_summary }} | ||
show_failed: ${{ inputs.show_failed }} | ||
show_disabled: ${{ inputs.show_disabled }} | ||
show_skipped: ${{ inputs.show_skipped }} | ||
|
||
- name: Run in windows | ||
if: runner.os == 'Windows' | ||
uses: eProsima/eProsima-CI/windows/junit_summary@feature/ctest2junit_translation | ||
with: | ||
junit_reports_dir: ${{ inputs.junit_reports_dir }} | ||
output_file: ${{ inputs.output_file }} | ||
print_summary: ${{ inputs.print_summary }} | ||
show_failed: ${{ inputs.show_failed }} | ||
show_disabled: ${{ inputs.show_disabled }} | ||
show_skipped: ${{ inputs.show_skipped }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
# Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
"""Script to parse the jUnit test results and create a summary.""" | ||
|
||
import argparse | ||
import xml.etree.ElementTree as ET | ||
|
||
DESCRIPTION = """Script to parse the jUnit test results and create a summary""" | ||
USAGE = ('python3 junit_summary.py') | ||
|
||
|
||
def parse_options(): | ||
""" | ||
Parse arguments. | ||
:return: The arguments parsed. | ||
""" | ||
parser = argparse.ArgumentParser( | ||
formatter_class=argparse.ArgumentDefaultsHelpFormatter, | ||
add_help=True, | ||
description=(DESCRIPTION), | ||
usage=(USAGE) | ||
) | ||
|
||
required_args = parser.add_argument_group('required arguments') | ||
required_args.add_argument( | ||
'-j', | ||
'--junit-report', | ||
type=str, | ||
required=True, | ||
help='Path to junit report file.' | ||
) | ||
required_args.add_argument( | ||
'-o', | ||
'--output-file', | ||
type=str, | ||
required=True, | ||
help='Path to output file.' | ||
) | ||
parser.add_argument( | ||
'-p', | ||
'--print-summary', | ||
action='store_true', | ||
help='Print the summary to STDOUT' | ||
) | ||
parser.add_argument( | ||
'-f', | ||
'--show-failed', | ||
action='store_true', | ||
help='Show a list of failed tests' | ||
) | ||
parser.add_argument( | ||
'-d', | ||
'--show-disabled', | ||
action='store_true', | ||
help='Show a list of disabled tests' | ||
) | ||
parser.add_argument( | ||
'-s', | ||
'--show-skipped', | ||
action='store_true', | ||
help='Show a list of skipped tests' | ||
) | ||
|
||
return parser.parse_args() | ||
|
||
def junit_report_to_dict(junit_report): | ||
"""Convert a jUnit report to a dictionary.""" | ||
result = { | ||
'passed_tests': [], | ||
'failed_tests': [], | ||
'disabled_tests': [], | ||
'skipped_tests': [], | ||
} | ||
tree = ET.parse(junit_report) | ||
root = tree.getroot() | ||
result['tests'] = root.attrib['tests'] | ||
result['failures'] = root.attrib['failures'] | ||
result['disabled'] = root.attrib['disabled'] | ||
result['skipped'] = root.attrib['skipped'] | ||
result['time'] = root.attrib['time'] | ||
result['timestamp'] = root.attrib['timestamp'] | ||
|
||
for child in root: | ||
if child.tag == 'testcase': | ||
if child.attrib['status'] == "run": | ||
result['passed_tests'].append(child.attrib['name']) | ||
|
||
elif child.attrib['status'] == "fail": | ||
result['failed_tests'].append(child.attrib['name']) | ||
|
||
elif child.attrib['status'] == "ignored": | ||
result['disabled_tests'].append(child.attrib['name']) | ||
|
||
elif child.attrib['status'] == "notrun": | ||
result['skipped_tests'].append(child.attrib['name']) | ||
|
||
return result | ||
|
||
def create_md_summary(results_dict, show_failed, show_disabled, show_skipped): | ||
"""Create Markdown summary from results.""" | ||
# Test summary | ||
summary = '## Test summary\n' | ||
|
||
# Table header | ||
summary += '|Total number of tests|Test failures|Disabled test|Skipped test|Spent time|Timestamp|\n' | ||
summary += '|-|-|-|-|-|-|\n' | ||
|
||
# Entry | ||
summary += f'|{results_dict["tests"]}' | ||
summary += f'|{results_dict["failures"]}' | ||
summary += f'|{results_dict["disabled"]}' | ||
summary += f'|{results_dict["skipped"]}' | ||
summary += f'|{results_dict["time"]}' | ||
summary += f'|{results_dict["timestamp"]}' | ||
summary += '|\n' | ||
|
||
# Failed tests list | ||
if show_failed is True and len(results_dict['failed_tests']) != 0: | ||
summary += '\n## Failed tests\n' | ||
for failed_test in results_dict['failed_tests']: | ||
summary += f'* {failed_test}\n' | ||
|
||
# Disabled tests list | ||
if show_disabled is True and len(results_dict['disabled_tests']) != 0: | ||
summary += '\n## Disabled tests\n' | ||
for failed_test in results_dict['disabled_tests']: | ||
summary += f'* {failed_test}\n' | ||
|
||
# Skipped tests list | ||
if show_skipped is True and len(results_dict['skipped_tests']) != 0: | ||
summary += '\n## Skipped tests\n' | ||
for failed_test in results_dict['skipped_tests']: | ||
summary += f'* {failed_test}\n' | ||
|
||
return summary | ||
|
||
|
||
if __name__ == '__main__': | ||
# Parse arguments | ||
args = parse_options() | ||
results = junit_report_to_dict(args.junit_report) | ||
|
||
# Create summary | ||
summary = create_md_summary( | ||
results, | ||
args.show_failed, | ||
args.show_disabled, | ||
args.show_skipped | ||
) | ||
|
||
# Print summary if required | ||
if args.print_summary is True: | ||
print(summary) | ||
|
||
# Write output if required | ||
if args.output_file != '': | ||
with open(args.output_file, 'a') as file: | ||
file.write( | ||
create_md_summary( | ||
results, | ||
args.show_failed, | ||
args.show_disabled, | ||
args.show_skipped | ||
) | ||
) | ||
|
||
# Exit code is the number of failed tests | ||
exit(int(results['failures'])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
name: 'junit_summary' | ||
description: 'Generate a summary from a jUnit report. This summary shows in the workflow summary page. Exit code is number of failed tests.' | ||
|
||
inputs: | ||
junit_reports_dir: | ||
description: 'Path to directory containing XML files with the jUnit reports' | ||
required: true | ||
|
||
output_file: | ||
description: 'Path to the file where the summary will be written' | ||
required: true | ||
|
||
print_summary: | ||
description: 'Whether to print the summary (Default: True)' | ||
required: false | ||
default: 'True' | ||
|
||
show_failed: | ||
description: 'Whether to show the list of failed tests (Default: True)' | ||
required: false | ||
default: 'True' | ||
|
||
show_disabled: | ||
description: 'Whether to show the list of disabled tests (Default: False)' | ||
required: false | ||
default: 'False' | ||
|
||
show_skipped: | ||
description: 'Whether to show the list of skipped tests (Default: False)' | ||
required: false | ||
default: 'False' | ||
|
||
runs: | ||
using: composite | ||
steps: | ||
- name: jUnit Summary | ||
id: junit_summary | ||
shell: bash | ||
run: | | ||
OUTPUT_FILE_OPTION="" | ||
if [[ ! -z "${{ inputs.output_file }}" ]] | ||
then | ||
OUTPUT_FILE_OPTION="--output-file ${{ inputs.output_file }}" | ||
fi | ||
PRINT_SUMMARY_OPTION="" | ||
if [[ "${{ inputs.print_summary }}" == "True" ]] | ||
then | ||
PRINT_SUMMARY_OPTION="--print-summary" | ||
fi | ||
SHOW_FAILED_OPTION="" | ||
if [[ "${{ inputs.show_failed }}" == "True" ]] | ||
then | ||
SHOW_FAILED_OPTION="--show-failed" | ||
fi | ||
SHOW_DISABLED_OPTION="" | ||
if [[ "${{ inputs.show_disabled }}" == "True" ]] | ||
then | ||
SHOW_DISABLED_OPTION="--show-disabled" | ||
fi | ||
SHOW_SKIPPED_OPTION="" | ||
if [[ "${{ inputs.show_skipped }}" == "True" ]] | ||
then | ||
SHOW_SKIPPED_OPTION="--show-skipped" | ||
fi | ||
EXIT_CODE=0 | ||
for JUNIT_REPORT in ${{ inputs.junit_reports_dir }}/*.xml | ||
do | ||
python3 ${{ github.action_path }}/../../junit_summary.py \ | ||
--junit-report ${JUNIT_REPORT} \ | ||
${OUTPUT_FILE_OPTION} \ | ||
${PRINT_SUMMARY_OPTION} \ | ||
${SHOW_FAILED_OPTION} \ | ||
${SHOW_DISABLED_OPTION} \ | ||
${SHOW_SKIPPED_OPTION} | ||
EXIT_CODE=$((${EXIT_CODE} + $?)) | ||
done | ||
exit ${EXIT_CODE} |
Oops, something went wrong.