ci(coverage): enforce 50% patch coverage gate for PRs (#10011)
Arduino Lint / lint (push) Has been cancelled
Build Examples with C++ Compiler / build-examples (push) Has been cancelled
MicroPython CI / Build esp32 port (push) Has been cancelled
MicroPython CI / Build rp2 port (push) Has been cancelled
MicroPython CI / Build stm32 port (push) Has been cancelled
MicroPython CI / Build unix port (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_NORMAL_8BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_SDL - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build ESP IDF ESP32S3 (push) Has been cancelled
C/C++ CI / Run tests with 32bit build (push) Has been cancelled
C/C++ CI / Run tests with 64bit build (push) Has been cancelled
BOM Check / bom-check (push) Has been cancelled
Verify that lv_conf_internal.h matches repository state / verify-conf-internal (push) Has been cancelled
Verify GDB constants are up-to-date / verify-gdb-consts (push) Has been cancelled
Verify the widget property name / verify-property-name (push) Has been cancelled
Verify code formatting / verify-formatting (push) Has been cancelled
Compare file templates with file names / template-check (push) Has been cancelled
Build Docs / build-and-deploy (push) Has been cancelled
Test API JSON generator / Test API JSON (push) Has been cancelled
Install LVGL using CMake / build-examples (push) Has been cancelled
Check Makefile / Build using Makefile (push) Has been cancelled
Check Makefile for UEFI / Build using Makefile for UEFI (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/benchmark_results_comment/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/filter_docker_logs/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/serialize_results/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark 32b - lv_conf_perf32b (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark 64b - lv_conf_perf64b (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Save PR Number (push) Has been cancelled
Hardware Performance Test / Hardware Performance Benchmark (push) Has been cancelled
Hardware Performance Test / HW Benchmark - Save PR Number (push) Has been cancelled
Performance Tests CI / Perf Tests OPTIONS_TEST_PERF_32B - Ubuntu (push) Has been cancelled
Performance Tests CI / Perf Tests OPTIONS_TEST_PERF_64B - Ubuntu (push) Has been cancelled
Port repo release update / run-release-branch-updater (push) Has been cancelled
Verify Font License / verify-font-license (push) Has been cancelled
Verify Kconfig / verify-kconfig (push) Has been cancelled

This commit is contained in:
VIFEX
2026-04-24 17:20:56 +08:00
committed by GitHub
parent 2f4e03ffbd
commit 95a4dea683
4 changed files with 47 additions and 6 deletions
+4 -1
View File
@@ -141,7 +141,10 @@ jobs:
git fetch --no-tags --prune origin ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}
MB=$(git merge-base ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }})
echo "Merge-base: $MB"
python scripts/check_gcov_coverage.py --commit="${MB}...${{ github.event.pull_request.head.sha }}"
python scripts/check_gcov_coverage.py \
--commit="${MB}...${{ github.event.pull_request.head.sha }}" \
--fail-under=50 \
--min-lines=5
else
echo "Not a pull request, skipping code coverage analysis."
fi
+18
View File
@@ -0,0 +1,18 @@
# gcovr configuration
#
# Auto-discovered when --root points to this directory.
# Shared by tests/main.py and scripts/check_gcov_coverage.py.
# Only include LVGL source files
filter = src/(?:.*/)?lv_.*\.c
# Exclude hardware/GPU-dependent code that cannot be tested in CI.
# These modules require physical hardware or OS features unavailable
# in the CI environment and always show 0% coverage.
exclude = src/draw/nanovg/
exclude = src/draw/opengles/
exclude = src/drivers/opengles/
exclude = src/drivers/wayland/
exclude = src/drivers/display/drm/
exclude = src/drivers/display/fb/
exclude = src/drivers/libinput/
+24 -4
View File
@@ -41,6 +41,18 @@ def create_argument_parser() -> argparse.ArgumentParser:
help="Fail if coverage is below this percentage (0-100), default: 0 (no failure)",
)
parser.add_argument(
"--min-lines",
type=int,
metavar="N",
default=0,
help=(
"Skip --fail-under enforcement when new coverable lines < N. "
"Small patches produce noisy percentages; this avoids false positives. "
"Default: 0 (always enforce)"
),
)
return parser
@@ -92,7 +104,6 @@ def get_coverage_data(root: str) -> Dict[str, Dict[int, int]]:
non-coverable and will be ignored by the uncovered check.
Raises: subprocess.CalledProcessError if gcovr fails
"""
filter_pattern = os.path.join(root, r"src/(?:.*/)?lv_.*\.c")
cmd = [
"gcovr",
"--gcov-ignore-parse-errors",
@@ -100,8 +111,6 @@ def get_coverage_data(root: str) -> Dict[str, Dict[int, int]]:
"-",
"--root",
root,
"--filter",
filter_pattern,
]
result = subprocess.run(
@@ -296,6 +305,7 @@ def report_coverage(
*,
total_label: str,
skipped_noncoverable: Optional[int] = None,
min_lines: int = 0,
) -> int:
"""
Print a standardized coverage report and return exit code (0/1).
@@ -305,6 +315,7 @@ def report_coverage(
"New coverable lines (per gcovr)" for commit mode, or
"Coverable lines (per gcovr)" for path mode)
- skipped_noncoverable: when provided, prints the skipped non-coverable count
- min_lines: when > 0, skip --fail-under enforcement if total < min_lines
"""
title = f" Coverage analysis results for {header} "
@@ -320,7 +331,14 @@ def report_coverage(
if total > 0:
coverage_percent = (covered / total) * 100
print(f"Coverage: {coverage_percent:.2f}%")
if coverage_percent < fail_under:
# Check if this patch is too small to enforce the threshold
if min_lines > 0 and fail_under > 0 and total < min_lines:
print(
f"\n Only {total} new coverable line(s) (< {min_lines}), "
f"skipping --fail-under enforcement."
)
elif coverage_percent < fail_under:
print(
f"\n✗ Coverage {coverage_percent:.2f}% is below required {fail_under}%"
)
@@ -354,6 +372,7 @@ def main() -> int:
if args.path:
# Path mode: ignore commit, compute coverage for file/dir
# --min-lines is not applied here since it targets patch (commit) mode.
covered, total, uncovered = check_path_coverage(args.path, root)
return report_coverage(
@@ -378,6 +397,7 @@ def main() -> int:
fail_under=args.fail_under,
total_label="New coverable lines (per gcovr)",
skipped_noncoverable=skipped_noncoverable,
min_lines=args.min_lines,
)
except subprocess.CalledProcessError as e:
+1 -1
View File
@@ -182,7 +182,7 @@ def generate_code_coverage_report():
'--root', root_dir, '--html-details', '--output',
html_report_file, '--xml', 'report/coverage.xml',
'-j', str(os.cpu_count()), '--print-summary', '--merge-mode-functions=merge-use-line-min',
'--html-title', 'LVGL Test Coverage', '--filter', os.path.join(root_dir, 'src/.*/lv_.*\\.c')]
'--html-title', 'LVGL Test Coverage']
subprocess.check_call(cmd)
print("Done: See %s" % html_report_file, flush=True)