Add Gitlab webhook
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Action;
|
||||
|
||||
use Model\GithubWebhook;
|
||||
use Integration\GithubWebhook;
|
||||
|
||||
/**
|
||||
* Create automatically a comment from a webhook
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Action;
|
||||
|
||||
use Model\GithubWebhook;
|
||||
use Integration\GithubWebhook;
|
||||
|
||||
/**
|
||||
* Set a category automatically according to a label
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Action;
|
||||
|
||||
use Model\GithubWebhook;
|
||||
use Integration\GithubWebhook;
|
||||
|
||||
/**
|
||||
* Assign a task to someone
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
namespace Action;
|
||||
|
||||
use Model\GithubWebhook;
|
||||
use Integration\GitlabWebhook;
|
||||
use Integration\GithubWebhook;
|
||||
use Model\Task;
|
||||
|
||||
/**
|
||||
@@ -25,6 +26,8 @@ class TaskClose extends Base
|
||||
Task::EVENT_MOVE_COLUMN,
|
||||
GithubWebhook::EVENT_COMMIT,
|
||||
GithubWebhook::EVENT_ISSUE_CLOSED,
|
||||
GitlabWebhook::EVENT_COMMIT,
|
||||
GitlabWebhook::EVENT_ISSUE_CLOSED,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -39,6 +42,8 @@ class TaskClose extends Base
|
||||
switch ($this->event_name) {
|
||||
case GithubWebhook::EVENT_COMMIT:
|
||||
case GithubWebhook::EVENT_ISSUE_CLOSED:
|
||||
case GitlabWebhook::EVENT_COMMIT:
|
||||
case GitlabWebhook::EVENT_ISSUE_CLOSED:
|
||||
return array();
|
||||
default:
|
||||
return array('column_id' => t('Column'));
|
||||
@@ -56,6 +61,8 @@ class TaskClose extends Base
|
||||
switch ($this->event_name) {
|
||||
case GithubWebhook::EVENT_COMMIT:
|
||||
case GithubWebhook::EVENT_ISSUE_CLOSED:
|
||||
case GitlabWebhook::EVENT_COMMIT:
|
||||
case GitlabWebhook::EVENT_ISSUE_CLOSED:
|
||||
return array('task_id');
|
||||
default:
|
||||
return array('task_id', 'column_id');
|
||||
@@ -86,6 +93,8 @@ class TaskClose extends Base
|
||||
switch ($this->event_name) {
|
||||
case GithubWebhook::EVENT_COMMIT:
|
||||
case GithubWebhook::EVENT_ISSUE_CLOSED:
|
||||
case GitlabWebhook::EVENT_COMMIT:
|
||||
case GitlabWebhook::EVENT_ISSUE_CLOSED:
|
||||
return true;
|
||||
default:
|
||||
return $data['column_id'] == $this->getParam('column_id');
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
namespace Action;
|
||||
|
||||
use Model\GithubWebhook;
|
||||
use Integration\GithubWebhook;
|
||||
use Integration\GitlabWebhook;
|
||||
|
||||
/**
|
||||
* Create automatically a task from a webhook
|
||||
@@ -22,6 +23,7 @@ class TaskCreation extends Base
|
||||
{
|
||||
return array(
|
||||
GithubWebhook::EVENT_ISSUE_OPENED,
|
||||
GitlabWebhook::EVENT_ISSUE_OPENED,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Action;
|
||||
|
||||
use Model\GithubWebhook;
|
||||
use Integration\GithubWebhook;
|
||||
|
||||
/**
|
||||
* Open automatically a task
|
||||
|
||||
@@ -52,7 +52,6 @@ class Project extends Base
|
||||
$this->response->html($this->projectLayout('project/show', array(
|
||||
'project' => $project,
|
||||
'stats' => $this->project->getStats($project['id']),
|
||||
'webhook_token' => $this->config->get('webhook_token'),
|
||||
'title' => $project['name'],
|
||||
)));
|
||||
}
|
||||
@@ -152,6 +151,22 @@ class Project extends Base
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Integrations page
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function integration()
|
||||
{
|
||||
$project = $this->getProjectManagement();
|
||||
|
||||
$this->response->html($this->projectLayout('project/integrations', array(
|
||||
'project' => $project,
|
||||
'title' => t('Integrations'),
|
||||
'webhook_token' => $this->config->get('webhook_token'),
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a form to edit a project
|
||||
*
|
||||
|
||||
@@ -57,7 +57,27 @@ class Webhook extends Base
|
||||
|
||||
$result = $this->githubWebhook->parsePayload(
|
||||
$this->request->getHeader('X-Github-Event'),
|
||||
$this->request->getJson()
|
||||
$this->request->getJson() ?: array()
|
||||
);
|
||||
|
||||
echo $result ? 'PARSED' : 'IGNORED';
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Gitlab webhooks
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function gitlab()
|
||||
{
|
||||
if ($this->config->get('webhook_token') !== $this->request->getStringParam('token')) {
|
||||
$this->response->text('Not Authorized', 401);
|
||||
}
|
||||
|
||||
$this->gitlabWebhook->setProjectId($this->request->getIntegerParam('project_id'));
|
||||
|
||||
$result = $this->gitlabWebhook->parsePayload(
|
||||
$this->request->getJson() ?: array()
|
||||
);
|
||||
|
||||
echo $result ? 'PARSED' : 'IGNORED';
|
||||
|
||||
49
app/Integration/Base.php
Normal file
49
app/Integration/Base.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Integration;
|
||||
|
||||
use Pimple\Container;
|
||||
|
||||
/**
|
||||
* Base class
|
||||
*
|
||||
* @package integration
|
||||
* @author Frederic Guillot
|
||||
*
|
||||
* @property \Model\Task $task
|
||||
* @property \Model\TaskFinder $taskFinder
|
||||
* @property \Model\User $user
|
||||
*/
|
||||
abstract class Base
|
||||
{
|
||||
/**
|
||||
* Container instance
|
||||
*
|
||||
* @access protected
|
||||
* @var \Pimple\Container
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @access public
|
||||
* @param \Pimple\Container $container
|
||||
*/
|
||||
public function __construct(Container $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load automatically class from the container
|
||||
*
|
||||
* @access public
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
return $this->container[$name];
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Model;
|
||||
namespace Integration;
|
||||
|
||||
use Event\GenericEvent;
|
||||
use Model\Task;
|
||||
|
||||
/**
|
||||
* Github Webhook model
|
||||
* Github Webhook
|
||||
*
|
||||
* @package model
|
||||
* @package integration
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class GithubWebhook extends Base
|
||||
@@ -89,7 +90,7 @@ class GithubWebhook extends Base
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($task['is_active'] == Task::STATUS_OPEN) {
|
||||
if ($task['is_active'] == Task::STATUS_OPEN && $task['project_id'] == $this->project_id) {
|
||||
$this->container['dispatcher']->dispatch(
|
||||
self::EVENT_COMMIT,
|
||||
new GenericEvent(array('task_id' => $task_id) + $task)
|
||||
213
app/Integration/GitlabWebhook.php
Normal file
213
app/Integration/GitlabWebhook.php
Normal file
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
namespace Integration;
|
||||
|
||||
use Event\GenericEvent;
|
||||
use Event\TaskEvent;
|
||||
use Model\Task;
|
||||
|
||||
/**
|
||||
* Gitlab Webhook
|
||||
*
|
||||
* @package integration
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class GitlabWebhook extends Base
|
||||
{
|
||||
/**
|
||||
* Events
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const EVENT_ISSUE_OPENED = 'gitlab.webhook.issue.opened';
|
||||
const EVENT_ISSUE_CLOSED = 'gitlab.webhook.issue.closed';
|
||||
const EVENT_COMMIT = 'gitlab.webhook.commit';
|
||||
|
||||
/**
|
||||
* Supported webhook events
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TYPE_PUSH = 'push';
|
||||
const TYPE_ISSUE = 'issue';
|
||||
|
||||
/**
|
||||
* Project id
|
||||
*
|
||||
* @access private
|
||||
* @var integer
|
||||
*/
|
||||
private $project_id = 0;
|
||||
|
||||
/**
|
||||
* Set the project id
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id Project id
|
||||
*/
|
||||
public function setProjectId($project_id)
|
||||
{
|
||||
$this->project_id = $project_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse events
|
||||
*
|
||||
* @access public
|
||||
* @param array $payload Gitlab event
|
||||
* @return boolean
|
||||
*/
|
||||
public function parsePayload(array $payload)
|
||||
{
|
||||
switch ($this->getType($payload)) {
|
||||
case self::TYPE_PUSH:
|
||||
return $this->handlePushEvent($payload);
|
||||
case self::TYPE_ISSUE;
|
||||
return $this->handleIssueEvent($payload);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get event type
|
||||
*
|
||||
* @access public
|
||||
* @param array $payload Gitlab event
|
||||
* @return string
|
||||
*/
|
||||
public function getType(array $payload)
|
||||
{
|
||||
if (isset($payload['object_kind']) && $payload['object_kind'] === 'issue') {
|
||||
return self::TYPE_ISSUE;
|
||||
}
|
||||
|
||||
if (isset($payload['commits'])) {
|
||||
return self::TYPE_PUSH;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse push event
|
||||
*
|
||||
* @access public
|
||||
* @param array $payload Gitlab event
|
||||
* @return boolean
|
||||
*/
|
||||
public function handlePushEvent(array $payload)
|
||||
{
|
||||
foreach ($payload['commits'] as $commit) {
|
||||
$this->handleCommit($commit);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse commit
|
||||
*
|
||||
* @access public
|
||||
* @param array $commit Gitlab commit
|
||||
* @return boolean
|
||||
*/
|
||||
public function handleCommit(array $commit)
|
||||
{
|
||||
$task_id = $this->task->getTaskIdFromText($commit['message']);
|
||||
|
||||
if (! $task_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$task = $this->taskFinder->getById($task_id);
|
||||
|
||||
if (! $task) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($task['is_active'] == Task::STATUS_OPEN && $task['project_id'] == $this->project_id) {
|
||||
|
||||
$this->container['dispatcher']->dispatch(
|
||||
self::EVENT_COMMIT,
|
||||
new TaskEvent(array('task_id' => $task_id) + $task)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse issue event
|
||||
*
|
||||
* @access public
|
||||
* @param array $payload Gitlab event
|
||||
* @return boolean
|
||||
*/
|
||||
public function handleIssueEvent(array $payload)
|
||||
{
|
||||
switch ($payload['object_attributes']['state']) {
|
||||
case 'opened':
|
||||
return $this->handleIssueOpened($payload['object_attributes']);
|
||||
case 'closed':
|
||||
return $this->handleIssueClosed($payload['object_attributes']);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle new issues
|
||||
*
|
||||
* @access public
|
||||
* @param array $issue Issue data
|
||||
* @return boolean
|
||||
*/
|
||||
public function handleIssueOpened(array $issue)
|
||||
{
|
||||
$event = array(
|
||||
'project_id' => $this->project_id,
|
||||
'reference' => $issue['id'],
|
||||
'title' => $issue['title'],
|
||||
'description' => $issue['description']."\n\n[".t('Gitlab Issue').']('.$issue['url'].')',
|
||||
);
|
||||
|
||||
$this->container['dispatcher']->dispatch(
|
||||
self::EVENT_ISSUE_OPENED,
|
||||
new GenericEvent($event)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle issue closing
|
||||
*
|
||||
* @access public
|
||||
* @param array $issue Issue data
|
||||
* @return boolean
|
||||
*/
|
||||
public function handleIssueClosed(array $issue)
|
||||
{
|
||||
$task = $this->taskFinder->getByReference($issue['id']);
|
||||
|
||||
if ($task) {
|
||||
$event = array(
|
||||
'project_id' => $this->project_id,
|
||||
'task_id' => $task['id'],
|
||||
'reference' => $issue['id'],
|
||||
);
|
||||
|
||||
$this->container['dispatcher']->dispatch(
|
||||
self::EVENT_ISSUE_CLOSED,
|
||||
new GenericEvent($event)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -556,8 +556,8 @@ return array(
|
||||
// 'Webhooks' => '',
|
||||
// 'API' => '',
|
||||
// 'Integration' => '',
|
||||
// 'Github webhook' => '',
|
||||
// 'Help on Github webhook' => '',
|
||||
// 'Github webhooks' => '',
|
||||
// 'Help on Github webhooks' => '',
|
||||
// 'Create a comment from an external provider' => '',
|
||||
// 'Github issue comment created' => '',
|
||||
// 'Configure' => '',
|
||||
@@ -626,4 +626,11 @@ return array(
|
||||
// 'Your swimlane have been created successfully.' => '',
|
||||
// 'Example: "Bug, Feature Request, Improvement"' => '',
|
||||
// 'Default categories for new projects (Comma-separated)' => '',
|
||||
// 'Gitlab commit received' => '',
|
||||
// 'Gitlab issue opened' => '',
|
||||
// 'Gitlab issue closed' => '',
|
||||
// 'Gitlab webhooks' => '',
|
||||
// 'Help on Gitlab webhooks' => '',
|
||||
// 'Integrations' => '',
|
||||
// 'Integration with third-party services' => '',
|
||||
);
|
||||
|
||||
@@ -556,8 +556,8 @@ return array(
|
||||
'Webhooks' => 'Webhooks',
|
||||
'API' => 'API',
|
||||
'Integration' => 'Integration',
|
||||
'Github webhook' => 'Github Webhook',
|
||||
'Help on Github webhook' => 'Hilfe bei einem Github Webhook',
|
||||
'Github webhooks' => 'Github Webhook',
|
||||
'Help on Github webhooks' => 'Hilfe bei einem Github Webhook',
|
||||
'Create a comment from an external provider' => 'Kommentar eines externen Providers hinzufügen',
|
||||
'Github issue comment created' => 'Github Fehler Kommentar hinzugefügt',
|
||||
'Configure' => 'konfigurieren',
|
||||
@@ -626,4 +626,11 @@ return array(
|
||||
// 'Your swimlane have been created successfully.' => '',
|
||||
// 'Example: "Bug, Feature Request, Improvement"' => '',
|
||||
// 'Default categories for new projects (Comma-separated)' => '',
|
||||
// 'Gitlab commit received' => '',
|
||||
// 'Gitlab issue opened' => '',
|
||||
// 'Gitlab issue closed' => '',
|
||||
// 'Gitlab webhooks' => '',
|
||||
// 'Help on Gitlab webhooks' => '',
|
||||
// 'Integrations' => '',
|
||||
// 'Integration with third-party services' => '',
|
||||
);
|
||||
|
||||
@@ -556,8 +556,8 @@ return array(
|
||||
// 'Webhooks' => '',
|
||||
// 'API' => '',
|
||||
// 'Integration' => '',
|
||||
// 'Github webhook' => '',
|
||||
// 'Help on Github webhook' => '',
|
||||
// 'Github webhooks' => '',
|
||||
// 'Help on Github webhooks' => '',
|
||||
// 'Create a comment from an external provider' => '',
|
||||
// 'Github issue comment created' => '',
|
||||
// 'Configure' => '',
|
||||
@@ -626,4 +626,11 @@ return array(
|
||||
// 'Your swimlane have been created successfully.' => '',
|
||||
// 'Example: "Bug, Feature Request, Improvement"' => '',
|
||||
// 'Default categories for new projects (Comma-separated)' => '',
|
||||
// 'Gitlab commit received' => '',
|
||||
// 'Gitlab issue opened' => '',
|
||||
// 'Gitlab issue closed' => '',
|
||||
// 'Gitlab webhooks' => '',
|
||||
// 'Help on Gitlab webhooks' => '',
|
||||
// 'Integrations' => '',
|
||||
// 'Integration with third-party services' => '',
|
||||
);
|
||||
|
||||
@@ -556,8 +556,8 @@ return array(
|
||||
// 'Webhooks' => '',
|
||||
// 'API' => '',
|
||||
// 'Integration' => '',
|
||||
// 'Github webhook' => '',
|
||||
// 'Help on Github webhook' => '',
|
||||
// 'Github webhooks' => '',
|
||||
// 'Help on Github webhooks' => '',
|
||||
// 'Create a comment from an external provider' => '',
|
||||
// 'Github issue comment created' => '',
|
||||
// 'Configure' => '',
|
||||
@@ -626,4 +626,11 @@ return array(
|
||||
// 'Your swimlane have been created successfully.' => '',
|
||||
// 'Example: "Bug, Feature Request, Improvement"' => '',
|
||||
// 'Default categories for new projects (Comma-separated)' => '',
|
||||
// 'Gitlab commit received' => '',
|
||||
// 'Gitlab issue opened' => '',
|
||||
// 'Gitlab issue closed' => '',
|
||||
// 'Gitlab webhooks' => '',
|
||||
// 'Help on Gitlab webhooks' => '',
|
||||
// 'Integrations' => '',
|
||||
// 'Integration with third-party services' => '',
|
||||
);
|
||||
|
||||
@@ -556,8 +556,8 @@ return array(
|
||||
'Webhooks' => 'Webhooks',
|
||||
'API' => 'API',
|
||||
'Integration' => 'Intégration',
|
||||
'Github webhook' => 'Webhook Github',
|
||||
'Help on Github webhook' => 'Aide sur les webhooks Github',
|
||||
'Github webhooks' => 'Webhook Github',
|
||||
'Help on Github webhooks' => 'Aide sur les webhooks Github',
|
||||
'Create a comment from an external provider' => 'Créer un commentaire depuis un fournisseur externe',
|
||||
'Github issue comment created' => 'Commentaire créé sur un ticket Github',
|
||||
'Configure' => 'Configurer',
|
||||
@@ -626,4 +626,11 @@ return array(
|
||||
'Your swimlane have been created successfully.' => 'Votre swimlane a été créée avec succès.',
|
||||
'Example: "Bug, Feature Request, Improvement"' => 'Exemple: « Incident, Demande de fonctionnalité, Amélioration »',
|
||||
'Default categories for new projects (Comma-separated)' => 'Catégories par défaut pour les nouveaux projets (séparé par des virgules)',
|
||||
'Gitlab commit received' => '« Commit » reçu via Gitlab',
|
||||
'Gitlab issue opened' => 'Ouverture d\'un ticket sur Gitlab',
|
||||
'Gitlab issue closed' => 'Fermeture d\'un ticket sur Gitlab',
|
||||
'Gitlab webhooks' => 'Webhook Gitlab',
|
||||
'Help on Gitlab webhooks' => 'Aide sur les webhooks Gitlab',
|
||||
'Integrations' => 'Intégrations',
|
||||
'Integration with third-party services' => 'Intégration avec des services externes',
|
||||
);
|
||||
|
||||
@@ -556,8 +556,8 @@ return array(
|
||||
'Webhooks' => 'Webhook',
|
||||
'API' => 'API',
|
||||
'Integration' => 'Integráció',
|
||||
'Github webhook' => 'Github webhook',
|
||||
'Help on Github webhook' => 'Github Webhook súgó',
|
||||
'Github webhooks' => 'Github webhooks',
|
||||
'Help on Github webhooks' => 'Github Webhook súgó',
|
||||
'Create a comment from an external provider' => 'Megjegyzés létrehozása külső felhasználótól',
|
||||
'Github issue comment created' => 'Github issue megjegyzés létrehozva',
|
||||
'Configure' => 'Konfigurál',
|
||||
@@ -626,4 +626,11 @@ return array(
|
||||
// 'Your swimlane have been created successfully.' => '',
|
||||
// 'Example: "Bug, Feature Request, Improvement"' => '',
|
||||
// 'Default categories for new projects (Comma-separated)' => '',
|
||||
// 'Gitlab commit received' => '',
|
||||
// 'Gitlab issue opened' => '',
|
||||
// 'Gitlab issue closed' => '',
|
||||
// 'Gitlab webhooks' => '',
|
||||
// 'Help on Gitlab webhooks' => '',
|
||||
// 'Integrations' => '',
|
||||
// 'Integration with third-party services' => '',
|
||||
);
|
||||
|
||||
@@ -556,8 +556,8 @@ return array(
|
||||
// 'Webhooks' => '',
|
||||
// 'API' => '',
|
||||
// 'Integration' => '',
|
||||
// 'Github webhook' => '',
|
||||
// 'Help on Github webhook' => '',
|
||||
// 'Github webhooks' => '',
|
||||
// 'Help on Github webhooks' => '',
|
||||
// 'Create a comment from an external provider' => '',
|
||||
// 'Github issue comment created' => '',
|
||||
// 'Configure' => '',
|
||||
@@ -626,4 +626,11 @@ return array(
|
||||
// 'Your swimlane have been created successfully.' => '',
|
||||
// 'Example: "Bug, Feature Request, Improvement"' => '',
|
||||
// 'Default categories for new projects (Comma-separated)' => '',
|
||||
// 'Gitlab commit received' => '',
|
||||
// 'Gitlab issue opened' => '',
|
||||
// 'Gitlab issue closed' => '',
|
||||
// 'Gitlab webhooks' => '',
|
||||
// 'Help on Gitlab webhooks' => '',
|
||||
// 'Integrations' => '',
|
||||
// 'Integration with third-party services' => '',
|
||||
);
|
||||
|
||||
@@ -556,8 +556,8 @@ return array(
|
||||
// 'Webhooks' => '',
|
||||
// 'API' => '',
|
||||
// 'Integration' => '',
|
||||
// 'Github webhook' => '',
|
||||
// 'Help on Github webhook' => '',
|
||||
// 'Github webhooks' => '',
|
||||
// 'Help on Github webhooks' => '',
|
||||
// 'Create a comment from an external provider' => '',
|
||||
// 'Github issue comment created' => '',
|
||||
// 'Configure' => '',
|
||||
@@ -626,4 +626,11 @@ return array(
|
||||
// 'Your swimlane have been created successfully.' => '',
|
||||
// 'Example: "Bug, Feature Request, Improvement"' => '',
|
||||
// 'Default categories for new projects (Comma-separated)' => '',
|
||||
// 'Gitlab commit received' => '',
|
||||
// 'Gitlab issue opened' => '',
|
||||
// 'Gitlab issue closed' => '',
|
||||
// 'Gitlab webhooks' => '',
|
||||
// 'Help on Gitlab webhooks' => '',
|
||||
// 'Integrations' => '',
|
||||
// 'Integration with third-party services' => '',
|
||||
);
|
||||
|
||||
@@ -556,8 +556,8 @@ return array(
|
||||
// 'Webhooks' => '',
|
||||
// 'API' => '',
|
||||
// 'Integration' => '',
|
||||
// 'Github webhook' => '',
|
||||
// 'Help on Github webhook' => '',
|
||||
// 'Github webhooks' => '',
|
||||
// 'Help on Github webhooks' => '',
|
||||
// 'Create a comment from an external provider' => '',
|
||||
// 'Github issue comment created' => '',
|
||||
// 'Configure' => '',
|
||||
@@ -626,4 +626,11 @@ return array(
|
||||
// 'Your swimlane have been created successfully.' => '',
|
||||
// 'Example: "Bug, Feature Request, Improvement"' => '',
|
||||
// 'Default categories for new projects (Comma-separated)' => '',
|
||||
// 'Gitlab commit received' => '',
|
||||
// 'Gitlab issue opened' => '',
|
||||
// 'Gitlab issue closed' => '',
|
||||
// 'Gitlab webhooks' => '',
|
||||
// 'Help on Gitlab webhooks' => '',
|
||||
// 'Integrations' => '',
|
||||
// 'Integration with third-party services' => '',
|
||||
);
|
||||
|
||||
@@ -556,8 +556,8 @@ return array(
|
||||
// 'Webhooks' => '',
|
||||
// 'API' => '',
|
||||
'Integration' => 'Integração',
|
||||
// 'Github webhook' => '',
|
||||
'Help on Github webhook' => 'Ajuda para o Github webhook',
|
||||
// 'Github webhooks' => '',
|
||||
'Help on Github webhooks' => 'Ajuda para o Github webhooks',
|
||||
'Create a comment from an external provider' => 'Criar um comentário de um provedor externo',
|
||||
// 'Github issue comment created' => '',
|
||||
'Configure' => 'Configurar',
|
||||
@@ -626,4 +626,11 @@ return array(
|
||||
// 'Your swimlane have been created successfully.' => '',
|
||||
// 'Example: "Bug, Feature Request, Improvement"' => '',
|
||||
// 'Default categories for new projects (Comma-separated)' => '',
|
||||
// 'Gitlab commit received' => '',
|
||||
// 'Gitlab issue opened' => '',
|
||||
// 'Gitlab issue closed' => '',
|
||||
// 'Gitlab webhooks' => '',
|
||||
// 'Help on Gitlab webhooks' => '',
|
||||
// 'Integrations' => '',
|
||||
// 'Integration with third-party services' => '',
|
||||
);
|
||||
|
||||
@@ -556,8 +556,8 @@ return array(
|
||||
// 'Webhooks' => '',
|
||||
// 'API' => '',
|
||||
// 'Integration' => '',
|
||||
// 'Github webhook' => '',
|
||||
// 'Help on Github webhook' => '',
|
||||
// 'Github webhooks' => '',
|
||||
// 'Help on Github webhooks' => '',
|
||||
// 'Create a comment from an external provider' => '',
|
||||
// 'Github issue comment created' => '',
|
||||
// 'Configure' => '',
|
||||
@@ -626,4 +626,11 @@ return array(
|
||||
// 'Your swimlane have been created successfully.' => '',
|
||||
// 'Example: "Bug, Feature Request, Improvement"' => '',
|
||||
// 'Default categories for new projects (Comma-separated)' => '',
|
||||
// 'Gitlab commit received' => '',
|
||||
// 'Gitlab issue opened' => '',
|
||||
// 'Gitlab issue closed' => '',
|
||||
// 'Gitlab webhooks' => '',
|
||||
// 'Help on Gitlab webhooks' => '',
|
||||
// 'Integrations' => '',
|
||||
// 'Integration with third-party services' => '',
|
||||
);
|
||||
|
||||
@@ -556,8 +556,8 @@ return array(
|
||||
// 'Webhooks' => '',
|
||||
// 'API' => '',
|
||||
// 'Integration' => '',
|
||||
// 'Github webhook' => '',
|
||||
// 'Help on Github webhook' => '',
|
||||
// 'Github webhooks' => '',
|
||||
// 'Help on Github webhooks' => '',
|
||||
// 'Create a comment from an external provider' => '',
|
||||
// 'Github issue comment created' => '',
|
||||
// 'Configure' => '',
|
||||
@@ -626,4 +626,11 @@ return array(
|
||||
// 'Your swimlane have been created successfully.' => '',
|
||||
// 'Example: "Bug, Feature Request, Improvement"' => '',
|
||||
// 'Default categories for new projects (Comma-separated)' => '',
|
||||
// 'Gitlab commit received' => '',
|
||||
// 'Gitlab issue opened' => '',
|
||||
// 'Gitlab issue closed' => '',
|
||||
// 'Gitlab webhooks' => '',
|
||||
// 'Help on Gitlab webhooks' => '',
|
||||
// 'Integrations' => '',
|
||||
// 'Integration with third-party services' => '',
|
||||
);
|
||||
|
||||
@@ -556,8 +556,8 @@ return array(
|
||||
// 'Webhooks' => '',
|
||||
// 'API' => '',
|
||||
// 'Integration' => '',
|
||||
// 'Github webhook' => '',
|
||||
// 'Help on Github webhook' => '',
|
||||
// 'Github webhooks' => '',
|
||||
// 'Help on Github webhooks' => '',
|
||||
// 'Create a comment from an external provider' => '',
|
||||
// 'Github issue comment created' => '',
|
||||
// 'Configure' => '',
|
||||
@@ -626,4 +626,11 @@ return array(
|
||||
// 'Your swimlane have been created successfully.' => '',
|
||||
// 'Example: "Bug, Feature Request, Improvement"' => '',
|
||||
// 'Default categories for new projects (Comma-separated)' => '',
|
||||
// 'Gitlab commit received' => '',
|
||||
// 'Gitlab issue opened' => '',
|
||||
// 'Gitlab issue closed' => '',
|
||||
// 'Gitlab webhooks' => '',
|
||||
// 'Help on Gitlab webhooks' => '',
|
||||
// 'Integrations' => '',
|
||||
// 'Integration with third-party services' => '',
|
||||
);
|
||||
|
||||
@@ -556,8 +556,8 @@ return array(
|
||||
'Webhooks' => '网络钩子',
|
||||
'API' => '应用程序接口',
|
||||
'Integration' => '整合',
|
||||
'Github webhook' => 'Github 网络钩子',
|
||||
'Help on Github webhook' => 'Github 网络钩子帮助',
|
||||
'Github webhooks' => 'Github 网络钩子',
|
||||
'Help on Github webhooks' => 'Github 网络钩子帮助',
|
||||
'Create a comment from an external provider' => '从外部创建一个评论',
|
||||
'Github issue comment created' => '已经创建了Github问题评论',
|
||||
'Configure' => '配置',
|
||||
@@ -626,4 +626,11 @@ return array(
|
||||
'Your swimlane have been created successfully.' => '已经成功创建泳道。',
|
||||
// 'Example: "Bug, Feature Request, Improvement"' => '',
|
||||
// 'Default categories for new projects (Comma-separated)' => '',
|
||||
// 'Gitlab commit received' => '',
|
||||
// 'Gitlab issue opened' => '',
|
||||
// 'Gitlab issue closed' => '',
|
||||
// 'Gitlab webhooks' => '',
|
||||
// 'Help on Gitlab webhooks' => '',
|
||||
// 'Integrations' => '',
|
||||
// 'Integration with third-party services' => '',
|
||||
);
|
||||
|
||||
@@ -21,7 +21,7 @@ class Acl extends Base
|
||||
'task' => array('readonly'),
|
||||
'board' => array('readonly'),
|
||||
'project' => array('feed'),
|
||||
'webhook' => array('task', 'github'),
|
||||
'webhook' => array('task', 'github', 'gitlab'),
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Model;
|
||||
|
||||
use Integration\GitlabWebhook;
|
||||
use Integration\GithubWebhook;
|
||||
use SimpleValidator\Validator;
|
||||
use SimpleValidator\Validators;
|
||||
|
||||
@@ -79,6 +81,9 @@ class Action extends Base
|
||||
GithubWebhook::EVENT_ISSUE_ASSIGNEE_CHANGE => t('Github issue assignee change'),
|
||||
GithubWebhook::EVENT_ISSUE_LABEL_CHANGE => t('Github issue label change'),
|
||||
GithubWebhook::EVENT_ISSUE_COMMENT => t('Github issue comment created'),
|
||||
GitlabWebhook::EVENT_COMMIT => t('Gitlab commit received'),
|
||||
GitlabWebhook::EVENT_ISSUE_OPENED => t('Gitlab issue opened'),
|
||||
GitlabWebhook::EVENT_ISSUE_CLOSED => t('Gitlab issue closed'),
|
||||
);
|
||||
|
||||
asort($values);
|
||||
|
||||
@@ -29,6 +29,7 @@ use Pimple\Container;
|
||||
* @property \Model\ProjectPermission $projectPermission
|
||||
* @property \Model\SubTask $subTask
|
||||
* @property \Model\SubtaskHistory $subtaskHistory
|
||||
* @property \Model\Swimlane $swimlane
|
||||
* @property \Model\Task $task
|
||||
* @property \Model\TaskCreation $taskCreation
|
||||
* @property \Model\TaskExport $taskExport
|
||||
|
||||
@@ -22,7 +22,6 @@ class ClassProvider implements ServiceProviderInterface
|
||||
'Config',
|
||||
'DateParser',
|
||||
'File',
|
||||
'GithubWebhook',
|
||||
'LastLogin',
|
||||
'Notification',
|
||||
'Project',
|
||||
@@ -53,6 +52,10 @@ class ClassProvider implements ServiceProviderInterface
|
||||
'Template',
|
||||
'Session',
|
||||
),
|
||||
'Integration' => array(
|
||||
'GitlabWebhook',
|
||||
'GithubWebhook',
|
||||
)
|
||||
);
|
||||
|
||||
public function register(Container $container)
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Subscriber;
|
||||
|
||||
use Event\GenericEvent;
|
||||
use Model\Task;
|
||||
use Model\GithubWebhook;
|
||||
use Integration\GithubWebhook;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
class ProjectModificationDateSubscriber extends Base implements EventSubscriberInterface
|
||||
|
||||
15
app/Template/project/integrations.php
Normal file
15
app/Template/project/integrations.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<div class="page-header">
|
||||
<h2><?= t('Integration with third-party services') ?></h2>
|
||||
</div>
|
||||
|
||||
<h3><i class="fa fa-github fa-fw"></i> <?= t('Github webhooks') ?></h3>
|
||||
<div class="listing">
|
||||
<input type="text" class="auto-select" readonly="readonly" value="<?= $this->getCurrentBaseUrl().$this->u('webhook', 'github', array('token' => $webhook_token, 'project_id' => $project['id'])) ?>"/><br/>
|
||||
<p class="form-help"><a href="http://kanboard.net/documentation/github-webhooks" target="_blank"><?= t('Help on Github webhooks') ?></a></p>
|
||||
</div>
|
||||
|
||||
<h3><i class="fa fa-git fa-fw"></i> <?= t('Gitlab webhooks') ?></h3>
|
||||
<div class="listing">
|
||||
<input type="text" class="auto-select" readonly="readonly" value="<?= $this->getCurrentBaseUrl().$this->u('webhook', 'gitlab', array('token' => $webhook_token, 'project_id' => $project['id'])) ?>"/><br/>
|
||||
<p class="form-help"><a href="http://kanboard.net/documentation/gitlab-webhooks" target="_blank"><?= t('Help on Gitlab webhooks') ?></a></p>
|
||||
</div>
|
||||
@@ -53,14 +53,3 @@
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</table>
|
||||
|
||||
<?php if ($this->acl->isAdminUser()): ?>
|
||||
<div class="page-header">
|
||||
<h2><?= t('Integration') ?></h2>
|
||||
</div>
|
||||
|
||||
<h3><i class="fa fa-github fa-fw"></i><?= t('Github webhook') ?></h3>
|
||||
<input type="text" class="auto-select" readonly="readonly" value="<?= $this->getCurrentBaseUrl().$this->u('webhook', 'github', array('token' => $webhook_token, 'project_id' => $project['id'])) ?>"/><br/>
|
||||
<p class="form-help"><a href="http://kanboard.net/documentation/github-webhooks" target="_blank"><?= t('Help on Github webhook') ?></a></p>
|
||||
|
||||
<?php endif ?>
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
<li>
|
||||
<?= $this->a(t('Public access'), 'project', 'share', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<li>
|
||||
<?= $this->a(t('Integrations'), 'project', 'integration', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<li>
|
||||
<?= $this->a(t('Edit project'), 'project', 'edit', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
|
||||
@@ -7,7 +7,7 @@ use Model\Task;
|
||||
use Model\TaskCreation;
|
||||
use Model\TaskFinder;
|
||||
use Model\Project;
|
||||
use Model\GithubWebhook;
|
||||
use Integration\GithubWebhook;
|
||||
|
||||
class ActionTaskCloseTest extends Base
|
||||
{
|
||||
|
||||
@@ -10,10 +10,10 @@ use Model\TaskPosition;
|
||||
use Model\TaskCreation;
|
||||
use Model\TaskFinder;
|
||||
use Model\Category;
|
||||
use Model\GithubWebhook;
|
||||
use Integration\GithubWebhook;
|
||||
|
||||
class ActionTest extends Base
|
||||
{/*
|
||||
{
|
||||
public function testSingleAction()
|
||||
{
|
||||
$tp = new TaskPosition($this->container);
|
||||
@@ -61,7 +61,7 @@ class ActionTest extends Base
|
||||
$this->assertEquals(4, $t1['column_id']);
|
||||
$this->assertEquals(0, $t1['is_active']);
|
||||
}
|
||||
*/
|
||||
|
||||
public function testMultipleActions()
|
||||
{
|
||||
$tp = new TaskPosition($this->container);
|
||||
|
||||
116
tests/units/GitlabWebhookTest.php
Normal file
116
tests/units/GitlabWebhookTest.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__.'/Base.php';
|
||||
|
||||
use Integration\GitlabWebhook;
|
||||
use Model\TaskCreation;
|
||||
use Model\TaskFinder;
|
||||
use Model\Project;
|
||||
|
||||
class GitlabWebhookTest extends Base
|
||||
{
|
||||
private $push_payload = '{"before":"9187f41ba34a2b40d41c50ed4b624ce374c5e583","after":"b3caaee62ad27dc31497946065ac18299784aee4","ref":"refs/heads/master","user_id":74067,"user_name":"Fred","project_id":124474,"repository":{"name":"kanboard","url":"git@gitlab.com:minicoders/kanboard.git","description":"Test repo","homepage":"https://gitlab.com/minicoders/kanboard"},"commits":[{"id":"b3caaee62ad27dc31497946065ac18299784aee4","message":"Fix bug #2\n","timestamp":"2014-12-28T20:31:48-05:00","url":"https://gitlab.com/minicoders/kanboard/commit/b3caaee62ad27dc31497946065ac18299784aee4","author":{"name":"Frédéric Guillot","email":"git@localhost"}}],"total_commits_count":1}';
|
||||
private $issue_open_payload = '{"object_kind":"issue","user":{"name":"Fred","username":"minicoders","avatar_url":"https://secure.gravatar.com/avatar/3c44936e5a56f80711bff14987d2733f?s=40\u0026d=identicon"},"object_attributes":{"id":103356,"title":"Test Webhook","assignee_id":null,"author_id":74067,"project_id":124474,"created_at":"2014-12-29 01:24:24 UTC","updated_at":"2014-12-29 01:24:24 UTC","position":0,"branch_name":null,"description":"- test1\r\n- test2","milestone_id":null,"state":"opened","iid":1,"url":"https://gitlab.com/minicoders/kanboard/issues/1","action":"open"}}';
|
||||
private $issue_closed_payload = '{"object_kind":"issue","user":{"name":"Fred","username":"minicoders","avatar_url":"https://secure.gravatar.com/avatar/3c44936e5a56f80711bff14987d2733f?s=40\u0026d=identicon"},"object_attributes":{"id":103361,"title":"uu","assignee_id":null,"author_id":74067,"project_id":124474,"created_at":"2014-12-29 01:28:44 UTC","updated_at":"2014-12-29 01:34:47 UTC","position":0,"branch_name":null,"description":"","milestone_id":null,"state":"closed","iid":4,"url":"https://gitlab.com/minicoders/kanboard/issues/4","action":"update"}}';
|
||||
|
||||
public function testGetEventType()
|
||||
{
|
||||
$g = new GitlabWebhook($this->container);
|
||||
|
||||
$this->assertEquals(GitlabWebhook::TYPE_PUSH, $g->getType(json_decode($this->push_payload, true)));
|
||||
$this->assertEquals(GitlabWebhook::TYPE_ISSUE, $g->getType(json_decode($this->issue_open_payload, true)));
|
||||
$this->assertEquals(GitlabWebhook::TYPE_ISSUE, $g->getType(json_decode($this->issue_closed_payload, true)));
|
||||
$this->assertEquals('', $g->getType(array()));
|
||||
}
|
||||
|
||||
public function testHandleCommit()
|
||||
{
|
||||
$g = new GitlabWebhook($this->container);
|
||||
$p = new Project($this->container);
|
||||
$tc = new TaskCreation($this->container);
|
||||
$tf = new TaskFinder($this->container);
|
||||
|
||||
$this->assertEquals(1, $p->create(array('name' => 'test')));
|
||||
$g->setProjectId(1);
|
||||
|
||||
$this->container['dispatcher']->addListener(GitlabWebhook::EVENT_COMMIT, function() {});
|
||||
|
||||
$event = json_decode($this->push_payload, true);
|
||||
|
||||
// No task
|
||||
$this->assertFalse($g->handleCommit($event['commits'][0]));
|
||||
|
||||
// Create task with the wrong id
|
||||
$this->assertEquals(1, $tc->create(array('title' => 'test', 'project_id' => 1)));
|
||||
$this->assertFalse($g->handleCommit($event['commits'][0]));
|
||||
|
||||
// Create task with the right id
|
||||
$this->assertEquals(2, $tc->create(array('title' => 'test', 'project_id' => 1)));
|
||||
$this->assertTrue($g->handleCommit($event['commits'][0]));
|
||||
|
||||
$called = $this->container['dispatcher']->getCalledListeners();
|
||||
$this->assertArrayHasKey(GitlabWebhook::EVENT_COMMIT.'.closure', $called);
|
||||
}
|
||||
|
||||
public function testHandleIssueOpened()
|
||||
{
|
||||
$g = new GitlabWebhook($this->container);
|
||||
$g->setProjectId(1);
|
||||
|
||||
$this->container['dispatcher']->addListener(GitlabWebhook::EVENT_ISSUE_OPENED, array($this, 'onOpen'));
|
||||
|
||||
$event = json_decode($this->issue_open_payload, true);
|
||||
$this->assertTrue($g->handleIssueOpened($event['object_attributes']));
|
||||
|
||||
$called = $this->container['dispatcher']->getCalledListeners();
|
||||
$this->assertArrayHasKey(GitlabWebhook::EVENT_ISSUE_OPENED.'.GitlabWebhookTest::onOpen', $called);
|
||||
}
|
||||
|
||||
public function testHandleIssueClosed()
|
||||
{
|
||||
$g = new GitlabWebhook($this->container);
|
||||
$p = new Project($this->container);
|
||||
$tc = new TaskCreation($this->container);
|
||||
$tf = new TaskFinder($this->container);
|
||||
|
||||
$this->assertEquals(1, $p->create(array('name' => 'test')));
|
||||
$g->setProjectId(1);
|
||||
|
||||
$this->container['dispatcher']->addListener(GitlabWebhook::EVENT_ISSUE_CLOSED, array($this, 'onClose'));
|
||||
|
||||
$event = json_decode($this->issue_closed_payload, true);
|
||||
|
||||
// Issue not there
|
||||
$this->assertFalse($g->handleIssueClosed($event['object_attributes']));
|
||||
|
||||
$called = $this->container['dispatcher']->getCalledListeners();
|
||||
$this->assertEmpty($called);
|
||||
|
||||
// Create a task with the issue reference
|
||||
$this->assertEquals(1, $tc->create(array('title' => 'A', 'project_id' => 1, 'reference' => 103361)));
|
||||
$task = $tf->getByReference(103361);
|
||||
$this->assertNotEmpty($task);
|
||||
|
||||
$this->assertTrue($g->handleIssueClosed($event['object_attributes']));
|
||||
|
||||
$called = $this->container['dispatcher']->getCalledListeners();
|
||||
$this->assertArrayHasKey(GitlabWebhook::EVENT_ISSUE_CLOSED.'.GitlabWebhookTest::onClose', $called);
|
||||
}
|
||||
|
||||
public function onOpen($event)
|
||||
{
|
||||
$data = $event->getAll();
|
||||
$this->assertEquals(1, $data['project_id']);
|
||||
$this->assertEquals(103356, $data['reference']);
|
||||
$this->assertEquals('Test Webhook', $data['title']);
|
||||
$this->assertEquals("- test1\r\n- test2\n\n[Gitlab Issue](https://gitlab.com/minicoders/kanboard/issues/1)", $data['description']);
|
||||
}
|
||||
|
||||
public function onClose($event)
|
||||
{
|
||||
$data = $event->getAll();
|
||||
$this->assertEquals(1, $data['project_id']);
|
||||
$this->assertEquals(1, $data['task_id']);
|
||||
$this->assertEquals(103361, $data['reference']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user