Skip to content

Plugin system #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Nov 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions deploy-config.orig.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,19 @@
*/
define('CLEANUP_WORK_TREE', false);

/* CALLBACK_FILE:
* Filename of a PHP script containing callback functions to
/* CALLBACK_CLASSES:
* Classnames containing callback functions to
* be triggered at the end of the script on success or failure.
* Useful to connect to your preferred notification system.
* Note:
* - Classes must implement Plugin Interface
* - Class names have to match their file-name (case-sensitive), e.g. "Discord.class.php" has class "Discord"
* - The array keys contain only the class name, e.g. array("Discord")
*/
define('CALLBACK_FILE', '');
define('CALLBACK_CLASSES', array(
));

/* PLUGINS_FOLDER:
* Folder containing all webhook plugins/classes, default: 'plugins/'
*/
define('PLUGINS_FOLDER','plugins/');
70 changes: 55 additions & 15 deletions deploy.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@
// Measure execution time
$time = -microtime(true);

// Autoloader for plugin classes
spl_autoload_register(function($className){
$namespace=str_replace("\\","/",__NAMESPACE__);
$className=str_replace("\\","/",$className);
$class=(!defined("PLUGINS_FOLDER") ? "plugins/" : PLUGINS_FOLDER).(empty($namespace)?"":$namespace."/")."{$className}.class.php";
include_once($class);
});

/* Functions */

// Output buffering handler
Expand All @@ -29,36 +37,59 @@ function errorPage($msg) {
}

