1

I want to restrict certain users from pushing changesets to the default branch of a repository. If it is possible, how would you do it?

Martin Geisler
  • 72,968
  • 25
  • 171
  • 229
themaniac27
  • 1,109
  • 3
  • 15
  • 27
  • Please, provide more information regarding your server setup. – C2H5OH Apr 11 '12 at 19:51
  • We store our repositories on a machine with windows server 2008 installed. The version of mercurial on that machine is 1.7.5. All of our repositories are set to go to the c:\repository folder. Each user has their own local clone on their machines. Users only commit to the server when their work is complete. From there they have to login with their username and password before they can actually commit to re repository. I looked into using [acl.deny.branches] but haven't had any luck in actually restricting users. – themaniac27 Apr 12 '12 at 16:40

2 Answers2

4

The ACL extension should work for you. However, you need to take into account the following considerations:

  • The extension must be enabled in the server repositories. That is, the hgrc file of each served repository should have ACL settings defined:

    [extensions]
    acl =
    
    [hooks]
    pretxnchangegroup.acl = python:hgext.acl.hook
    
    [acl]
    sources = serve
    
    [acl.deny.branches]
    default = user1, user2, user3
    
  • These users that have push denied are system users. That is, the username is taken from the credentials provided by the web server in your case. It has nothing to do with the Author: field in the commit metadata.

  • You can only allow or deny complete chagegroups. If one of your denied users pushes a group of commits containing a single commit to the default branch, the whole push will be denied (even if the other commits are allowed). This is not so strange if your users tend to merge with the default branch very often.

You could also write your own pretxnchangegroup hook but you will not be much more capable than the ACL extension.

salicideblock
  • 388
  • 3
  • 8
C2H5OH
  • 5,452
  • 2
  • 27
  • 39
0

The current answer will check at the moment when you push (and the check is server side, as what I make up from the acl code). What you want is a check on commit to your local repository. For that you should make a 'pretxncommit'-hook (note there are multiple kinds of hooks that act on different events).

Do the following:

According to A successful Git branching model, there should be no direct commits on master, only merges. To impose this we can add a callback hook to mercurial to check commits and disallow them if they are directly on master. To do that add the following line of code in your project's .hg/hgrc:

[hooks]
pretxncommit.nocommittomasterhook = python:%USERPROFILE%\hgnocommittomaster.py:nocommittomaster

The in your Windows homedirectory create the file 'hgnocommittomaster.py' with contents (original example):

from mercurial.node import bin, nullid
from mercurial import util

# Documentation is here: https://www.mercurial-scm.org/wiki/MercurialApi
# Script based on: https://www.mercurial-scm.org/wiki/HookExamples

def nocommittomaster(ui, repo, node, **kwargs):
    n = bin(node)
    start = repo.changelog.rev(n)
    end = len(repo.changelog)
    failed = False
    for rev in xrange(start, end):
        n = repo.changelog.node(rev)
        ctx = repo[n]
        p = ctx.parents()
        if ctx.branch()  == 'master' and len(p) == 1:
            if p[0].branch() != 'master':
                # commit that creates the branch, allowed
                continue
            if len(ctx.files()) == 0 and len(ctx.tags()) == 1:  # will not hit?, '.hgtags' always changed?
                continue    # Only a tag is added; allowed.
            elif len(ctx.files()) == 1 and len(ctx.tags()) == 1:
                if ctx.files()[0] == '.hgtags':
                    continue    # Only a tag is added; allowed.
            ui.warn(' - changeset rev=%d (%s) on stable branch and is not a merge !\n' % (rev,ctx))
            failed = True
    if failed:
        ui.warn('* Please strip the offending changeset(s)\n'
                '* and re-do them, if needed, on another branch!\n')
        return True

This post was inspired by: Mercurial pre commit hook and Mercurial Pre-Commit Hook: How to hook to python program in current directory?

isgoed
  • 724
  • 6
  • 12