From 1cfcacbbebc67ab900de61f0c1e3a6d82858a6b9 Mon Sep 17 00:00:00 2001 From: Yaman Qalieh Date: Fri, 24 Jun 2022 05:04:49 -0400 Subject: [PATCH] [BugzillaBridge] Add new bridge (#2825) --- bridges/BugzillaBridge.php | 180 ++++++++++++++++++++++++++++ bridges/KernelBugTrackerBridge.php | 3 +- bridges/MozillaBugTrackerBridge.php | 3 +- 3 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 bridges/BugzillaBridge.php diff --git a/bridges/BugzillaBridge.php b/bridges/BugzillaBridge.php new file mode 100644 index 00000000..16ce4a28 --- /dev/null +++ b/bridges/BugzillaBridge.php @@ -0,0 +1,180 @@ + array( + 'instance' => array( + 'name' => 'Instance URL', + 'required' => true, + 'exampleValue' => 'https://bugzilla.mozilla.org' + ) + ), + 'Bug comments' => array( + 'id' => array( + 'name' => 'Bug tracking ID', + 'type' => 'number', + 'required' => true, + 'title' => 'Insert bug tracking ID', + 'exampleValue' => 121241 + ), + 'limit' => array( + 'name' => 'Number of comments to return', + 'type' => 'number', + 'required' => false, + 'title' => 'Specify number of comments to return', + 'defaultValue' => -1 + ), + 'skiptags' => array( + 'name' => 'Skip offtopic comments', + 'type' => 'checkbox', + 'title' => 'Excludes comments tagged as advocacy, metoo, or offtopic from the feed' + ) + ) + ); + + const SKIPPED_ACTIVITY = array( + 'cc' => true, + 'comment_tag' => true + ); + + const SKIPPED_TAGS = array('advocacy', 'metoo', 'offtopic'); + + private $instance; + private $bugid; + private $buguri; + private $title; + + public function getName() { + if (!is_null($this->title)) { + return $this->title; + } + return parent::getName(); + } + + public function getURI() { + return $this->buguri ?? parent::getURI(); + } + + public function collectData() { + $this->instance = rtrim($this->getInput('instance'), '/'); + $this->bugid = $this->getInput('id'); + $this->buguri = $this->instance . '/show_bug.cgi?id=' . $this->bugid; + + $url = $this->instance . '/rest/bug/' . $this->bugid; + $this->getTitle($url); + $this->collectComments($url . '/comment'); + $this->collectUpdates($url . '/history'); + + usort($this->items, function($a, $b) { + return $b['timestamp'] <=> $a['timestamp']; + }); + + if ($this->getInput('limit') > 0) { + $this->items = array_slice($this->items, 0, $this->getInput('limit')); + } + } + + protected function getTitle($url) { + // Only request the summary for a faster request + $json = json_decode(getContents($url . '?include_fields=summary'), true); + $this->title = 'Bug ' . $this->bugid . ' - ' . + $json['bugs'][0]['summary'] . ' - ' . + // Remove https:// + substr($this->instance, 8); + } + + protected function collectComments($url) { + $json = json_decode(getContents($url), true); + + // Array of comments is here + if (!isset($json['bugs'][$this->bugid]['comments'])) { + returnClientError('Cannot find REST endpoint'); + } + + foreach($json['bugs'][$this->bugid]['comments'] as $comment) { + $item = array(); + if ($this->getInput('skiptags') and + array_intersect(self::SKIPPED_TAGS, $comment['tags'])) { + continue; + } + $item['categories'] = $comment['tags']; + $item['uri'] = $this->buguri . '#c' . $comment['count']; + $item['title'] = 'Comment ' . $comment['count']; + $item['timestamp'] = $comment['creation_time']; + $item['author'] = $this->getUser($comment['creator']); + $item['content'] = $comment['text']; + if (isset($comment['is_markdown']) and $comment['is_markdown']) { + $item['content'] = markdownToHtml($item['content']); + } + if (!is_null($comment['attachment_id'])) { + $item['enclosures'] = array($this->instance . '/attachment.cgi?id=' . $comment['attachment_id']); + } + $this->items[] = $item; + } + } + + protected function collectUpdates($url) { + $json = json_decode(getContents($url), true); + + // Array of changesets which contain an array of changes + if (!isset($json['bugs']['0']['history'])) { + returnClientError('Cannot find REST endpoint'); + } + + foreach($json['bugs']['0']['history'] as $changeset) { + $author = $this->getUser($changeset['who']); + $timestamp = $changeset['when']; + foreach($changeset['changes'] as $change) { + // Skip updates to the cc list and comment tagging + if (isset(self::SKIPPED_ACTIVITY[$change['field_name']])) { + continue; + } + + $item = array(); + $item['uri'] = $this->buguri; + $item['title'] = 'Updated'; + $item['timestamp'] = $timestamp; + $item['author'] = $author; + $item['content'] = ucfirst($change['field_name']) . ': ' . + ($change['removed'] === '' ? '[nothing]' : $change['removed']) . ' -> ' . + ($change['added'] === '' ? '[nothing]' : $change['added']); + $this->items[] = $item; + } + } + } + + protected function getUser($user) { + // Check if the user endpoint is available + if ($this->loadCacheValue($this->instance . 'userEndpointClosed')) { + return $user; + } + + $cache = $this->loadCacheValue($this->instance . $user); + if (!is_null($cache)) { + return $cache; + } + + $url = $this->instance . '/rest/user/' . $user . '?include_fields=real_name'; + try { + $json = json_decode(getContents($url), true); + if (isset($json['error']) and $json['error']) { + throw new Exception; + } + } catch (Exception $e) { + $this->saveCacheValue($this->instance . 'userEndpointClosed', true); + return $user; + } + + $username = $json['users']['0']['real_name']; + + if (empty($username)) { + $username = $user; + } + $this->saveCacheValue($this->instance . $user, $username); + return $username; + } +} diff --git a/bridges/KernelBugTrackerBridge.php b/bridges/KernelBugTrackerBridge.php index 81321966..0c56dedf 100644 --- a/bridges/KernelBugTrackerBridge.php +++ b/bridges/KernelBugTrackerBridge.php @@ -3,7 +3,8 @@ class KernelBugTrackerBridge extends BridgeAbstract { const NAME = 'Kernel Bug Tracker'; const URI = 'https://bugzilla.kernel.org'; - const DESCRIPTION = 'Returns feeds for bug comments'; + const DESCRIPTION = 'DEPRECATED: Use BugzillaBridge instead. +Returns feeds for bug comments'; const MAINTAINER = 'logmanoriginal'; const PARAMETERS = array( 'Bug comments' => array( diff --git a/bridges/MozillaBugTrackerBridge.php b/bridges/MozillaBugTrackerBridge.php index 58cea51e..d284e460 100644 --- a/bridges/MozillaBugTrackerBridge.php +++ b/bridges/MozillaBugTrackerBridge.php @@ -3,7 +3,8 @@ class MozillaBugTrackerBridge extends BridgeAbstract { const NAME = 'Mozilla Bug Tracker'; const URI = 'https://bugzilla.mozilla.org'; - const DESCRIPTION = 'Returns feeds for bug comments'; + const DESCRIPTION = 'DEPRECATED: Use BugzillaBridge instead. +Returns feeds for bug comments'; const MAINTAINER = 'AntoineTurmel'; const PARAMETERS = array( 'Bug comments' => array(