Skip to content

Instantly share code, notes, and snippets.

@kezzyhko
Last active October 14, 2020 16:22
Show Gist options
  • Save kezzyhko/052c19ae447b0ef547af5d104c5f629b to your computer and use it in GitHub Desktop.
Save kezzyhko/052c19ae447b0ef547af5d104c5f629b to your computer and use it in GitHub Desktop.
Script for automatic deployment of php web apps from github
<?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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment