diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1622,6 +1622,7 @@ 'PhabricatorInternationalizationManagementWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementWorkflow.php', 'PhabricatorIteratedMD5PasswordHasher' => 'infrastructure/util/password/PhabricatorIteratedMD5PasswordHasher.php', 'PhabricatorJIRAAuthProvider' => 'applications/auth/provider/PhabricatorJIRAAuthProvider.php', + 'PhabricatorJIRAConfigOptions' => 'applications/doorkeeper/option/PhabricatorJIRAConfigOptions.php', 'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/PhabricatorJavelinLinter.php', 'PhabricatorJumpNavHandler' => 'applications/search/engine/PhabricatorJumpNavHandler.php', 'PhabricatorKeyValueDatabaseCache' => 'applications/cache/PhabricatorKeyValueDatabaseCache.php', @@ -4443,6 +4444,7 @@ 'PhabricatorInternationalizationManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorIteratedMD5PasswordHasher' => 'PhabricatorPasswordHasher', 'PhabricatorJIRAAuthProvider' => 'PhabricatorOAuth1AuthProvider', + 'PhabricatorJIRAConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorJavelinLinter' => 'ArcanistLinter', 'PhabricatorKeyValueDatabaseCache' => 'PhutilKeyValueCache', 'PhabricatorLDAPAuthProvider' => 'PhabricatorAuthProvider', diff --git a/src/applications/doorkeeper/option/PhabricatorJIRAConfigOptions.php b/src/applications/doorkeeper/option/PhabricatorJIRAConfigOptions.php new file mode 100644 --- /dev/null +++ b/src/applications/doorkeeper/option/PhabricatorJIRAConfigOptions.php @@ -0,0 +1,45 @@ +newOption('jira.post-comment', 'bool', true) + ->setBoolOptions( + array( + pht('Enable commenting'), + pht('Disable commenting'), + )) + ->setSummary(pht('Post comment on JIRA issues when revision updated.')) + ->setDescription( + pht( + 'Each time a revision is updated, Differential can post a comment '. + 'on the linked JIRA issue(s). This can be informative, but can also '. + 'overwhelm users with notifications if they are also notified by '. + 'Phabricator.')), + $this->newOption('jira.post-link', 'bool', true) + ->setBoolOptions( + array( + pht('Enable remote link'), + pht('Disable remote link'), + )) + ->setSummary(pht('On JIRA issues add remote links to revisions.')) + ->setDescription( + pht( + 'JIRA issues can have Remote Links to web artifacts related to '. + 'the given issue. This option adds the revision under "implement in" '. + 'under the Issue Links section of the JIRA ticket.')) + ); + } + +} diff --git a/src/applications/doorkeeper/worker/DoorkeeperFeedWorkerJIRA.php b/src/applications/doorkeeper/worker/DoorkeeperFeedWorkerJIRA.php --- a/src/applications/doorkeeper/worker/DoorkeeperFeedWorkerJIRA.php +++ b/src/applications/doorkeeper/worker/DoorkeeperFeedWorkerJIRA.php @@ -54,8 +54,6 @@ return; } - $story_text = $this->renderStoryText(); - $xobjs = mgroup($xobjs, 'getApplicationDomain'); foreach ($xobjs as $domain => $xobj_list) { $accounts = id(new PhabricatorExternalAccountQuery()) @@ -78,13 +76,13 @@ foreach ($xobj_list as $xobj) { foreach ($accounts as $account) { try { - $provider->newJIRAFuture( - $account, - 'rest/api/2/issue/'.$xobj->getObjectID().'/comment', - 'POST', - array( - 'body' => $story_text, - ))->resolveJSON(); + + if (self::shouldPostComment()) + $this->postComment($account, $object); + + if (self::shouldPostLink()) + $this->postLink($account, $object); + break; } catch (HTTPFutureResponseStatus $ex) { phlog($ex); @@ -161,6 +159,63 @@ return $try_users; } + private static function shouldPostComment() { + return PhabricatorEnv::getEnvConfig('jira.post-comment'); + } + + private static function shouldPostLink() { + return PhabricatorEnv::getEnvConfig('jira.post-link'); + } + + private function postComment($account, $xobj) { + $provider = $this->getProvider(); + $object = $this->getStoryObject(); + $publisher = $this->getPublisher(); + $uri = $publisher->getObjectURI($object); + + $provider->newJIRAFuture( + $account, + 'rest/api/2/issue/'.$xobj->getObjectID().'/comment', + 'POST', + array( + 'body' => renderStoryText() + ))->resolveJSON(); + } + + private function postLink($account, $xobj) { + $provider = $this->getProvider(); + $object = $this->getStoryObject(); + $publisher = $this->getPublisher(); + $uri = $publisher->getObjectURI($object); + + $provider->newJIRAFuture( + $account, + 'rest/api/2/issue/'.$xobj->getObjectID().'/remotelink', + 'POST', + // format documented at https://developer.atlassian.com/display/JIRADEV/Fields+in+Remote+Issue+Links + array( + 'globalId' => 'phabricatorPhid=' . $object->getPHID(), + 'application' => array( + 'type' => 'org.phabricator.differential', + 'name' => 'Differential', + ), + 'relationship' => 'implemented in', + 'object' => array( + 'url' => $uri, + 'title' => $object->getMonogram(), + 'summary' => $object->getTitle(), + 'icon' => array( + // TODO use Differential gear icon in 16x16, hosted locally + 'url16x16' => 'https://secure.phabricator.com/rsrc/image/apple-touch-icon.png', + 'title' => 'Revision', + ), + 'status' => array( + 'resolved' => $publisher->isObjectClosed($object) + ), + ), + ))->resolveJSON(); + } + private function renderStoryText() { $object = $this->getStoryObject(); $publisher = $this->getPublisher();