Running PHPUnit tests before git push

What usually happens

“Great, I’ve just finished this new feature and it works perfectly, let’s merge it with the rest of the code so the team can now benefit from it..”

git add .
git commit -m "-blablabla"
git flow feature finish "blabla-feature-name"
git push origin develop

“Oops, I forgot to pass tests after closing the feature branch…”

./vendor/bin/simple-phpunit

...F
FAILURES!
Tests:4... Failures: 1

We’ve all done it before, pushed code that didn’t pass tests…

Pre-Push git hook solution

On this blog post I’ll show you how to set a pre-push script, so every time you push code to your remote repository (develop or master only for this example), it’ll try to run your tests. And as a result, it will only push the code if tests pass.

This is intended to be like a safety net, specially if you’re working with a team and your code needs to be tested before being pushed!

This is what the script file looks like:

#!/usr/bin/env php

< ?php

/**
 * ===========================
 * This hook will only allow git push if your all test pass
 * To activate this hook, you need to place this file in the .git/hooks folder
 * ===========================
 **/


$gitBranch = shell_exec('git branch | grep \*');
$branchName = trim(str_replace('*', '', $gitBranch));
if( $branchName !== 'develop' && $branchName !== 'master' ) {
    echo "You're not in master or develop, so hook tests won't activate.." . PHP_EOL;
    exit(0);
}

echo "Running tests.. ";
exec('./vendor/bin/simple-phpunit', $output, $returnCode);
if ($returnCode !== 0) {
  // Show full output
  echo PHP_EOL . implode($output, PHP_EOL) . PHP_EOL;
  echo "Cannot push changes untill tests are OK.." . PHP_EOL;
  exit(1);
}

// Show summary (last line)
echo array_pop($output) . PHP_EOL;
exit(0);
Note1: Notice the start of script tag < ?php . You will need to remove the white space so PHP interprets the code.
Note2: The name of this file must be pre-push and must be located inside the .git/hooks folder in your project. This is because git will look for that actual file before pushing.

So if we dive into the code, it's pretty simple.

The first block looks in what branch you're located. I've just set up this script to run tests when you try and push to develop or master. You can modify/delete this part if you want a different behaviour.

The second block is the actual running of the tests. This only runs if you're located in develop or master.

As you can see, if return code after running tests is different than 0, AKA a tests failed, it'll exit the script with an exit(1), letting git know it must not push the code.

If all test pass, it'll exit with an exit(0) and so, the code will be pushed.

And that's it! Simple right?

There are other git hooks that might be useful for you. Try looking at the .git/hooks folder for samples (pre-commit, pre-rebase, pre-receive...) and let me know if you use any other ones!

Cheers and safe coding! 🙂