Skip to content

Commit b032304

Browse files
cfriedtkartben
authored andcommitted
scripts: ci: check_compliance: use git-top to check modules
BoardYml, DeviceTreeBindings, Kconfig, and KconfigBasic checks can be run with a decentralized west manifest. Signed-off-by: Chris Friedt <[email protected]>
1 parent 07a023d commit b032304

File tree

1 file changed

+65
-68
lines changed

1 file changed

+65
-68
lines changed

scripts/ci/check_compliance.py

Lines changed: 65 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,42 @@ def get_files(filter=None, paths=None):
8080
files.remove(file)
8181
return files
8282

83+
def get_module_setting_root(root, settings_file):
84+
"""
85+
Parse the Zephyr module generated settings file given by 'settings_file'
86+
and return all root settings defined by 'root'.
87+
"""
88+
# Invoke the script directly using the Python executable since this is
89+
# not a module nor a pip-installed Python utility
90+
root_paths = []
91+
92+
if os.path.exists(settings_file):
93+
with open(settings_file, 'r') as fp_setting_file:
94+
content = fp_setting_file.read()
95+
96+
lines = content.strip().split('\n')
97+
for line in lines:
98+
root = root.upper()
99+
if line.startswith(f'"{root}_ROOT":'):
100+
_, root_path = line.split(":", 1)
101+
root_paths.append(Path(root_path.strip('"')))
102+
return root_paths
103+
104+
def get_vendor_prefixes(path, errfn = print) -> set[str]:
105+
vendor_prefixes = set()
106+
with open(path) as fp:
107+
for line in fp.readlines():
108+
line = line.strip()
109+
if not line or line.startswith("#"):
110+
continue
111+
try:
112+
vendor, _ = line.split("\t", 2)
113+
vendor_prefixes.add(vendor)
114+
except ValueError:
115+
errfn(f"Invalid line in {path}:\"{line}\".")
116+
errfn("Did you forget the tab character?")
117+
return vendor_prefixes
118+
83119
class FmtdFailure(Failure):
84120
def __init__(
85121
self, severity, title, file, line=None, col=None, desc="", end_line=None, end_col=None
@@ -120,19 +156,21 @@ class ComplianceTest:
120156
Link to documentation related to what's being tested
121157
122158
path_hint:
123-
The path the test runs itself in. This is just informative and used in
124-
the message that gets printed when running the test.
125-
126-
There are two magic strings that can be used instead of a path:
127-
- The magic string "<zephyr-base>" can be used to refer to the
128-
environment variable ZEPHYR_BASE or, when missing, the calculated base of
129-
the zephyr tree
130-
- The magic string "<git-top>" refers to the top-level repository
131-
directory. This avoids running 'git' to find the top-level directory
132-
before main() runs (class variable assignments run when the 'class ...'
133-
statement runs). That avoids swallowing errors, because main() reports
134-
them to GitHub
159+
The path the test runs itself in. By default it uses the magic string
160+
"<git-top>" which refers to the top-level repository directory.
161+
162+
This avoids running 'git' to find the top-level directory before main()
163+
runs (class variable assignments run when the 'class ...' statement
164+
runs). That avoids swallowing errors, because main() reports them to
165+
GitHub.
166+
167+
Subclasses may override the default with a specific path or one of the
168+
magic strings below:
169+
- "<zephyr-base>" can be used to refer to the environment variable
170+
ZEPHYR_BASE or, when missing, the calculated base of the zephyr tree.
135171
"""
172+
path_hint = "<git-top>"
173+
136174
def __init__(self):
137175
self.case = TestCase(type(self).name, "Guidelines")
138176
# This is necessary because Failure can be subclassed, but since it is
@@ -204,7 +242,6 @@ class CheckPatch(ComplianceTest):
204242
"""
205243
name = "Checkpatch"
206244
doc = "See https://docs.zephyrproject.org/latest/contribute/guidelines.html#coding-style for more details."
207-
path_hint = "<git-top>"
208245

209246
def run(self):
210247
checkpatch = ZEPHYR_BASE / 'scripts' / 'checkpatch.pl'
@@ -263,7 +300,6 @@ class BoardYmlCheck(ComplianceTest):
263300
"""
264301
name = "BoardYml"
265302
doc = "Check the board.yml file format"
266-
path_hint = "<zephyr-base>"
267303

268304
def check_board_file(self, file, vendor_prefixes):
269305
"""Validate a single board file."""
@@ -278,20 +314,19 @@ def check_board_file(self, file, vendor_prefixes):
278314
desc=desc)
279315

280316
def run(self):
281-
vendor_prefixes = ["others"]
282-
with open(os.path.join(ZEPHYR_BASE, "dts", "bindings", "vendor-prefixes.txt")) as fp:
283-
for line in fp.readlines():
284-
line = line.strip()
285-
if not line or line.startswith("#"):
286-
continue
287-
try:
288-
vendor, _ = line.split("\t", 2)
289-
vendor_prefixes.append(vendor)
290-
except ValueError:
291-
self.error(f"Invalid line in vendor-prefixes.txt:\"{line}\".")
292-
self.error("Did you forget the tab character?")
293-
294-
path = Path(ZEPHYR_BASE)
317+
path = resolve_path_hint(self.path_hint)
318+
319+
vendor_prefixes = {"others"}
320+
# add vendor prefixes from the main zephyr repo
321+
vendor_prefixes |= get_vendor_prefixes(ZEPHYR_BASE / "dts" / "bindings" / "vendor-prefixes.txt", self.error)
322+
323+
# add vendor prefixes from the current repo
324+
dts_roots = get_module_setting_root('dts', path / "zephyr" / "module.yml")
325+
for dts_root in dts_roots:
326+
vendor_prefix_file = dts_root / "dts" / "bindings" / "vendor-prefixes.txt"
327+
if vendor_prefix_file.exists():
328+
vendor_prefixes |= get_vendor_prefixes(vendor_prefix_file, self.error)
329+
295330
for file in path.glob("**/board.yml"):
296331
self.check_board_file(file, vendor_prefixes)
297332

@@ -302,7 +337,6 @@ class ClangFormatCheck(ComplianceTest):
302337
"""
303338
name = "ClangFormat"
304339
doc = "See https://docs.zephyrproject.org/latest/contribute/guidelines.html#clang-format for more details."
305-
path_hint = "<git-top>"
306340

307341
def run(self):
308342
exe = f"clang-format-diff.{'exe' if platform.system() == 'Windows' else 'py'}"
@@ -344,7 +378,6 @@ class DevicetreeBindingsCheck(ComplianceTest):
344378
"""
345379
name = "DevicetreeBindings"
346380
doc = "See https://docs.zephyrproject.org/latest/build/dts/bindings.html for more details."
347-
path_hint = "<zephyr-base>"
348381

349382
def run(self, full=True):
350383
dts_bindings = self.parse_dt_bindings()
@@ -381,7 +414,6 @@ class KconfigCheck(ComplianceTest):
381414
"""
382415
name = "Kconfig"
383416
doc = "See https://docs.zephyrproject.org/latest/build/kconfig/tips.html for more details."
384-
path_hint = "<zephyr-base>"
385417

386418
# Top-level Kconfig file. The path can be relative to srctree (ZEPHYR_BASE).
387419
FILENAME = "Kconfig"
@@ -437,27 +469,6 @@ def get_modules(self, modules_file, sysbuild_modules_file, settings_file):
437469
))
438470
fp_module_file.write(content)
439471

