From e8fdf478bbc9d0bfe82031df370fe711e4b03607 Mon Sep 17 00:00:00 2001 From: Aviv Eyal Date: Thu, 12 Nov 2015 19:30:43 +0000 Subject: [PATCH] JIRA Integration: Link and/or Comment Summary: Current JIRA integration is quite noisy in terms of email, and makes users hunt and peck for the related revisions. Teach it to create an Issue Link on the JIRA side, and allow to disable commenting. Test Plan: comment on revision in each of the 4 settings, check JIRA end for expected result. Reviewers: btrahan, eMxyzptlk, epriestley, #blessed_reviewers, avivey Reviewed By: epriestley, #blessed_reviewers Subscribers: avivey, vhbit, jra3, eMxyzptlk, frenchs, aik099, svemir, rmuslimov, cpa199, waynea, epriestley, Korvin, hach-que Projects: #doorkeeper Maniphest Tasks: T5422 Differential Revision: https://secure.phabricator.com/D9858 --- .../provider/PhabricatorJIRAAuthProvider.php | 48 ++++++++++- .../worker/DoorkeeperJIRAFeedWorker.php | 86 ++++++++++++++++--- 2 files changed, 123 insertions(+), 11 deletions(-) diff --git a/src/applications/auth/provider/PhabricatorJIRAAuthProvider.php b/src/applications/auth/provider/PhabricatorJIRAAuthProvider.php index c81cbe64aa..8bbbedc3c6 100644 --- a/src/applications/auth/provider/PhabricatorJIRAAuthProvider.php +++ b/src/applications/auth/provider/PhabricatorJIRAAuthProvider.php @@ -77,6 +77,8 @@ final class PhabricatorJIRAAuthProvider extends PhabricatorOAuth1AuthProvider { const PROPERTY_JIRA_URI = 'oauth1:jira:uri'; const PROPERTY_PUBLIC_KEY = 'oauth1:jira:key:public'; const PROPERTY_PRIVATE_KEY = 'oauth1:jira:key:private'; + const PROPERTY_REPORT_LINK = 'oauth1:jira:report:link'; + const PROPERTY_REPORT_COMMENT = 'oauth1:jira:report:comment'; public function readFormValuesFromProvider() { @@ -100,6 +102,10 @@ final class PhabricatorJIRAAuthProvider extends PhabricatorOAuth1AuthProvider { return array( self::PROPERTY_JIRA_NAME => $name, self::PROPERTY_JIRA_URI => $request->getStr(self::PROPERTY_JIRA_URI), + self::PROPERTY_REPORT_LINK => + $request->getInt(self::PROPERTY_REPORT_LINK, 0), + self::PROPERTY_REPORT_COMMENT => + $request->getInt(self::PROPERTY_REPORT_COMMENT, 0), ); } @@ -175,6 +181,7 @@ final class PhabricatorJIRAAuthProvider extends PhabricatorOAuth1AuthProvider { 'JIRA 5 or earlier.')); $is_setup = $this->isSetup(); + $viewer = $request->getViewer(); $e_required = $request->isFormPost() ? null : true; @@ -249,11 +256,40 @@ final class PhabricatorJIRAAuthProvider extends PhabricatorOAuth1AuthProvider { id(new AphrontFormStaticControl()) ->setLabel(pht('Public Key')) ->setValue($pkey)); + + $form + ->appendRemarkupInstructions( + pht( + '= Integration Options = '."\n". + 'Configure how to record Revisions on JIRA tasks.'."\n\n". + 'Note you\'ll have to restart the daemons for this to take '. + 'effect.')) + ->appendChild( + id(new AphrontFormCheckboxControl()) + ->addCheckbox( + self::PROPERTY_REPORT_LINK, + 1, + new PHUIRemarkupView( + $viewer, + pht( + 'Create **Issue Link** to the Revision, as an "implemented '. + 'in" relationship.')), + $this->shouldCreateJIRALink())) + ->appendChild( + id(new AphrontFormCheckboxControl()) + ->addCheckbox( + self::PROPERTY_REPORT_COMMENT, + 1, + new PHUIRemarkupView( + $viewer, + pht( + '**Post a comment** in the JIRA task, similar to the '. + 'emails Phabricator sends.')), + $this->shouldCreateJIRAComment())); } } - /** * JIRA uses a setup step to generate public/private keys. */ @@ -286,4 +322,14 @@ final class PhabricatorJIRAAuthProvider extends PhabricatorOAuth1AuthProvider { return $adapter->newJIRAFuture($path, $method, $params); } + public function shouldCreateJIRALink() { + $config = $this->getProviderConfig(); + return $config->getProperty(self::PROPERTY_REPORT_LINK, true); + } + + public function shouldCreateJIRAComment() { + $config = $this->getProviderConfig(); + return $config->getProperty(self::PROPERTY_REPORT_COMMENT, true); + } + } diff --git a/src/applications/doorkeeper/worker/DoorkeeperJIRAFeedWorker.php b/src/applications/doorkeeper/worker/DoorkeeperJIRAFeedWorker.php index 7c6f15cf04..24631ed1b3 100644 --- a/src/applications/doorkeeper/worker/DoorkeeperJIRAFeedWorker.php +++ b/src/applications/doorkeeper/worker/DoorkeeperJIRAFeedWorker.php @@ -40,6 +40,14 @@ final class DoorkeeperJIRAFeedWorker extends DoorkeeperFeedWorker { return; } + $do_anything = ($this->shouldPostComment() || $this->shouldPostLink()); + if (!$do_anything) { + $this->log( + "%s\n", + pht('JIRA integration is configured not to post anything.')); + return; + } + $xobjs = id(new DoorkeeperExternalObjectQuery()) ->setViewer($viewer) ->withPHIDs($jira_issue_phids) @@ -60,7 +68,6 @@ final class DoorkeeperJIRAFeedWorker extends DoorkeeperFeedWorker { return; } - $story_text = $this->renderStoryText(); $xobjs = mgroup($xobjs, 'getApplicationDomain'); foreach ($xobjs as $domain => $xobj_list) { @@ -84,13 +91,16 @@ final class DoorkeeperJIRAFeedWorker extends DoorkeeperFeedWorker { 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(); + $jira_key = $xobj->getObjectID(); + + if ($this->shouldPostComment()) { + $this->postComment($account, $jira_key); + } + + if ($this->shouldPostLink()) { + $this->postLink($account, $jira_key); + } + break; } catch (HTTPFutureResponseStatus $ex) { phlog($ex); @@ -169,14 +179,70 @@ final class DoorkeeperJIRAFeedWorker extends DoorkeeperFeedWorker { return $try_users; } + private function shouldPostComment() { + return $this->getProvider()->shouldCreateJIRAComment(); + } + + private function shouldPostLink() { + return $this->getProvider()->shouldCreateJIRALink(); + } + + private function postComment($account, $jira_key) { + $provider = $this->getProvider(); + + $provider->newJIRAFuture( + $account, + 'rest/api/2/issue/'.$jira_key.'/comment', + 'POST', + array( + 'body' => $this->renderStoryText(), + ))->resolveJSON(); + } + private function renderStoryText() { $object = $this->getStoryObject(); $publisher = $this->getPublisher(); $text = $publisher->getStoryText($object); - $uri = $publisher->getObjectURI($object); - return $text."\n\n".$uri; + if ($this->shouldPostLink()) { + return $text; + } else { + // include the link in the comment + return $text."\n\n".$publisher->getObjectURI($object); + } } + private function postLink($account, $jira_key) { + $provider = $this->getProvider(); + $object = $this->getStoryObject(); + $publisher = $this->getPublisher(); + $icon_uri = celerity_get_resource_uri('rsrc/favicons/favicon-16x16.png'); + + $provider->newJIRAFuture( + $account, + 'rest/api/2/issue/'.$jira_key.'/remotelink', + 'POST', + + // format documented at http://bit.ly/1K5T0Li + array( + 'globalId' => $object->getPHID(), + 'application' => array( + 'type' => 'com.phacility.phabricator', + 'name' => 'Phabricator', + ), + 'relationship' => 'implemented in', + 'object' => array( + 'url' => $publisher->getObjectURI($object), + 'title' => $publisher->getObjectTitle($object), + 'icon' => array( + 'url16x16' => $icon_uri, + 'title' => 'Phabricator', + ), + 'status' => array( + 'resolved' => $publisher->isObjectClosed($object), + ), + ), + ))->resolveJSON(); + } } -- 2.51.2