Subversion hook php framework
Subversion provides very powerful hook system which allows extending it with custom logic. Hook is a command line script which is executed on selected repository event receiving metadata as command line arguments and providing results within output and exit code.
With a help of hook script you can validate commit log message or even submitted changes before saving them into repository and notify user if there are any errors.
If you have php on your server with a help of special PHP class your very powerful subversion hook might look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #!/usr/bin/php <?php require '/var/svn/common-hooks/CommitTests.php'; putenv('PATH=/usr/bin'); new CommitTests($argv[1], $argv[2], array( 'LogMessageLength' => array(3), 'TabIndents' => array(array('php', 'phtml')), 'TrailingSpaces' => array(array('php', 'phtml', 'ini')), 'SvnProperties' => array(array( 'php' => array('svn:keywords=Revision', 'svn:eol-style=LF'), 'phtml' => array('svn:keywords=Revision', 'svn:eol-style=LF'), 'html' => array('svn:eol-style=LF'), )), )); |
This script have following pre-commit validation rules:
- Minimum log message length is 3 characters
- Tab indents are not allowed in *.php and *.phtml files
- Trailing spaces are not allowed in *.php, *.phtml and *.ini files
- *.php and *.phtml files should have following svn tags set: svn:keywords=Revision, svn:eol-style=LF
- *.html files should have svn tag svn:eol-style=LF
Download CommitTests.php file.
Thanks so much, this works great! Following your example, it was very easy to edit your tests and add my own. I added a test that verifies PHP syntax is correct before committing (for certain file extensions only), and also added some logic that will copy the committed files to a specific location for further testing (only if all other tests pass. I wanted to run this copy action in the postcommit hook, but the CommitTests class doesn’t seem to work properly in the postcommit hook. Specifically, it doesn’t seem to know what files were committed).
Here’s the method to check syntax:
***********************
class CommitTests
{
[...snip...]
//path to php binary
public static $PHP = “/usr/local/php-cgi/bin/php”;
/**
* Tests if the committed files pass PHP syntax checking
*
* @param string $msg error messages placeholder
* @param array $filetypes array of file types which should be tested
* @return bool
*/
protected function _testPHPSyntax(&$msg, array $filetypes=array()){
$result = true;
$files = $this->_getChangedFiles($filetypes);
$tempDir = sys_get_temp_dir();
foreach ($files as $file => $extension) {
$content = $this->_getFileContent($file);
$tempfile = tempnam($tempDir, “stax_”);
file_put_contents($tempfile, $content);
$tempfile = realpath($tempfile); //sort out the formatting of the filename
$output = shell_exec(self::$PHP.’ -l “‘.$tempfile.’”‘);
//try to find a parse error text and chop it off
$syntaxErrorMsg = preg_replace(“/Errors parsing.*$/”, “”, $output, -1, $count);
if ($count > 0) { //found errors
$result = false;
$syntaxErrorMsg = str_replace($tempfile,$file,$syntaxErrorMsg); //replace temp filename with real filename
$msg .= “\t[$file] PHP Syntax error in file. Message: $syntaxErrorMsg\n”;
}
unlink($tempfile);
}
return $result;
}
[...snip...]
}
***********************
And run it with:
new CommitTests($argv[1], $argv[2], array(
‘PHPSyntax’=>array(array(‘php’)), //array contains file extensions to check
….etc….
));
***********************
Thanks so much for sharing! This framework saved me a lot of time.
Adam