2010-09-14

Avoiding PHP syntax errors with Subversion pre-commit hooks

Since my last few posts have all been about Subversion, I figured I'd do another. Our new team member is an experienced programmer, but has not had any experience with PHP. And he's not real good about actually running his code before submitting it.

PHP allows you to run its command line executable with a -l flag to catch any syntax errors in your code. Very simple, but can really help catch some stupid errors. Yes, they should definitely be caught by a code review, but code reviewers should also be able to assume that the code actually runs.

So here's a Subversion pre-commit hook that will run PHP lint on all PHP files and reject the commit if any of them fail.

#!/usr/local/bin/php
<?php
/**
* Pre-commit Subversion script.
*
* @author Omni Adams <omni@digitaldarkness.com>
*/
/**
* Path to the awk binary.
*/
define('AWK', '/usr/bin/awk');
/**
* Path to the grep binary.
*/
define('GREP', '/bin/grep');
/**
* Path to the php binary.
*/
define('PHP', '/usr/local/bin/php');
/**
* Path to svnlook binary.
*/
define('SVNLOOK', '/usr/bin/svnlook');
/**
* Divider to inject into error messages to pretty them up.
*/
define('DIVIDER',
'********************************************************************************');
/**
* Run PHP lint on every PHP file that changed.
*
* If any of the PHP files in the current transaction have lint errors, writes
* an error message to standard error and returns true.
* @param string $transaction SVN transaction ID.
* @param string $repository Full path to the repository.
* @return boolean True if there was an error.
*/
function runPhpLint($transaction, $repository) {
$errors = false;
$changedCommand = SVNLOOK . ' changed -t "'
. $transaction . '" "'
. $repository . '" '
. '| ' . GREP . ' "^[UA]" '
. '| ' . GREP . ' "\\.php$" '
. '| ' . AWK . ' \'{print $2}\'';
exec($changedCommand, $changedOutput);
foreach ($changedOutput as $file) {
$lint = array();
$lintCommand = SVNLOOK . ' cat -t "'
. $transaction . '" "'
. $repository . '" "' . $file . '" '
. '| ' . PHP . ' -l';
exec($lintCommand, $lint);
if ('No syntax errors detected in -' == $lint[0]) {
// Lint returns text on good files,
// don't write that to standard
// error or consider it an error.
continue;
}
$message = PHP_EOL . DIVIDER . PHP_EOL . PHP_EOL
. $file . ' contains PHP error(s):' . PHP_EOL;
foreach ($lint as $line) {
// PHP lint includes some blank lines in its output.
if ('' == $line) {
continue;
}
// PHP lint tells us where the error is,
// which because we pass it in by piping it
// to standard in, doesn't tell us anything.
if ('Errors parsing -' == $line) {
continue;
}
$message .= "\t" . $line . PHP_EOL;
}
file_put_contents('php://stderr', $message . PHP_EOL);
$errors = true;
}
return $errors;
}
if (runPhpLint($transaction, $repository)) {
exit(1);
}
exit(0);
view raw svn-lint.php hosted with ❤ by GitHub

No comments:

Post a Comment