Skip to content

Commit

Permalink
Implement registrar for JIRA
Browse files Browse the repository at this point in the history
  • Loading branch information
Aeliot-Tm committed Jun 6, 2024
1 parent 338883f commit 388f608
Show file tree
Hide file tree
Showing 7 changed files with 318 additions and 1 deletion.
18 changes: 17 additions & 1 deletion .todo-registrar.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,23 @@
declare(strict_types=1);

use Aeliot\TodoRegistrar\Config;
use Aeliot\TodoRegistrar\Enum\RegistrarType;
use Aeliot\TodoRegistrar\Service\File\Finder;

return (new Config())
->setFinder(new Finder());
->setFinder(new Finder())
->setRegistrar(RegistrarType::JIRA, [
'issue' => [
'addTagToLabels' => true,
'components' => ['Component-1', 'Component-2'],
'labels' => ['Label-1', 'Label-2'],
'tagPrefix' => 'tag-',
'type' => 'Bug',
],
'projectKey' => 'Todo',
'service' => [
'host' => $_ENV['JIRA_HOST'] ?? 'localhost',
'personalAccessToken' => $_ENV['JIRA_PERSONAL_ACCESS_TOKEN'] ?? null,
'tokenBasedAuth' => true,
]
]);
29 changes: 29 additions & 0 deletions src/Dto/Comment/CommentPart.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ public function addLine(string $line): void
$this->lines[] = $line;
}

public function getFirstLine(): string
{
if (!$this->lines) {
throw new \RuntimeException('Cannot get line till injected one');
}

return reset($this->lines);
}

/**
* @return string[]
*/
Expand All @@ -41,6 +50,11 @@ public function getTag(): ?string
return $this->tagMetadata?->getTag();
}

public function getTagMetadata(): ?TagMetadata
{
return $this->tagMetadata;
}

public function getContent(): string
{
if (!$this->lines) {
Expand All @@ -49,4 +63,19 @@ public function getContent(): string

return implode('', $this->lines);
}

public function injectKey(string $key): void
{
if (!$this->lines) {
throw new \RuntimeException('Cannot get line till injected one');
}

$prefixLength = $this->tagMetadata?->getPrefixLength();
if (!$prefixLength) {
throw new \RuntimeException('Cannot get prefix length');
}

$line = $this->lines[0];
$this->lines[0] = substr($line, 0, $prefixLength) . " $key " . substr($line, $prefixLength);
}
}
71 changes: 71 additions & 0 deletions src/Service/Registrar/JIRA/IssueConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

declare(strict_types=1);

namespace Aeliot\TodoRegistrar\Service\Registrar\JIRA;

final class IssueConfig
{
private bool $addTagToLabels;
/**
* @var string[]
*/
private array $components;
private string $issueType;
/**
* @var string[]
*/
private array $labels;
private string $projectKey;
private string $tagPrefix;

/**
* @param array<string,mixed> $config
*/
public function __construct(array $config)
{
$issue = $config['issue'];
$this->addTagToLabels = $issue['addTagToLabels'] ?? false;
$this->components = (array) ($issue['components'] ?? []);
$this->issueType = $issue['type'];
$this->labels = (array) ($issue['labels'] ?? []);
$this->projectKey = $config['projectKey'];
$this->tagPrefix = $issue['tagPrefix'] ?? '';
}

public function addTagToLabels(): bool
{
return $this->addTagToLabels;
}

/**
* @return string[]
*/
public function getComponents(): array
{
return $this->components;
}

public function getIssueType(): string
{
return $this->issueType;
}

/**
* @return string[]
*/
public function getLabels(): array
{
return $this->labels;
}

public function getProjectKey(): string
{
return $this->projectKey;
}

public function getTagPrefix(): string
{
return $this->tagPrefix;
}
}
111 changes: 111 additions & 0 deletions src/Service/Registrar/JIRA/IssueServiceArrayConfigPreparer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php

declare(strict_types=1);

namespace Aeliot\TodoRegistrar\Service\Registrar\JIRA;