440-
def get_module_setting_root(self, root, settings_file):
441-
"""
442-
Parse the Zephyr module generated settings file given by 'settings_file'
443-
and return all root settings defined by 'root'.
444-
"""
445-
# Invoke the script directly using the Python executable since this is
446-
# not a module nor a pip-installed Python utility
447-
root_paths = []
448-
449-
if os.path.exists(settings_file):
450-
with open(settings_file, 'r') as fp_setting_file:
451-
content = fp_setting_file.read()
452-
453-
lines = content.strip().split('\n')
454-
for line in lines:
455-
root = root.upper()
456-
if line.startswith(f'"{root}_ROOT":'):
457-
_, root_path = line.split(":", 1)
458-
root_paths.append(Path(root_path.strip('"')))
459-
return root_paths
460-
461472
def get_kconfig_dts(self, kconfig_dts_file, settings_file):
462473
"""
463474
Generate the Kconfig.dts using dts/bindings as the source.
@@ -1146,6 +1157,7 @@ class KconfigBasicNoModulesCheck(KconfigBasicCheck):
11461157
defined only in a module.
11471158
"""
11481159
name = "KconfigBasicNoModules"
1160+
path_hint = "<zephyr-base>"
11491161

11501162
def get_modules(self, modules_file, sysbuild_modules_file, settings_file):
11511163
with open(modules_file, 'w') as fp_module_file:
@@ -1212,6 +1224,7 @@ class SysbuildKconfigBasicNoModulesCheck(SysbuildKconfigCheck, KconfigBasicNoMod
12121224
but defined only in a module.
12131225
"""
12141226
name = "SysbuildKconfigBasicNoModules"
1227+
path_hint = "<zephyr-base>"
12151228

12161229

12171230
class Nits(ComplianceTest):
@@ -1221,7 +1234,6 @@ class Nits(ComplianceTest):
12211234
"""
12221235
name = "Nits"
12231236
doc = "See https://docs.zephyrproject.org/latest/contribute/guidelines.html#coding-style for more details."
1224-
path_hint = "<git-top>"
12251237

12261238
def run(self):
12271239
# Loop through added/modified files
@@ -1315,7 +1327,6 @@ class GitDiffCheck(ComplianceTest):
13151327
"""
13161328
name = "GitDiffCheck"
13171329
doc = "Git conflict markers and whitespace errors are not allowed in added changes"
1318-
path_hint = "<git-top>"
13191330

13201331
def run(self):
13211332
offending_lines = []
@@ -1343,7 +1354,6 @@ class GitLint(ComplianceTest):
13431354
"""
13441355
name = "Gitlint"
13451356
doc = "See https://docs.zephyrproject.org/latest/contribute/guidelines.html#commit-guidelines for more details"
1346-
path_hint = "<git-top>"
13471357

13481358
def run(self):
13491359
# By default gitlint looks for .gitlint configuration only in
@@ -1366,7 +1376,6 @@ class PyLint(ComplianceTest):
13661376
"""
13671377
name = "Pylint"
13681378
doc = "See https://www.pylint.org/ for more details"
1369-
path_hint = "<git-top>"
13701379

13711380
def run(self):
13721381
# Path to pylint configuration file
@@ -1441,9 +1450,6 @@ class Identity(ComplianceTest):
14411450
"""
14421451
name = "Identity"
14431452
doc = "See https://docs.zephyrproject.org/latest/contribute/guidelines.html#commit-guidelines for more details"
1444-
# git rev-list and git log don't depend on the current (sub)directory
1445-
# unless explicited
1446-
path_hint = "<git-top>"
14471453

14481454
def run(self):
14491455
for shaidx in get_shas(COMMIT_RANGE):
@@ -1484,7 +1490,6 @@ class BinaryFiles(ComplianceTest):
14841490
"""
14851491
name = "BinaryFiles"
14861492
doc = "No binary files allowed."
1487-
path_hint = "<git-top>"
14881493

14891494
def run(self):
14901495
BINARY_ALLOW_PATHS = ("doc/", "boards/", "samples/")
@@ -1507,7 +1512,6 @@ class ImageSize(ComplianceTest):
15071512
"""
15081513
name = "ImageSize"
15091514
doc = "Check the size of image files."
1510-
path_hint = "<git-top>"
15111515

15121516
def run(self):
15131517
SIZE_LIMIT = 250 << 10
@@ -1537,7 +1541,6 @@ class MaintainersFormat(ComplianceTest):
15371541
"""
15381542
name = "MaintainersFormat"
15391543
doc = "Check that MAINTAINERS file parses correctly."
1540-
path_hint = "<git-top>"
15411544

15421545
def run(self):
15431546
MAINTAINERS_FILES = ["MAINTAINERS.yml", "MAINTAINERS.yaml"]
@@ -1557,7 +1560,6 @@ class ModulesMaintainers(ComplianceTest):
15571560
"""
15581561
name = "ModulesMaintainers"
15591562
doc = "Check that all modules have a MAINTAINERS entry."
1560-
path_hint = "<git-top>"
15611563

15621564
def run(self):
15631565
MAINTAINERS_FILES = ["MAINTAINERS.yml", "MAINTAINERS.yaml"]
@@ -1592,7 +1594,6 @@ class YAMLLint(ComplianceTest):
15921594
"""
15931595
name = "YAMLLint"
15941596
doc = "Check YAML files with YAMLLint."
1595-
path_hint = "<git-top>"
15961597

15971598
def run(self):
15981599
config_file = ZEPHYR_BASE / ".yamllint"
@@ -1623,7 +1624,6 @@ class SphinxLint(ComplianceTest):
16231624

16241625
name = "SphinxLint"
16251626
doc = "Check Sphinx/reStructuredText files with sphinx-lint."
1626-
path_hint = "<git-top>"
16271627

16281628
# Checkers added/removed to sphinx-lint's default set
16291629
DISABLE_CHECKERS = ["horizontal-tab", "missing-space-before-default-role"]
@@ -1665,7 +1665,6 @@ class KeepSorted(ComplianceTest):
16651665
"""
16661666
name = "KeepSorted"
16671667
doc = "Check for blocks of code or config that should be kept sorted."
1668-
path_hint = "<git-top>"
16691668

16701669
MARKER = "zephyr-keep-sorted"
16711670

@@ -1761,7 +1760,6 @@ class Ruff(ComplianceTest):
17611760
"""
17621761
name = "Ruff"
17631762
doc = "Check python files with ruff."
1764-
path_hint = "<git-top>"
17651763

17661764
def run(self):
17671765
for file in get_files(filter="d"):
@@ -1809,7 +1807,6 @@ class TextEncoding(ComplianceTest):
18091807
"""
18101808
name = "TextEncoding"
18111809
doc = "Check the encoding of text files."
1812-
path_hint = "<git-top>"
18131810

18141811
ALLOWED_CHARSETS = ["us-ascii", "utf-8"]
18151812

0 commit comments

Comments
 (0)