Show a patch.

GET /api/1.1/patches/18046/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 18046,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/18046/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/18046/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api",
        "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=api",
        "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=api",
            "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"
    ]
}