final class IssueServiceArrayConfigPreparer
{
/**
* @param array<string, mixed> $config
*
* @return array<string, mixed>
*/
public function prepare(array $config): array
{
$serviceConfig = [
'jiraHost' => $config['host'],
'useTokenBasedAuth' => $config['tokenBasedAuth'] ?? false,
'jiraLogEnabled' => $config['logEnabled'] ?? false,
'cookieAuthEnabled' => $config['cookieAuthEnabled'] ?? false,
];

$this->addAuthOptions($serviceConfig, $config);
$this->addCookieOptions($serviceConfig, $config);
$this->addCurlOptions($serviceConfig, $config);
$this->addLogOptions($serviceConfig, $config);
$this->addProxyOptions($serviceConfig, $config);

if ($config['serviceDeskId']) {
$serviceConfig['serviceDeskId'] = $config['serviceDeskId'];
}

return $serviceConfig;
}


/**
* @param array<string, mixed> $serviceConfig
* @param array<string, mixed> $config
*/
private function addAuthOptions(array &$serviceConfig, array $config): void
{
if ($serviceConfig['tokenBasedAuth']) {
$serviceConfig['jiraUser'] = $config['jiraUser'];
$serviceConfig['jiraPassword'] = $config['jiraPassword'];
} else {
$serviceConfig['personalAccessToken'] = $config['personalAccessToken'];
}
}

/**
* @param array<string, mixed> $serviceConfig
* @param array<string, mixed> $config
*/
private function addCookieOptions(array &$serviceConfig, array $config): void
{
if ($serviceConfig['cookieAuthEnabled']) {
$serviceConfig['cookieFile'] = $config['cookieFile'];
}
}

/**
* @param array<string, mixed> $serviceConfig
* @param array<string, mixed> $config
*/
private function addCurlOptions(array &$serviceConfig, array $config): void
{
$fields = [
'sslVerifyHost',
'sslVerifyPeer',
'sslCert',
'sslCertPassword',
'sslKey',
'sslKeyPassword',
'verbose',
'userAgent',
];

$options = array_intersect_key($config['curl'] ?? [], array_flip($fields));
$options = array_filter($options, static fn(mixed $x): bool => isset($x));
$keys = array_map(static fn(string $x): string => 'curlOpt' . ucfirst($x), array_keys($options));

$serviceConfig += array_combine($keys, $options);
}

/**
* @param array<string, mixed> $serviceConfig
* @param array<string, mixed> $config
*/
private function addLogOptions(array &$serviceConfig, array $config): void
{
if ($serviceConfig['jiraLogEnabled']) {
$serviceConfig['jiraLogFile'] = $config['logFile'];
$serviceConfig['jiraLogLevel'] = $config['logLevel'] ?? 'WARNING';
}
}

/**
* @param array<string, mixed> $serviceConfig
* @param array<string, mixed> $config
*/
private function addProxyOptions(array &$serviceConfig, array $config): void
{
if ($config['proxyEnabled'] ?? false) {
$serviceConfig['proxyServer'] = $config['proxyServer'];
$serviceConfig['proxyPort'] = $config['proxyPort'];
$serviceConfig['proxyUser'] = $config['proxyUser'];
$serviceConfig['proxyPassword'] = $config['proxyPassword'];
}
}
}
60 changes: 60 additions & 0 deletions src/Service/Registrar/JIRA/JiraRegistrar.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

namespace Aeliot\TodoRegistrar\Service\Registrar\JIRA;

use Aeliot\TodoRegistrar\Dto\Comment\CommentPart;
use Aeliot\TodoRegistrar\Service\Registrar\RegistrarInterface;
use JiraRestApi\Issue\IssueField;
use JiraRestApi\Issue\IssueService;

final class JiraRegistrar implements RegistrarInterface
{
public function __construct(
private IssueConfig $issueConfig,
private IssueService $issueService,
) {
}

public function isRegistered(CommentPart $commentPart): bool
{
$lineWithoutPrefix = substr($commentPart->getFirstLine(), $commentPart->getPrefixLength());

return preg_match('/^\\s*\\b[A-Z]+-\\d+\\b/i', $lineWithoutPrefix);
}

public function register(CommentPart $commentPart): void
{
$issueField = $this->createIssueField($commentPart);
$issue = $this->issueService->create($issueField);
$commentPart->injectKey($issue->key);
}

private function createIssueField(CommentPart $commentPart): IssueField
{
$issueField = new IssueField();
$issueField
->setProjectKey($this->issueConfig->getProjectKey())
->setIssueTypeAsString($this->issueConfig->getIssueType())
->setSummary($commentPart->getFirstLine())
->setDescription($commentPart->getContent())
->addComponentsAsArray($this->issueConfig->getComponents());

$assignee = $commentPart->getTagMetadata()?->getAssignee();
if ($assignee) {
$issueField->setAssigneeNameAsString($assignee);
}

$labels = $this->issueConfig->getLabels();
if ($this->issueConfig->addTagToLabels()) {
$labels[] = strtolower(sprintf('%s%s', $this->issueConfig->getTagPrefix(), $commentPart->getTag()));
}

foreach ($labels as $label) {
$issueField->addLabelAsString($label);
}

return $issueField;
}
}
28 changes: 28 additions & 0 deletions src/Service/Registrar/JIRA/JiraRegistrarFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Aeliot\TodoRegistrar\Service\Registrar\JIRA;

use Aeliot\TodoRegistrar\Service\Registrar\RegistrarFactoryInterface;
use Aeliot\TodoRegistrar\Service\Registrar\RegistrarInterface;
use JiraRestApi\Configuration\ArrayConfiguration;
use JiraRestApi\Issue\IssueService;

final class JiraRegistrarFactory implements RegistrarFactoryInterface
{
public function create(array $config): RegistrarInterface
{
return new JiraRegistrar(
new IssueConfig($config),
$this->createIssueService($config['service']),
);
}

private function createIssueService(array $config): IssueService
{
$serviceConfig = (new IssueServiceArrayConfigPreparer())->prepare($config);

return new IssueService(new ArrayConfiguration($serviceConfig));
}
}
2 changes: 2 additions & 0 deletions src/Service/Registrar/RegistrarFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Aeliot\TodoRegistrar\Service\Registrar;

use Aeliot\TodoRegistrar\Enum\RegistrarType;
use Aeliot\TodoRegistrar\Service\Registrar\JIRA\JiraRegistrarFactory;

final class RegistrarFactory
{
Expand All @@ -19,6 +20,7 @@ public function createRegistrar(RegistrarType $type, array $config): RegistrarIn
private function getExactFactory(RegistrarType $type): RegistrarFactoryInterface
{
return match ($type) {
RegistrarType::JIRA => new JiraRegistrarFactory(),
// TODO add factory of different registrars
default => throw new \DomainException(sprintf('Not supported registrar type "%s"', $type->value)),
};
Expand Down

0 comments on commit 388f608

Please sign in to comment.