Skip to content

Commit

Permalink
Refs #20441: Add action to print a simple summary from jUnit reports
Browse files Browse the repository at this point in the history
Signed-off-by: EduPonz <eduardoponz@eprosima.com>
  • Loading branch information
EduPonz committed Feb 13, 2024
1 parent b0bb8d6 commit bac2f80
Show file tree
Hide file tree
Showing 4 changed files with 399 additions and 0 deletions.
57 changes: 57 additions & 0 deletions multiplatform/junit_summary/action.yaml
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 }}
180 changes: 180 additions & 0 deletions resources/junit_summary.py
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']))
84 changes: 84 additions & 0 deletions ubuntu/junit_summary/action.yaml
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}
Loading

0 comments on commit bac2f80

Please sign in to comment.