Getting Build Status for Merge Requests on GitLab with Bitrise & Other CI Tools

Mehmed Mert
9 min readMar 28, 2019

In agile software development, a very often used method for sharing knowledge about the code across the team members, verifying the quality and making decisions if necessary is the code review. Mostly this is done technically by using merge requests (or pull requests, MR/PR), which is supported by most of the popular source code hosting and versioning (VC) services like GitLab, Bitbucket etc. On the other hand, Continuous Integration (CI) and the necessary tools are also an indispensable part of modern software development.

Furthermore, these two methods are also combined together by many teams, as the unit tests, integration tests etc. are run as part of the CI build process when a merge request was created by a team member, in order to achieve even more safe feeling about code changes. So, when someone creates an MR, the corresponding CI workflow is run, the status is shown and depending on the result the developers can decide whether to accept or to decline the MR. Most of the modern VC services (e.g. GitLab, Bitbucket) come up meanwhile with an integrated build module for CI and the feature I just described is available out of the box. But in some cases, development teams still can’t or don’t want to make use of the integrated CI feature due to various reasons and have to get the CI done by an extra service.

In this article, I want to share with you my experience in the case described above and show you how to get the build status on your VC service from your CI system, in the concrete example with GitLab & Bitrise. I don’t want to go into details and explain how GitLab & Bitrise in general works since this is a topic for another article.

Getting Status via “GitLab status” Step

In bitrise, there is a standard step called “GitLab status” which you can use out of the box for getting the build status for your merge requests or even for tracking the status of all the commits (depending on how the build workflow on bitrise is set up):

In order to make this step work, it’s necessary to provide some information about your GitLab system and a token for authentication:

Let me shortly explain each of the required (and optional) fields and where to get them from:

GitLab API base URL (required)

It is the URL to the API of your project on GitLab, no matter if it is hosted on a private server or on the GitLab cloud. It consists of the following information:

https://[base URL of your GitLab host]/api/v4/projects/[the project id]

The base URL of your GitLab host is something you should know.

The second part with “/api/v4/projects/” is the actual link to the API of your project. Note that the latest version of the API is “v4” and if your GitLab (when hosting on a private server) is up to date, this should be fine.

It is also not that tricky finding out the project id — you can see it directly under the project title in the home page of your project.

GitLab private token (required)

This the token, that is used for authentication by the API call. If you haven’t created one before, you have to create one by navigating to the GitLab profile settings → access token. You’ll be shown following screen:

After entering a name and an expiration date you have to select (at least) the “api” option in order to give the necessary rights for API calls associated with the new access token.

Furthermore, you could consider using a dedicated CI profile (if not using one already) and create the access token for it, in order not to reveal your personal access token to the CI system and the people using it.

Important note: After you’ve created a token make sure that you store it temporarily somewhere or create immediately a secret environment variable in Bitrise and reference it in the step. Don’t copy & paste it in clear text into the field! For that, you can easily create one by clicking on the field and a dialog will be shown where you can set the name and the value of the variable:

After you confirm, the field will be automatically referenced to the variable.

Repository URL (required)

As the name suggests, it’s the URL to your GitLab repository. Luckily, you get it entered for free from Bitrise as an environment variable — GIT_REPOSITORY_URL — and normally you don’t have to and even shouldn’t change it.

Commit hash (required)

This is the git commit hash for which the status is supposed to be reported to GitLab and as the repository URL, you get it for free from Bitrise — it is the BITRISE_GIT_COMMIT environment variable and is entered already by default.

Target URL

The URL provided there serves as a link to the build from GitLab pipelines page. Although this is an optional field, I would suggest to not remove the provided by default value there — BITRISE_BUILD_URL — so that you can navigate from GitLab UI directly to the page of the build, especially useful when a build fails and you want to look for more failure details.

Context

This is a label for GitLab to differentiate the status from the status of possibly other systems. The default value set for the step is Bitrise, but you can practically name it however you want.

Set Specific Status

This is also an optional field, where you can set additionally a specific status, which could be one of the following: auto, pending, running, success, failed, canceled. It is auto by default and if not changed to something else, it would report the current build status. And if your GitLab status step is the last one in your workflow, depending on the outcome of the build it will be either success (if no steps failed before) or failed.

So, in order to get status “running” you need to specify this additionally since it’s not possible to get it automatically with auto. I’m gonna explain a bit later when to use which status.

Description

This field is for a short description of the status. You have here the possibility to describe additionally the status, for example, if it’s a failure, you can specify with this an explanation of the reason for it, like failed unit tests etc.

