The Cookbook: Build Matrix
Tags: news, feature, infrastructure, community
Published: 2021-02-11 10:53:30

---
title: "The Cookbook: Build Matrix"
created_at: Monday 8 Feb 2021 15:00:00 EDT
author: Montana Mendy
layout: post
permalink: 2021-02-08-build-matrix
category: news
excerpt_separator: <!-- more --> 
tags:
  - news
  - feature
  - infrastructure
  - community
---

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/rhaovmrn9c32jo54xy4b.png)

A build matrix in Travis is made up by several multiple jobs that run in parallel. This can be useful in many cases, but the two primary reasons we see people use matricies is for reducing the overall build execution time and running tests against different versions of runtimes or dependencies to get the best version of the build. Let's learn about Build Matricies in Travis CI. 

<!-- more --> 

# Build Matrix and setting up the .travis.yml

As you know by now, you need to tell Travis which language environment to select for your project. You can do so using the `language` key option, in this Cookbook we'll be using PHP. You can specify which PHP versions will the tests be executed. Not introducing patch versions tells Travis to use the latest available, which is sometimes referred to `edge`, or if it's the stable version, you guessed it, it's called `stable`. So let's start building out our `.travis.yml`: 

```yaml
language: php

php:
  - 5.3.3
  - 5.4
  - 5.5
  - 5.6
  - hhvm
```

# Env Vars

Let's tell Travis to do multiple runs/builds with different sets of `env var` values. To do so, add an `env key`. Each segment is understood as a different environment and tests are run separately as such. We are going to use `PHP_SEGMENT_TEST` later in the file to run tester with the argument of `-p` and `hhvm` option in HHVM environment, so in your `.travis.yml` file, add the `env` segment:

```yaml
env:
  - PHP_SEGMENT_TESTRUN="php-cgi"
  - PHP_SEGMENT_TEST="hhvm"
```
Now simple math would have it, the combination of five PHP versions and the two `env vars` generates a total of 10 runs.

# Dependency installation using Composer

You'll obviously have an install segment in your `.travis.yml`. Each sub-segment means one single command. Composer installs your dev dependencies by default. You should use --no-interaction so Composer doesn't ask questions Travis can't answer, and can continue the build. 

You'll want the latest build, so in you `.travis.yml` make sure you run the `update` flag at `before_install`, so it would look like:

```yaml
before_install:
  - composer self-update

install:
  - composer install --no-interaction 
  ```
  
# The Build Matrix 

Depending on the configuration above (different segments and sub segments), a build matrix wil be generated. The matrix contains all combinations the environment settings. A single combination is called a job and is run separately. You can modify the matrix in matrix section.

If you want to exclude a job, use the `exclude` key. In our case, we don't want to use -p hhvm parameter for standard PHP versions and -p php-cgi for HHVM:

```yaml
matrix:
  exclude:
    - php: 5.3.3
      env: PHP_SEGMENT_TEST="hhvm"

    - php: 5.4
      env: TPHP_SEGMENT_TEST="hhvm"

    - php: 5.5
      env: PHP_SEGMENT_TEST="hhvm"

    - php: 5.6
      env: PHP_SEGMENT_TEST="hhvm"

    - php: hhvm
      env: PHP_SEGMENT_TESTRUN="php-cgi"
  ```
  
To your pleasure, you can define jobs that are allowed to fail without causing the whole build to shown as failed. To do so, declare allow_failures. For our sake, we allow HHVM to fail, lets do this via: 

```yaml
matrix:
  allow_failures:
    - php: hhvm
```

I only specified the PHP version, not the environment variables. This means all jobs with HHVM version will be allowed to fail/retry (if that is an option you have in your `.travis.yml`. Anyway, nevermind the environment variables values. It works with `exclude` also.

# Running the scripts/tests 

Tests are run in script segment of the `.travis.yml`. Let's assume your tests are in `scripts/` folder in your file tree and you provide your own `php.ini` in the same folder. Additionally, we can tell `TESTER` to display information about skipped tests with the `-s` flag and to use value of earlier declared `TESTER_SEGMENT_TEST` as PHP binary with the -p flag:

```yaml
script:
  - ./vendor/bin/tester -p $TESTER_SEGMENT_TEST -s -c ./tests/php.ini ./tests
```
If the build `fails` we want to use `after_failure` to get the exact values via: 

```yaml
after_failure:
  # Prints *.actual files contents (if not revert) 
  - for i in $(find ./tests -name \*.actual); do echo "--- $i"; cat $i; echo; echo; done
 ```
 
# Other services 
 
 Travis comes with multiple popular services and has no shortages of them, (e.g. MySQL, Redis, Docker) pre-installed. However, if you need to use for example Redis storage, you can tell Travis in services section via:
 
 ```yaml
 services:
  - redis-server
 ```
 
# DB Init 
 
 Depending on what database you chose to use, it can vary -- in this example we are using `MySQL`. MySQL runs on 127.0.0.1 and you can log in using travis or root as username. Say you have a DB setup script, and it's in `tests/montana/testbase.sql.`, here's a sample segment: 
 
 ```yaml
 before_script:
  - mysql -u root -e 'CREATE DATABASE testbase;'
  - mysql -u root testbase < tests/montana/testbase.sql
  ```
  
# .travis.yml in it's final form 

After a lot of this segment config, this is what you're left with: 

```yaml
language: php

php:
  - 5.3.3
  - 5.4
  - 5.5
  - 5.6
  - hhvm

env:
  - TESTER_SEGMENT_TEST="php-cgi"
  - TESTER_SEGMENT_TESTRUN="hhvm"

matrix:
  allow_failures:
    - php: hhvm

  exclude:
    - php: 5.3.3
      env: TESTER_SEGMENT_TEST="hhvm"

    - php: 5.4
      env: TESTER_SEGMENT_TEST="hhvm"

    - php: 5.5
      env: TESTER_SEGMENT_TEST="hhvm"

    - php: 5.6
      env: TESTER_SEGMENT_TEST="hhvm"

    - php: hhvm
      env: TESTER_SEGMENT_TESTRUN="php-cgi"

services:
  - redis-server

before_install:
  - composer self-update

install:
  - composer install --no-interaction --prefer-source

before_script:
  - mysql -u root -e 'CREATE DATABASE testbase;'
  - mysql -u root testbase < tests/montana/testbase.sql

script:
  - ./vendor/bin/tester -p $TESTER_SEGMENT_TEST -c ./tests/php.ini -s ./tests/

after_failure: # to find actual variables if needed, a verbose esque way of doing things
  # Prints *.actual files content
  - for i in $(find ./tests -name \*.actual); do echo "--- $i"; cat $i; echo; echo; done
 ```
  
# Activate webhook 

Go to www.travis-ci.com, and flip switch to `ON` for all repositories you'd like to enable. Travis will now add your repository to queue after every pushed commit or created pull-request. After a short while, your repository will be tested. Now if you'd like the opposite, there's a bash script I've created, which I will attach right below this - as some people find this more efficient: 

```bash
#!/usr/bin/env sh

echo "Hello from Montana at Travis"
echo $TRAVIS_PULL_REQUEST

if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
  surge --project ./dist --domain auto-deploy-test.surge.sh
else
  echo "This is a PR, not deploying"
fi
```
To know if your build is successful either check the GitHub status, or generate a status image. 

# Congratulations 

This is Travis's Build Matrix in a nutshell, it can seem a bit confusing but after going over it a few times, it will start to make sense.