scripts: compliance: add sphinx-lint linter

ReStructuredText can sometimes be tricky to get right, especially for
folks that might be more familiar with Markdown.

This adds a Sphinx/RST linter to the compliance check script to help
catch common issues that can easily go unnoticed and cause rendering
issues.

Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
diff --git a/.github/workflows/compliance.yml b/.github/workflows/compliance.yml
index 09168ab..39815d8 100644
--- a/.github/workflows/compliance.yml
+++ b/.github/workflows/compliance.yml
@@ -38,7 +38,7 @@
       run: |
         pip3 install setuptools
         pip3 install wheel
-        pip3 install python-magic lxml junitparser gitlint pylint pykwalify yamllint clang-format unidiff
+        pip3 install python-magic lxml junitparser gitlint pylint pykwalify yamllint clang-format unidiff sphinx-lint
         pip3 install west
 
     - name: west setup
diff --git a/.gitignore b/.gitignore
index f590a8a..266b95a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -91,4 +91,5 @@
 ModulesMaintainers.txt
 Nits.txt
 Pylint.txt
+SphinxLint.txt
 YAMLLint.txt
diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py
index 54964d4..58a2e6d 100755
--- a/scripts/ci/check_compliance.py
+++ b/scripts/ci/check_compliance.py
@@ -1495,6 +1495,49 @@
                                       p.line, col=p.column, desc=p.desc)
 
 
+class SphinxLint(ComplianceTest):
+    """
+    SphinxLint
+    """
+
+    name = "SphinxLint"
+    doc = "Check Sphinx/reStructuredText files with sphinx-lint."
+    path_hint = "<git-top>"
+
+    # Checkers added/removed to sphinx-lint's default set
+    DISABLE_CHECKERS = ["horizontal-tab", "missing-space-before-default-role"]
+    ENABLE_CHECKERS = ["default-role"]
+
+    def run(self):
+        for file in get_files():
+            if not file.endswith(".rst"):
+                continue
+
+            try:
+                # sphinx-lint does not expose a public API so interaction is done via CLI
+                subprocess.run(
+                    f"sphinx-lint -d {','.join(self.DISABLE_CHECKERS)} -e {','.join(self.ENABLE_CHECKERS)} {file}",
+                    check=True,
+                    stdout=subprocess.PIPE,
+                    stderr=subprocess.STDOUT,
+                    shell=True,
+                    cwd=GIT_TOP,
+                )
+
+            except subprocess.CalledProcessError as ex:
+                for line in ex.output.decode("utf-8").splitlines():
+                    match = re.match(r"^(.*):(\d+): (.*)$", line)
+
+                    if match:
+                        self.fmtd_failure(
+                            "error",
+                            "SphinxLint",
+                            match.group(1),
+                            int(match.group(2)),
+                            desc=match.group(3),
+                        )
+
+
 class KeepSorted(ComplianceTest):
     """
     Check for blocks of code or config that should be kept sorted.
diff --git a/scripts/requirements-compliance.txt b/scripts/requirements-compliance.txt
index 0d5fe21..a439698 100644
--- a/scripts/requirements-compliance.txt
+++ b/scripts/requirements-compliance.txt
@@ -9,3 +9,4 @@
 pylint>=3
 unidiff
 yamllint
+sphinx-lint