Usage in a workflow

After you’ve got a basic idea of what kind of parameter the step has, you may now imagine how it should be used in your workflow. It’s plausible that you need to use this step at least two times in your workflow — once to mark the build as running and once to indicate the result as successful or failed. The key parameter here is, of course, the specific status. You can use auto to report the result of the build — as described above, depending on the previous steps in the workflow, it will report either success or failure to GitLab. The current version of the step (0.9.4) however is implemented so, that when auto is used somewhere else than at the end of the workflow, it will report always a failure (since it checks actually if the return value of the script is equal to 0. And if not, it sends a “failure”). This means, in order to mark your build as running, you need to specify this extra.

Conclusion

In order to get the build status for your merge requests and also for the commits at all, you can use the “GitLab Status” step in the corresponding Bitrise workflow — once at the start and once at the end. All you need is to provide the required parameters for the step properly — “GitLab API base URL”, “GitLab private token”, “Repository URL”, “Commit hash”. The step at the start though should specify the status running. In contrast, the step at the end can simply use the status auto.

Getting Status via a Custom Script

However, the standard “GitLab Status” step developed by the Bitrise has unfortunately still some issues and I wasn’t able to get it to work properly (btw., there is even an issue that a reported on the steps repository page — https://github.com/bitrise-steplib/steps-gitlab-status/issues/11). This situation led me to look for and find another solution — to use the GitLab Commits API, which is also the GitLab Status step based on, and to make calls to it directly with proprietary shell scripts.

The GitLab Commits API

The GitLab Commits API basically provides the necessary interface to interact with, in order to achieve our goal. All you need to do is to make a curl call for the build status to a commit providing the required parameters properly, similar to the field described above:

curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/17/statuses/18f3e63d05582537db6d183d9d557be09e1f90c8?state=success"

The custom Script for the commit status

After figuring out the call for build status to a commit in the GitLab Commits API it wasn’t very hard to write down a shell script using the variables provided by the Bitrise environment. The idea, though, is again to make one call at the begin of the scrip and one at the end. Here how both scripts look like:

# call indicating the build as "running" (at the begin of the workflow):curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" "https://gitlab.example.com/api/v4/projects/$GITLAB_PROJECT_ID/statuses/$BITRISE_GIT_COMMIT?state=running&target_url=$BITRISE_BUILD_URL"# call for reporting the result of the build (at the end of the workflow):if [ $BITRISE_BUILD_STATUS == "0" ]
then
curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" "https://gitlab.example.com/api/v4/projects/$GITLAB_PROJECT_ID/statuses/$BITRISE_GIT_COMMIT?state=success&target_url=$BITRISE_BUILD_URL"
else
curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" "https://gitlab.example.com/api/v4/projects/$GITLAB_PROJECT_ID/statuses/$BITRISE_GIT_COMMIT?state=failed&target_url=$BITRISE_BUILD_URL"
fi

Note that GITLAB_PROJECT_ID is not a standard Bitrise environment variable, but it was defined by me.

In order to include those scripts in your workflow, you can use the standard “Script” step provided by Bitrise:

Important also to note, that for the script for the end of the workflow should be turned on the option “Run if the previous Step failed”, otherwise the result of the build won’t be sent to GitLab when some of the steps in between fail:

Conclusion

The solution with a custom script for getting the build status on GitLab worked so far well for me. Except on Bitrise, you could theoretically use it also on other CI tools as long as you provide the required parameters to the API call. However, also this solution has some problems and/or limitations which I’ll try to describe in the last section of my post.

Troubles and Limitations

Although the approach with a custom script worked, there are still some troubles and limitations with Bitrise for the usage of the GitLab Commits API.

In general, there is no possibility to indicate all kind of statuses, like for canceled or waiting builds.

Zombie builds running forever

Since we have to do at least two requests to indicate the status of a commit it is quite possible that the second request for completion of the build doesn’t take place due to whatever reason (for example canceled builds), although the build is run to the end. In such a case we would see on GitLab the build “running” and if it is not the latest commit for the branch, the status would remain forever (until we “cancel” it on GitLab manually). The other option is to restart the build for the same commit in Bitrise and make sure that this time the API call for the build outcome will take place.

No waiting builds

In Bitrise, if there are builds in the queue waiting to be started, there is no way to indicate that somehow to external services, like GitLab, since no build-code is run until the time it is started because of its architecture. And after the build is started, it doesn’t make any sense to indicate it as “waiting”.

--

--