Missed Team ’24? Catch up on announcements here.

×
Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

Stash pre-receive hook - get list of merges

JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 8, 2014

Morning... I'm looking to restrict people committing directly on an integration branch... so it should happen only through a merge from a feature branch.

Whether this is a good idea or not is moot at this stage, it's just about winning hearts and minds.

I'm struggling with commitService.getChangesetsBetween and traverse... basically I'm looking to check that any commit on the integration branch is a result of a merge.

There must be code floating about that does this, I have seen screenshots of a hipchat integration where it says "Charles was a naughty boy, he committed directly to the master branch". That's not entirely suitable for our regulators, so I need to find that code and formalise it a bit.

On the other hand I think in the past Jens has said this is tricky.

5 answers

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

1 vote
Balázs Szakmáry
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 11, 2014

Something like this:

protected static final String mergeBegin = "merge";
protected static final String refsHeads = "refs/heads/";
protected static final String featureBranchPrefix = "feature/";
protected static final String bugfixBranchPrefix = "bugfix/";

public boolean onReceive(@Nonnull final RepositoryHookContext context,
 @Nonnull final Collection<RefChange> refChanges,
 @Nonnull final HookResponse hookResponse)
{
 for(RefChange refChange: refChanges)
 {
  //branches being deleted and changes to non-branch refs are ignored
  if (RefChangeType.DELETE == refChange.getType() || !refChange.getRefId().startsWith(refsHeads)) continue;

  final ChangesetsBetweenRequest request = new ChangesetsBetweenRequest.Builder(repository)
   .exclude(refChange.getFromHash()) //this is all 0's for RefChangeType.ADD
   .include(refChange.getToHash())
   .build();
  final Page<Changeset> cs = commitService.getChangesetsBetween(request, PageUtils.newRequest(0, 9999));
  
  for(Changeset changeset: cs.getValues())
  {
   //false for the new commit, true for the old ones
   if (!changesetIndex.isMemberOf(changeset.getId(), repository))
    {
     final String commitMessage = changeset.getMessage();
     if (commitMessage.toLowerCase().startsWith(mergeBegin.toLowerCase()))
     {
      continue;
     }
     final String branchName = refChange.getRefId().substring(Common.refsHeads.length());
     if (branchName.toLowerCase().startsWith(featureBranchPrefix.toLowerCase()))
     {
      continue;
     }
     else if (branchName.toLowerCase().startsWith(bugfixBranchPrefix.toLowerCase()))
     {
      continue;
     }
     //reject push if a commit is new, not merge, not made to a feature/bugfix branch
     return false;
    }
  }
 }
 //accept push if no offending commit is found
 return true;
}

JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 11, 2014

Thanks... this opens up some new avenues for me.

0 votes
Balázs Szakmáry
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 11, 2014

Two more ideas that came to me over the weekend:

- Reject everything where the commit msg. does not start with "Merge" OR is a push to a branch whose name starts with "feature/" "bugfix/", etc. (I have some code similar to this, if you want.)

- If the RefChanges for the push, check for a pull request ref being deleted.

JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 11, 2014

> I have some code similar to this, if you want

Any sample code would be helpful, thanks.

0 votes
JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 8, 2014

I think repositoryMetadataService.resolveRef (repo, changeSetId) may help.

0 votes
Balázs Szakmáry
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 8, 2014

The branch permissions are a way to restrict access to certain branches to a subset of the people who can otherwise write the repo.

If your repo is set to be writeable for {A, B, C, D} and you set one rule in branch permissions, something like refs/heads/release/ allowed only for {D} then A, B, and C are going to be able to push to all branches except for refs/heads/release/* and D will be able to push anything, including merging code to refs/heads/release/* .

As far as I can tell, this is exactly what you want, isn't it?

JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 8, 2014

Not really. That just makes D a bottleneck for reviews. In my case even D must work on a branch, then merge.

Balázs Szakmáry
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 8, 2014

I just read your original question again and now I see what you want:
You want to reject all commits to certain branches, unless they come from a pull request.

Either you need to find that the commit has two parents, or perhaps you can listen for one of the PullRequest*Event events.

JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 8, 2014

Yeah it wasn't very clear. Really, I am hoping that @Charles will come on here and point me to that example code from the hipchat integration.

0 votes
Balázs Szakmáry
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 8, 2014

- I think what you want could be achieved easiest with branch permissions: restrict push access to the integration branches to the people you do want to allow to merge code there.

- There are two things that are special to the merge commits, if you really want to detect those:
- By default, the commit message starts with "Merge". (This is always true, unless somebody edits the merge commit comments created by the tools by hand.)
- It has more than one parent.

JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 8, 2014

It can be achieved easiest with branch permissions but I don't think it gives me what I want, which might be to allow anyone to merge to trunk from a feature branch (I'll deal with pull req approvals later). So I don't want to restrict to just some privileged few.

1) not nearly reliable enough.

2) I may want to prevent merging from a release branch too... so I need the refs of the parents.

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

TAGS
AUG Leaders

Atlassian Community Events