esp-idf/tools/ci/dynamic_pipelines/scripts/generate_report.py
Aleksei Apaseev 63bd3a18ad ci: add failed jobs report generator. Improve Target Test Report
Introduced changes:
- refactor the cli script used for report generation
- introduce failed jobs report generator
- cover job report generation with tests
- add job failure rate
- add test cases failure rate
- add current branch / other branches statistic for failed jobs / testcases
2024-06-20 14:40:54 +08:00

102 lines
4.0 KiB
Python

# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import argparse
import glob
import os
import typing as t
import __init__ # noqa: F401 # inject the system path
from dynamic_pipelines.report import BuildReportGenerator
from dynamic_pipelines.report import JobReportGenerator
from dynamic_pipelines.report import TargetTestReportGenerator
from dynamic_pipelines.utils import fetch_failed_jobs
from dynamic_pipelines.utils import parse_testcases_from_filepattern
from idf_ci.app import import_apps_from_txt
def main() -> None:
parser: argparse.ArgumentParser = setup_argument_parser()
args: argparse.Namespace = parser.parse_args()
report_actions: t.Dict[str, t.Callable[[argparse.Namespace], None]] = {
'build': generate_build_report,
'target_test': generate_target_test_report,
'job': generate_jobs_report,
}
report_action = report_actions.get(args.report_type)
if report_action is None:
raise ValueError('Unknown report type is requested to be generated.')
report_action(args)
def setup_argument_parser() -> argparse.ArgumentParser:
report_type_parser: argparse.ArgumentParser = argparse.ArgumentParser(add_help=False)
report_type_parser.add_argument(
'--report-type', choices=['build', 'target_test', 'job'], required=True, help='Type of report to generate'
)
report_type_args: argparse.Namespace
remaining_args: t.List[str]
report_type_args, remaining_args = report_type_parser.parse_known_args()
parser: argparse.ArgumentParser = argparse.ArgumentParser(
description='Update reports in MR pipelines based on the selected report type',
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
parents=[report_type_parser],
)
common_arguments(parser)
conditional_arguments(report_type_args, parser)
return parser
def common_arguments(parser: argparse.ArgumentParser) -> None:
parser.add_argument('--project-id', type=int, default=os.getenv('CI_PROJECT_ID'), help='Project ID')
parser.add_argument('--mr-iid', type=int, default=os.getenv('CI_MERGE_REQUEST_IID'), help='Merge Request IID')
parser.add_argument('--pipeline-id', type=int, default=os.getenv('PARENT_PIPELINE_ID'), help='Pipeline ID')
parser.add_argument('--job-id', type=int, default=os.getenv('CI_JOB_ID'), help='Job ID')
parser.add_argument('--commit-id', default=os.getenv('CI_COMMIT_SHA'), help='MR commit ID')
def conditional_arguments(report_type_args: argparse.Namespace, parser: argparse.ArgumentParser) -> None:
if report_type_args.report_type == 'build':
parser.add_argument('--app-list-filepattern', default='list_job_*.txt', help='Pattern to match app list files')
elif report_type_args.report_type == 'target_test':
parser.add_argument(
'--junit-report-filepattern', default='XUNIT_RESULT*.xml', help='Pattern to match JUnit report files'
)
def generate_build_report(args: argparse.Namespace) -> None:
apps: t.List[t.Any] = [
app for file_name in glob.glob(args.app_list_filepattern) for app in import_apps_from_txt(file_name)
]
report_generator = BuildReportGenerator(
args.project_id, args.mr_iid, args.pipeline_id, apps=apps
)
report_generator.post_report(args.job_id, args.commit_id)
def generate_target_test_report(args: argparse.Namespace) -> None:
test_cases: t.List[t.Any] = parse_testcases_from_filepattern(args.junit_report_filepattern)
report_generator = TargetTestReportGenerator(
args.project_id, args.mr_iid, args.pipeline_id, test_cases=test_cases
)
report_generator.post_report(args.job_id, args.commit_id)
def generate_jobs_report(args: argparse.Namespace) -> None:
jobs: t.List[t.Any] = fetch_failed_jobs(args.commit_id)
if not jobs:
return
report_generator = JobReportGenerator(args.project_id, args.mr_iid, args.pipeline_id, jobs=jobs)
report_generator.post_report(args.job_id, args.commit_id)
if __name__ == '__main__':
main()