Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci: add component test apps #381

Merged
merged 22 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
1063029
ci(pre-commit): add repository consistency checks
igrr Sep 18, 2024
102bda2
change(bdc_motor): add test_app (build test only)
igrr Sep 18, 2024
26ebc98
change(ccomp_timer): move unit tests to component test app
igrr Sep 19, 2024
a6b6865
ci(coremark): add example test
igrr Sep 19, 2024
46884c8
change(esp_encrypted_img): move unit tests to component test app
igrr Sep 19, 2024
d60d376
change(essl): add test_app (build test only)
igrr Sep 19, 2024
785b11d
change(expat): move unit tests to component test app
igrr Sep 19, 2024
0496ed0
change(jsmn): add test_app (build test only)
igrr Sep 19, 2024
d999ee9
change(json_generator): add test_app (build test only)
igrr Sep 19, 2024
738e843
change(json_parser): move unit tests to component test app
igrr Sep 19, 2024
556ecce
change(libpng): add test_app
igrr Sep 19, 2024
c4d27a3
change(libsodium): move tests to component test app, check exp output
igrr Sep 19, 2024
9185b89
change(onewire_bus): add test_app (build test only)
igrr Sep 19, 2024
f50ed94
change(pcap): add test_app (build test only)
igrr Sep 19, 2024
79ba1fb
change(pid_ctrl): add test_app (build test only)
igrr Sep 19, 2024
236768d
change(qrcode): add test_app (build test only)
igrr Sep 19, 2024
e371b32
change(quirc): move unit tests to component test app
igrr Sep 19, 2024
2f8d411
change(zlib): add test_app (build test only)
igrr Sep 19, 2024
74bd709
change(spi_nand_flash): use unity_test_utils_memory.h in test app
igrr Sep 27, 2024
41e68cc
change(global): add set(COMPONENTS main) in more apps
igrr Sep 23, 2024
a155997
ci(cbor): fix regex in cbor example test
igrr Sep 23, 2024
2e27d50
ci: use single workflow for examples and test apps
igrr Sep 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions .github/ISSUE_TEMPLATE/bug-report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ body:
- bdc_motor
- catch2
- cbor
- ccomp_timer
- coap
- coremark
- dhara
- eigen
- esp_delta_ota
- esp_encrypted_img
- esp_lcd_qemu_rgb
- esp_jpeg
- esp_lcd_qemu_rgb
- esp_serial_slave_link
- expat
- fmt
Expand All @@ -38,15 +41,20 @@ body:
- json_generator
- json_parser
- led_strip
- libpng
- libsodium
- network_provisioning
- nghttp
- onewire_bus
- pcap
- pid_ctrl
- qrcode
- quirc
- sh2lib
- test_app
- spi_nand_flash
- supertinycron
- thorvg
- zlib
- Other
validations:
required: true
Expand Down
4 changes: 2 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE/new_component.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
- [ ] Component contains README.md
- [ ] Component contains idf_component.yml file with `url` field defined
- [ ] Component was added to [upload job](https://github.com/espressif/idf-extra-components/blob/master/.github/workflows/upload_component.yml#L18)
- [ ] Component was added to [build job](https://github.com/espressif/idf-extra-components/blob/master/test_app/CMakeLists.txt#L8)
- [ ] _Optional:_ Component contains unit tests
- [ ] Component has an example project
- [ ] _Optional:_ Component has a test_app
- [ ] CI passing

# Change description
Expand Down
123 changes: 123 additions & 0 deletions .github/consistency_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/usr/bin/env python
# This script performs various consistency checks on the repository.
import argparse
import logging
import glob
import os
from pathlib import Path

import yaml


LOG = logging.getLogger("consistency_check")
failures = 0


def main():
parser = argparse.ArgumentParser()
parser.add_argument("--root", default=".", help="Root directory of the repository")
args = parser.parse_args()

logging.basicConfig(level=logging.INFO)

check_build_manifests_added_to_config(args)
check_components_added_to_upload_job(args)
check_components_added_to_issue_template(args)

if failures:
LOG.error(f"Found {failures} issues")
raise SystemExit(1)


#### Checks ####

def check_build_manifests_added_to_config(args):
LOG.info("Checking that all .build-test-rules.yml files are added to .idf_build_apps.toml")

build_manifests_from_repo = set(glob.glob(f"{args.root}/**/.build-test-rules.yml", recursive=True))
# exclude the ones under 'managed_components'
build_manifests_from_repo = set([Path(f) for f in build_manifests_from_repo if "managed_components" not in f])

idf_build_apps_toml = load_toml(os.path.join(args.root, ".idf_build_apps.toml"))
build_manifests_from_config = set([Path(f) for f in idf_build_apps_toml.get("manifest_file", [])])

missing = build_manifests_from_repo - build_manifests_from_config
if missing:
LOG.error(f"Missing build manifests in .idf_build_apps.toml: {missing}")
add_failure()


def check_components_added_to_upload_job(args):
LOG.info("Checking that all components are added to the upload job")

components_from_repo = set([Path(f).name for f in get_component_dirs(args)])

upload_job = load_yaml(os.path.join(args.root, ".github/workflows/upload_component.yml"))
upload_job_steps = upload_job.get("jobs", {}).get("upload_components", {}).get("steps", [])
upload_job_step = next((step for step in upload_job_steps if step.get("name") == "Upload components to component service"), None)
components_from_upload_job = set([name.strip() for name in upload_job_step.get("with", {}).get("directories", "").split(";")])

missing = components_from_repo - components_from_upload_job
if missing:
LOG.error(f"Missing components in upload job: {missing}")
add_failure()


def check_components_added_to_issue_template(args):
LOG.info("Checking that all components are added to the issue template")

issue_template = load_yaml(os.path.join(args.root, ".github/ISSUE_TEMPLATE/bug-report.yml"))
issue_template_component = next((element for element in issue_template.get("body", []) if element.get("id") == "component"), None)
components_from_issue_template = set(issue_template_component.get("attributes", {}).get("options", []))

components_from_repo = set([Path(component).name for component in get_component_dirs(args)])
missing = components_from_repo - components_from_issue_template
if missing:
LOG.error(f"Missing components in issue template: {missing}")
add_failure()
extra = components_from_issue_template - components_from_repo - set(["Other"])
if extra:
LOG.error(f"Extra components in issue template: {extra}")
add_failure()


#### Utility functions ####

def load_toml(filepath) -> dict:
try:
import tomllib # type: ignore # python 3.11

try:
with open(str(filepath), 'rb') as fr:
return tomllib.load(fr)
except Exception as e:
raise ValueError(f"Failed to load {filepath}: {e}")
except ImportError:
import toml

try:
return toml.load(str(filepath))
except Exception as e:
raise ValueError(f"Failed to load {filepath}: {e}")


def load_yaml(filepath) -> dict:
with open(filepath, "r") as f:
return yaml.safe_load(f)


def get_component_dirs(args):
"""
Returns a list of component paths in this repository.
"""
components_from_repo = set(glob.glob(f"{args.root}/*/idf_component.yml"))
components_from_repo = [Path(f).parent.name for f in components_from_repo]
return components_from_repo

def add_failure():
global failures
failures += 1


if __name__ == "__main__":
main()
49 changes: 49 additions & 0 deletions .github/get_idf_build_apps_args.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env python3

import argparse
import os

def main():
parser = argparse.ArgumentParser()
parser.add_argument('-v', '--verbose', action='store_true', help='Enable verbose output')
parser.add_argument('modified_files_list', type=argparse.FileType('r'), help='Input file containing list of modified files')
parser.add_argument('idf_build_apps_args', type=argparse.FileType('w'), help='Output file containing idf-build-apps arguments')
args = parser.parse_args()

modified_files = args.modified_files_list.read().splitlines()
idf_build_apps_args = []
idf_build_apps_args += [
'--modified-files',
';'.join(modified_files)
]

if args.verbose:
print('Modified files:')
for file in sorted(modified_files):
print(f' - {file}')

modified_components = set()
excluded_dirs = ['.github', 'test_app']
for file in modified_files:
toplevel = file.split('/')[0]
if toplevel in excluded_dirs:
continue
if not os.path.isdir(toplevel):
continue
modified_components.add(toplevel)

idf_build_apps_args += [
'--modified-components',
';'.join(modified_components)
]

args.idf_build_apps_args.write(' '.join(idf_build_apps_args))

if args.verbose:
print('Modified components:')
for component in sorted(modified_components):
print(f' - {component}')


if __name__ == '__main__':
main()
48 changes: 48 additions & 0 deletions .github/get_pytest_args.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env python3

import argparse
import json
import glob


def main():
parser = argparse.ArgumentParser()
parser.add_argument('-v', '--verbose', action='store_true', help='Enable verbose output')
parser.add_argument('--target', type=str, required=True, help='Target to run tests for')
parser.add_argument('build_info_json', type=str, help='Input file(s) containing build info generated by idf-build-apps. Accepts globs.')
parser.add_argument('pytest_args', type=argparse.FileType('w'), help='Output file containing pytest arguments')

args = parser.parse_args()
pytest_args = []
app_json_files = glob.glob(args.build_info_json)
if args.verbose:
print(f'Found {len(app_json_files)} app_json files')
for app_json_file in app_json_files:
print(f' - {app_json_file}')
for app_json_file in app_json_files:
with open(app_json_file, 'r') as build_info_json:
if args.verbose:
print(f'Processing {app_json_file}')
for app_json_line in build_info_json.readlines():
app_json = json.loads(app_json_line)
skip = False
if app_json['target'] != args.target:
continue
if app_json['build_status'] == 'skipped':
if args.verbose:
print(f'Skipping {app_json["app_dir"]})')
pytest_args += [
'--ignore',
app_json['app_dir']
]
else:
if args.verbose:
print(f'Not skipping {app_json["app_dir"]})')


args.pytest_args.write(' '.join(pytest_args))


if __name__ == '__main__':
main()

Loading
Loading