SVN pre-commit hook which can syntax check all files

If you manage a project which uses Subversion you’re going to eventually want to check the syntax of files before they get committed to the repository. Checking files before they get committed to the repository solves at least two problems for me.

  1. It stops me from checking something in, noticing it doesn’t work and committing a fixed version only moments later.
  2. It prevents other users from accidentally checking in broken code

A quick search online will reveal that it’s easy to check the syntax of your PHP files before they are committed. All you need to use is a pre-commit hook. Unfortunately scripts I found would all stop on the first error which was not the behavior I wanted. I wanted to check all of the files I was committing and get a list of all errors immediately. So, I wrote my own pre-commit hook.

Checking All PHP Files With A pre-commit Hook

The script I came up with is in PHP. Save this in the hooks directory of your Subversion repository. Name it pre-commit and make it executable.

#!/usr/bin/php 
<?php 

// Set these manually since Subversion doesn't set ENV
$PHP = '/usr/bin/php'; 
$SVNLOOK = '/usr/bin/svnlook'; 
$AWK = '/usr/bin/awk'; 
$GREP = '/bin/egrep'; 
$SED = '/bin/sed'; 
 
$REPOS = $argv[1]; 
$TXN = $argv[2]; 
 
// Find the changes...
$CHANGED=`$SVNLOOK changed -t "$TXN" "$REPOS" | $GREP "^[U|A]" | $AWK '{print $2}'`; 
// ...as an array
$CHANGED = split("\n",trim(rtrim($CHANGED))); 
 
$errors = Array();

// Perform specific actions based on the file extension 
foreach($CHANGED as $FILE){ 
 switch(pathinfo($FILE,PATHINFO_EXTENSION)){ 
 case 'php': 
 case 'class': 
    // Get just the error/no error message from php -l
    $cmd="$SVNLOOK cat -t '$TXN' '$REPOS' '$FILE' | $PHP -l | head -2 | tail -1"; 
    $msg=trim(rtrim(`$cmd`)); 
    if(preg_match('/No syntax errors detected/',$msg) != 1){ 
       $msg = preg_replace('/in - /','',$msg); 
       $errors[] = "In $FILE: $msg"; 
    }
   break; 
  case 'js':
    // You could do something else for JavaScript -- like JSLint, if you're brave
    break;
 } 
} 
 
// Print all the errors in a nice list
if(count($errors) > 0){ 
 $warning =" 
************************************************************************* 
* Please correct the following errors before commiting these changes! * 
************************************************************************* 
"; 
 error_log($warning); 
 for($i = 1;$i <= count($errors);$i++){ 
 error_log("$i. " . $errors[($i - 1)]); 
 } 
 
 exit(-1); 
} 
 
exit(0);

This script will check all of the files that changed based on their file extension. You could check .js files one way and .php another way. You can extend this script by simply adding more cases to the switch statement.

The script collects all errors and then prints a nice list when it’s done. The output looks like this:

svn commit -m "pre-commit hook test"
Sending        test_scripts/info.php
Sending        test_scripts/user_read.php
Transmitting file data ..svn: Commit failed (details follow):
svn: Commit blocked by pre-commit hook (exit code 255) with output:

*************************************************************************
*  Please correct the following errors before commiting these changes!  *
*************************************************************************

1. In /test_scripts/info.php: Parse error: syntax error, unexpected $end on line 4
2. In /test_scripts/user_read.php: Parse error: syntax error, unexpected T_ENCAPSED_AND_WHITESPACE, expecting T_STRING or T_VARIABLE or T_NUM_STRING on line 8

I’m not going to say that it’s the most elegant output in the world but it does the job and I haven’t checked in a bad PHP file since.

This entry was posted in Programming, Something Interesting and tagged , , , , , , , , . Bookmark the permalink.

2 Responses to SVN pre-commit hook which can syntax check all files

  1. Great, thanks for sharing, we’re using this now at Ivaldi!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Current day month ye@r *