precommit mercurial hook to stop commits to the wrong branch
Faheem Mitha
faheem at faheem.info
Sun Oct 13 18:37:52 UTC 2013
On Sat, 12 Oct 2013, Faheem Mitha wrote:
> On Fri, 11 Oct 2013, Faheem Mitha wrote:
>> On Thu, 10 Oct 2013, Faheem Mitha wrote:
>>> I see there is also http://mercurial.selenic.com/wiki/PythonHglib
>> I posted the following approach to SO:
>> http://stackoverflow.com/a/19305079/350713
>> The post appears below. However, I still have a problem.
>> I use mq, and when it comes to mq commits, I don't care what commits
>> are made to what branch, because mq itself doesn't really care about
>> branches (an mq patch takes the name of whatever branch it is
>> qpushed to), and so one can merrily pop and push mq patches between
>> branches.
>> So, is there some good way to tell the hook that if the commit in
>> progress is an mq commit, don't do anything?
>> I looked at mq.py for a bit, but didn't see any obvious way to do
>> this. As you can see, I am using hglib for my hook, so a solution
>> that integrates with hglib would be nice, but if I have to drop down
>> to a low level API, then I guess I can live with that.
>> Regards, Faheem
>> ########################################################################
>> Using @Ry4an's solution as a starting point, I came up with the
>> following script using the new hglib API.
>> #!/usr/bin/python
>> # Abort commit to the debian branch if it is not contained in a debian
>> # subdirectory
>> # Similary abort commit to non-debian branches if it is contained in a
>> # debian subdirectory
>> import hglib, os, sys
>> client = hglib.open("/home/faheem/hooktest")
>> ctx = client['tip']
>> files = ctx.files()
>> branch = ctx.branch()
>> for f in files:
>> d = os.path.dirname(f)
>> if branch == "debian" and d != "debian":
>> sys.exit("cannot commit %s (file not in 'debian' directory) to
>> 'debian' branch"%f)
>> if branch != "debian" and d == "debian":
>> sys.exit("cannot commit %s (file in 'debian' directory) to non
>> 'debian' branch"%f)
> Here is an in-process hook which allows MQ commits. Thanks to Brendan and
> Bob Hood for helpful information. However, I *still* have a problem. I can
> convert an MQ commit into a regular commit with qfinish, and the hook
> doesn't stop me. Does anyone have any ideas about that?
> ##########################################################################
> def abort_commit_to_wrong_branch(ui, repo, **kwargs):
> # If repo has '_committingpatch' attribute, then it is an mq
> # commit in progress, so return 'False'
> import os
> ctx = repo[kwargs['node']]
> files = ctx.files()
> branch = ctx.branch()
> if hasattr(repo, "_committingpatch"):
> for f in files:
> d = os.path.dirname(f)
> if branch == "debian" and d != "debian":
> ui.warn("Warning: committing %s (file not in 'debian'
> directory) to 'debian' branch. Allowed since this ia an MQ commit.\n"%f)
> if branch != "debian" and d == "debian":
> ui.warn("Warning: committing %s (file in 'debian' directory)
> to non 'debian' branch. Allowed since this ia an MQ commit.\n"%f)
> return False
> for f in files:
> d = os.path.dirname(f)
> if branch == "debian" and d != "debian":
> ui.warn("Error: cannot commit %s (file not in 'debian' directory)
> to 'debian' branch\n"%f)
> return True
> if branch != "debian" and d == "debian":
> ui.warn("Error: cannot commit %s (file in 'debian' directory) to
> non 'debian' branch\n"%f)
> return True
One approach to the qfinish problem is to create a pre-qfinish hook as
follows. Thanks to Brendan Cully for the suggestion and various hints.
These two hooks were used in .hgrc as follows:
[hooks]
pretxncommit.foo = python:mercurial_hooks.abort_commit_to_wrong_branch
pre-qfinish.bar = python:mercurial_hooks.qfinish_abort_commit_to_wrong_branch
Comments/corrections appreciated.
Regards, Faheem
def qfinish_abort_commit_to_wrong_branch(ui, repo, **kwargs):
"""
Don't allow qfinish on 'debian' branch including files not
contained in the 'debian/' directory. Also don't allow qfinish on
non-'debian' branches including files contained in the 'debian/'
directory. Don't restrict MQ commits.
"""
from mercurial import scmutil
import os
if not repo.mq.applied:
ui.status(('no patches applied\n'))
return True
opts = kwargs['opts']
# case corresponding to `-a`. no revisions specified.
if opts.get('applied'):
revrange = ('qbase::qtip',)
# case where revision(s) specified
revrange = kwargs['pats']
revs = scmutil.revrange(repo, revrange)
# loop over revisions
for rev in revs:
ctx = repo[rev]
files = ctx.files()
branch = ctx.branch()
for f in files:
d = os.path.dirname(f)
if branch == "debian" and d != "debian":
ui.warn("Error: cannot commit %s (file not in 'debian' directory) to 'debian' branch\n"%f)
return True
if branch != "debian" and d == "debian":
ui.warn("Error: cannot commit %s (file in 'debian' directory) to non 'debian' branch\n"%f)
return True
More information about the Mercurial
mailing list