07 December 2016

GitLab CI with Behat

Getting up and running with GitLab's CI is simple, but figuring out the more technical details and how to keep things simple can take some time. If you are not yet familiar with GitLab CI, the docs would be a good place to start.

This example uses a basic Docker PHP image, shows you how to pull other repositories using a secret SSH key, change some PHP settings, install Composer, and then run Behat. We are not going to use MySQL to build an entire site, so Behat will be running against a persistent development site that sits elsewhere.

Here is the skeleton for our .gitlab-ci.yml, in a repository containing a Drupal site:

# Select an image from https://hub.docker.com/_/php/.
image: php:5.6

# Cache the folder where Composer will be installing dependencies to.
  - tests/vendor/

# All the setup that every possible task we'll be doing gets done here.
- apt-get stuff
- ssh-agent stuff
- git clone our test repo
- configure PHP
- get composer
- run composer

# We only have one task, a test to run Behat.
  - export behat params and run features

Let's go fill in the pseudo-code with some some real commands and provide details for some of the more fancy stuff.


- apt-get -qq update
- apt-get -qq install git unzip > /dev/null

We want apt-get to not clutter the output with normal debug messages, so we use -qq, which should suppress all normal messages. There's a catch though, messages from dpkg still come through, so we redirect stdout to /dev/null to squelch those. We know what apt-get does and we don't want to scroll through walls of text when checking up on our build status in the GitLab UI.

Git will be used to clone our separate test repository, but if your tests are already in with your codebase, then you can leave this out.

Unzip, while not required, is preferred by Composer to fetch packages.


If you need to fetch another repository, you will need access to a top secret private/public SSH keypair. Thankfully, there is a special section in the GitLab CI docs that covers this.

  1. Create a new SSH key pair with ssh-keygen
  2. Add the private key as a Secret Variable to the project
  3. Run the ssh-agent during build to load the private key.

You will obviously also want to add the public key as a deploy key to your other project, in our case a repository containing Behat tests.

# Run ssh-agent
- eval $(ssh-agent -s)
# Add ssh key stored in SSH_PRIVATE_KEY variable to the agent store
- ssh-add <(echo "$SSH_PRIVATE_KEY")
# Disable host key checking (NOTE: makes you susceptible to man-in-the-middle attacks)
# WARNING: use only in docker container, if you use it with shell you will overwrite your user's ssh config
- mkdir -p ~/.ssh
- echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config

You should now be able to clone you other repository, in our case we do that into a directory named "tests".

- git clone git@gitlab.com:path-to-tests.git ~/tests


There is one specific PHP error that Behat made when being run, that of a missing timezone. The GitLab CI docs have a section on how to add a custom php.ini file.

- echo "date.timezone = Pacific/Auckland" > /usr/local/etc/php/conf.d/test.ini


- cd /usr/local/bin && curl -sS https://getcomposer.org/installer | php -- --filename=composer
- chmod +x composer
- cd ~/tests && composer -q install

If your tests are accessible to the main repository, just cd back to ~, if they are elsewhere, cd to that location. We use --quiet to hide a few dozen lines of noise from Composer too, but be aware that this also suppresses errors. So if you need to debug something going wrong with this step, remove the -q. You also don't have to do a global install for Composer or make it executable, but I prefer to have things looking clean.


I found that GitLab CI doesn't output colours for Behat in the UI, so I took a look in the Behat docs and found a flag that could be used to force colours to be shown:

Behat tries hard to identify if your terminal supports colors or not, but sometimes it still fails. In such cases, you can force behat to use colors ...

Since we don't set up Selenium or PhantomJS in this example, exclude @javascript when you run your tests. You might also want to setup your BEHAT_PARAMS if needed. And it doesn't hurt to run init either.

- bin/behat --init
- BEHAT_PARAMS='{"extensions":{"Behat\\MinkExtension":{"base_url":"http://www.example.com/"}}}'
- bin/behat --colors #or
- bin/behat --tags '~@javascript' --colors

Watch it run!

You should now have enough in your CI YAML file to run your tests on every commit. When another developer breaks the build, you'll be the first to know.

GitLab CI terminal output

Of course, as stated at the beginning, we're not building an entire Drupal site with files and a database, so if you have a dedicated development or testing server, point Behat at it until you figure the rest out.

Hopefully we'll come back soon with a "part 2" and trigger the tests to run in a completely sandboxed environment.

By Dieuwe de Boer