diff --git a/src/applications/auth/provider/PhabricatorJIRAAuthProvider.php b/src/applications/auth/provider/PhabricatorJIRAAuthProvider.php --- a/src/applications/auth/provider/PhabricatorJIRAAuthProvider.php +++ b/src/applications/auth/provider/PhabricatorJIRAAuthProvider.php @@ -77,6 +77,8 @@ 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 @@ 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 @@ 'JIRA 5 or earlier.')); $is_setup = $this->isSetup(); + $viewer = $request->getViewer(); $e_required = $request->isFormPost() ? null : true; @@ -249,11 +256,40 @@ 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 @@ 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 --- a/src/applications/doorkeeper/worker/DoorkeeperJIRAFeedWorker.php +++ b/src/applications/doorkeeper/worker/DoorkeeperJIRAFeedWorker.php @@ -40,6 +40,14 @@ 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 @@ return; } - $story_text = $this->renderStoryText(); $xobjs = mgroup($xobjs, 'getApplicationDomain'); foreach ($xobjs as $domain => $xobj_list) { @@ -84,13 +91,16 @@ 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 @@ 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(); + } }