mirror of
https://github.com/espressif/esp-matter.git
synced 2026-04-27 11:03:05 +00:00
85a04cf3bf
Add pytest to CI Fix CI
254 lines
9.0 KiB
Python
254 lines
9.0 KiB
Python
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
|
|
|
# SPDX-License-Identifier: CC0-1.0
|
|
|
|
# This file is used in CI generate binary files for different kinds of apps
|
|
|
|
import argparse
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import List
|
|
|
|
import logging
|
|
|
|
idf_build_apps_logger = logging.getLogger('idf_build_apps')
|
|
from idf_build_apps import App, build_apps, find_apps, setup_logging
|
|
|
|
# from idf_ci_utils import IDF_PATH, get_pytest_app_paths, get_pytest_cases, get_ttfw_app_paths
|
|
|
|
PROJECT_ROOT = Path(__file__).parent.parent.parent.absolute()
|
|
DEF_APP_PATH = PROJECT_ROOT / 'examples'
|
|
APPS_BUILD_PER_JOB = 30
|
|
PYTEST_C6_APPS = [
|
|
{"target": "esp32c6", "name": "light"},
|
|
]
|
|
MANIFEST_FILES = [
|
|
str(PROJECT_ROOT / 'examples' / '.build-rules.yml'),
|
|
]
|
|
|
|
PYTEST_H2_APPS = [
|
|
{"target": "esp32h2", "name": "light"},
|
|
{"target": "esp32s3", "name": "thread_border_router"},
|
|
]
|
|
MANIFEST_FILES = [
|
|
str(PROJECT_ROOT / 'examples' / '.build-rules.yml'),
|
|
]
|
|
|
|
PYTEST_C3_APPS = [
|
|
{"target": "esp32c3", "name": "light"},
|
|
{"target": "esp32c3", "name": "test_optional_attributes"},
|
|
]
|
|
MANIFEST_FILES = [
|
|
str(PROJECT_ROOT / 'examples' / '.build-rules.yml'),
|
|
]
|
|
|
|
PYTEST_C2_APPS = [
|
|
{"target": "esp32c2", "name": "light"},
|
|
]
|
|
MANIFEST_FILES = [
|
|
str(PROJECT_ROOT / 'examples' / '.build-rules.yml'),
|
|
]
|
|
|
|
# Exclude list for no-pytest apps in CI on merge request or branch pipelines.
|
|
# The below examples will be built on main branch pipeline.
|
|
NO_PYTEST_REMAINING_APPS = [
|
|
{"target": "esp32c2", "name": "light_switch"},
|
|
{"target": "esp32c6", "name": "light_switch"},
|
|
{"target": "esp32h2", "name": "light_switch"},
|
|
{"target": "esp32" , "name": "light_switch"},
|
|
{"target": "esp32c2", "name": "generic_switch"},
|
|
{"target": "esp32c6", "name": "generic_switch"},
|
|
{"target": "esp32h2", "name": "generic_switch"},
|
|
{"target": "esp32h2", "name": "multiple_on_off_plugin_units"},
|
|
{"target": "esp32c3", "name": "multiple_on_off_plugin_units"},
|
|
{"target": "esp32" , "name": "multiple_on_off_plugin_units"},
|
|
{"target": "esp32s3", "name": "multiple_on_off_plugin_units"},
|
|
{"target": "esp32" , "name": "room_air_conditioner"},
|
|
{"target": "esp32c3", "name": "room_air_conditioner"},
|
|
{"target": "esp32c2", "name": "room_air_conditioner"},
|
|
{"target": "esp32c6", "name": "room_air_conditioner"},
|
|
{"target": "esp32h2", "name": "room_air_conditioner"},
|
|
{"target": "esp32" , "name": "door_lock"},
|
|
{"target": "esp32c3", "name": "door_lock"},
|
|
{"target": "esp32c2", "name": "door_lock"},
|
|
{"target": "esp32c6", "name": "door_lock"},
|
|
{"target": "esp32h2", "name": "door_lock"},
|
|
{"target": "esp32s3", "name": "ota_provider"},
|
|
{"target": "esp32c3", "name": "sensors"},
|
|
{"target": "esp32" , "name": "refrigerator"},
|
|
{"target": "esp32c3", "name": "refrigerator"},
|
|
{"target": "esp32c2", "name": "refrigerator"},
|
|
{"target": "esp32c6", "name": "refrigerator"},
|
|
{"target": "esp32h2", "name": "refrigerator"},
|
|
{"target": "esp32" , "name": "demo/badge"},
|
|
]
|
|
MANIFEST_FILES = [
|
|
str(PROJECT_ROOT / 'examples' / '.build-rules.yml'),
|
|
]
|
|
|
|
def _is_c6_pytest_app(app: App) -> bool:
|
|
print(app.name, app.target)
|
|
for pytest_app in PYTEST_C6_APPS:
|
|
print(pytest_app["name"], pytest_app["target"])
|
|
if app.name == pytest_app["name"] and app.target == pytest_app["target"]:
|
|
return True
|
|
return False
|
|
|
|
def _is_h2_pytest_app(app: App) -> bool:
|
|
for pytest_app in PYTEST_H2_APPS:
|
|
if app.name == pytest_app["name"] and app.target == pytest_app["target"]:
|
|
return True
|
|
return False
|
|
|
|
def _is_c3_pytest_app(app: App) -> bool:
|
|
for pytest_app in PYTEST_C3_APPS:
|
|
if app.name == pytest_app["name"] and app.target == pytest_app["target"]:
|
|
return True
|
|
return False
|
|
|
|
def _is_c2_pytest_app(app: App) -> bool:
|
|
for pytest_app in PYTEST_C2_APPS:
|
|
if app.name == pytest_app["name"] and app.target == pytest_app["target"]:
|
|
return True
|
|
return False
|
|
|
|
# Function to check for no_pytest excluded list apps.
|
|
def _is_no_pytest_remaining_app(app: App) -> bool:
|
|
for no_pytest_app in NO_PYTEST_REMAINING_APPS:
|
|
if app.name == no_pytest_app["name"] and app.target == no_pytest_app["target"]:
|
|
return True
|
|
return False
|
|
|
|
def get_cmake_apps(
|
|
paths: List[str],
|
|
target: str,
|
|
config_rules_str: List[str],
|
|
) -> List[App]:
|
|
apps = find_apps(
|
|
paths,
|
|
recursive=True,
|
|
target=target,
|
|
build_dir='build_@t_@w',
|
|
config_rules_str=config_rules_str,
|
|
build_log_filename='build_log.txt',
|
|
size_json_filename='size.json',
|
|
check_warnings=False,
|
|
manifest_files=MANIFEST_FILES,
|
|
)
|
|
return apps
|
|
|
|
def main(args: argparse.Namespace) -> None:
|
|
apps = get_cmake_apps(args.paths, args.target, args.config)
|
|
|
|
# no_pytest and only_pytest can not be both True
|
|
assert not (args.no_pytest and args.pytest_c6 and args.pytest_h2 and args.pytest_c3 and args.pytest_c2)
|
|
if args.no_pytest:
|
|
apps_for_build = [app for app in apps if not (_is_c6_pytest_app(app) or _is_h2_pytest_app(app) or _is_no_pytest_remaining_app(app))]
|
|
elif args.pytest_c6:
|
|
apps_for_build = [app for app in apps if _is_c6_pytest_app(app)]
|
|
elif args.pytest_h2:
|
|
apps_for_build = [app for app in apps if _is_h2_pytest_app(app)]
|
|
elif args.pytest_c3:
|
|
apps_for_build = [app for app in apps if _is_c3_pytest_app(app)]
|
|
elif args.pytest_c2:
|
|
apps_for_build = [app for app in apps if _is_c2_pytest_app(app)]
|
|
elif args.no_pytest_remaining:
|
|
apps_for_build = [app for app in apps if _is_no_pytest_remaining_app(app)]
|
|
else:
|
|
apps_for_build = apps[:]
|
|
|
|
idf_build_apps_logger.info('Found %d apps after filtering', len(apps_for_build))
|
|
idf_build_apps_logger.info(
|
|
'Suggest setting the parallel count to %d for this build job',
|
|
len(apps_for_build) // APPS_BUILD_PER_JOB + 1,
|
|
)
|
|
|
|
ret_code = build_apps(
|
|
apps_for_build,
|
|
parallel_count=args.parallel_count,
|
|
parallel_index=args.parallel_index,
|
|
dry_run=False,
|
|
collect_size_info=args.collect_size_info,
|
|
# build_verbose=0,
|
|
keep_going=True,
|
|
ignore_warning_strs=[r".*"],
|
|
copy_sdkconfig=True,
|
|
)
|
|
|
|
sys.exit(ret_code)
|
|
|
|
if __name__ == '__main__':
|
|
parser = argparse.ArgumentParser(
|
|
description='Build all the apps for different test types. Will auto remove those non-test apps binaries',
|
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
)
|
|
parser.add_argument('paths', nargs='*', help='Paths to the apps to build.')
|
|
parser.add_argument(
|
|
'-t',
|
|
'--target',
|
|
default='all',
|
|
help='Build apps for given target. could pass "all" to get apps for all targets',
|
|
)
|
|
parser.add_argument(
|
|
'--config',
|
|
default=['sdkconfig.ci=default', 'sdkconfig.ci.*=', '=default'],
|
|
action='append',
|
|
help='Adds configurations (sdkconfig file names) to build. This can either be '
|
|
'FILENAME[=NAME] or FILEPATTERN. FILENAME is the name of the sdkconfig file, '
|
|
'relative to the project directory, to be used. Optional NAME can be specified, '
|
|
'which can be used as a name of this configuration. FILEPATTERN is the name of '
|
|
'the sdkconfig file, relative to the project directory, with at most one wildcard. '
|
|
'The part captured by the wildcard is used as the name of the configuration.',
|
|
)
|
|
parser.add_argument(
|
|
'--parallel-count', default=1, type=int, help='Number of parallel build jobs.'
|
|
)
|
|
parser.add_argument(
|
|
'--parallel-index',
|
|
default=1,
|
|
type=int,
|
|
help='Index (1-based) of the job, out of the number specified by --parallel-count.',
|
|
)
|
|
parser.add_argument(
|
|
'--no_pytest',
|
|
action="store_true",
|
|
help='Exclude pytest apps defined in PYTEST_H2_APPS and PYTEST_C6_APPS and some optional no-pytest apps',
|
|
)
|
|
parser.add_argument(
|
|
'--no_pytest_remaining',
|
|
action="store_true",
|
|
help='Build the excluded no-pytest apps using manual trigger.',
|
|
)
|
|
parser.add_argument(
|
|
'--pytest_c6',
|
|
action="store_true",
|
|
help='Only build pytest apps, defined in PYTEST_C6_APPS',
|
|
)
|
|
parser.add_argument(
|
|
'--pytest_h2',
|
|
action="store_true",
|
|
help='Only build pytest apps, defined in PYTEST_H2_APPS',
|
|
)
|
|
parser.add_argument(
|
|
'--pytest_c3',
|
|
action="store_true",
|
|
help='Only build pytest apps, defined in PYTEST_C3_APPS',
|
|
)
|
|
parser.add_argument(
|
|
'--pytest_c2',
|
|
action="store_true",
|
|
help='Only build pytest apps, defined in PYTEST_C2_APPS',
|
|
)
|
|
parser.add_argument(
|
|
'--collect-size-info',
|
|
type=argparse.FileType('w'),
|
|
help='If specified, the test case name and size info json will be written to this file',
|
|
)
|
|
|
|
arguments = parser.parse_args()
|
|
if not arguments.paths:
|
|
arguments.paths = [DEF_APP_PATH]
|
|
setup_logging(verbose=1) # Info
|
|
main(arguments)
|
|
|