Mercurial Hook - change commit commit message

Change Made this basic hook to prevent branch name mismatch and bugID message errors. https://gist.github.com/2583189

So basically the idea is that the hook should add โ€œBugID: xyzโ€ to the end of the commit messages if the branch name looks like bug_123 or feature_123. However, I am having trouble finding how to do this, since most pretxncommit user examples do not want to change the description of the change set.

This is what I still have. It updates .hg / commit.save with the correct message, but this message is never passed to the commit. However, it appears in the default message box (tortoiseshell) of the next commit. Maybe pretxncommit is not the right hook?

Can I use the precommit hook, read the commit.save file and repo ['tip']. branch () and change what, if so, where would I get the branch name from?

# # Fogbugz automaticically add BugID:123 to commit messages based on branch names. # Your branch name must be in the format feature_123_description or bug_123_description # import re import mercurial, sys, os _branch_regex = re.compile('(feature|bug|case|bugid|fogbugz)_(\d+)') _commit_regex = re.compile(r'\b(?P<case>(review|case|bug[zs]?(\s| )*(id)?:?)s?(\s| )*([#:; ]| )+)((([ ,:;#]|and)*)(?P<bugid>\d+))+',re.I) def pretxncommithook(ui, repo, **kwargs): ui.write('hook pretxncommithook running from fogbugz.py\n') """ Checks a single commit message for adherence to commit message rules. To use add the following to your project .hg/hgrc for each project you want to check, or to your user hgrc to apply to all projects. [hooks] pretxncommit.fogbugz = python:fogbugz.pretxncommithook """ hg_commit_message = repo['tip'].description() commit_has_bugid = _commit_regex.match(hg_commit_message) is not None match = _branch_regex.match(repo['tip'].branch()) if match: hg_commit_message = hg_commit_message + ' BugID:'+ match.groups()[1] #hg_commit_message needs to be escaped for characters like > os.system('echo ' + hg_commit_message + ' > .hg/commit.save') 

In a slightly unrelated note, if someone from the Fogbugz / Kiln team sees this ... please update your software to read the branch name, I will not need to point BugID: x to every damned commit. First of all, I spend my time. Secondly, if the case identifier is incorrectly printed, it will not be displayed on the error without a lot of noise. Many developers use a branch for each error / function system. This is the policy of the company where I work. Fogbugz sucks.

+8
python mercurial mercurial-hook
source share
2 answers

I think the problem is that the pretxncommit hook pretxncommit executed at the point where you cannot change anything else. And you also cannot receive a commit message at this point, because it is not set in any accessible context object.

repo['tip'].description() does not apply to the fixed list of changes, but to the tip already made earlier, which would be repo[None] , but since some digging in the source showed that this is not the same context object that is saved therefore there is no change in it.

the only way I could find is to use an earlier hook-like precommit - and commitctx method of the repository as follows:

 def precommit_hook(repo, **kwargs): # keep a copy of repo.commitctx commitctx = repo.commitctx def updatectx(ctx, error): # check if `ctx.branch()` matches ... # update commit text ctx._text += " ... additional text" # call original return commitctx(ctx, error) # monkeypatch the commit method repo.commitctx = updatectx 

in this way, cou can access the context object just before it is committed.

+6
source share

The mata answer is smart, but itโ€™s actually a built-in way to do this if you are ready to write your own extension ( very simple , a little more than just writing down the hook functionality you wanted to write anyway).

The โ€œrightโ€ way to do this is to subclass the repository into reposetup , as shown in docstring mercurial.extensions.wrapfunction (because it turns out that wrapfunction not the right way to do this for repos:

 Wrapping methods of the repository object is not recommended since it conflicts with extensions that extend the repository by subclassing. All extensions that need to extend methods of localrepository should use this subclassing trick: namely, reposetup() should look like def reposetup(ui, repo): class myrepo(repo.__class__): def whatever(self, *args, **kwargs): [...extension stuff...] super(myrepo, self).whatever(*args, **kwargs) [...extension stuff...] repo.__class__ = myrepo 

So, for example, your extension will look like this:

 #!/usr/bin/python import re import mercurial, sys, os _branch_regex = re.compile('(feature|bug|case|bugid|fogbugz)_(\d+)') _commit_regex = re.compile(r'\b(?P<case>(review|case|bug[zs]?(\s| )*(id)?:?)s?(\s| )*([#:; ]| )+)((([ ,:;#]|and)*)(?P<bugid>\d+))+',re.I) #One of mercurial callbacks for extensions. This is where you # you want to subclass repo to add your functionality. def reposetup(ui, repo): #Create a derived class that actually does what you want. class myrepo(repo.__class__): def commitctx(self, ctx, *args, **kwargs): match = _branch_regex.match(ctx.branch()) if match: ctx._text += ' BugID:'+ match.groups()[1] #Make sure to actually use the new subclass. repo.__class__ = myrepo ### Finish off the extensions stuff # We aren't adding any commands to hg. cmdtables = {} #List of known compatible versions of hg. testedwith = '2.7.1' 

I tested this and it works great. You can use the extension by saving it in the python file, say /some-path/fogbugz.py and adding it to the extensions group in hgrc:

 [extensions] fogbugz = /some-path/fogbugz.py 
+5
source share

All Articles