@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

authored by

Aviv Eyal and committed by
turadg
e8fdf478 7e3d8082

+123 -11
+47 -1
src/applications/auth/provider/PhabricatorJIRAAuthProvider.php
··· 77 77 const PROPERTY_JIRA_URI = 'oauth1:jira:uri'; 78 78 const PROPERTY_PUBLIC_KEY = 'oauth1:jira:key:public'; 79 79 const PROPERTY_PRIVATE_KEY = 'oauth1:jira:key:private'; 80 + const PROPERTY_REPORT_LINK = 'oauth1:jira:report:link'; 81 + const PROPERTY_REPORT_COMMENT = 'oauth1:jira:report:comment'; 80 82 81 83 82 84 public function readFormValuesFromProvider() { ··· 100 102 return array( 101 103 self::PROPERTY_JIRA_NAME => $name, 102 104 self::PROPERTY_JIRA_URI => $request->getStr(self::PROPERTY_JIRA_URI), 105 + self::PROPERTY_REPORT_LINK => 106 + $request->getInt(self::PROPERTY_REPORT_LINK, 0), 107 + self::PROPERTY_REPORT_COMMENT => 108 + $request->getInt(self::PROPERTY_REPORT_COMMENT, 0), 103 109 ); 104 110 } 105 111 ··· 175 181 'JIRA 5 or earlier.')); 176 182 177 183 $is_setup = $this->isSetup(); 184 + $viewer = $request->getViewer(); 178 185 179 186 $e_required = $request->isFormPost() ? null : true; 180 187 ··· 249 256 id(new AphrontFormStaticControl()) 250 257 ->setLabel(pht('Public Key')) 251 258 ->setValue($pkey)); 259 + 260 + $form 261 + ->appendRemarkupInstructions( 262 + pht( 263 + '= Integration Options = '."\n". 264 + 'Configure how to record Revisions on JIRA tasks.'."\n\n". 265 + 'Note you\'ll have to restart the daemons for this to take '. 266 + 'effect.')) 267 + ->appendChild( 268 + id(new AphrontFormCheckboxControl()) 269 + ->addCheckbox( 270 + self::PROPERTY_REPORT_LINK, 271 + 1, 272 + new PHUIRemarkupView( 273 + $viewer, 274 + pht( 275 + 'Create **Issue Link** to the Revision, as an "implemented '. 276 + 'in" relationship.')), 277 + $this->shouldCreateJIRALink())) 278 + ->appendChild( 279 + id(new AphrontFormCheckboxControl()) 280 + ->addCheckbox( 281 + self::PROPERTY_REPORT_COMMENT, 282 + 1, 283 + new PHUIRemarkupView( 284 + $viewer, 285 + pht( 286 + '**Post a comment** in the JIRA task, similar to the '. 287 + 'emails Phabricator sends.')), 288 + $this->shouldCreateJIRAComment())); 252 289 } 253 290 254 291 } 255 - 256 292 257 293 /** 258 294 * JIRA uses a setup step to generate public/private keys. ··· 284 320 $adapter->setTokenSecret($account->getProperty('oauth1.token.secret')); 285 321 286 322 return $adapter->newJIRAFuture($path, $method, $params); 323 + } 324 + 325 + public function shouldCreateJIRALink() { 326 + $config = $this->getProviderConfig(); 327 + return $config->getProperty(self::PROPERTY_REPORT_LINK, true); 328 + } 329 + 330 + public function shouldCreateJIRAComment() { 331 + $config = $this->getProviderConfig(); 332 + return $config->getProperty(self::PROPERTY_REPORT_COMMENT, true); 287 333 } 288 334 289 335 }
+76 -10
src/applications/doorkeeper/worker/DoorkeeperJIRAFeedWorker.php
··· 40 40 return; 41 41 } 42 42 43 + $do_anything = ($this->shouldPostComment() || $this->shouldPostLink()); 44 + if (!$do_anything) { 45 + $this->log( 46 + "%s\n", 47 + pht('JIRA integration is configured not to post anything.')); 48 + return; 49 + } 50 + 43 51 $xobjs = id(new DoorkeeperExternalObjectQuery()) 44 52 ->setViewer($viewer) 45 53 ->withPHIDs($jira_issue_phids) ··· 60 68 return; 61 69 } 62 70 63 - $story_text = $this->renderStoryText(); 64 71 65 72 $xobjs = mgroup($xobjs, 'getApplicationDomain'); 66 73 foreach ($xobjs as $domain => $xobj_list) { ··· 84 91 foreach ($xobj_list as $xobj) { 85 92 foreach ($accounts as $account) { 86 93 try { 87 - $provider->newJIRAFuture( 88 - $account, 89 - 'rest/api/2/issue/'.$xobj->getObjectID().'/comment', 90 - 'POST', 91 - array( 92 - 'body' => $story_text, 93 - ))->resolveJSON(); 94 + $jira_key = $xobj->getObjectID(); 95 + 96 + if ($this->shouldPostComment()) { 97 + $this->postComment($account, $jira_key); 98 + } 99 + 100 + if ($this->shouldPostLink()) { 101 + $this->postLink($account, $jira_key); 102 + } 103 + 94 104 break; 95 105 } catch (HTTPFutureResponseStatus $ex) { 96 106 phlog($ex); ··· 169 179 return $try_users; 170 180 } 171 181 182 + private function shouldPostComment() { 183 + return $this->getProvider()->shouldCreateJIRAComment(); 184 + } 185 + 186 + private function shouldPostLink() { 187 + return $this->getProvider()->shouldCreateJIRALink(); 188 + } 189 + 190 + private function postComment($account, $jira_key) { 191 + $provider = $this->getProvider(); 192 + 193 + $provider->newJIRAFuture( 194 + $account, 195 + 'rest/api/2/issue/'.$jira_key.'/comment', 196 + 'POST', 197 + array( 198 + 'body' => $this->renderStoryText(), 199 + ))->resolveJSON(); 200 + } 201 + 172 202 private function renderStoryText() { 173 203 $object = $this->getStoryObject(); 174 204 $publisher = $this->getPublisher(); 175 205 176 206 $text = $publisher->getStoryText($object); 177 - $uri = $publisher->getObjectURI($object); 178 207 179 - return $text."\n\n".$uri; 208 + if ($this->shouldPostLink()) { 209 + return $text; 210 + } else { 211 + // include the link in the comment 212 + return $text."\n\n".$publisher->getObjectURI($object); 213 + } 180 214 } 181 215 216 + private function postLink($account, $jira_key) { 217 + $provider = $this->getProvider(); 218 + $object = $this->getStoryObject(); 219 + $publisher = $this->getPublisher(); 220 + $icon_uri = celerity_get_resource_uri('rsrc/favicons/favicon-16x16.png'); 221 + 222 + $provider->newJIRAFuture( 223 + $account, 224 + 'rest/api/2/issue/'.$jira_key.'/remotelink', 225 + 'POST', 226 + 227 + // format documented at http://bit.ly/1K5T0Li 228 + array( 229 + 'globalId' => $object->getPHID(), 230 + 'application' => array( 231 + 'type' => 'com.phacility.phabricator', 232 + 'name' => 'Phabricator', 233 + ), 234 + 'relationship' => 'implemented in', 235 + 'object' => array( 236 + 'url' => $publisher->getObjectURI($object), 237 + 'title' => $publisher->getObjectTitle($object), 238 + 'icon' => array( 239 + 'url16x16' => $icon_uri, 240 + 'title' => 'Phabricator', 241 + ), 242 + 'status' => array( 243 + 'resolved' => $publisher->isObjectClosed($object), 244 + ), 245 + ), 246 + ))->resolveJSON(); 247 + } 182 248 }