|
<?php |
|
|
|
|
|
|
|
// constants |
|
|
|
define('WEBHOOK_SECRET', 'https://youtu.be/dQw4w9WgXcQ'); |
|
define('REPOSITORY_FULL_NAME', 'user/repo'); |
|
define('SSH_HOST', 'github_key1'); # see https://gist.github.com/kezzyhko/734b83a763c1feb6f38fdf096800718f |
|
define('WEBROOT_SYMLINC', '/home/user/app'); |
|
define('OLD_ACTUAL_WEBROOT', realpath(WEBROOT_SYMLINC)); |
|
define('ACTUAL_WEBROOT_PATTERN', WEBROOT_SYMLINC.'#%s'); |
|
|
|
|
|
|
|
// helper functions |
|
|
|
function check($condition, $status_code=200, $message='') { |
|
if ($condition !== true) { |
|
http_response_code($status_code); |
|
die($message); |
|
} |
|
} |
|
|
|
function shell_with_print($cmd_pattern, ...$argv) { |
|
$cmd = sprintf("$cmd_pattern 2>&1", ...$argv); |
|
echo $cmd; |
|
echo "\n"; |
|
system($cmd, $ret); |
|
return ($ret == 0); |
|
} |
|
|
|
|
|
|
|
// get the payload |
|
|
|
$request_content = file_get_contents('php://input'); |
|
$payload = json_decode($request_content, true); |
|
|
|
|
|
|
|
// check signature |
|
|
|
[$type, $hash_from_header] = explode('=', $_SERVER['HTTP_X_HUB_SIGNATURE']); |
|
check(in_array($type, hash_hmac_algos()), 422, 'wrong alorithm type'); |
|
$calculated_hash = hash_hmac($type, $request_content, WEBHOOK_SECRET); |
|
check(hash_equals($calculated_hash, $hash_from_header), 403, 'hmacs do not match'); |
|
|
|
|
|
|
|
// check that we need to do something with this event |
|
|
|
check($_SERVER['HTTP_X_GITHUB_EVENT'] === 'push', 200, 'event is not push'); // push |
|
check($payload['repository']['full_name'] === REPOSITORY_FULL_NAME, 200, "wrong repository {$payload['repository']['full_name']}"); // correct repo |
|
check($payload['ref'] === "refs/heads/{$payload['repository']['master_branch']}", 200, "not default branch"); // default branch |
|
|
|
|
|
|
|
// get updates from github |
|
|
|
define('NEW_ACTUAL_WEBROOT', sprintf(ACTUAL_WEBROOT_PATTERN, $payload['after'])); |
|
|
|
if (!file_exists(NEW_ACTUAL_WEBROOT)) { |
|
check(shell_with_print('git clone --depth 1 ssh://%s/%s.git %s', SSH_HOST, REPOSITORY_FULL_NAME, NEW_ACTUAL_WEBROOT), 409, 'could not clone'); // clone last version |
|
// or use $payload['repository']['ssh_url'] |
|
|
|
shell_with_print('rm -rf %s/.git', NEW_ACTUAL_WEBROOT); // remove .git dir |
|
} |
|
|
|
shell_with_print('ln -sfn %s %s', NEW_ACTUAL_WEBROOT, WEBROOT_SYMLINC); // update symlink |
|
|
|
// shell_with_print('rm -rf %s', OLD_ACTUAL_WEBROOT); // remove the most recent old files |
|
// it's not recommended, because sometimes symlink is still pointing to the previous dir and the website will be unaccessable for a brief period of time |
|
// also, it may be useful to keep old files in case something goes wrong to change symlinc back quickly |
|
// instead, you can remove old files, except the most recent, using the following: |
|
shell_with_print( |
|
"find $(dirname '%s') -maxdepth 1 -path '%s' ! -path '%s' ! -path '%s' -exec rm -rf {} +", |
|
ACTUAL_WEBROOT_PATTERN, |
|
sprintf(ACTUAL_WEBROOT_PATTERN, '*'), |
|
OLD_ACTUAL_WEBROOT, |
|
NEW_ACTUAL_WEBROOT |
|
); |
|
// but it only works if all files, including WEBROOT_SYMLINC, OLD_ACTUAL_WEBROOT, NEW_ACTUAL_WEBROOT, and ACTUAL_WEBROOT_PATTERN are in the same folder |
|
|
|
|
|
|