...
 
Commits (23)
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -51,12 +51,20 @@ Books are automatically published when the corresponding branch is updated their
### Setting up automatic publishing
#### GitHub
Auto updates are configured via webhooks within the repository on GitHub. You will need to be an owner (not just a collaborator) of the repository in order to perform these steps.
1. Go to `https://github.com/civicrm/[repo-name]/settings/hooks/new`
1. Set the **Payload URL** to https://docs.civicrm.org/admin/listen
1. Set the **Content type** to 'application/json'
1. Set **Which events would you like to trigger this webhook?** to 'Let me select individual events' and select 'Pull request' and 'Push' (since these are the only events that should trigger an update)
1. Go to `https://github.com/[user-or-group-name]/[repo-name]/settings/hooks/new`
2. Set the **Payload URL** to https://docs.civicrm.org/admin/listen
3. Set the **Content type** to 'application/json'
4. Set **Which events would you like to trigger this webhook?** to 'Let me select individual events' and select 'Pull request' and 'Push' (since these are the only events that should trigger an update)
#### GitLab
1. Go to `https://lab.civicrm.org/[user-or-group-name]/[repo-name]/settings/integrations
2. Set the **URL** to https://docs.civicrm.org/admin/listen
3. Set the **Trigger** to 'Push events' and 'Tag push events'.
### Manual publishing
......@@ -104,26 +112,64 @@ You should be able to see the app at http://localhost:8080.
**Note**: the following steps are only useful and necessary for people looking after CiviCRM's documentation *infrastructure*. You don't need to do this if you just want to [contribute to documentation content](https://docs.civicrm.org/dev/en/master/documentation/).
1. Ensure that that you have [pip](https://packaging.python.org/en/latest/install_requirements_linux/#installing-pip-setuptools-wheel-with-linux-package-managers) (for python) and [composer](https://getcomposer.org/) (for php) installed..
2. [Install MkDocs](https://docs.civicrm.org/dev/en/master/documentation/#mkdocs). Ensure that MkDocs is installed as root so that it can be accessed from the src/publish.php script (typically invoked as https://docs.civicrm.org/publish.php)*
3. clone this repository to somewhere like /var/www/civicrm-docs and run `composer install`
```bash
$ git clone /var/www/civicrm-docs
$ cd /var/www/civicrm-docs
$ composer install
```
4. Set appropriate permissions on web/static
5. Configure an nginx virtual host
```bash
$ cd /etc/nginx/sites-enabled
$ ln -s /var/www/civicrm-docs/app/config/nginx.conf civicrm-docs
```
1. Install the pre-requisites:
**Note**: the example commands have been tested on Ubuntu 16.04 and 18.04.
* [nginx](https://nginx.org):
``` bash
sudo apt install nginx
```
* [mysql](https://mysql.com):
``` bash
sudo apt install mysql-server
```
* [php 7.1](https://php.net):
``` bash
sudo apt install software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt update
sudo apt install php7.1-fpm php7.1-mcrypt php7.1-mbstring php7.1-cli php7.1-xml php7.1-mysql php7.1-gd php7.1-imagick php7.1-recode php7.1-tidy php7.1-xmlrpc
```
* [pip](https://packaging.python.org/en/latest/install_requirements_linux/#installing-pip-setuptools-wheel-with-linux-package-managers):
``` bash
sudo apt install python-pip
```
* [composer](https://getcomposer.org)
``` bash
sudo apt install composer
```
* [mkdocs](https://mkdocs.org) *CiviCRM Docs Publisher expects MkDocs version 0.16.x*
``` bash
sudo -H pip install mkdocs==0.16.3
sudo -H pip install mkdocs-material==1.4.1
sudo -H pip install pygments==2.2.0
sudo -H pip install pymdown-extensions==2.0
```
**Note**: Ensure that MkDocs is installed as root so that it can be accessed from the src/publish.php script (typically invoked as https://docs.civicrm.org/publish.php)*
2. clone this repository to somewhere like /var/www/civicrm-docs and run `composer install`
```bash
git clone https://lab.civicrm.org/documentation/docs-publisher.git /var/www/civicrm-docs
cd /var/www/civicrm-docs
composer install
```
3. Set appropriate permissions on web/static
4. Update the nginx configuration file to point to the php7.1-fpm socket and fix the root.
[- root /var/www/web; -]
[+ root /var/www/civicrm-docs/web; +]
[- fastcgi_pass unix:/var/run/php-fpm.sock; -]
[+ fastcgi_pass unix:/var/run/php/php7.1-fpm.sock; +]
5. Configure the nginx virtual host
```bash
cd /etc/nginx/sites-enabled
ln -s /var/www/civicrm-docs/app/config/civicrm-docs.conf civicrm-docs
```
6. Reload your nginx config and you should be up and running.
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -20,8 +20,7 @@ class AppKernel extends Kernel {
if (in_array($this->getEnvironment(), ['dev', 'test'], TRUE)) {
$bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle();
$bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
$bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle();
$bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle();
$bundles[] = new Symfony\Bundle\MakerBundle\MakerBundle();
}
if ('dev' === $this->getEnvironment()) {
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
server {
server_name localhost;
listen *:8080;
root /var/www/web;
server_name v2018.docs.civicrm.dev.mjco.uk;
root /var/www/civicrm-docs-v2018/web;
# For a development configuration, change "app" to "app_dev" everywhere
# below. Then you'll see the Symfony web debug toolbar when viewing pages.
......@@ -26,7 +25,7 @@ server {
}
location ~ ^/app_dev\.php(/|$) {
fastcgi_pass unix:/var/run/php-fpm.sock;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
# When you are using symlinks to link the document root to the
......@@ -50,7 +49,15 @@ server {
return 404;
}
#error_log /var/log/nginx/civicrm-docs-error.log;
#access_log /var/log/nginx/civicrm-docs-access.log;
}
error_log /var/log/nginx/civicrm-docs-error.log;
access_log /var/log/nginx/civicrm-docs-access.log;
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/v2018.docs.civicrm.dev.mjco.uk/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/v2018.docs.civicrm.dev.mjco.uk/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
......@@ -23,7 +23,7 @@ framework:
engines: ['twig']
default_locale: "%locale%"
trusted_hosts: ~
trusted_proxies: ~
#trusted_proxies: ~ # Deprecated v3.3
session:
# http://symfony.com/doc/current/reference/configuration/framework.html#handler-id
handler_id: session.handler.native_file
......@@ -66,3 +66,8 @@ swiftmailer:
username: "%mailer_user%"
password: "%mailer_password%"
spool: { type: memory }
# Sensio Framework Configuration
sensio_framework_extra:
router:
annotations: false
......@@ -17,10 +17,10 @@ monolog:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
channels: [!event]
channels: ["!event"]
console:
type: console
channels: [!event, !doctrine]
channels: ["!event", "!doctrine"]
# uncomment to get logging in your browser
# you may have to allow bigger header sizes in your Web server configuration
#firephp:
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
# Learn more about services, parameters and containers at
# http://symfony.com/doc/current/book/service_container.html
parameters:
books_dir: %kernel.root_dir%/../books
books_dir: "%kernel.root_dir%/../books"
services:
_defaults:
autowire: true
autoconfigure: true
library:
class: AppBundle\Model\Library
arguments:
- %books_dir%
- "%books_dir%"
public: true
github.hook.processor:
class: AppBundle\Utils\GitHubHookProcessor
webhook.processor:
class: AppBundle\Utils\WebhookProcessor
arguments:
-
- '@github.webhook_handler'
- '@gitlab.webbook_handler'
public: true
github.webhook_handler:
class: AppBundle\Utils\WebhookAdapters\GithubHandler
public: true
gitlab.webbook_handler:
class: AppBundle\Utils\WebhookAdapters\GitlabHandler
public: true
mkdocs:
class: AppBundle\Utils\MkDocs
......@@ -28,6 +45,7 @@ services:
- '@mkdocs'
- '@git'
- '@paths'
public: true
filesystem:
class: AppBundle\Utils\FileSystem
......@@ -35,8 +53,8 @@ services:
paths:
class: AppBundle\Utils\Paths
arguments:
- '%kernel.root_dir%'
- '%kernel.cache_dir%'
- "%kernel.root_dir%"
- "%kernel.cache_dir%"
git:
class: AppBundle\Utils\GitTools
......@@ -56,7 +74,7 @@ services:
streamhandler:
class: Monolog\Handler\StreamHandler
arguments:
- %kernel.logs_dir%/publish.log
- "%kernel.logs_dir%/publish.log"
app.exception_listener:
class: AppBundle\EventListener\ExceptionListener
......
#!/bin/bash
find web/static var -exec setfacl -m u:www-data:rwx {} \;
find web/static var -exec setfacl -m u:docs:rwx {} \;
if id "www-data" >/dev/null 2>&1; then
find web/static var -exec setfacl -m u:www-data:rwx {} \;
fi
if id "$USER" >/dev/null 2>&1; then
find web/static var -exec setfacl -m u:$USER:rwx {} \;
fi
if id "co" >/dev/null 2>&1; then
find web/static var -exec setfacl -x u:co {} \;
fi
if id "www-data" >/dev/null 2>&1; then
find web/static var -type d -exec setfacl -m d:u:www-data:rwx {} \;
find web/static var -type d -exec setfacl -m d:u:docs:rwx {} \;
find web/static var -type d -exec setfacl -x d:u:co {} \;
\ No newline at end of file
fi
if id "$USER" >/dev/null 2>&1; then
find web/static var -type d -exec setfacl -m d:u:$USER:rwx {} \;
fi
if id "co" >/dev/null 2>&1; then
find web/static var -type d -exec setfacl -x d:u:co {} \;
fi
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -6,17 +6,17 @@ langs:
en:
repo: 'https://github.com/civicrm/civicrm-user-guide'
versions:
5: # This is stored as $slug
name: 5 / Latest # If omitted, use $slug
"5": # This is stored as $slug
name: "5 / Latest" # If omitted, use $slug
path: latest # If omitted, use a URL-safe version of $slug
branch: master # If omitted, use $slug
redirects: # These are not displayed anywhere
- current
- stable
- 4.7
4.6:
branch: 4.6
name: 4.6 / Long Term Support
- "4.7"
"4.6":
branch: "4.6"
name: "4.6 / Long Term Support"
redirects:
- lts
ca:
......
File mode changed from 100644 to 100755
......@@ -18,39 +18,28 @@
},
"require": {
"php": "^7.0",
"symfony/symfony": "^3.0",
"symfony/symfony": "^4.1",
"doctrine/orm": "^2.5",
"twig/twig": "^1.33",
"twig/twig": "^2.5",
"doctrine/doctrine-bundle": "^1.6",
"doctrine/doctrine-cache-bundle": "^1.2",
"symfony/swiftmailer-bundle": "^2.3",
"symfony/monolog-bundle": "^2.8",
"sensio/distribution-bundle": "^5.0",
"sensio/framework-extra-bundle": "^3.0.2",
"symfony/swiftmailer-bundle": "^3.2",
"symfony/monolog-bundle": "^3.3",
"sensio/framework-extra-bundle": "^5.2",
"incenteev/composer-parameter-handler": "^2.0",
"symfony/web-server-bundle": "^3.3"
"phpunit/phpunit": "^7.4"
},
"require-dev": {
"sensio/generator-bundle": "^3.0",
"symfony/phpunit-bridge": "^3.0",
"phpunit/phpunit": "^5.7"
"symfony/maker-bundle": "^1.7",
"symfony/phpunit-bridge": "^4.1",
"symfony/web-server-bundle": "^4.1"
},
"scripts": {
"post-install-cmd": [
"Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget"
"Incenteev\\ParameterHandler\\ScriptHandler::buildParameters"
],
"post-update-cmd": [
"Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget"
"Incenteev\\ParameterHandler\\ScriptHandler::buildParameters"
]
},
"extra": {
......
This diff is collapsed.
......@@ -10,10 +10,11 @@
<php>
<ini name="error_reporting" value="-1" />
<server name="KERNEL_DIR" value="app/" />
<env name="KERNEL_CLASS" value="AppKernel" />
</php>
<testsuites>
<testsuite name="Project Test Suite">
<testsuite name="CiviCRM Docs Publisher Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -2,11 +2,12 @@
namespace AppBundle\Controller;
use AppBundle\Model\WebhookEvent;
use AppBundle\Utils\Publisher;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\Routing\Annotation\Route;
use AppBundle\Model\Library;
......@@ -56,50 +57,46 @@ class PublishController extends Controller {
* @Route("/admin/listen")
*/
public function ListenAction(Request $request) {
$body = $request->getContent();
$event = $request->headers->get('X-GitHub-Event');
$processor = $this->get('github.hook.processor');
try {
$hookData = $processor->process($event, json_decode($body));
}
catch (\Exception $e) {
$response = "CRITICAL - Skipping the publishing process due to the "
. "following reason: " . $e->getMessage();
return new Response($response, 200);
}
$processor = $this->get('webhook.processor');
$event = $processor->process($request);
$library = $this->get('library');
$identifiers = $library->getIdentifiersByRepo($processor->repo);
if ($identifiers) {
$this->publisher = $this->get('publisher');
foreach ($identifiers as $identifier) {
$fullIdentifier = "{$identifier}/{$processor->branch}";
$this->publisher->publish($fullIdentifier);
$this->sendEmail($fullIdentifier, $hookData);
}
$response = $this->publisher->getMessagesInPlainText();
$identifiers = $library->getIdentifiersByRepo($event->getRepo());
if (!$identifiers) {
$msg = "CRITICAL - No books found which match " . $event->getRepo();
return new Response($msg, Response::HTTP_BAD_REQUEST);
}
else {
$response = "CRITICAL - No books found which match {$processor->repo}";
$this->publisher = $this->get('publisher');
foreach ($identifiers as $identifier) {
$fullIdentifier = sprintf('%s/%s', $identifier, $event->getBranch());
$this->publisher->publish($fullIdentifier);
$this->sendEmail($fullIdentifier, $event);
}
$response = $this->publisher->getMessagesInPlainText();
return new Response($response, 200);
return new Response($response);
}
/**
* Send notification emails after publishing
*
* @param string $identifier
* @param array $hookData
* @param WebhookEvent $event
*/
private function sendEmail(string $identifier, $hookData) {
private function sendEmail(string $identifier, WebhookEvent $event) {
/**
* Array of strings for email addresses that should receive the
* notification email. If none are specified, then the email will be sent to
* all addresses set in the book's yaml configuration
*/
$extraRecipients = $hookData['recipients'];
$commits = $hookData['commits'];
$extraRecipients = $event->getNotificationRecipients();
$commits = $event->getCommits();
$library = $this->get('library');
$messages = $this->get('publisher')->getMessages();
$parts = $library::parseIdentifier($identifier);
......@@ -118,8 +115,7 @@ class PublishController extends Controller {
'commits' => $commits,
];
$body = $this->renderView('AppBundle:Emails:notify.html.twig', $renderParams);
$mail = \Swift_Message::newInstance()
->setSubject($subject)
$mail = (new \Swift_Message($subject))
->setFrom('no-reply@civicrm.org', "CiviCRM docs")
->setTo($recipients)
->setBody($body, 'text/html');
......
......@@ -3,7 +3,7 @@
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\Routing\Annotation\Route;
class ReadController extends Controller {
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -4,7 +4,7 @@ namespace AppBundle\Model;
use AppBundle\Utils\LocaleTools;
class Language {
class Language implements \Countable {
/**
* @var string
......@@ -33,6 +33,14 @@ class Language {
*/
public $watchers = array();
/**
* Implement a count() method.
*/
public function count() {
if (is_array($this->versions)) {
return count($this->versions);
}
}
/**
* Initialize a language with values in it.
*
......@@ -71,7 +79,7 @@ class Language {
}
// If no versions were defined, then add one version (with default values)
if (count($this->versions) == 0) {
if (empty($this->versions)) {
$this->versions[] = new Version('latest', 'Latest', 'latest', 'master', ['stable', 'current']);
}
}
......@@ -173,7 +181,7 @@ class Language {
* @return bool
*/
public function isMultiVersion() {
return count($this->versions) > 1;
return $this->count() > 1;
}
/**
......@@ -182,7 +190,7 @@ class Language {
* @return integer
*/
public function countVersions() {
return count($this->versions);
return $this->count();
}
/**
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
<?php
namespace AppBundle\Model;
class WebhookEvent {
const SOURCE_GITHUB = 'Github';
const SOURCE_GITLAB = 'Gitlab';
/**
* @var string
* Where did the hook original, e.g. github
*/
protected $source = '';
/**
* @var string
* What sort of event is it, for example "push"
*/
protected $type = '';
/**
* @var string
* The repo this event was fired from
*/
protected $repo = '';
/**
* @var string
* The branch the event was fired from
*/
protected $branch = '';
/**
* @var \stdClass[]
* An array of commits in the event, each commit will have properties "ID",
* "author" and "message"
*/
protected $commits = [];
/**
* @return string
*/
public function getSource(): string {
return $this->source;
}
/**
* @param string $source
* @return $this
*/
public function setSource(string $source) {
$this->source = $source;
return $this;
}
/**
* @return string
*/
public function getType(): string {
return $this->type;
}
/**
* @param string $type
* @return $this
*/
public function setType(string $type) {
$this->type = $type;
return $this;
}
/**
* @return string
*/
public function getRepo(): string {
return $this->repo;
}
/**
* @param string $repo
* @return $this
*/
public function setRepo(string $repo) {
$this->repo = $repo;
return $this;
}
/**
* @return string
*/
public function getBranch(): string {
return $this->branch;
}
/**
* @param string $branch
* @return $this
*/
public function setBranch(string $branch) {
$this->branch = $branch;
return $this;
}
/**
* @param array $commit
*/
public function addCommit(array $commit) {
$this->commits[] = $commit;
}
/**
* @param \stdClass[] $commits
*/
public function setCommits(array $commits) {
$this->commits = $commits;
}
/**
* @return \stdClass[]
*/
public function getCommits() {
return $this->commits;
}
/**
* @return array
*/
public function getCommitMessages() {
return array_column($this->getCommits(), 'message');
}
/**
* @return array
* Email address of all those who should be notified about the event
*/
public function getNotificationRecipients() {
$recipients = [];
foreach ($this->getCommits() as $commit) {
$author = $commit->author ?? NULL;
if (property_exists($author, 'email')) {
$recipients[] = $author->email;
}
}
// filter out mails that start with "do not reply"
$recipients = preg_grep('/^(donot|no)reply@/', $recipients, PREG_GREP_INVERT);
return array_unique($recipients);
}
}
File mode changed from 100644 to 100755
......@@ -20,7 +20,7 @@
{% for commit in commits %}
<li>
<strong><a href="{{ commit.url }}">{{ commit.id }}</a></strong> |
{{ commit.message }} | {{ commit.author.username }}
{{ commit.message }} | {{ commit.author.name }}
</li>
{% endfor %}
</ul>
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
<?php
namespace AppBundle\Utils;
class GitHubHookProcessor {
/**
* @var string the URL for the repository
*/
public $repo;
/**
* @var string the name of the branch to publish
*/
public $branch;
/**
* Process a GitHub webhook
*
* @param string $event
* e.g. 'pull_request', 'push'
*
* @param mixed $payload
* An object given by json_decode()
*
* @return array
*
* @throws \Exception
*/
public function process($event, $payload) {
if (empty($payload)) {
throw new \Exception("No payload data supplied");
}
if (empty($event)) {
throw new \Exception("Unable to determine webhook event type from "
. "request headers");
}
if ($event != 'push') {
throw new \Exception("Webhook event type is not 'push'");
}
return $this->getDetailsFromPush($payload);
}
/**
* Use a "push" event to figure out what branch and repo we are talking
* about, and the also work out what emails we should send.
*
* @param mixed $payload
* An object given by json_decode()
*
* @return array
*
* @throws \Exception
*/
protected function getDetailsFromPush($payload) {
$this->branch = preg_replace("#.*/(.*)#", "$1", $payload->ref);
if (empty($this->branch)) {
throw new \Exception("Unable to determine branch from payload data");
}
$this->repo = $payload->repository->html_url;
if (empty($this->repo)) {
throw new \Exception("Unable to determine repository from payload data");
}
$recipients = [];
foreach ($payload->commits as $commit) {
$this->addRecipients($recipients, $commit->author->email);
$this->addRecipients($recipients, $commit->committer->email);
}
return [
'commits' => $payload->commits,
'recipients' => $recipients
];
}
/**
* Adds one or more email recipients, and makes sure all recipients are
* kept unique
*
* @param array $new
* Array of strings for emails of people to notify
* @param array $existing
* Existing recipients so far
* @return array
* Unique array of recipients
*/
protected function addRecipients($existing, $new) {
if (!is_array($new)) {
$new = array($new);
}
// remove any email addresses begins with "donotreply@" or "noreply"
$new = preg_grep('/^(donot|no)reply@/', $new, PREG_GREP_INVERT);
return array_unique(array_merge($existing, $new));
}
}
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
<?php
namespace AppBundle\Utils\WebhookAdapters;
use AppBundle\Model\WebhookEvent;
use Symfony\Component\HttpFoundation\Request;
class GithubHandler implements WebhookHandler {
/**
* @inheritdoc
*/
public function handle(Request $request): WebhookEvent {
$event = new WebhookEvent();
$event->setType($request->headers->get('X-GitHub-Event'));
$event->setSource($event::SOURCE_GITHUB);
$this->getDetailsFromPush($event, $request->getContent());
return $event;
}
/**
* @inheritdoc
*/
public function canHandle(Request $request): bool {
return $request->headers->has('X-Github-Event');
}
/**
* Use a "push" event to figure out what branch and repo we are talking
* about, and the also work out what emails we should send.
*
* @param WebhookEvent $event
* @param string $payload
*
* @return WebhookEvent
*
* @throws \Exception
*/
protected function getDetailsFromPush(WebhookEvent $event, $payload) {
$payload = json_decode($payload);
if (empty($payload)) {
throw new \Exception('Could not decode webhook body');
}
$branch = basename($payload->ref);;
if (empty($branch)) {
throw new \Exception("Unable to determine branch from payload data");
}
$repo = $payload->repository->html_url;
if (empty($repo)) {
throw new \Exception("Unable to determine repository from payload data");
}
$event->setRepo($repo);
$event->setBranch($branch);
$event->setCommits($payload->commits);
return $event;
}
}
<?php
namespace AppBundle\Utils\WebhookAdapters;
use AppBundle\Model\WebhookEvent;
use Symfony\Component\HttpFoundation\Request;
class GitlabHandler implements WebhookHandler {
/**
* @inheritdoc
*/
public function handle(Request $request): WebhookEvent {
$event = new WebhookEvent();
$event->setType($this->getEventType($request));
$event->setSource($event::SOURCE_GITLAB);
$this->getDetailsFromPush($event, $request->getContent());
return $event;
}
/**
* @inheritdoc
*/
public function canHandle(Request $request): bool {
return $request->headers->has('X-Gitlab-Event');
}
/**
* Use a "push" event to figure out what branch and repo we are talking
* about, and the also work out what emails we should send.
*
* @param WebhookEvent $event
* @param string $payload
*
* @return WebhookEvent
*
* @throws \Exception
*/
protected function getDetailsFromPush(WebhookEvent $event, $payload) {
$payload = json_decode($payload);
if (empty($payload)) {
throw new \Exception('Could not decode webhook body');
}
$branch = basename($payload->ref);;
if (empty($branch)) {
throw new \Exception("Unable to determine branch from payload data");
}
$repo = $payload->repository->homepage;
if (empty($repo)) {
throw new \Exception("Unable to determine repository from payload data");
}
$event->setRepo($repo);
$event->setBranch($branch);
$event->setCommits($payload->commits);
return $event;
}
/**
* @param Request $request
* @return string
* @throws \Exception
*/
protected function getEventType(Request $request) : string {
switch ($request->headers->get('X-Gitlab-Event')) {
case 'Push Hook':
return self::EVENT_PUSH;
default:
throw new \Exception('Unrecognized webhook event type');
}
}
}
<?php
namespace AppBundle\Utils\WebhookAdapters;
use AppBundle\Model\WebhookEvent;
use Symfony\Component\HttpFoundation\Request;
interface WebhookHandler {
const EVENT_PUSH = 'push';
/**
* Turns a request into a webhook event
*
* @param Request $request
* @return WebhookEvent
*/
public function handle(Request $request) : WebhookEvent;
/**
* Decides whether or not this adapter can handle the incoming request
*
* @param Request $request
* @return bool
*/
public function canHandle(Request $request) : bool;
}
<?php
namespace AppBundle\Utils;
use AppBundle\Model\WebhookEvent;
use AppBundle\Utils\WebhookAdapters\WebhookHandler;
use Symfony\Component\HttpFoundation\Request;
class WebhookProcessor {
/**
* @var WebhookHandler[]
*/
protected $handlers = [];
/**
* @param WebhookHandler[] $handlers
*/
public function __construct(array $handlers) {
$this->handlers = $handlers;
}
/**
* Process a webhook
*
* @param Request $request
*
* @return WebhookEvent
*
* @throws \Exception
*/
public function process(Request $request) {
$event = null;
foreach ($this->handlers as $handler) {
if ($handler->canHandle($request)) {
$event = $handler->handle($request);
break;
}
}
if (!$event) {
throw new \Exception('Could not handle webhook event');
}
if ($event->getType() != 'push') {
throw new \Exception("Webhook event type is not 'push'");
}
return $event;
}
}
......@@ -2,6 +2,7 @@
namespace AppBundle\Tests\Controller;
use AppBundle\Model\Library;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Bundle\SwiftmailerBundle\DataCollector\MessageDataCollector;
use Symfony\Component\HttpFoundation\Response;
......@@ -15,10 +16,13 @@ class PublishControllerTest extends WebTestCase {
$client = static::createClient();
$client->enableProfiler();
$hookBody = $this->getGithubRequestBody();
$hookBody = $this->getTestBookRequestBody();
$headers = $this->getHeaders();
$endpoint = '/admin/listen';
$testLibrary = new Library(__DIR__ . '/../Files/books');
$client->getContainer()->set('library', $testLibrary);
$client->request('POST', $endpoint, [], [], $headers, $hookBody);
$statusCode = $client->getResponse()->getStatusCode();
......@@ -41,8 +45,8 @@ class PublishControllerTest extends WebTestCase {
/**
* @return string
*/
private function getGithubRequestBody(): string {
return file_get_contents(__DIR__ . '/../Files/webhook-push-sample.json');
private function getTestBookRequestBody(): string {
return file_get_contents(__DIR__ . '/../Files/webhook-gitlab-push-test-book.json');
}
/**
......@@ -50,7 +54,7 @@ class PublishControllerTest extends WebTestCase {
*/
private function getHeaders(): array {
$headers = [
'HTTP_X-GitHub-Event' => 'push', // prefix required for non-standard
'HTTP_X-GitLab-Event' => 'Push Hook', // prefix required for non-standard
'Content-Type' => 'application/json'
];
......
name: TestBook
description: Real repo, but used for testing publishing
langs:
en:
repo: 'https://lab.civicrm.org/seanmadsen/docs-test-book'
......@@ -39,7 +39,7 @@
"id": "c337788155114d32a585be201c7c9a96bcb2ba9a",
"tree_id": "c10d6a99bb2413c68db1afb2e56239ae7f673ffe",
"distinct": true,
"message": "Merge pull request #409 from meusselea/build_profile_doc_imporvemet\n\nTidy up hook_civicrm_buildForm Documentation and remove comments from…",
"message": "Merge pull request #409 from meusselea/build_profile_doc_improvement",
"timestamp": "2017-10-09T20:24:31+01:00",
"url": "https://github.com/civicrm/civicrm-dev-docs/commit/c337788155114d32a585be201c7c9a96bcb2ba9a",
"author": {
......@@ -67,7 +67,7 @@
"id": "c337788155114d32a585be201c7c9a96bcb2ba9a",
"tree_id": "c10d6a99bb2413c68db1afb2e56239ae7f673ffe",
"distinct": true,
"message": "Merge pull request #409 from meusselea/build_profile_doc_imporvemet\n\nTidy up hook_civicrm_buildForm Documentation and remove comments from…",
"message": "Merge pull request #409 from meusselea/build_profile_doc_improvement",
"timestamp": "2017-10-09T20:24:31+01:00",
"url": "https://github.com/civicrm/civicrm-dev-docs/commit/c337788155114d32a585be201c7c9a96bcb2ba9a",
"author": {
......
{
"object_kind": "push",
"before": "95790bf891e76fee5e1747ab589903a6a1f80f22",
"after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
"ref": "refs/heads/master",
"checkout_sha": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
"user_id": 4,
"user_name": "John Smith",
"user_username": "jsmith",
"user_email": "john@example.com",
"user_avatar": "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80",
"project_id": 15,
"project":{
"name":"Diaspora",
"description":"",
"web_url":"http://example.com/mike/diaspora",
"avatar_url":null,
"git_ssh_url":"git@example.com:mike/diaspora.git",
"git_http_url":"http://example.com/mike/diaspora.git",
"namespace":"Mike",
"visibility_level":0,
"path_with_namespace":"mike/diaspora",
"default_branch":"master",
"homepage":"http://example.com/mike/diaspora",
"url":"git@example.com:mike/diaspora.git",
"ssh_url":"git@example.com:mike/diaspora.git",
"http_url":"http://example.com/mike/diaspora.git"
},
"repository":{
"name": "Diaspora",
"url": "git@example.com:mike/diaspora.git",
"description": "",
"homepage": "http://example.com/mike/diaspora",
"git_http_url":"http://example.com/mike/diaspora.git",
"git_ssh_url":"git@example.com:mike/diaspora.git",
"visibility_level":0
},
"commits": [
{
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"message": "Update Catalan translation to e38cb41.",
"timestamp": "2011-12-12T14:27:31+02:00",
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"author": {
"name": "Jordi Mallach",
"email": "jordi@softcatala.org"
},
"added": ["CHANGELOG"],
"modified": ["app/controller/application.rb"],
"removed": []
},
{
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
"message": "fixed readme",
"timestamp": "2012-01-03T23:36:29+02:00",
"url": "http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
"author": {
"name": "GitLab dev user",
"email": "gitlabdev@dv6700.(none)"
},
"added": ["CHANGELOG"],
"modified": ["app/controller/application.rb"],
"removed": []
}
],
"total_commits_count": 4
}
{
"object_kind": "push",
"event_name": "push",
"before": "fa364e3d1ecb7a6bd1c95895253cc93daa2c8503",
"after": "6926446cb5a979f9a7dcdb7a9da9e7b4723304aa",
"ref": "refs/heads/master",
"checkout_sha": "6926446cb5a979f9a7dcdb7a9da9e7b4723304aa",
"message": null,
"user_id": 32,
"user_name": "michael",
"user_username": "michael",
"user_email": "michael@compucorp.co.uk",
"user_avatar": "/uploads/-/system/user/avatar/32/avatar.png",
"project_id": 1,
"project": {
"name": "docs-test-book",
"description": "",
"web_url": "https://lab.civicrm.org/seanmadsen/docs-test-book",
"avatar_url": null,
"git_ssh_url": "git@lab.civicrm.org:seanmadsen/docs-test-book.git",
"git_http_url": "https://lab.civicrm.org/seanmadsen/docs-test-book.git",
"namespace": "seanmadsen",
"visibility_level": 20,
"path_with_namespace": "seanmadsen/docs-test-book",
"default_branch": "master",
"ci_config_path": null,
"homepage": "https://lab.civicrm.org/seanmadsen/docs-test-book",
"url": "git@lab.civicrm.org:seanmadsen/docs-test-book.git",
"ssh_url": "git@lab.civicrm.org:seanmadsen/docs-test-book.git",
"http_url": "https://lab.civicrm.org/seanmadsen/docs-test-book.git"
},
"commits": [
{
"id": "6926446cb5a979f9a7dcdb7a9da9e7b4723304aa",
"message": "change 5\n",
"timestamp": "2017-03-08T02:18:02-07:00",
"url": "https://lab.civicrm.org/seanmadsen/docs-test-book/commit/6926446cb5a979f9a7dcdb7a9da9e7b4723304aa",
"author": {
"name": "Sean Madsen",
"email": "sean@seanmadsen.com"
},
"added": [],
"modified": [
"docs/index.md"
],
"removed": []
},
{
"id": "7d800aba7fc4e7009071fecdfbdfaa9af98e2be3",
"message": "Merge pull request #2 from seanmadsen/test2\n\nchange 4",
"timestamp": "2017-03-08T02:11:32-07:00",
"url": "https://lab.civicrm.org/seanmadsen/docs-test-book/commit/7d800aba7fc4e7009071fecdfbdfaa9af98e2be3",
"author": {
"name": "Sean Madsen",
"email": "sean@seanmadsen.com"
},
"added": [],
"modified": [
"docs/index.md"
],
"removed": []
},
{
"id": "fa364e3d1ecb7a6bd1c95895253cc93daa2c8503",
"message": "change 4\n",
"timestamp": "2017-03-08T00:58:04-07:00",
"url": "https://lab.civicrm.org/seanmadsen/docs-test-book/commit/fa364e3d1ecb7a6bd1c95895253cc93daa2c8503",
"author": {
"name": "Sean Madsen",
"email": "sean@seanmadsen.com"
},
"added": [],
"modified": [
"docs/index.md"
],
"removed": []
}
],
"total_commits_count": 3,
"repository": {
"name": "docs-test-book",
"url": "git@lab.civicrm.org:seanmadsen/docs-test-book.git",
"description": "",
"homepage": "https://lab.civicrm.org/seanmadsen/docs-test-book",
"git_http_url": "https://lab.civicrm.org/seanmadsen/docs-test-book.git",
"git_ssh_url": "git@lab.civicrm.org:seanmadsen/docs-test-book.git",
"visibility_level": 20
}
}
......@@ -2,7 +2,7 @@
namespace AppBundle\Model;
class LibraryTest extends \PHPUnit_Framework_TestCase {
class LibraryTest extends \PHPUnit\Framework\TestCase {
/**
* @param string $identifier
......