Recently I was involved in a change over from bitbucket server to bitbucket cloud. It was pretty seemless, but there was one major issue – automerge, which is available on bitbucket server, is not available on bitbucket cloud. For many people, maybe that’s not a big deal, but for us it definitely felt like a step back. We had to do TWO pull requests anytime we did a release, one to master from the release branch and one from master back into the core development branch. In the event of a hotfix… yep, two pull requests there too. In a world of automation being used to make life simpler and to make sure the key steps are done, not having automerge just felt wrong to me and all these other people. So I decided to implement a solution and make it as generic as I could so you can use it for whatever projects you have. I chose to utilize bitbucket pipelines as the driver for this feature. If you haven’t used pipelines you are encouraged to check out their intro here. Let’s check out the solution.
First I describe a more “ideal way”. But I also describe a modified way to implement the same pipeline. The modified way doesn’t require the “bot”… but it’s not as nice. However, it will allow a small group to get things going quick.
Ideal way:
- Create a “bot” user – this is really just a dummy user that you will give lots of permissions to so it can do stuff on your behalf.
- In the repo, Go to pipelines -> settings
- Turn on pipelines.
- Go to pipelines -> SSH Keys and generate a set of keys
- Copy the public key and go paste it into the bots profile in the ssh keys section.
- Go to the repo you want to configure.
- Choose the development branch
- Give the bot permissions to merge into that branch without a pull request.
Slightly modified way:
If you decide not to go the bot route, you still need to do everything else. You just place the tie the SSH keys you generate into your own user instead. And as long as you have sufficient permissions it will work just fine.
Now that you have pipelines enabled let’s define a simple pipeline that takes whatever is in “master” and merges it to “develop”. The easiest way to it is probably just to copy this one.
# Merges master into development anytime master is updated # Is a bit of hack needed because bitbucket cloud does not, at the time of this creation. # support automatic merges in their cloud product. # Built with lots of trial and error. No promises. # Useful info: https://confluence.atlassian.com/bitbucket/variables-in-pipelines-794502608.html # More guides at https://confluence.atlassian.com/x/5Q4SMw for more examples. # Only use spaces to indent your .yml configuration. # I tried to use variables where possible to keep it generic # Author: Josh Ahlstrom # Initial Creation Date: 2019-03-19 # NOTE: Pay no attention to the image utilized below. I chose dotnet, but it probably doesn't matter # which one you choose since it is script which means we'll be working "from the shell" anyway. # ----- image: microsoft/dotnet:sdk pipelines: branches: master: - step: script: - apt-get update -y - apt-get install git -y - mkdir repos - cd repos # full name variable used to make things generic - git clone git@bitbucket.org:$BITBUCKET_REPO_FULL_NAME - cd $BITBUCKET_REPO_SLUG # variables for git info such as "$GIT_USERNAME" "$GIT_EMAIL" - git config user.name "$GITBOT_USERNAME" - git config user.email "$GITBOT_EMAIL" - git checkout develop - git merge master - git push
Alright, so now let’s talk about what this does. Keep in mind that a pipeline can be thought of as running in it’s own little linux VM. So you’ve got quite a bit of freedom in what you do.
A quick word of caution: pipelines appear to use “build” minutes. I think they should be called pipeline minutes because you don’t actually have to build in a pipeline, but I digress. If I read it correctly, most accounts come with 50 minutes for free. I ran it a BUNCH of times times getting these scripts set up (maybe 20 times or so) which only totaled about 5 minutes. Anyway, if you have limited minutes that’d you’d prefer to use otherwise then this might not be the way to implement automerge for you – but maybe it’ll give you some other ideas.
Here goes. I’ll show some script and then describe what it does for the whole script.
image: microsoft/dotnet:sdk
First, we tell the pipeline that it’s going to run under an image that knows all about dotnet. There is a docker one, a javascript one… lots of options. I don’t think it matters (as noted in the snippit) which one you use because we’re just doing basic shell commands. It appears that all the images can handle that much.
pipelines: branches: master:
You can apply different pipelines to different branches, in this case we just want to apply this pipeline to the master branch.
- step: script:
The first (and only) step in our master branch pipeline is to run a script. This just runs it right on the command line BUT has access to certain variables that you can set up in bitbucket, either at the account level or the repo/pipeline level. Some are also global to bitbucket. More on variables later.
- apt-get update -y - apt-get install git -y
The first two lines of the script just install git.
- mkdir repos - cd repos
The next two lines create a directory for us to clone our repo into and move us into that directory.
# full name variable used to make things generic - git clone git@bitbucket.org:$BITBUCKET_REPO_FULL_NAME
The next two lines (including one comment line) actually clone the repo. We use a bitbucket variable here to make things generic and simple to use on multiple repos. The first variable, $BITBUCKET_REPO_FULL_NAME, returns the full name of the repo including the account number.
- cd $BITBUCKET_REPO_SLUG
Then we “cd” into the repo directory. We use another bitbucket provided variable here, $BITBUCKET_REPO_SLUG. It’s like the shortname of the repo. When you clone a repo from bitbucket and then you look at the directory name it was cloned into… that’s what the value of $BITBUCKET_REPO_SLUG is.
# variables for git info such as "$GIT_USERNAME" "$GIT_EMAIL" - git config user.name "$GITBOT_USERNAME" - git config user.email "$GITBOT_EMAIL"
The next three lines set up the pipeline’s VM git with some made up name and email. This is just because our next step will want to know them.
- git checkout develop - git merge master - git push
The last three lines checkout the branch we want to merge into, merge master into it, then then push that branch back up to bitbucket.
We’re almost done!
You might have noticed I used a couple of variables $GITBOT_USERNAME and $GITBOT_EMAIL. Those two I had to create myself. Again, ideally this would just be the username of your real “bot” but even if it is you would want to store it in a variable. You’d just store it in an account variable instead of a repo one. In any case, to set up the variables in the repository you just go to the repository -> settings -> “scroll down” to pipelines -> “then choose” repository variables. Read the little blurb at the top of that page to see how variables work. Basically, don’t include the “$” in your variable name – you only need that to access your variable in scripts.
Finally, to make this work, the “bot” user (or yourself) will need permission to merge into the TARGET branch directly (ie. without a pull request) in order for all of this to work. So make sure you give whichever “bot” / user that got the SSH key you generated earlier permissions to merge directly. You do that in repository -> settings -> branch permissions.
And that’s it! Place this script into a file called bitbucket-pipelines.yml in the top level of your repo and you’re done!
Now when you merge into master, the pipeline should kick off and your automerge should happen as planned!
I hope you found this useful. If you have ideas on how to improve this please feel free to comment!
The seed that spawned this idea came from a similar solution to a similar problem presented here.