ci: Apply coccinelle scripts in git diffs

This scripts receives the same parameter of what_changed.py. And run
coccinelle scripts for code guideline compliance in the given git
commits. e.g: ./guideline_check.py --commits origin/master..HEAD

Signed-off-by: Flavio Ceolin <flavio.ceolin@intel.com>
diff --git a/scripts/ci/guideline_check.py b/scripts/ci/guideline_check.py
new file mode 100755
index 0000000..44752e3
--- /dev/null
+++ b/scripts/ci/guideline_check.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) 2021 Intel Corporation
+
+import os
+import sh
+import argparse
+import re
+from unidiff import PatchSet
+
+if "ZEPHYR_BASE" not in os.environ:
+    exit("$ZEPHYR_BASE environment variable undefined.")
+
+repository_path = os.environ['ZEPHYR_BASE']
+
+sh_special_args = {
+    '_tty_out': False,
+    '_cwd': repository_path
+}
+
+coccinelle_scripts = ["/scripts/coccinelle/reserved_names.cocci",
+                      "/scripts/coccinelle/same_identifier.cocci",
+                      "/scripts/coccinelle/identifier_length.cocci",
+                      ]
+
+
+def parse_coccinelle(contents: str, violations: dict):
+    reg = re.compile("([a-zA-Z0-9/]*\\.[ch]:[0-9]*)(:[0-9\\-]*: )(.*)")
+    for line in contents.split("\n"):
+        r = reg.match(line)
+        if r:
+            f = r.group(1)
+            if f in violations:
+                violations[f].append(r.group(3))
+            else:
+                violations[r.group(1)] = [r.group(3)]
+
+
+def parse_args():
+    parser = argparse.ArgumentParser(
+        description="Check if change requires full twister")
+    parser.add_argument('-c', '--commits', default=None,
+                        help="Commit range in the form: a..b")
+    return parser.parse_args()
+
+
+def main():
+    args = parse_args()
+    if not args.commits:
+        exit("missing commit range")
+
+    commit = sh.git("diff", args.commits, **sh_special_args)
+    patch_set = PatchSet(commit)
+    zephyr_base = os.getenv("ZEPHYR_BASE")
+    violations = {}
+    numViolations = 0
+
+    for f in patch_set:
+        if not f.path.endswith(".c") and not f.path.endswith(".h") or not os.path.exists(zephyr_base + "/" + f.path):
+            continue
+
+        for script in coccinelle_scripts:
+            script_path = os.getenv("ZEPHYR_BASE") + "/" + script
+            cocci = sh.coccicheck(
+                "--mode=report",
+                "--cocci=" +
+                script_path,
+                f.path,
+                **sh_special_args)
+            parse_coccinelle(cocci, violations)
+
+        for hunk in f:
+            for line in hunk:
+                if line.is_added:
+                    violation = "{}:{}".format(f.path, line.target_line_no)
+                    if violation in violations:
+                        numViolations += 1
+                        print(
+                            "{}:{}".format(
+                                violation, "\t\n".join(
+                                    violations[violation])))
+
+    return numViolations
+
+
+if __name__ == "__main__":
+    ret = main()
+    exit(ret)