Applying GitLab Labels Automatically

Brian O'Connell ·
Aug 19, 2016 · 4 min read

This is a customer story on how Brian uses GitLab Webhooks to apply labels automatically to his projects' merge requests.

This article follows up his previous post, on how using GitLab Labels helps him to direct focus and improve his workflow.

Automatic application of GitLab Labels

In my previous post I described how to use GitLab Labels to easily triage. @shochdoerfer asked me:

@boc_tothefuture how can @GitLab labels be applied automatically for issues or merge requests?

A quick webhook server

We use GitLab webhooks to automatically apply labels to incoming merge requests (MRs). To process the webhooks, we wrote a simple webrick server whose process is supervised by runit and the incredibly well written runit cookbook.

Adding labels automatically

Using the Webrick as a base it’s fairly easy to get labels added to your MRs when they are opened. When the request comes in to your webrick server, look at the GitLab object_kind to see if it's a MR.

def merge_request?(request_body)
  body['object_kind'] == 'merge_request'

If the code is a merge request, the next step is calculate the labels that should be applied to the MR. In our case that is a ‘Needs Review’ label if the MR is just being opened. Then because we use Semver and thor-scmversion we just scan all the commit messages for #patch, #minor and #major to apply the appropriate Semver tag to the MR.

You will need a valid GitLab API key to modify and or request data about a MR.

def update_labels(gitlab_server, api_key, request_body )
  project_id = request_body['object_attributes']['target_project_id']
  request_id = ['object_attributes']['id']
  labels = ['Needs Review'] if request_body['object_attributes']['action']
  semver_increment = semver_increment(gitlab_server, api_key,request_body )
  labels += semver_increment if semver_increment

  merge_data = {id: hook_id(hook), project_id: project_id(hook), labels: labels.to_a.sort.join(',')}
  url = "#{gitlab_server}/api/v3/projects/#{project_id}/merge_requests/#{request_id}?private_token=#{api_key}"
  RestClient::Request.execute(:method => :put, :payload => merge_data, :url => url)

def semver_increment(gitlab_server, api_key, request_body)
  from_branch = request_body['object_attributes']['target_branch']
  to_branch = request_body['object_attributes']['source_branch']
  project_id = request_body['object_attributes']['target_project_id']

  params = { private_token: api_key, from: from_branch, to: to_branch }
  url = "#{gitlab_server}/api/v3/projects/#{project_id}/repository/compare"
  changelog = JSON.parse(RestClient::Request.execute(:method => :get, :url => url, :headers => { params: params }))
  changelog = (changelog['commits'] || []).map { |commit| commit['message'] }
  return 'Major' if changelog.any? { |msg| msg.include? '#major' }
  return 'Minor' if changelog.any? { |msg| msg.include? '#minor' }
  return 'Patch' if changelog.any? { |msg| msg.include? '#patch' }

Pro tips

You will need to do some extra work to make this work on updates. For updates you will need pull the current labels and merge them where appropriate. This is necessary to update the labels when a subsequent commit to the MR takes it from a #patch to a #minor or #major.

You should thread your webrick server so the processing of the updating of incoming requests is in an different thread than the accepting of webhooks from GitLab. If you don’t do multi-thread you may run into issues where GitLab resends the webhooks because of a timeout. The default timeout in GitLab is 10 seconds. Simple threading with rubythread and a queue should be sufficient.

Thanks to my colleague Cameron McAvoy who added the label processing to the original webhook server I wrote.

This post was originally published by Brian O'Connell himself.

Open in Web IDE View source