Using for Static Code Analysis & Regression Testing

June 30, 2017

Tags:Platformsh,Quality Assurance is a PaaS platform with support for deployments using git push. The platform currently provides support for PHP, NodeJS, Python and RoR applications (beta), along with associated services like search (Solr, Elasticsearch), databases (Postgres, MySQL, MongoDB), queuing (RabbitMQ) and caching (Redis). The platform is an excellent choice for setting up a development, staging and production environment very quickly and having a robust workflow set up for continuous integration and delivery.

At Axelerant, we are big fans of automation, and in this article, we will see how we can use along with GitLab, Pronto and Behat to set up a workflow wherein the pushed code will go through static code analysis, followed by regression testing.

Our project for this article is going to be a PHP Slim application called HelloUser. The objective of this project is to build a small web app which responds to the user with ‘Hello’ along with their name.

Let’s start off by setting up GitLab.

Create a new project called HelloUser in GitLab.


As soon as we click on the ‘Create project’ button, we’ll have our new project ready to be used.


Copy the Git URL and start your favorite command line tool (I used Mac OS X and terminal for this purpose).

Create a directory called hellouser and move into it. This is where we’ll be storing our code base.

To be able to sync everything we do locally on our workstation with our GitLab server, we’ll need to set up Git. Follow these steps to complete the setup:

Initialize a Git repository      - git init

Add a remote called gitlab  - git remote add gitlab

Now let’s go ahead and set up

Log in to by visiting and choose to create a new platform.

The following screenshots describe the actions you’ll need to perform in order to get a new project set up on


Select the ‘Add A Platform’ link.


Choose the appropriate subscription plan. We are going to use the Development plan offered by More details about subscription plans and pricing can be found at


Choose the region where you want your infrastructure to be provisioned. This can have an impact on latency, so choose the region closest to your users.


Specify the name of the project. In our case we are using ‘HelloUser’ as the name of the project.


Since we have a code repository already set up for the project, we are going to choose the ‘Import your existing code’ option.


Click on the ‘Continue Later’ link and go to the Account Setting section to generate an API token:


Also set up your SSH Keys right now to allow access to servers using SSH.


We’ll need this API token and SSH key pair later on while configuring the setup to do a push to

Before we start off coding our application, we’ll need to add a couple of environment variables to our project in GitLab.

1. DOCKER_AUTH_CONFIG – This variable contains the Docker authorization configuration to allow the CI jobs to pull Docker images from private repositories. Here is a sample value which can be provided against this key:


