From 7da1e4b801a2880190deebd19afc86837588ce91 Mon Sep 17 00:00:00 2001 From: Kyle Micallef Bonnici Date: Wed, 9 Jul 2025 00:37:06 +0200 Subject: [PATCH 1/2] CI: devicetree: linting to check_compliance.py Use dts-linter to check each touched file in PR Signed-off-by: Kyle Micallef Bonnici --- .github/workflows/compliance.yml | 25 ++++++++ .gitignore | 4 ++ doc/contribute/style/devicetree.rst | 1 + doc/contribute/style/index.rst | 33 ++++++++++ package-lock.json | 36 +++++++++++ package.json | 6 ++ scripts/checkpatch.pl | 5 ++ scripts/ci/check_compliance.py | 99 +++++++++++++++++++++++++++++ 8 files changed, 209 insertions(+) create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.github/workflows/compliance.yml b/.github/workflows/compliance.yml index 0c502115f0c..98cf6812292 100644 --- a/.github/workflows/compliance.yml +++ b/.github/workflows/compliance.yml @@ -60,6 +60,23 @@ jobs: west config manifest.group-filter -- +ci,-optional west update -o=--depth=1 -n 2>&1 1> west.update.log || west update -o=--depth=1 -n 2>&1 1> west.update2.log + - name: Cache npm dependencies + uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + with: + path: ~/.npm + key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-npm- + + - name: Setup Node.js + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + with: + node-version: "lts/*" + check-latest: true + + - name: Install Node dependencies + run: npm ci + - name: Run Compliance Tests continue-on-error: true id: compliance @@ -86,6 +103,14 @@ jobs: name: compliance.xml path: compliance.xml + - name: upload-dts-linter-patch + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + continue-on-error: true + if: hashFiles('dts_linter.patch') != '' + with: + name: dts_linter.patch + path: dts_linter.patch + - name: check-warns run: | if [[ ! -s "compliance.xml" ]]; then diff --git a/.gitignore b/.gitignore index 3c5deca2ccc..d6c011d5f81 100644 --- a/.gitignore +++ b/.gitignore @@ -73,6 +73,7 @@ target/ # CI output compliance.xml +dts_linter.patch _error.types # Tag files @@ -112,3 +113,6 @@ SysbuildKconfigBasicNoModules.txt TextEncoding.txt YAMLLint.txt ZephyrModuleFile.txt + +# Node dependecies +node_modules diff --git a/doc/contribute/style/devicetree.rst b/doc/contribute/style/devicetree.rst index 90d8bba0044..3e154027d54 100644 --- a/doc/contribute/style/devicetree.rst +++ b/doc/contribute/style/devicetree.rst @@ -4,6 +4,7 @@ Devicetree Style Guidelines ########################### * Indent with tabs. + * Tab size is 8 characters. * Follow the Devicetree specification conventions and rules. * If the Linux kernel rules in `Devicetree Sources (DTS) Coding Style `_ diff --git a/doc/contribute/style/index.rst b/doc/contribute/style/index.rst index d0ff1814d4c..f4b72e2f5cc 100644 --- a/doc/contribute/style/index.rst +++ b/doc/contribute/style/index.rst @@ -85,3 +85,36 @@ When there are differences between the `Coding Style Guidelines`_ guidelines and formatting generated by code formatting tools, the `Coding Style Guidelines`_ guidelines take precedence. If there is ambiguity between formatting tools and the guidelines, maintainers may decide which style should be adopted. + +dts-linter +============ + +The `dts-linter `_ can be helpful +to quickly reformat large amounts of devicetree files to our `Coding Style Guidelines`_ +standards. You can also run it manually like this: + +For individual files +.. code-block:: bash + + npx dts-linter --format --file board.dts --file board_pinctrl.dtsi --patchFile diff.patch + git apply diff.patch + +You can omit ``--file`` and this will format all files under the directory where the command +has been called. Alternatively ``--cwd`` can also be passed set the base dir where the tool +should look for files. This option is also used to make the paths relative in the patch file. + +You can also fix in place with +.. code-block:: bash + + npx dts-linter --formatFixAll + + +If you want to format file while developing and is using a VS Code like IDEs you can install the extension +* For VS Code: Install the extension from the +`VS Code Marketplace `_ or +`Open VSIX `_ +* For other editors with LSP Client support: Use the devicetree-language-server +`devicetree-language-server `_ + +Make sure you follow `Devicetree Style Guidelines `_ +requirements to configure the editor correctly. diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000000..176acbe4ab6 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,36 @@ +{ + "name": "zephyr", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "dts-linter": "^0.3.0-beta2" + } + }, + "node_modules/devicetree-language-server": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/devicetree-language-server/-/devicetree-language-server-0.5.2.tgz", + "integrity": "sha512-zg1+ky82g5LOw+gmY6kKP2TLMko72tD1ln195HJnZx8WSk1Qi+oCvcvUzoVPQDJrUs8QNaSbp7+tmhHf85Lsuw==", + "license": "Apache-2.0", + "bin": { + "devicetree-language-server": "dist/server.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/dts-linter": { + "version": "0.3.0-beta2", + "resolved": "https://registry.npmjs.org/dts-linter/-/dts-linter-0.3.0-beta2.tgz", + "integrity": "sha512-1jPGqk+d8+pDlpn+xRx/isDulDIe6ZxK77h2eZ0dem9xya154+WnUmoofquznvjCJOhYYZHPT6ThIP/EsC2kSQ==", + "license": "Apache-2.0", + "dependencies": { + "devicetree-language-server": "^0.5.2" + }, + "bin": { + "dts-linter": "dist/dts-linter.js" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000000..52dfec12a94 --- /dev/null +++ b/package.json @@ -0,0 +1,6 @@ +{ + "private": true, + "dependencies": { + "dts-linter": "^0.3.0-beta2" + } +} diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 8f964bc654b..351bacedf6d 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2572,6 +2572,11 @@ sub process { next; } + # skip package-lock.json and package.json files specifically + if ($realfile =~ /package(-lock)?\.json$/) { + next; + } + #make up the handle for any error we report on this line if ($showfile) { $prefix = "$realfile:$realline: " diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 540744d7e12..71ac14f2cf1 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -491,6 +491,105 @@ def required_false_check(self, binding): "'required: false' is redundant, please remove" ) + +class DevicetreeLintingCheck(ComplianceTest): + """ + Checks if we are introducing syntax or formatting issues to devicetree files. + """ + name = "DevicetreeLinting" + doc = "See https://docs.zephyrproject.org/latest/contribute/style/devicetree.html for more details." + + def _parse_json_output(self, cmd, cwd=None): + """Run command and parse single JSON output with issues array""" + result = subprocess.run( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + check=False, + text=True, + cwd=cwd or GIT_TOP + ) + + if not result.stdout.strip(): + return None + + try: + json_data = json.loads(result.stdout) + return json_data + except json.JSONDecodeError as e: + raise RuntimeError(f"Failed to parse dts-linter JSON output: {e}") + + def run(self): + # Get changed DTS files + dts_files = [ + file for file in get_files(filter="d") + if file.endswith((".dts", ".dtsi", ".overlay")) + ] + + if not dts_files: + self.skip('No DTS') + + temp_patch_files = [] + batch_size = 500 + + for i in range(0, len(dts_files), batch_size): + batch = dts_files[i:i + batch_size] + + # use a temporary file for each batch + temp_patch = f"dts_linter_{i}.patch" + temp_patch_files.append(temp_patch) + + cmd = [ + "npx", "--no", "dts-linter", "--", + "--outputFormat", "json", + "--format", + "--patchFile", temp_patch, + ] + for file in batch: + cmd.extend(["--file", file]) + + try: + json_output = self._parse_json_output(cmd) + + if json_output and "issues" in json_output: + cwd = json_output.get("cwd", "") + logging.info(f"Processing issues from: {cwd}") + + for issue in json_output["issues"]: + level = issue.get("level", "unknown") + message = issue.get("message", "") + + if level == "info": + logging.info(message) + else: + title = issue.get("title", "") + file = issue.get("file", "") + line = issue.get("startLine", None) + col = issue.get("startCol", None) + end_line = issue.get("endLine", None) + end_col = issue.get("endCol", None) + self.fmtd_failure(level, title, file, line, col, message, end_line, end_col) + + except subprocess.CalledProcessError as ex: + stderr_output = ex.stderr if ex.stderr else "" + if stderr_output.strip(): + self.failure(f"dts-linter found issues:\n{stderr_output}") + else: + self.failure("dts-linter failed with no output. " + "Make sure you install Node.JS and then run npm ci inside ZEPHYR_BASE") + except RuntimeError as ex: + self.failure(f"{ex}") + + # merge all temp patch files into one + with open("dts_linter.patch", "wb") as final_patch: + for patch in temp_patch_files: + with open(patch, "rb") as f: + shutil.copyfileobj(f, final_patch) + + # cleanup + for patch in temp_patch_files: + os.remove(patch) + class KconfigCheck(ComplianceTest): """ Checks is we are introducing any new warnings/errors with Kconfig, From 07b8911e87cc975f29aa087f8d39b0f23bfc1338 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 19 Sep 2025 12:27:09 -0400 Subject: [PATCH 2/2] dummy Signed-off-by: Anas Nashif --- boards/96boards/aerocore2/96b_aerocore2.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/96boards/aerocore2/96b_aerocore2.dts b/boards/96boards/aerocore2/96b_aerocore2.dts index 339f61df6e0..0908d189b99 100644 --- a/boards/96boards/aerocore2/96b_aerocore2.dts +++ b/boards/96boards/aerocore2/96b_aerocore2.dts @@ -21,8 +21,8 @@ zephyr,ccm = &ccm0; }; - leds { - compatible = "gpio-leds"; + + leds { compatible = "gpio-leds"; yellow_led_1: led_1 { gpios = <&gpioe 10 GPIO_ACTIVE_HIGH>;