Pre-commit hook in Git: Running PHPUnit

Pre-commit hooks in git are one of those things you hardly think about but can help you automate tasks and do last-minute checks.
A good example of this is running unit tests before commits, to make sure nothing broke; or checking your files using PHP_CodeSniffer.

With [DocBlox][1] I use them to run my unit tests as I personally believe these should be ran (and fixed!) before any commit.

> _Please note: contrary to Subversion pre-commit hooks are those used by Git installed locally. This is quite logical but makes it a little harder to enforce certain policies._

What is a hook in Git?
——————————————————-

Hooks in Git are, as with Subversion, command line scripts which are executed at a pre-determined moment. Because these are plain scripts they enable you to write the intended functionality in any programming language.

> _In this article we will be writing a pre-commit hook for use under Linux. Under Windows you will need to copy the code into a file different from your hook-file and invoke that using the following command:_
>
> php -f
>
> _That will ensure execution under Windows._

In this article we will only talk about the Pre-commit hook; though Git knows a total of [16 different hooks] [2] at time of writing. All these hooks are used in the same way and should pose no challenge after reading this.

> _The Pre-commit hook is a script that runs before your commit is actually resolved; it is possible to abort the commit if an exit code other than 0 is provided. More on this later in this article._

All client-side hooks (git actually has some server-side hooks as well) can be found in the _.git/hooks_ folder of your project. During initialization of your repository has your folder been populated with example hooks; among which the pre-commit. These sample hooks are disabled and can be enabled by removing their _.sample_ extension.

We will do no such thing; we intend to create a new file.

Creating a new hook
———————–

A hook in Git must:

* have the exact name as specified for the intended hook; which is in this case `pre-commit` (if you have no such file, create it now)
* be executable; it is acceptable to set the permissions of a hook to 0x777, which can be done using the following command

chmod 777 .git/hooks/pre-commit

After you have created the new file for your hook (you did do this by now, right?) we start by adding the first two and most important lines of code:

#!/usr/bin/php
<?php

That's it! You do not need any more to start creating your own hook using PHP code.

Making it useful: Adding automated unit tests
—————————————————-

Right. Now we need to add something useful.
Let's add the possibility for automated unit testing; which aborts the build when a test has failed!

The most basic form of this is:

exec('phpunit', $output, $returnCode); // cwd is assumed here
if ($returnCode != 0) { echo implode(PHP_EOL, $output); }
die($returnCode);

This code executes `phpunit` and outputs the test results whenever a test has failed.
By returning phpUnit's own error code we automatically return a non-zero value when the tests have failed. This then results in an aborted commit.

It is that simple.

Full version
————-

To show you what is possible I have included my own pre-commit hook as a Gist:

[gist id=975252]

What is next?
—————

I intend to follow up on this post with another which will show you how to add support for PHP_CodeSniffer; which only checks the files that you have just committed.

See you back next time!

[1]: http://www.docblox-project.org "DocBlox"
[2]: http://www.kernel.org/pub/software/scm/git/docs/githooks.html "Git hooks"