From patchwork Wed Dec 21 22:12:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 18046 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 3F4A1C3200 for ; Wed, 21 Dec 2022 22:12:46 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 98ACD61F15; Wed, 21 Dec 2022 23:12:45 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1671660765; bh=2gVvG33raAVU42asgnkSylqlBelc/OkgoDHR4OQ1ERI=; h=To:Date:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=X8D0IdRYuAju/DxH79f1cIO9SInXc7H3Y4J+TE8j4j0fLMPwZy+00NW4IE7NkCcl4 zPFeQwGvYJuJE3qGLI5mrC0VztEXLWuX07G39TQa5rvdNMZi2y0nDWYSVN0Ov8pdpK 8kz5c0f90l71/IbPTl9kZ1G2V3SQ5U3ljdopYX5HQGM3N3h2fW2iwIHHyNPWohhSAA mUg0nWHyYTCiiaCkrlGWFhHGHSs1MyQupw/aXPckGr6aliDATNrGquBL4wodwhe08B bKmvzBQVtxvXBzcBHq3Vc1PeKt6Mkun7RSunYyl83I3MTY6C0A9nXcz8mYvhjZDTc4 JiCjX+6YmzNnQ== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9C8CC61F15 for ; Wed, 21 Dec 2022 23:12:43 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="OOEt5kAH"; dkim-atps=neutral Received: from pendragon.ideasonboard.com (213-243-189-158.bb.dnainternet.fi [213.243.189.158]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 0CEDFFB for ; Wed, 21 Dec 2022 23:12:42 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1671660763; bh=2gVvG33raAVU42asgnkSylqlBelc/OkgoDHR4OQ1ERI=; h=From:To:Subject:Date:From; b=OOEt5kAHP/hlxTZ/PRCGPBU6mKwpnyoiioRvxUdS9Uqt9edmZutTUn6jMF+oDvSew nYQqsUNClTnVA5cRnF7w8egaGPNnIho7Ug3/I3PbZAv96bnPTIJ1aMPLyxJMtFPFCk SOAqvYlHFEfeine21CxLuLLt5mKfGGAmcs8ca/Bs= 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 Subject: [libcamera-devel] [PATCH v2] utils: checkstyle.py: Add commit title checker X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Laurent Pinchart via libcamera-devel From: Laurent Pinchart Reply-To: Laurent Pinchart Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a commit checker to ensure that commit titles start with a prefix. The commit issue message lists prefix candidates retrieved from the git log. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Reviewed-by: Jacopo Mondi --- Changes since v1: - Reduce indentation --- utils/checkstyle.py | 62 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) base-commit: f66a5c447b65bce774a1bc2d01034f437bf764b5 prerequisite-patch-id: 55c457bf621237f99229898adb78e18b259ab74b diff --git a/utils/checkstyle.py b/utils/checkstyle.py index a11d95cc5808..364e13d6533d 100755 --- a/utils/checkstyle.py +++ b/utils/checkstyle.py @@ -352,6 +352,68 @@ class HeaderAddChecker(CommitChecker): return issues +class TitleChecker(CommitChecker): + prefix_regex = re.compile(r'[0-9a-f]+ (([a-zA-Z0-9_.-]+: )+)') + release_regex = re.compile(r'libcamera v[0-9]+\.[0-9]+\.[0-9]+') + + @classmethod + def check(cls, commit, top_level): + title = commit.title + + # Ignore release commits, they don't need a prefix. + if TitleChecker.release_regex.fullmatch(title): + return [] + + prefix_pos = title.find(': ') + if prefix_pos != -1 and prefix_pos != len(title) - 2: + return [] + + # Find prefix candidates by searching the git history + msgs = subprocess.run(['git', 'log', '--no-decorate', '--oneline', '-n100', '--'] + commit.files(), + stdout=subprocess.PIPE).stdout.decode('utf-8') + prefixes = {} + prefixes_count = 0 + for msg in msgs.splitlines(): + prefix = TitleChecker.prefix_regex.match(msg) + if not prefix: + continue + + prefix = prefix.group(1) + if prefix in prefixes: + prefixes[prefix] += 1 + else: + prefixes[prefix] = 1 + + prefixes_count += 1 + + if not prefixes: + return [CommitIssue('Commit title is missing prefix')] + + # Sort the candidates by number of occurrences and pick the best ones. + # When multiple prefixes are possible without a clear winner, we want to + # display the most common options to the user, but without the most + # unlikely options to avoid too long messages. As a heuristic, select + # enough candidates to cover at least 2/3 of the possible prefixes, but + # never more than 4 candidates. + prefixes = list(prefixes.items()) + prefixes.sort(key=lambda x: x[1], reverse=True) + + candidates = [] + candidates_count = 0 + for prefix in prefixes: + candidates.append(f"`{prefix[0]}'") + candidates_count += prefix[1] + if candidates_count >= prefixes_count * 2 / 3 or \ + len(candidates) == 4: + break + + candidates = candidates[:-2] + [' and '.join(candidates[-2:])] + candidates = ', '.join(candidates) + + return [CommitIssue('Commit title is missing prefix, ' + 'possible candidates are ' + candidates)] + + # ------------------------------------------------------------------------------ # Style Checkers #