Adam Parkin
Adam Parkin

Reputation: 18660

Bitbucket: Enforce merge-only by pull request on branch workflow

Our team uses Bitbucket for hosting our Mercurial repository. We have a single repo which is cloned to our dev VM's upon provisioning them. We use a fairly typical feature branch -> pull request -> review -> merge feature into default from the PR workflow.

What we'd like: to be able to restrict things such that one cannot push to the default branch by command-line (to avoid accidental commits to that branch). Ie - we want to enforce it so that the only way default is modified is via a pull request.

Note that forking isn't really an option due to the VM setup (we'd have to add complexity to the VM provisioning to do the fork, and set all that up on the provisioned VM, and even then that just means that when someone accidentally pushes to default they're just messing up their fork).

Branch Restrictions seem promising, and while we can set it up that nobody can push via the command line, it then means only a single named user or group can do the actual merge of the PR (which we don't want, ideally anyone on the team can merge, just only through a Bitbucket PR).

Is this possible? Any suggestions?

Upvotes: 2

Views: 333

Answers (1)

Adam Parkin
Adam Parkin

Reputation: 18660

So I ended up solving this with Mercurial hooks. Specifically I created the following file, which I named prevent_default_push.py and put in the .hg directory of my clone.

# branches to prevent being pushed to by command line.
# Separate branches by spaces
restricted_branches = "default".lower().split()

def branch_name(repo):
    return repo[None].branch().lower()

def is_restricted(branch):
    return branch in restricted_branches

def prevent_default(ui, repo, *args, **kwargs):
    if is_restricted(branch_name(repo)): 
        print("Preventing push to default branch")
        return True
    return False

def prevent_commit(ui, repo, *args, **kwargs):
    branch = branch_name(repo)
    if is_restricted(branch): 
        print("You're on a restricted branch (%s), are you sure you want to commit? [YN]" % branch)
        res = raw_input().strip().lower()
        return res != "y"
    return False

And then edited the .hg/hgrc file to use these hooks:

[hooks]
pre-push = python:.hg/prevent_default_push.py:prevent_default 
pre-commit = python:.hg/prevent_default_push.py:prevent_commit

Then when trying to do a commit while on the default branch, you get a confirmation prompt, and if you try doing a push to default it's straight up rejected.

Example run:

$ hg commit
You're on a restricted branch (default), are you sure you want to commit? [YN]
n
abort: pre-commit hook failed

Where "n" is what I typed.

The plus side of this is that while the stuff in your .hg directory isn't under version control (so a clone won't get it), we can incorporate into our provisioning mechansims the automation of putting these hooks in place on a provisioned VM.

Upvotes: 1

Related Questions