285583cb0471 — sietse.brouwer tip 6 years ago
add the ticket-in-message hook
1 files changed, 83 insertions(+), 0 deletions(-)

A => ticket_in_message.py
A => ticket_in_message.py +83 -0
@@ 0,0 1,83 @@ 
+import re, os, sys, mercurial
+
+# Adapted from a solution by Micha Kops
+# http://www.hascode.com/2012/12/creating-pre-commit-hooks-in-git-and-mercurial-prefix-commit-messages-for-featurestory-branches/
+
+"""
+An hg hook with the following behaviour:
+
+* If there is a ticket number in the commit message, do nothing
+* else, if there is a ticket number in the current branch, use that 
+  (add it to the message)
+* else, if there is a ticket number in the incoming branch, use that
+* else, fail the commit
+
+Usage:
+
+# .hg/hgrc
+
+[hooks]
+
+precommit.ticket_in_message = python:.../.../ticket_in_message.py:ensure_ticket_in_message
+"""
+
+TICKET_PATTERN = '[A-Z]+-[0-9]+'
+
+# precommit hook
+def ensure_ticket_in_message(ui, repo, hooktype, parent1, parent2):
+    """
+    Replace the repo's 'commit a transaction' function with a wrapper
+    that tries to insert a ticket number into the commit message.
+    """
+
+    def ensure_ticket_in_message(workingctx):
+        """
+        Return a workingctx with a ticket number in the commit message.
+        If neither original message nor branch names supply a ticket
+        number, sys.exit with status 1.
+        """
+
+        # This function is not clean, it depends on 'ui' being present
+        # in the defining environment
+
+        ticket = re.compile('(?:RS|YH|DTAP)-[0-9]+')
+        ticket = re.compile(TICKET_PATTERN)
+
+        tickets_in_message = ticket.findall(workingctx._text)
+
+        tickets_in_branch_names = ticket.findall(workingctx.branch())
+        p2 = workingctx.p2()
+        if p2:
+            tickets_in_branch_names.extend(ticket.findall(p2.branch()))
+
+        # We found a ticket name in the message: 
+        # return an untouched workingctx
+        if tickets_in_message:
+            return workingctx
+
+        # No ticket in the message, but we can get it from the branch:
+        # return a workingctx with an updated message
+        elif (not tickets_in_message) and tickets_in_branch_names:
+
+            ticket_name = tickets_in_branch_names[0]
+            workingctx._text = '{ticket}: {message}'.format(
+                ticket=ticket_name,
+                message=workingctx._text
+            )
+            ui.status(workingctx._text + '\n')
+
+            return workingctx
+
+        # No ticket name anywhere: fail.
+        elif (not tickets_in_message) and (not tickets_in_branch_names):
+            ui.warn('No ticket name found in commit message or branch name.\n')
+            sys.exit(1)
+ 
+    commitctx = repo.commitctx
+
+    def rewrite_and_commitctx(workingctx, error):
+        """A wrapper around the repo's commitctx function."""
+        workingctx = ensure_ticket_in_message(workingctx)
+        return commitctx(workingctx, error)
+      
+    repo.commitctx = rewrite_and_commitctx