"auths": {

"": {

"auth": "XXXX"




Look into ~/.docker/config.json on your machine to know what values to use for this key.

2. PLATFORM_PROJECT_ID – This variable contains the project id of the project we had setup on

Let’s get started with coding our application.

Fire up your favorite editor and create a file called composer.json in the hellouser directory which we had created earlier.


 "require": {

   "slim/slim": "3.*"



Create a .gitignore file


Finally let’s write our application code in a file called index.php


 require __DIR__ . "/vendor/autoload.php";


 $app = new Slim\App;


 $app->get('/', function($req, $resp) {

   $resp->getBody()->write(“Welcome to HelloUser app. Try /YOUR-NAME!”);

   return $resp;



 $app->get(‘/{name}, function($req, $resp) {

   $name = $req->getAttribute(‘name’);

   $resp->getBody()->write(“Hello, $name”);

   return $resp;



With our code in place, let’s focus on writing our behat test case. For more information about test driven development you might want to check articles with the QA tag at

Create a folder called behat and create the following files:

1. behat/behat.yml




   '': %paths.base%/features/bootstrap




       - FeatureContext


       - %paths.base%/features



       browser_name: 'phantomjs'

       goutte: ~

       javascript_session: selenium2



       base_url: ENV_BASE_URL

2. behat/features/hellouser.feature

Feature: Sample test



   Given I am on the homepage


 Scenario: Test home page

   Then I should see "Welcome"


 Scenario: Test a user page

   When I am on "/avni"

   Then I should see "Hello, foo"


3. behat/features/bootstrap/FeatureContext.php



use Behat\Behat\Context\Context;

use Behat\Behat\Context\SnippetAcceptingContext;

use Behat\Gherkin\Node\PyStringNode;

use Behat\Gherkin\Node\TableNode;

use Behat\MinkExtension\Context\MinkContext;



* Defines application features from the specific context.


class FeatureContext extends MinkContext implements Context, SnippetAcceptingContext




    * Initializes context.


    * Every scenario gets its own context instance.

    * You can also pass arbitrary arguments to the

    * context constructor through behat.yml.


   public function __construct()




4. Edit composer.json and add the following code segment to it:

"require-dev" : {

   "behat/behat" : "3.0.*",

   "behat/mink-goutte-driver" : "*",

   "behat/mink-browserkit-driver" : "*",

   "behat/mink-extension" : "2.*",

   "behat/mink-selenium2-driver" : "*",

   "behat/mink" : "*"


 "config": {

   "bin-dir": "bin/"





export ENV_BASE_URL=`cat scripts/platform.url`



echo "---Setup behat---"

composer install

bin/behat --init

cp -r behat/features/* features; cp behat/behat.yml behat.yml

sed -i 's@ENV_BASE_URL@'"$ENV_BASE_URL"'@' behat.yml

sed -i 's@ENV_PROJECT@'"$CI_PROJECT_NAME"'@' behat.yml

echo "---Starting behat---"

bin/behat features/${CI_PROJECT_NAME}.feature


Now it’s time to integrate everything.


Create a file called scripts/

#!/usr/bin/env bash

set -e


# This script can be configured by specifying different environment variables in

# your .gitlab-ci.yml file's invocation of the script. If those are omitted, as

# in this example, the defaults below and throughout the script should be used.


# Check basic requirements from Config.

if [ -z "$PLATFORM_PROJECT_ID" ]; then

 echo "PLATFORM_PROJECT_ID is required, please contact support if you don't know how to do it."

 exit 1



# By default we use master as the Platform parent env.



# By default we don't allow master to be deployed.



# Prepare the variables.



# Platform command path.

CLI_CMD=${CLI_CMD:-"$HOME/.platformsh/bin/platform --yes"}


if [ -z "$PF_BRANCH" ]; then

 echo "Source branch (CI_BUILD_REF_NAME or PF_DEST_BRANCH) not defined."

 exit 1



# This script is not for production deployments.

if [ "$PF_BRANCH" = "master" ] && [ "$ALLOW_MASTER" != 1 ]; then

 echo "Not pushing master branch."




# Set the project for further CLI commands.




# Push to PS.

COMMAND_PUSH="${CLI_CMD} push --verbose --force --target=${PF_BRANCH}"

if [ "$PF_PARENT_ENV" != "$PF_BRANCH" ]; then

 COMMAND_PUSH="$COMMAND_PUSH --activate --parent=${PF_PARENT_ENV}"




# Clean up already merged and inactive environments.

COMMAND_CLEANUP="${CLI_CMD} environment:delete  --verbose --inactive --merged --environment=${PF_PARENT_ENV} --exclude=master --exclude="${PF_BRANCH}" --yes --delete-branch --no-wait || true"



# Store url of new environment in a file

${CLI_CMD} environment:url -e $CI_BUILD_REF_NAME --pipe | head -1 > scripts/platform.url


Let’s create a .gitlab-ci.yml file.



- push-to-platform

- execute-behat





- docker:dind



 image: maxc0d3r/platformshcli:maxc0d3r



   PF_PARENT_ENV: "master"


 stage: push-to-platform


 - chmod +x ./scripts/

 - script -q -e -c "./scripts/"



   - scripts/platform.url

   expire_in: 1 week


   - autoscaler



 image: maxc0d3r/behat

 stage: execute-behat


 - echo "---Starting behat---"

 - ls -lR

 - chmod +x ./behat/

 - script -q -e -c "./behat/"


   - autoscaler


We are making use of two Docker images for our jobs:


This is a private Docker image which can be usedto push code to The code used to build this Docker image is available at Fork the repository, modify the code as described in the README and create your own Docker image for use. You’ll need an API token and the SSH Key pair which we’d generated earlier while setting up the project on We are also using the autoscaling feature of GitLab, and the runners are tagged as autoscaler. We’ll cover more on how to set up autoscaling of GitLab runners in another post.


This is a publicly available Docker image with dependencies required for the installation of behat. The code used to build this Docker image is available at

We are generating an artifact in the deploy-hellouser job called scripts/platform.url. This file will contain the URL of the application when it’s deployed to We will be using this file to know the URL in test-hellouser job and configure behat to test against this URL.

Let’s push our code, and voila, we can see the pipelines in action.


So our pipeline failed in the second stage, that is test-hellouser. Let’s look at our job details to see the reason for failure: image11.jpg

Great! So our test failed because it was meant to fail. Let’s push a change into our feature file (behat/features/hellouser.feature):

Feature: Sample test



   Given I am on the homepage


 Scenario: Test home page

   Then I should see "Welcome"


 Scenario: Test a user page

   When I am on "/avni"

   Then I should see "Hello, avni"


Let’s look back at our pipelines:


Cool! So we have our test cases passing now. We’ll be adding more features into our setup, like static code analysis, in the future. Keep visiting our team blog to know what’s cooking.