Last active
January 5, 2016 03:15
-
-
Save steinkel/9771687 to your computer and use it in GitHub Desktop.
git php pre-receive hook to detect syntax and phpcs errors for CakePHP projects
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/php | |
<?php | |
/** | |
* This hook is a rewrite of http://git.661346.n2.nabble.com/Odd-results-writing-a-Git-pre-receive-hook-to-syntax-check-PHP-files-td5471120.html | |
* Thanks to Chris Patti for this thread | |
* @todo: detect when a new subdirectory is comitted and process all files recursive | |
*/ | |
function finish($exitCode = 0, $message = '') { | |
if (!empty($message)) { | |
echo $message; | |
echo PHP_EOL; | |
} | |
if ($exitCode) { | |
echo PHP_EOL; | |
echo "https://www.youtube.com/watch?v=XLUSqtqHxXc"; | |
echo PHP_EOL; | |
} | |
exit(intval($exitCode)); | |
} | |
/** | |
* Get the old and new refs from the input params | |
* @return array | |
*/ | |
function parseHookInput() { | |
$fpstdin = fopen("php://stdin", "r"); | |
$line = fgets($fpstdin); | |
list($old_sha1, $new_sha1, $refname) = explode(" ", $line); | |
return array($old_sha1, $new_sha1); | |
} | |
/** | |
* Check if this is a new branch | |
* @param type $old_sha1 | |
* @param type $new_sha1 | |
* @return boolean | |
*/ | |
function detectNewBranch($oldSha1, $newSha1) { | |
return ($oldSha1 == "0000000000000000000000000000000000000000"); | |
} | |
function parseDiff($oldSha1, $newSha1, $diffCmd, $regex) { | |
$diff = array(); | |
$returnCode = 0; | |
exec($diffCmd, $diff, $returnCode); | |
if ($returnCode != 0) { | |
finish(0, "Can't execute git ls-tree. Failing gracefully and allowing this push"); | |
} | |
//If we can execute the git diff I'm assuming we have access to a working git. | |
foreach ($diff as &$diffLine) { | |
$matches = array(); | |
preg_match($regex, $diffLine, $matches); | |
//check file not deleted | |
if (isset($matches[1]) && isset($matches[2]) && $matches[1] != '0000000') { | |
$blob = $matches[1]; | |
$filename = $matches[2]; | |
processFile($blob, $filename); | |
} | |
} | |
} | |
/** | |
* Process a file, lint & phpcs | |
* @param type $blob | |
* @param type $filename | |
*/ | |
function processFile($blob, $filename) { | |
$needle = '/(\.php)$/'; | |
if (preg_match($needle, $filename)) { | |
//echo "Checking $filename\n"; | |
$output = array(); | |
$returnCode = 0; | |
exec("git show $blob | /usr/bin/php -l 2>&1", $output, $returnCode); | |
if ($returnCode != 0) { | |
echo $filename . '---------------'; | |
echo PHP_EOL; | |
echo(implode(PHP_EOL, $output)); | |
finish(1); | |
} | |
//@todo: dry refactor this | |
exec("git show $blob | phpcs --standard=CakePHP", $output, $returnCode); | |
if ($returnCode != 0) { | |
echo $filename . '---------------'; | |
echo PHP_EOL; | |
echo(implode(PHP_EOL, $output)); | |
finish(1); | |
} | |
} | |
} | |
function parseCommit($oldSha1, $newSha1) { | |
//if this is the first commit on a new branch, $old_sha1 wil be a bunch of zeroes, and so | |
//git diff --raw will fail, since there's no old ref to compare against. So, we parse the | |
//results of git diff-tree -root=$new_sha1 instead to get the blob and filename we'll need. | |
$isNewBranch = detectNewBranch($oldSha1, $newSha1); | |
if ($isNewBranch) { | |
$diffCmd = "git diff-tree --root $newSha1"; | |
$regex = "/\:\d+ \d+ \w+ (\w+) \w\t(.+)/"; | |
} else { | |
$diffCmd = "git diff --raw $oldSha1 $newSha1"; | |
$regex = "/\:\d+ \d+ \w+... (\w+)... \w\t(.+)/"; | |
} | |
parseDiff($oldSha1, $newSha1, $diffCmd, $regex); | |
} | |
//End function definitions. Main code body starts here. | |
//This pre-receive git hook gets passed the ref before the push, and the ref that would be | |
//created if the push succeeds. | |
list($oldSha1, $newSha1) = parseHookInput(); | |
parseCommit($oldSha1, $newSha1); | |
finish(0); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment