Files
boost-tasks/webhook/webhook.php
Daniel James 94fb6839fe Stop stahing changes to git repos
I've moved the local changes from the website into the repo, so this shouldn't
be required anymore.
2018-02-12 12:59:49 +00:00

233 lines
6.9 KiB
PHP

<?php
require_once(__DIR__.'/../vendor/autoload.php');
use BoostTasks\Settings;
use BoostTasks\RepoBase;
use BoostTasks\Log;
// use RuntimeException;
function webhook() {
header("Content-Type: text/plain");
Settings::init(array('config-file' => __DIR__.'/../var/webhook.neon', 'webhook' => true));
$event = get_webhook_event();
Log::info("Handling event {$event->event_type}");
switch($event->event_type) {
case 'push':
webhook_push_handler($event);
break;
case 'pull_request':
webhook_pull_request_handler($event);
break;
default:
throw new RuntimeException("Unrecognized event: {$event->event_type}");
}
}
function webhook_push_handler($event) {
// TODO: Move to configuration?
$repos = array(
'boost' => array(
'master' => array('path' => '/home/www/shared/repos/boost-master', 'method' => 'reset'),
'develop' => array('path' => '/home/www/shared/repos/boost-develop', 'method' => 'reset'),
),
'website' => array(
'master' => '/home/www/live.boost.org',
'beta' => array('path' => '/home/www/beta.boost.org', 'method' => 'reset'),
),
'build' => array(
'website' => '/home/www/shared/build-site',
),
'documentation-fixes' => array(
'master' => '/home/www/shared/repos/documentation-fixes',
),
);
$payload = $event->payload;
$branch = preg_replace('@^refs/heads/@', '', $payload->ref);
$repo_path = null;
if (array_key_exists($payload->repository->name, $repos)) {
$branches = $repos[$payload->repository->name];
}
else {
echo "Nothing to do for repository: {$payload->repository->name}.\n";
return false;
}
if (array_key_exists($branch, $branches)) {
$repo_details = $branches[$branch];
$repo_path = $branches[$branch];
}
else {
echo "Ignoring repository {$payload->repository->name}, ref: {$payload->ref}\n";
return false;
}
// Get the update method that we're going to use.
if (is_array($repo_details)) {
$repo_path = $repo_details['path'];
$update_method = array_get($repo_details, 'method', 'pull');
} else {
$repo_path = $repo_details;
$update_method = 'pull';
}
// These aren't needed until later, but getting them out of the way
// before doing anything with side effects.
$email_title = "[boost website] Error updating {$payload->repository->name} {$branch}";
$git_commits = commit_details($payload);
// Update the repo
echo "Updating {$repo_path}\n";
$git_output = update_git_checkout($repo_path, $update_method, $branch);
// Email if something went wrong when updating.
if (!$git_output) {
echo "Done.\n";
} else {
echo "Done with git error, emailing results.\n";
$result = '';
$result .= "Pull\n";
$result .= "====\n";
$result .= $git_output;
$result .= "\n";
$result .= "Commits\n";
$result .= "=======\n";
$result .= $git_commits;
$result .= "\n";
// Email the result
mail('dnljms@gmail.com', "{$email_title} update ".date('j M Y'), $result);
}
}
/* Returns output if anything failed */
function update_git_checkout($repo_path, $update_method, $branch) {
$failed = false;
$result = '';
$repo = new RepoBase($repo_path);
try {
switch($update_method) {
case 'pull':
$result .= $repo->commandWithOutput('pull -q --ff-only');
break;
case 'reset':
$result .= $repo->commandWithOutput("fetch -q");
$result .= $repo->commandWithOutput("reset --hard origin/{$branch}");
break;
default:
return "Error: invalid update method: {$update_method}";
}
}
catch (\RuntimeException $e) {
return "Git pull failed";
}
return '';
}
function commit_details($payload) {
$result = '';
$result .= "Branch: {$payload->ref}\n";
$result .= $payload->forced ? "Force pushed " : "Pushed ";
$result .= "by: {$payload->pusher->name} <{$payload->pusher->email}>\n";
foreach ($payload->commits as $commit) {
$result .= "\n";
$result .= "commit {$commit->id}\n";
$result .= "Author: {$commit->author->name} <{$commit->author->email}>\n";
$result .= "\n";
$result .= preg_replace('@^(?!$)@m', " ", $commit->message)."\n";
}
return $result;
}
function webhook_pull_request_handler($event) {
$payload = $event->payload;
$record = Settings::database()->dispense('pull_request_event');
$record->action = $payload->action;
$record->repo_full_name = $payload->repository->full_name;
$record->pull_request_id = $payload->pull_request->id;
$record->pull_request_number = $payload->pull_request->number;
$record->pull_request_url = $payload->pull_request->html_url;
$record->pull_request_title = $payload->pull_request->title;
$record->pull_request_created_at = $payload->pull_request->created_at;
$record->pull_request_updated_at = $payload->pull_request->updated_at;
$record->pull_request_state = $payload->pull_request->state;
$record->store();
}
class GitHubWebHookEvent {
var $event_type;
var $payload;
}
function get_webhook_event() {
$secret_key = Settings::settings('github-webhook-secret');
if (!$secret_key) {
throw new RuntimeException("github-webhook-secret not set.");
}
$post_body = file_get_contents('php://input');
// Check the signature
$signature = array_key_exists('HTTP_X_HUB_SIGNATURE', $_SERVER) ?
$_SERVER['HTTP_X_HUB_SIGNATURE'] : false;
if (!preg_match('@^(\w+)=(\w+)$@', $signature, $match)) {
throw new RuntimeException("Unable to parse signature");
}
$check_signature = hash_hmac($match[1], $post_body, $secret_key);
if ($check_signature != $match[2]) {
throw new RuntimeException("Signature doesn't match");
}
// Get the payload
switch($_SERVER['CONTENT_TYPE']) {
case 'application/json':
$payload_text = $post_body;
break;
case 'application/x-www-form-urlencoded':
if (!array_key_exists('payload', $_POST)) {
throw new RuntimeException("Unable to find payload");
}
$payload_text = $_POST['payload'];
break;
default:
throw new RuntimeException("Unexpected content_type: ".$_SERVER['CONTENT_TYPE']);
}
$payload = json_decode($payload_text);
if (!$payload) {
throw new RuntimeException("Error decoding payload.");
}
// Get the event type
if (!array_key_exists('HTTP_X_GITHUB_EVENT', $_SERVER)) {
throw new RuntimeException("No event found.");
}
$event_type = $_SERVER['HTTP_X_GITHUB_EVENT'];
$x = new GitHubWebHookEvent;
$x->event_type = $event_type;
$x->payload = $payload;
return $x;
}