Skip to content

Instantly share code, notes, and snippets.

@troelskn
Last active December 14, 2015 05:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save troelskn/5037326 to your computer and use it in GitHub Desktop.
Save troelskn/5037326 to your computer and use it in GitHub Desktop.
Some git-hooks for php development
#!/bin/sh
# /var/git/$REPONAME.git/hooks/
# This script just multiplexes the hook to multiple sub-scripts, since you can only have one hooks/post-receive
while read oldrev newrev refname
do
echo $oldrev $newrev $refname | /usr/share/doc/git-core/contrib/hooks/post-receive-email
echo $oldrev $newrev $refname | /home/buildbot/buildbot/scripts/post-receive-hook
done
#!/usr/bin/env php
<?php
// /home/buildbot/buildbot/scripts/post-receive-hook
require_once(dirname(realpath(__FILE__)).'/../bootstrap.inc.php');
$REPOSITORY = basename(getcwd());
foreach (explode("\n", trim(file_get_contents("php://stdin"))) as $line) {
list($OLDREV, $NEWREV, $REFNAME) = explode(" ", $line);
$sth = db()->prepare("insert into queue (oldrev, newrev, refname, repository, queued_at, result, build_started_at, build_completed_at, output) values (?, ?, ?, ?, now(), null, null, null, null)");
$sth->execute(array($OLDREV, $NEWREV, $REFNAME, $REPOSITORY));
}
#!/usr/bin/env php
<?php
// /var/git/$REPONAME.git/hooks/pre-receive
// Runs various checks on the inbound push and rejects if it isn't found credible
// There are some edge cases unhandled, so you may have to disable for some push'es
function verbose($str) {
// echo $str, "\n";
}
function exec_proc($command, $stdin = null) {
$descriptorspec = array(
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w") // stderr
);
$process = proc_open($command, $descriptorspec, $pipes);
if (is_resource($process)) {
if ($stdin) {
fwrite($pipes[0], $stdin);
}
fclose($pipes[0]);
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
$exit_code = proc_close($process);
return array($exit_code, $stdout, $stderr);
}
throw new Exception("Unable to open subprocess");
}
function git() {
$args = func_get_args();
$command = "git " . implode(" ", array_map('escapeshellarg', $args));
verbose("> {$command}");
return exec_proc($command);
}
function get_changed_files($base, $commit) {
list($code, $stdout, $stderr) = git('diff', '--numstat', '--name-only', '--diff-filter=ACMRTUXB', '--ignore-submodules', "{$base}..{$commit}");
if ($code != 0) {
echo $stderr;
echo $stdout;
throw new Exception("Subprocess exited with error");
}
return explode("\n", $stdout);
}
function get_new_file($filename, $commit) {
list($code, $stdout, $stderr) = git('show', "{$commit}:{$filename}");
if ($code != 0) {
echo $stderr;
echo $stdout;
throw new Exception("Subprocess exited with error");
}
return $stdout;
}
function store_file($fname, $contents) {
global $tmpdir;
if ($tmpdir === null) {
$tmpdir = tempnam("/tmp", "php");
unlink($tmpdir);
mkdir($tmpdir);
}
$fullname = $tmpdir.'/'.$fname;
if (!is_dir(dirname($fullname))) {
mkdir(dirname($fullname), 0777, true);
}
file_put_contents($fullname, $contents);
return $fullname;
}
function php_lint($filename) {
$command = "php -l " . escapeshellarg($filename);
verbose("> {$command}");
list($code, $stdout, $stderr) = exec_proc($command);
if ($code != 0) {
echo trim($stdout), "\n";
}
return $code == 0;
}
function detect_conflict_markers($fname, $contents) {
$result = true;
$linenum = 0;
foreach (explode("\n", $contents) as $line) {
$linenum++;
if (preg_match('/^(<<<<<<<|>>>>>>>)/', $line)) {
echo "Leftover conflict marker found in {$fname} on line {$linenum}\n";
$result = false;
}
}
return $result;
}
$line = file_get_contents('php://stdin');
list($base, $commit, $ref) = explode(" ", trim($line));
if ($base == "0000000000000000000000000000000000000000") {
verbose("Initial push received. Expecting everything to be fine");
exit;
}
$modified = get_changed_files($base, $commit);
$result = true;
foreach ($modified as $fname) {
$contents = get_new_file($fname, $commit);
if (preg_match('/[.]php$/', $fname)) {
$filename = store_file($fname, $contents);
$result = php_lint($filename) && $result;
}
$result = detect_conflict_markers($fname, $contents) && $result;
}
if (isset($tmpdir)) {
$command = "rm -rf ".escapeshellarg($tmpdir);
exec_proc($command);
verbose("> {$command}");
}
if (!$result) {
echo "Aborting.\n";
exit(1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment