{"id":18046,"url":"https://patchwork.libcamera.org/api/1.1/patches/18046/?format=json","web_url":"https://patchwork.libcamera.org/patch/18046/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20221221221237.3094-1-laurent.pinchart@ideasonboard.com>","date":"2022-12-21T22:12:37","name":"[libcamera-devel,v2] utils: checkstyle.py: Add commit title checker","commit_ref":null,"pull_url":null,"state":"accepted","archived":false,"hash":"0a4181a8818a8d362449f49f8b0140269bd01158","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/1.1/people/2/?format=json","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/18046/mbox/","series":[{"id":3685,"url":"https://patchwork.libcamera.org/api/1.1/series/3685/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=3685","date":"2022-12-21T22:12:37","name":"[libcamera-devel,v2] utils: checkstyle.py: Add commit title checker","version":2,"mbox":"https://patchwork.libcamera.org/series/3685/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/18046/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/18046/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 3F4A1C3200\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 21 Dec 2022 22:12:46 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 98ACD61F15;\n\tWed, 21 Dec 2022 23:12:45 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9C8CC61F15\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 21 Dec 2022 23:12:43 +0100 (CET)","from pendragon.ideasonboard.com (213-243-189-158.bb.dnainternet.fi\n\t[213.243.189.158])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 0CEDFFB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 21 Dec 2022 23:12:42 +0100 (CET)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1671660765;\n\tbh=2gVvG33raAVU42asgnkSylqlBelc/OkgoDHR4OQ1ERI=;\n\th=To:Date:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post:\n\tList-Help:List-Subscribe:From:Reply-To:From;\n\tb=X8D0IdRYuAju/DxH79f1cIO9SInXc7H3Y4J+TE8j4j0fLMPwZy+00NW4IE7NkCcl4\n\tzPFeQwGvYJuJE3qGLI5mrC0VztEXLWuX07G39TQa5rvdNMZi2y0nDWYSVN0Ov8pdpK\n\t8kz5c0f90l71/IbPTl9kZ1G2V3SQ5U3ljdopYX5HQGM3N3h2fW2iwIHHyNPWohhSAA\n\tmUg0nWHyYTCiiaCkrlGWFhHGHSs1MyQupw/aXPckGr6aliDATNrGquBL4wodwhe08B\n\tbKmvzBQVtxvXBzcBHq3Vc1PeKt6Mkun7RSunYyl83I3MTY6C0A9nXcz8mYvhjZDTc4\n\tJiCjX+6YmzNnQ==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1671660763;\n\tbh=2gVvG33raAVU42asgnkSylqlBelc/OkgoDHR4OQ1ERI=;\n\th=From:To:Subject:Date:From;\n\tb=OOEt5kAHP/hlxTZ/PRCGPBU6mKwpnyoiioRvxUdS9Uqt9edmZutTUn6jMF+oDvSew\n\tnYQqsUNClTnVA5cRnF7w8egaGPNnIho7Ug3/I3PbZAv96bnPTIJ1aMPLyxJMtFPFCk\n\tSOAqvYlHFEfeine21CxLuLLt5mKfGGAmcs8ca/Bs="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"OOEt5kAH\"; dkim-atps=neutral","To":"libcamera-devel@lists.libcamera.org","Date":"Thu, 22 Dec 2022 00:12:37 +0200","Message-Id":"<20221221221237.3094-1-laurent.pinchart@ideasonboard.com>","X-Mailer":"git-send-email 2.38.2","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [PATCH v2] utils: checkstyle.py: Add commit title\n\tchecker","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"Add a commit checker to ensure that commit titles start with a prefix.\nThe commit issue message lists prefix candidates retrieved from the git\nlog.\n\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\nChanges since v1:\n\n- Reduce indentation\n---\n utils/checkstyle.py | 62 +++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 62 insertions(+)\n\n\nbase-commit: f66a5c447b65bce774a1bc2d01034f437bf764b5\nprerequisite-patch-id: 55c457bf621237f99229898adb78e18b259ab74b","diff":"diff --git a/utils/checkstyle.py b/utils/checkstyle.py\nindex a11d95cc5808..364e13d6533d 100755\n--- a/utils/checkstyle.py\n+++ b/utils/checkstyle.py\n@@ -352,6 +352,68 @@ class HeaderAddChecker(CommitChecker):\n         return issues\n \n \n+class TitleChecker(CommitChecker):\n+    prefix_regex = re.compile(r'[0-9a-f]+ (([a-zA-Z0-9_.-]+: )+)')\n+    release_regex = re.compile(r'libcamera v[0-9]+\\.[0-9]+\\.[0-9]+')\n+\n+    @classmethod\n+    def check(cls, commit, top_level):\n+        title = commit.title\n+\n+        # Ignore release commits, they don't need a prefix.\n+        if TitleChecker.release_regex.fullmatch(title):\n+            return []\n+\n+        prefix_pos = title.find(': ')\n+        if prefix_pos != -1 and prefix_pos != len(title) - 2:\n+            return []\n+\n+        # Find prefix candidates by searching the git history\n+        msgs = subprocess.run(['git', 'log', '--no-decorate', '--oneline', '-n100', '--'] + commit.files(),\n+                              stdout=subprocess.PIPE).stdout.decode('utf-8')\n+        prefixes = {}\n+        prefixes_count = 0\n+        for msg in msgs.splitlines():\n+            prefix = TitleChecker.prefix_regex.match(msg)\n+            if not prefix:\n+                continue\n+\n+            prefix = prefix.group(1)\n+            if prefix in prefixes:\n+                prefixes[prefix] += 1\n+            else:\n+                prefixes[prefix] = 1\n+\n+            prefixes_count += 1\n+\n+        if not prefixes:\n+            return [CommitIssue('Commit title is missing prefix')]\n+\n+        # Sort the candidates by number of occurrences and pick the best ones.\n+        # When multiple prefixes are possible without a clear winner, we want to\n+        # display the most common options to the user, but without the most\n+        # unlikely options to avoid too long messages. As a heuristic, select\n+        # enough candidates to cover at least 2/3 of the possible prefixes, but\n+        # never more than 4 candidates.\n+        prefixes = list(prefixes.items())\n+        prefixes.sort(key=lambda x: x[1], reverse=True)\n+\n+        candidates = []\n+        candidates_count = 0\n+        for prefix in prefixes:\n+            candidates.append(f\"`{prefix[0]}'\")\n+            candidates_count += prefix[1]\n+            if candidates_count >= prefixes_count * 2 / 3 or \\\n+               len(candidates) == 4:\n+                break\n+\n+        candidates = candidates[:-2] + [' and '.join(candidates[-2:])]\n+        candidates = ', '.join(candidates)\n+\n+        return [CommitIssue('Commit title is missing prefix, '\n+                            'possible candidates are ' + candidates)]\n+\n+\n # ------------------------------------------------------------------------------\n # Style Checkers\n #\n","prefixes":["libcamera-devel","v2"]}