// Command to execute at the end of the script
function endScript($msg = "") {
function endScript($msg = "",$display = false) {
// Remove lock file
unlink(__DIR__ . '/deploy.lock');

// Flush buffer and prepare output for log and email
ob_end_flush();
global $output;

// Remove <head>, <script>, and <style> tags, including content
$output = preg_replace('/<head[\s\w\W\n]+<\/head>/m', '', $output);
$output = preg_replace('/<script[\s\w\W\n]+<\/script>/m', '', $output);
$output = preg_replace('/<style[\s\w\W\n]+<\/style>/m', '', $output);

// Add heading and strip tags
$output = str_repeat("~", 80) . "\n"
. '[' . date('c') . '] - ' . $_SERVER['REMOTE_ADDR'] . " - b=" . $_GET['b'] . ' c=' . $_GET['c'] . "\n"
. strip_tags($output);

// Decode HTML entities
$output = html_entity_decode($output);

// Collapse multiple blank lines into one
$output = preg_replace('/^\n+/m', "\n", $output);

// Save to log file
if(defined('LOG_FILE') && LOG_FILE !== '') error_log($output, 3, LOG_FILE);

// Send email notification
if(defined('EMAIL_NOTIFICATIONS') && EMAIL_NOTIFICATIONS !== '') error_log($output, 1, EMAIL_NOTIFICATIONS);

// Send error callback
if($msg && defined('CALLBACK_FILE') && file_exists(CALLBACK_FILE)){
require_once CALLBACK_FILE;
if(function_exists(callbackError)) {
callbackError($msg);
if(!empty($msg) && defined('CALLBACK_CLASSES') && !empty(CALLBACK_CLASSES)){
foreach (CALLBACK_CLASSES as $class) {
if(is_callable(array($class,"errorWebhook"))){
$callback = $class::errorWebhook($msg);
// prevent outputting after errorPage()
if($display === true){
if($callback === true){
echo "\n[Plugin: ".$class."] webhook successfully sent\n";
}else{
echo "ERR! Plugin '".$class."' returned: ".$callback;
}
}
}
}
}
die($msg);

// prevent outputting same error message from errorPage()
if($display === true){
die($msg);
}else{
die();
}
}

/* Begin Script Execution */
Expand Down Expand Up @@ -484,14 +515,23 @@ function cmd($command, $print = true, $dir = GIT_DIR) {
));

// Send success callback
if(defined('CALLBACK_FILE') && file_exists(CALLBACK_FILE)){
require_once CALLBACK_FILE;
if(function_exists(callbackSuccess)) {
callbackSuccess(array(
'branch' => $branch,
'commit' => $checkout,
'execTime' => $time + microtime(true)
));
if(defined('CALLBACK_CLASSES') && !empty(CALLBACK_CLASSES)){
foreach (CALLBACK_CLASSES as $class) {
if(is_callable(array($class,"successWebhook"))){
$callback = $class::successWebhook(array(
'remote' => REMOTE_REPOSITORY,
'branch' => $branch,
'targetDirectory' => TARGET_DIR,
'commit' => $checkout,
'execTime' => $time + microtime(true)
));

if($callback === true){
echo "\n[Plugin: ".$class."] webhook successfully sent\n";
}else{
echo "ERR! Plugin '".$class."' returned: ".$callback;
}
}
}
}
?>
Expand All @@ -501,4 +541,4 @@ function cmd($command, $print = true, $dir = GIT_DIR) {
</body>
</html>
<?php
endScript();
endScript("",true);
85 changes: 85 additions & 0 deletions plugins/Discord.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

/* DISCORD WEBHOOK CONFIGS:
* (OPTIONAL/DEFAULT TO FALSE) DISCORD_WEBHOOK: enables discord webhook notifications
* (REQUIRED) DISCORD_WEBHOOK_URL: the URL generated by Discord to receive webhooks
* (OPTIONAL) DISCORD_USER_NAME: the name that should be shown as the user sending the message
* (OPTIONAL) DISCORD_AVATAR_URL: the image to be used as the avatar for the user sending the message
*/

// allow for override by main configuration file
if(!defined("DISCORD_WEBHOOK")) define("DISCORD_WEBHOOK",false);
if(!defined("DISCORD_WEBHOOK_URL")) define("DISCORD_WEBHOOK_URL","");
if(!defined("DISCORD_USER_NAME")) define("DISCORD_USER_NAME","");
if(!defined("DISCORD_AVATAR_URL")) define("DISCORD_AVATAR_URL","");

class Discord implements Plugin {
public static function successWebhook($params){
$deployedMessage = "**Execution:** ".$params["execTime"]." seconds \n";
$deployedMessage .= "**Deployed:** \n(".$params["branch"].") ".$params["remote"]."\n";
$deployedMessage .= "**To:** ".$params["targetDirectory"]."\n";

return self::discordMessage($deployedMessage);
}

public static function errorWebhook($errorMessage){
return self::discordMessage($errorMessage,true);
}

private static function discordMessage($message,$error = false) {
// check configuration errors and correct them
if(!defined("DISCORD_WEBHOOK")) define("DISCORD_WEBHOOK",false);

// prevent execution if discord webhook not enabled
if(DISCORD_WEBHOOK === false) return "Discord webhook is not enabled";

// only check other discord configuration values, if discord webhook is enabled
if(!defined("DISCORD_WEBHOOK_URL") || empty(DISCORD_WEBHOOK_URL)){
return 'Discord webook url not configured';
}

// abort if no message set
if(empty($message)) return "No message provided";

if($error === false){
$data = array(
'username' => DISCORD_USER_NAME,
'avatar_url' => DISCORD_AVATAR_URL,
'embeds' => [[
"title" => "Deploy successful!",
"description" => strip_tags($message),
"color" => "3932074"
]]
);
}else{
$data = array(
'username' => DISCORD_USER_NAME,
'avatar_url' => DISCORD_AVATAR_URL,
'embeds' => [[
"title" => "Deploy failed..",
"description" => strip_tags($message),
"color" => "16727357"
]]
);
}

$data_string = json_encode($data);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, DISCORD_WEBHOOK_URL);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);

$output = curl_exec($curl);
$output = json_decode($output, true);
if (curl_getinfo($curl, CURLINFO_HTTP_CODE) != 204) {
return $output["message"];
}

curl_close($curl);
return true;
}
}
20 changes: 20 additions & 0 deletions plugins/Plugin.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

interface Plugin
{
/**
* successWebhook
*
* @param [array] $params information passed down to the plugin
* @return bool|string Returns true if no errors occured, else returns error message
*/
public static function successWebhook($params);

/**
* errorWebhook
*
* @param [string] $errorMessage the error message(s) passed down to the plugin
* @return bool|string Returns true if no errors occured, else returns error message
*/
public static function errorWebhook($errorMessage);
}