Published on May 2, 2018
4 min read
Here's how we went from a daily manual merge of GitLab Core into GitLab Enterprise to automated merges every three hours.
GitLab is an open source project, but also a commercial project. For historic
reasons, we have two Git repositories: gitlab-ce
for GitLab Core and
gitlab-ee
for GitLab Enterprise packages (you can read our recent blog post explaining GitLab self-managed tiers).
While we're working on having a single codebase, we still need to regularly
merge gitlab-ce
into gitlab-ee
since most of the development happens on
GitLab Core, but we also develop features on top of it for GitLab Starter, Premium, and Ultimate.
Until December 2017, the merge of gitlab-ce
into gitlab-ee
was manual
on a daily basis with basically the following commands (see the full documentation):
# the `origin` remote refers to https://gitlab.com/gitlab-org/gitlab-ee.git
# the `ce` remote refers to https://gitlab.com/gitlab-org/gitlab-ce.git
git fetch origin master
git checkout -b ce-to-ee origin/master
git fetch ce master
git merge --no-ff ce/master
At this point, since we'd merge a day's worth of GitLab Core's new commits,
chances were good we'd see conflicts.
Most of the time, the person responsible for this process would handle the
conflict resolutions, commit them and push the ce-to-ee
branch to GitLab.com.
There were a few problems with this approach:
Our plan was to have a single script that would automate the merge, and in the case of conflicts, identify the person best suited to resolve each of them. It would then create the merge request using the GitLab API and a GitLab API Ruby wrapper, and post a message in Slack when a new merge request was created or an existing one was still pending.
Finally, we'd use GitLab's pipeline schedules to run the script every three hours.
We chose to write the script in our release-tools
project, since it already
had a strong foundation for working with the relevant Git repositories.
This script was written iteratively as a set of classes over the course of a few months:
Project
classes and get rid of the Remotes
classhead
, status
, log
, fetch
, checkout_new_branch
, pull
, push
, and merge
to RemoteRepository
CommitAuthor
classThe last piece of the puzzle was the new upstream_merge
Rake task.
gitlab-ee
projectUnder Repository Settings > Deploy Keys of the gitlab-ee
project:
release-tools
projectUnder CI / CD Settings of the release-tools
project, create three secret
variables:
AUTO_UPSTREAM_MERGE_BOT_SSH_PRIVATE_KEY
for the SSH private keyGITLAB_API_PRIVATE_TOKEN
is a personal access token for our @gitlab-bot
userSLACK_UPSTREAM_MERGE_URL
which is the Slack webhook URL we created
specifically for this job and used in our Slack::UpstreamMergeNotification
classupstream_merge
Rake task for pipeline schedules onlyThis was heavily inspired by GitBot – automating boring Git operations with CI.
Create a new upstream-merge
CI job that:
~/.ssh
foldergitlab.com
to the ~/.ssh/known_hosts
filebundle exec rake upstream_merge
You can check out the task for yourself.
Under Schedules of the release-tools
project:
The CI job:
The Slack messages:
The merge request:
Since we started automating this process in December 2017, our dear
@gitlab-bot
created no fewer than 229 automatic merges, and we started
noticing the benefits immediately:
The last, perhaps least visible, but most important benefit, is that we reduced developer frustration and increased happiness by removing a tedious chore.
Find out which plan works best for your team
Learn about pricingLearn about what GitLab can do for your team
Talk to an expert