246 lines
9.3 KiB
PHP
246 lines
9.3 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace App\Service;
|
||
|
|
|
||
|
|
use App\Entity\JiraAssignee;
|
||
|
|
use App\Entity\JiraIssueType;
|
||
|
|
use App\Entity\JiraStatus;
|
||
|
|
use App\Entity\KanbanBoard;
|
||
|
|
use App\Entity\KanbanEntry;
|
||
|
|
use Zend\Cache\Storage\StorageInterface;
|
||
|
|
use Zend\Config\Config;
|
||
|
|
use Zend\Expressive\Router\RouterInterface;
|
||
|
|
use Zend\Http\Client;
|
||
|
|
use Zend\Json\Decoder;
|
||
|
|
use Zend\Json\Json;
|
||
|
|
|
||
|
|
class JiraCollectorService
|
||
|
|
{
|
||
|
|
|
||
|
|
const CACHE_KEY_KANBANBOARD = 'kanbanBoard';
|
||
|
|
|
||
|
|
/** @var StorageInterface */
|
||
|
|
private $cache;
|
||
|
|
|
||
|
|
/** @var Config */
|
||
|
|
private $config;
|
||
|
|
|
||
|
|
/** @var Client */
|
||
|
|
private $httpClient;
|
||
|
|
|
||
|
|
/** @var RouterInterface */
|
||
|
|
private $router;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* JiraClientService constructor.
|
||
|
|
* @param StorageInterface $cache
|
||
|
|
* @param Client $client
|
||
|
|
* @param Config $config
|
||
|
|
* @param RouterInterface $router
|
||
|
|
*/
|
||
|
|
public function __construct(StorageInterface $cache, Client $client, Config $config, RouterInterface $router)
|
||
|
|
{
|
||
|
|
$this->cache = $cache;
|
||
|
|
$this->router = $router;
|
||
|
|
$this->httpClient = $client;
|
||
|
|
$this->config = $config;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param int $filterId
|
||
|
|
* @param bool $forceReload
|
||
|
|
* @return KanbanBoard
|
||
|
|
*/
|
||
|
|
public function getKanbanBoard(int $filterId = null, bool $forceReload = false): KanbanBoard
|
||
|
|
{
|
||
|
|
$kanbanBoard = $this->cache->getItem('kanbanBoard');
|
||
|
|
if ($forceReload || null === $kanbanBoard) {
|
||
|
|
$user = $this->config->get('jira.user');
|
||
|
|
$password = $this->config->get('jira.password');
|
||
|
|
/** @var Config $kanbanBoardUriParams */
|
||
|
|
$kanbanBoardUriParams = $this->config->get('url.jiraKanbanBoard');
|
||
|
|
|
||
|
|
$kanbanBoardUri = sprintf(
|
||
|
|
$kanbanBoardUriParams['baseUrl'],
|
||
|
|
isset($filterId) ? $filterId : $kanbanBoardUriParams['filterId'],
|
||
|
|
implode(",", $kanbanBoardUriParams['fields']->toArray())
|
||
|
|
);
|
||
|
|
|
||
|
|
$response = $this->httpClient
|
||
|
|
->setUri($kanbanBoardUri)
|
||
|
|
->setAuth($user, $password)
|
||
|
|
->send();
|
||
|
|
|
||
|
|
if (!$response->isSuccess()) {
|
||
|
|
throw new \UnexpectedValueException("Bad JIRA result", $response->getStatusCode());
|
||
|
|
}
|
||
|
|
|
||
|
|
$parsedJsonData = Decoder::decode($response->getBody(), Json::TYPE_ARRAY);
|
||
|
|
|
||
|
|
$kanbanBoard = $this->hydrateKanbanBoard($parsedJsonData);
|
||
|
|
$this->cache->setItem(self::CACHE_KEY_KANBANBOARD, serialize($kanbanBoard));
|
||
|
|
} else {
|
||
|
|
$kanbanBoard = unserialize($kanbanBoard);
|
||
|
|
}
|
||
|
|
|
||
|
|
return $kanbanBoard;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param $parsedJsonData
|
||
|
|
* @return KanbanBoard
|
||
|
|
* @todo check if avatar has to be locally cached
|
||
|
|
*/
|
||
|
|
private function hydrateKanbanBoard($parsedJsonData): KanbanBoard
|
||
|
|
{
|
||
|
|
$kanbanBoard = new KanbanBoard();
|
||
|
|
|
||
|
|
foreach ($parsedJsonData['issues'] as $jsonIssue) {
|
||
|
|
$kanbanEntry = new KanbanEntry();
|
||
|
|
$kanbanEntry->setId(intval($jsonIssue['id']))
|
||
|
|
->setKey($jsonIssue['key'])
|
||
|
|
->setSummary($jsonIssue['fields']['summary'])
|
||
|
|
->setExternalLink($jsonIssue['fields']['customfield_10850'])
|
||
|
|
->setMhwebStatus($jsonIssue['fields']['customfield_10844'])
|
||
|
|
->setAnswerCode($jsonIssue['fields']['customfield_11692'])
|
||
|
|
->setIssuePriority($jsonIssue['fields']['priority']['name'])
|
||
|
|
->setIssuePriorityIcon($jsonIssue['fields']['priority']['iconUrl'])
|
||
|
|
->setLabels($jsonIssue['fields']['labels'])
|
||
|
|
->setFixVersions($jsonIssue['fields']['fixVersions']);
|
||
|
|
|
||
|
|
$spikeTimeSpent = 0;
|
||
|
|
array_map(function ($worklog) use (&$spikeTimeSpent) {
|
||
|
|
$spikeTimeSpent += strtoupper($worklog['comment']) == 'BLOCKED'
|
||
|
|
? 0
|
||
|
|
: $worklog['timeSpentSeconds'];
|
||
|
|
}, $jsonIssue['fields']['worklog']['worklogs']);
|
||
|
|
$kanbanEntry->setWorklog((int)ceil($spikeTimeSpent / 3600));
|
||
|
|
|
||
|
|
$secondsBlocked = 0;
|
||
|
|
array_map(function ($worklog) use (&$secondsBlocked) {
|
||
|
|
$secondsBlocked += strtoupper($worklog['comment']) == 'BLOCKED'
|
||
|
|
? $worklog['timeSpentSeconds']
|
||
|
|
: 0;
|
||
|
|
}, $jsonIssue['fields']['worklog']['worklogs']);
|
||
|
|
$kanbanEntry->setDaysBlocked((int)ceil($secondsBlocked / 28800));
|
||
|
|
|
||
|
|
// additional assignees : customfield_10401
|
||
|
|
if (isset($jsonIssue['fields']['customfield_10401'])) {
|
||
|
|
foreach ($jsonIssue['fields']['customfield_10401'] as $assignee) {
|
||
|
|
$avatarUrl = $this->router->generateUri('avatar.image', [
|
||
|
|
'signum' => $assignee['key'],
|
||
|
|
]);
|
||
|
|
|
||
|
|
$jiraAssignee = new JiraAssignee();
|
||
|
|
$jiraAssignee->setName($assignee['displayName'])
|
||
|
|
->setSignum($assignee['key'])
|
||
|
|
->setEmail(strtolower($assignee['emailAddress']))
|
||
|
|
->setAvatar($avatarUrl)
|
||
|
|
->setActive($assignee['active']);
|
||
|
|
$kanbanEntry->addAdditionalAssignee($jiraAssignee);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// externalId : customfield_10010
|
||
|
|
if (isset($jsonIssue['fields']['customfield_10010'])) {
|
||
|
|
$kanbanEntry->setExternalId($jsonIssue['fields']['customfield_10010']);
|
||
|
|
}
|
||
|
|
|
||
|
|
// prio : customfield_10840
|
||
|
|
if (isset($jsonIssue['fields']['customfield_11226'])) {
|
||
|
|
$kanbanEntry->setPrio($jsonIssue['fields']['customfield_11226']);
|
||
|
|
}
|
||
|
|
|
||
|
|
// functional area : customfield_11225
|
||
|
|
if (isset($jsonIssue['fields']['customfield_11225'])) {
|
||
|
|
foreach ($jsonIssue['fields']['customfield_11225'] as $functionalArea) {
|
||
|
|
$kanbanEntry->addFunctionalArea($functionalArea['value']);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// project : customfield_10840
|
||
|
|
if (isset($jsonIssue['fields']['customfield_10840'])) {
|
||
|
|
$kanbanEntry->setProject($jsonIssue['fields']['customfield_10840']['value']);
|
||
|
|
}
|
||
|
|
|
||
|
|
// mhweb hot : customfield_10847
|
||
|
|
if (isset($jsonIssue['fields']['customfield_10847'])) {
|
||
|
|
$boolVal = $jsonIssue['fields']['customfield_10847'][0]['value'] == 'yes';
|
||
|
|
$kanbanEntry->setMhwebHot($boolVal);
|
||
|
|
}
|
||
|
|
|
||
|
|
// mhweb external : customfield_10849
|
||
|
|
if (isset($jsonIssue['fields']['customfield_10849'])) {
|
||
|
|
$boolVal = $jsonIssue['fields']['customfield_10849'][0]['value'] == 'yes';
|
||
|
|
$kanbanEntry->setMhwebExternal($boolVal);
|
||
|
|
}
|
||
|
|
|
||
|
|
// team : customfield_10904
|
||
|
|
if (isset($jsonIssue['fields']['customfield_10904'])) {
|
||
|
|
$kanbanEntry->setTeam($jsonIssue['fields']['customfield_10904']['value']);
|
||
|
|
}
|
||
|
|
|
||
|
|
// team : customfield_12500
|
||
|
|
if (isset($jsonIssue['fields']['customfield_12500'])) {
|
||
|
|
$kanbanEntry->setTaurusPrio($jsonIssue['fields']['customfield_12500']);
|
||
|
|
}
|
||
|
|
|
||
|
|
// jira status
|
||
|
|
$jiraStatus = new JiraStatus();
|
||
|
|
$jiraStatus->setName($jsonIssue['fields']['status']['name'])
|
||
|
|
->setColor($jsonIssue['fields']['status']['statusCategory']['colorName']);
|
||
|
|
$kanbanEntry->setStatus($jiraStatus);
|
||
|
|
|
||
|
|
// assignee
|
||
|
|
if ($jsonIssue['fields']['assignee']) {
|
||
|
|
$avatarUrl = $this->router->generateUri('avatar.image', [
|
||
|
|
'signum' => $jsonIssue['fields']['assignee']['key'],
|
||
|
|
]);
|
||
|
|
|
||
|
|
$jiraAssignee = new JiraAssignee();
|
||
|
|
$jiraAssignee->setName($jsonIssue['fields']['assignee']['displayName'])
|
||
|
|
->setSignum($jsonIssue['fields']['assignee']['key'])
|
||
|
|
->setEmail(strtolower($jsonIssue['fields']['assignee']['emailAddress']))
|
||
|
|
->setAvatar($avatarUrl)
|
||
|
|
->setActive($jsonIssue['fields']['assignee']['active']);
|
||
|
|
|
||
|
|
$kanbanEntry->setAssignee($jiraAssignee);
|
||
|
|
unset($jiraAssignee);
|
||
|
|
}
|
||
|
|
|
||
|
|
// issue type
|
||
|
|
if ($jsonIssue['fields']['issuetype']) {
|
||
|
|
$jiraIssueType = new JiraIssueType();
|
||
|
|
$jiraIssueType->setName($jsonIssue['fields']['issuetype']['name'])
|
||
|
|
->setDescription($jsonIssue['fields']['issuetype']['description'])
|
||
|
|
->setIcon($jsonIssue['fields']['issuetype']['iconUrl']);
|
||
|
|
|
||
|
|
$kanbanEntry->setIssueType($jiraIssueType);
|
||
|
|
unset($jiraIssueType);
|
||
|
|
}
|
||
|
|
|
||
|
|
$kanbanEntry->setUpdatedAt(new \DateTime($jsonIssue['fields']['updated']));
|
||
|
|
|
||
|
|
switch ($jiraStatus->getName()) {
|
||
|
|
case "Backlog":
|
||
|
|
$kanbanBoard->addInbox($kanbanEntry);
|
||
|
|
break;
|
||
|
|
case "In Progress":
|
||
|
|
$kanbanBoard->addInProgress($kanbanEntry);
|
||
|
|
break;
|
||
|
|
case "Verification":
|
||
|
|
$kanbanBoard->addVerification($kanbanEntry);
|
||
|
|
break;
|
||
|
|
case "Done":
|
||
|
|
$kanbanBoard->addDone($kanbanEntry);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
unset($kanbanEntry);
|
||
|
|
}
|
||
|
|
|
||
|
|
return $kanbanBoard;
|
||
|
|
}
|
||
|
|
}
|