ci(file_templ_check): move template check next to the other static checks (#10582)

This commit is contained in:
André Costa
2026-09-02 13:40:15 +02:00
committed by GitHub
parent 10a43c215b
commit 6e7b977887
4 changed files with 58 additions and 74 deletions
-28
View File
@@ -1,28 +0,0 @@
name: Compare file templates with file names
on:
push:
pull_request:
# https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#concurrency
# Ensure that only one commit will be running tests at a time on each PR
concurrency:
group: ${{ github.ref }}-${{ github.workflow }}
cancel-in-progress: true
jobs:
template-check:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
fetch-depth: 0
- name: Setup Python
uses: actions/setup-python@v7
with:
python-version: 3.12
- name: Compare file templates with file names
run: python scripts/lv_templ_check.py --fix
- name: Check that repository is clean
run: git diff --exit-code >/dev/null 2>&1 || (echo "Please fix template issues using scripts/lv_templ_check.py"; false)
+12 -1
View File
@@ -125,6 +125,15 @@ jobs:
continue-on-error: true
run: python scripts/static_checks/check_comments.py src/core
# ------------------------------------------------------------------
# The file name dependent parts of every lv_*.c/lv_*.h file
# (@file comment, include guards) must match the file name
# ------------------------------------------------------------------
- name: "Check: file templates match file names"
id: file-template
continue-on-error: true
run: python scripts/static_checks/check_file_template.py
# ------------------------------------------------------------------
# Final gate – fail the job if any step above failed.
# This gives us full output from every check before failing.
@@ -141,7 +150,8 @@ jobs:
steps.defconfigs.outcome == 'failure' ||
steps.labeler-globs.outcome == 'failure' ||
steps.labeler-labels.outcome == 'failure' ||
steps.comments.outcome == 'failure'
steps.comments.outcome == 'failure' ||
steps.file-template.outcome == 'failure'
run: |
echo "Policy check results:"
@@ -167,6 +177,7 @@ jobs:
print_result "labeler-globs" "${{ steps.labeler-globs.outcome }}"
print_result "labeler-labels" "${{ steps.labeler-labels.outcome }}"
print_result "comments" "${{ steps.comments.outcome }}"
print_result "file-template" "${{ steps.file-template.outcome }}"
echo "---------------------"
echo "One or more policy checks failed. See above for details."
+1 -1
View File
@@ -36,7 +36,7 @@ repos:
# that depend on the file name are correct.
- id: template-check
name: Comparing file templates with file names
entry: python scripts/lv_templ_check.py --fix --quiet
entry: python scripts/static_checks/check_file_template.py --fix --quiet
stages: [ commit ]
language: system
pass_filenames: false
@@ -1,19 +1,29 @@
import re
#!/usr/bin/env python3
"""
Check that the file-name dependent parts of the lv_templ.c/lv_templ.h
templates match the actual file name.
Usage:
check_file_template.py [--fix] [-q] [-v]
"""
import argparse
import os
import re
import traceback
from pathlib import Path
SCRIPT_PATH = Path(__file__).resolve()
LVGL_ROOT_DIR = SCRIPT_PATH.parents[2]
ignored_file_prefixes = {
"lv_conf_template.h",
"lv_conf_cmsis.h",
"lv_test_perf_conf.h",
"lv_font_"
"lv_font_",
}
ignored_top_dirs = {
".git",
"docs"
}
ignored_top_dirs = {".git", "docs"}
h_filename_pattern = re.compile(r"lv_[\w.]*\.h")
h_pattern = re.compile(
@@ -21,15 +31,11 @@ h_pattern = re.compile(
r"@file +(\S*).+?"
r"\*/\s+?#ifndef +(\w+_H)\s+#define +(\w+_H).+"
r"#endif */\* *([^*]+?) *\*/\s*",
flags=re.DOTALL
flags=re.DOTALL,
)
c_filename_pattern = re.compile(r"lv_[\w.]*\.c")
c_pattern = re.compile(
r"\s*/\*\*.+?"
r"@file +(\S*)",
flags=re.DOTALL
)
c_pattern = re.compile(r"\s*/\*\*.+?" r"@file +(\S*)", flags=re.DOTALL)
file_comment_help_f = """\
'{0}' should have at the top:
@@ -59,6 +65,7 @@ instead, has:
# regex, arg parsing and other stuff skipped here.
def ignore_file(basename):
result = False
@@ -71,38 +78,32 @@ def ignore_file(basename):
def ignore_dir(path):
result = False
rel = os.path.relpath(path, LVGL_ROOT_DIR)
return rel.split(os.sep)[0] in ignored_top_dirs
for top_dir in ignored_top_dirs:
sub_path = os.path.join('lvgl', top_dir)
if sub_path in path:
result = True
break
return result
def debug(*args_, **kwargs):
if args.verbose:
print(*args_, **kwargs)
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument("--fix", action="store_true", help="fix incorrect files")
arg_parser.add_argument("-q", "--quiet", action="store_true", help="don't print mismatch info")
arg_parser.add_argument(
"-q", "--quiet", action="store_true", help="don't print mismatch info"
)
arg_parser.add_argument("-v", "--verbose", action="store_true", help="print debug info")
args = arg_parser.parse_args()
cfg_project_dir = '..'
base_dir = os.path.abspath(os.path.dirname(__file__))
project_dir = os.path.abspath(os.path.join(base_dir, cfg_project_dir))
debug(f'ignore dirs [{ignored_top_dirs}]')
debug(f"ignore dirs [{ignored_top_dirs}]")
ok = True
for root, dirs, basenames in os.walk(project_dir):
for root, dirs, basenames in os.walk(LVGL_ROOT_DIR):
if ignore_dir(root):
continue
debug(f'root [{root}]')
debug(f"root [{root}]")
for basename in basenames:
if ignore_file(basename):
continue
@@ -116,74 +117,74 @@ for root, dirs, basenames in os.walk(project_dir):
# -------------------------------------------------------------
if h_filename_pattern.fullmatch(basename):
a_file_was_processed = True
debug(f'Opening H file [{path}]')
debug(f"Opening H file [{path}]")
try:
with open(path, 'rb') as f:
cont = f.read().decode('utf-8')
with open(path, "rb") as f:
cont = f.read().decode("utf-8")
except:
print(f'Error attempting UTF-8 decode on [{path}].')
print(f"Error attempting UTF-8 decode on [{path}].")
traceback.print_exc()
continue
m = h_pattern.fullmatch(cont)
if m is not None:
debug(' Match.')
debug(" Match.")
if m[1] != basename:
file_ok = False
if not args.quiet:
print(file_comment_help_f.format(path, basename, m[1]))
guard_name = f"LV_{basename[3:-2].upper()}_H"
if any(m[i] != guard_name for i in range(2, 4+1)):
if any(m[i] != guard_name for i in range(2, 4 + 1)):
file_ok = False
if not args.quiet:
print(guard_help_f.format(path, guard_name, m[2], m[3], m[4]))
replacements = (basename, guard_name, guard_name, guard_name)
else:
debug(f' No match with regex [{h_pattern.pattern}].')
debug(f" No match with regex [{h_pattern.pattern}].")
# -------------------------------------------------------------
# C File?
# -------------------------------------------------------------
elif c_filename_pattern.fullmatch(basename):
a_file_was_processed = True
debug(f'Opening C file [{path}]')
debug(f"Opening C file [{path}]")
try:
with open(path, 'rb') as f:
cont = f.read().decode('utf-8')
with open(path, "rb") as f:
cont = f.read().decode("utf-8")
except:
print(f'Error attempting UTF-8 decode on [{path}].')
print(f"Error attempting UTF-8 decode on [{path}].")
traceback.print_exc()
continue
m = c_pattern.match(cont)
if m is not None:
debug(' Match.')
debug(" Match.")
if m[1] != basename:
file_ok = False
if not args.quiet:
print(file_comment_help_f.format(path, basename, m[1]))
replacements = (basename, )
replacements = (basename,)
else:
debug(f' No match with regex [{c_pattern.pattern}].')
debug(f" No match with regex [{c_pattern.pattern}].")
if a_file_was_processed:
if not file_ok:
debug(f'NOT OK [{path}]')
debug(f"NOT OK [{path}]")
ok = False
if args.fix:
for i in reversed(range(0, len(replacements))):
span = m.regs[i + 1]
repl = replacements[i]
cont = cont[:span[0]] + repl + cont[span[1]:]
cont = cont[: span[0]] + repl + cont[span[1] :]
with open(path, "w") as f:
f.write(cont)
else:
debug(f'OK [{path}]')
debug(f"OK [{path}]")
if not ok: