scripts: ci: check_compliance: Update KconfigCheck subclassing

So far, the behavior of different Kconfig checks has been parametrized
using the `run()` method, and every new check has introduced with it a
new argument to that method.

It's possible to replace each `run()` argument by way of overriding
different class methods and making better use of inheritance:

    free=False          Stub check_no_undef_outside_kconfig()
    no_modules=True     Stub get_modules()
    filename            Introduce class member FILENAME
    hwm                 (unused)

This should establish a more scalable and straightforward pattern for
adding future Kconfig checks. It also favors composability, which will
come in handy when implementing checks for sysbuild Kconfig.

Additionally, avoid duplicating `doc` and `path_hint` in every subclass.

Signed-off-by: Grzegorz Swiderski <grzegorz.swiderski@nordicsemi.no>
This commit is contained in:
Grzegorz Swiderski 2025-01-13 08:31:40 +01:00 committed by Benjamin Cabé
parent 17ba479585
commit 50d9ed5ce1

View file

@ -371,10 +371,11 @@ class KconfigCheck(ComplianceTest):
doc = "See https://docs.zephyrproject.org/latest/build/kconfig/tips.html for more details." doc = "See https://docs.zephyrproject.org/latest/build/kconfig/tips.html for more details."
path_hint = "<zephyr-base>" path_hint = "<zephyr-base>"
def run(self, full=True, no_modules=False, filename="Kconfig", hwm=None): # Top-level Kconfig file. The path can be relative to srctree (ZEPHYR_BASE).
self.no_modules = no_modules FILENAME = "Kconfig"
kconf = self.parse_kconfig(filename=filename, hwm=hwm) def run(self):
kconf = self.parse_kconfig()
self.check_top_menu_not_too_long(kconf) self.check_top_menu_not_too_long(kconf)
self.check_no_pointless_menuconfigs(kconf) self.check_no_pointless_menuconfigs(kconf)
@ -382,8 +383,7 @@ class KconfigCheck(ComplianceTest):
self.check_no_redefined_in_defconfig(kconf) self.check_no_redefined_in_defconfig(kconf)
self.check_no_enable_in_boolean_prompt(kconf) self.check_no_enable_in_boolean_prompt(kconf)
self.check_soc_name_sync(kconf) self.check_soc_name_sync(kconf)
if full: self.check_no_undef_outside_kconfig(kconf)
self.check_no_undef_outside_kconfig(kconf)
def get_modules(self, modules_file, settings_file): def get_modules(self, modules_file, settings_file):
""" """
@ -393,11 +393,6 @@ class KconfigCheck(ComplianceTest):
This is needed to complete Kconfig sanity tests. This is needed to complete Kconfig sanity tests.
""" """
if self.no_modules:
with open(modules_file, 'w') as fp_module_file:
fp_module_file.write("# Empty\n")
return
# Invoke the script directly using the Python executable since this is # Invoke the script directly using the Python executable since this is
# not a module nor a pip-installed Python utility # not a module nor a pip-installed Python utility
zephyr_module_path = os.path.join(ZEPHYR_BASE, "scripts", zephyr_module_path = os.path.join(ZEPHYR_BASE, "scripts",
@ -578,7 +573,7 @@ class KconfigCheck(ComplianceTest):
for arch in v2_archs['archs']: for arch in v2_archs['archs']:
fp.write('source "' + (Path(arch['path']) / 'Kconfig').as_posix() + '"\n') fp.write('source "' + (Path(arch['path']) / 'Kconfig').as_posix() + '"\n')
def parse_kconfig(self, filename="Kconfig", hwm=None): def parse_kconfig(self):
""" """
Returns a kconfiglib.Kconfig object for the Kconfig files. We reuse Returns a kconfiglib.Kconfig object for the Kconfig files. We reuse
this object for all tests to avoid having to reparse for each test. this object for all tests to avoid having to reparse for each test.
@ -638,7 +633,7 @@ class KconfigCheck(ComplianceTest):
# them: so some warnings might get printed # them: so some warnings might get printed
# twice. "warn_to_stderr=False" could unfortunately cause # twice. "warn_to_stderr=False" could unfortunately cause
# some (other) warnings to never be printed. # some (other) warnings to never be printed.
return kconfiglib.Kconfig(filename=filename) return kconfiglib.Kconfig(filename=self.FILENAME)
except kconfiglib.KconfigError as e: except kconfiglib.KconfigError as e:
self.failure(str(e)) self.failure(str(e))
raise EndTest raise EndTest
@ -1053,26 +1048,25 @@ class KconfigBasicCheck(KconfigCheck):
references inside the Kconfig tree. references inside the Kconfig tree.
""" """
name = "KconfigBasic" name = "KconfigBasic"
doc = "See https://docs.zephyrproject.org/latest/build/kconfig/tips.html for more details."
path_hint = "<zephyr-base>"
def run(self): def check_no_undef_outside_kconfig(self, kconf):
super().run(full=False) pass
class KconfigBasicNoModulesCheck(KconfigCheck):
class KconfigBasicNoModulesCheck(KconfigBasicCheck):
""" """
Checks if we are introducing any new warnings/errors with Kconfig when no Checks if we are introducing any new warnings/errors with Kconfig when no
modules are available. Catches symbols used in the main repository but modules are available. Catches symbols used in the main repository but
defined only in a module. defined only in a module.
""" """
name = "KconfigBasicNoModules" name = "KconfigBasicNoModules"
doc = "See https://docs.zephyrproject.org/latest/build/kconfig/tips.html for more details."
path_hint = "<zephyr-base>" def get_modules(self, modules_file, settings_file):
def run(self): with open(modules_file, 'w') as fp_module_file:
super().run(full=False, no_modules=True) fp_module_file.write("# Empty\n")
class KconfigHWMv2Check(KconfigCheck, ComplianceTest): class KconfigHWMv2Check(KconfigBasicCheck):
""" """
This runs the Kconfig test for board and SoC v2 scheme. This runs the Kconfig test for board and SoC v2 scheme.
This check ensures that all symbols inside the v2 scheme is also defined This check ensures that all symbols inside the v2 scheme is also defined
@ -1080,13 +1074,10 @@ class KconfigHWMv2Check(KconfigCheck, ComplianceTest):
This ensures the board and SoC trees are fully self-contained and reusable. This ensures the board and SoC trees are fully self-contained and reusable.
""" """
name = "KconfigHWMv2" name = "KconfigHWMv2"
doc = "See https://docs.zephyrproject.org/latest/guides/kconfig/index.html for more details."
def run(self): # Use dedicated Kconfig board / soc v2 scheme file.
# Use dedicated Kconfig board / soc v2 scheme file. # This file sources only v2 scheme tree.
# This file sources only v2 scheme tree. FILENAME = os.path.join(os.path.dirname(__file__), "Kconfig.board.v2")
kconfig_file = os.path.join(os.path.dirname(__file__), "Kconfig.board.v2")
super().run(full=False, hwm="v2", filename=kconfig_file)
class Nits(ComplianceTest): class Nits(ComplianceTest):