@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.

Fix several issues with application interactions while importing commits

Summary:
- Fixes T5851. Currently, if a commit has `Fixes T123`, we generate an email with just that before generating the commit email. Don't send/publish transactions about a commit before it imports (this is a tiny bit hacky, but well-contained and I don't think it causes any problems).
- Fixes T4864. Currently, we try to parse Differential information even if Differential is not installed. Instead, do this only if Differential is installed.
- Fixes T5771. Currently, if we can't figure out who the committer/author of a commit is, we don't publish a `Fixes T123` transaction. Instead, fall back to acting as "Diffusion" if we can't find a better actor. Most of this diff expands the role of application actors. The existing application actors (Herald and Harbormaster) seem to be working well.

Test Plan:
- Pushed a commit with `Fixes T123` and verified it did not generate email directly. (The task half of the transaction still does, correctly.)
- Uninstalled Differential and pushed a commit, got a clean import instead of an exception.
- Commented out author/committer PHIDs and pushed stuff, saw a "Diffusion" actor.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T5771, T4864, T5851

Differential Revision: https://secure.phabricator.com/D10221

+90 -44
+17 -4
src/applications/audit/editor/PhabricatorAuditEditor.php
··· 153 153 $status_accepted = PhabricatorAuditStatusConstants::ACCEPTED; 154 154 $status_concerned = PhabricatorAuditStatusConstants::CONCERNED; 155 155 156 - $actor_phid = $this->requireActor()->getPHID(); 156 + $actor_phid = $this->getActingAsPHID(); 157 157 $actor_is_author = ($object->getAuthorPHID()) && 158 158 ($actor_phid == $object->getAuthorPHID()); 159 159 ··· 317 317 $can_author_close = PhabricatorEnv::getEnvConfig($can_author_close_key); 318 318 319 319 $actor_is_author = ($object->getAuthorPHID()) && 320 - ($object->getAuthorPHID() == $this->requireActor()->getPHID()); 320 + ($object->getAuthorPHID() == $this->getActingAsPHID()); 321 321 322 322 switch ($action) { 323 323 case PhabricatorAuditActionConstants::CLOSE: ··· 348 348 protected function shouldSendMail( 349 349 PhabricatorLiskDAO $object, 350 350 array $xactions) { 351 - return true; 351 + return $this->isCommitMostlyImported($object); 352 352 } 353 353 354 354 protected function buildReplyHandler(PhabricatorLiskDAO $object) { ··· 467 467 protected function shouldPublishFeedStory( 468 468 PhabricatorLiskDAO $object, 469 469 array $xactions) { 470 - return true; 470 + return $this->isCommitMostlyImported($object); 471 + } 472 + 473 + private function isCommitMostlyImported(PhabricatorLiskDAO $object) { 474 + $has_message = PhabricatorRepositoryCommit::IMPORTED_MESSAGE; 475 + $has_changes = PhabricatorRepositoryCommit::IMPORTED_CHANGE; 476 + 477 + // Don't publish feed stories or email about events which occur during 478 + // import. In particular, this affects tasks being attached when they are 479 + // closed by "Fixes Txxxx" in a commit message. See T5851. 480 + 481 + $mask = ($has_message | $has_changes); 482 + 483 + return $object->isPartiallyImported($mask); 471 484 } 472 485 473 486 }
+5 -6
src/applications/differential/editor/DifferentialTransactionEditor.php
··· 98 98 PhabricatorLiskDAO $object, 99 99 PhabricatorApplicationTransaction $xaction) { 100 100 101 + $actor_phid = $this->getActingAsPHID(); 102 + 101 103 switch ($xaction->getTransactionType()) { 102 104 case DifferentialTransaction::TYPE_INLINE: 103 105 return $xaction->hasComment(); ··· 119 121 } 120 122 121 123 $actor = $this->getActor(); 122 - $actor_phid = $actor->getPHID(); 123 124 124 125 // These transactions can cause effects in two ways: by altering the 125 126 // status of an existing reviewer; or by adding the actor as a new ··· 151 152 case DifferentialAction::ACTION_REQUEST: 152 153 return ($object->getStatus() != $status_review); 153 154 case DifferentialAction::ACTION_RESIGN: 154 - $actor_phid = $this->getActor()->getPHID(); 155 155 foreach ($object->getReviewerStatus() as $reviewer) { 156 156 if ($reviewer->getReviewerPHID() == $actor_phid) { 157 157 return true; ··· 159 159 } 160 160 return false; 161 161 case DifferentialAction::ACTION_CLAIM: 162 - $actor_phid = $this->getActor()->getPHID(); 163 162 return ($actor_phid != $object->getAuthorPHID()); 164 163 } 165 164 } ··· 231 230 $object->setStatus(ArcanistDifferentialRevisionStatus::CLOSED); 232 231 return; 233 232 case DifferentialAction::ACTION_CLAIM: 234 - $object->setAuthorPHID($this->getActor()->getPHID()); 233 + $object->setAuthorPHID($this->getActingAsPHID()); 235 234 return; 236 235 } 237 236 break; ··· 247 246 $results = parent::expandTransaction($object, $xaction); 248 247 249 248 $actor = $this->getActor(); 250 - $actor_phid = $actor->getPHID(); 249 + $actor_phid = $this->getActingAsPHID(); 251 250 $type_edge = PhabricatorTransactions::TYPE_EDGE; 252 251 253 252 $status_plan = ArcanistDifferentialRevisionStatus::CHANGES_PLANNED; ··· 782 781 $action) { 783 782 784 783 $author_phid = $revision->getAuthorPHID(); 785 - $actor_phid = $this->getActor()->getPHID(); 784 + $actor_phid = $this->getActingAsPHID(); 786 785 $actor_is_author = ($author_phid == $actor_phid); 787 786 788 787 $config_abandon_key = 'differential.always-allow-abandon';
+1 -1
src/applications/maniphest/editor/ManiphestTransactionEditor.php
··· 410 410 protected function getMailTo(PhabricatorLiskDAO $object) { 411 411 return array( 412 412 $object->getOwnerPHID(), 413 - $this->requireActor()->getPHID(), 413 + $this->getActingAsPHID(), 414 414 ); 415 415 } 416 416
+37 -26
src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php
··· 43 43 $author_phid); 44 44 } 45 45 46 - $field_values = id(new DiffusionLowLevelCommitFieldsQuery()) 47 - ->setRepository($repository) 48 - ->withCommitRef($ref) 49 - ->execute(); 50 - $revision_id = idx($field_values, 'revisionID'); 46 + $differential_app = 'PhabricatorDifferentialApplication'; 47 + $revision_id = null; 48 + if (PhabricatorApplication::isClassInstalled($differential_app)) { 49 + $field_values = id(new DiffusionLowLevelCommitFieldsQuery()) 50 + ->setRepository($repository) 51 + ->withCommitRef($ref) 52 + ->execute(); 53 + $revision_id = idx($field_values, 'revisionID'); 51 54 52 - if (!empty($field_values['reviewedByPHIDs'])) { 53 - $data->setCommitDetail( 54 - 'reviewerPHID', 55 - reset($field_values['reviewedByPHIDs'])); 56 - } 55 + if (!empty($field_values['reviewedByPHIDs'])) { 56 + $data->setCommitDetail( 57 + 'reviewerPHID', 58 + reset($field_values['reviewedByPHIDs'])); 59 + } 57 60 58 - $data->setCommitDetail('differential.revisionID', $revision_id); 61 + $data->setCommitDetail('differential.revisionID', $revision_id); 62 + } 59 63 60 64 if ($author_phid != $commit->getAuthorPHID()) { 61 65 $commit->setAuthorPHID($author_phid); ··· 64 68 $commit->setSummary($data->getSummary()); 65 69 $commit->save(); 66 70 71 + // When updating related objects, we'll act under an omnipotent user to 72 + // ensure we can see them, but take actions as either the committer or 73 + // author (if we recognize their accounts) or the Diffusion application 74 + // (if we do not). 75 + 76 + $actor = PhabricatorUser::getOmnipotentUser(); 77 + $acting_as_phid = nonempty( 78 + $committer_phid, 79 + $author_phid, 80 + id(new PhabricatorDiffusionApplication())->getPHID()); 81 + 67 82 $conn_w = id(new DifferentialRevision())->establishConnection('w'); 68 83 69 84 // NOTE: The `differential_commit` table has a unique ID on `commitPHID`, ··· 78 93 $should_autoclose = $repository->shouldAutocloseCommit($commit, $data); 79 94 80 95 if ($revision_id) { 81 - // TODO: Check if a more restrictive viewer could be set here 82 96 $revision_query = id(new DifferentialRevisionQuery()) 83 97 ->withIDs(array($revision_id)) 84 - ->setViewer(PhabricatorUser::getOmnipotentUser()) 98 + ->setViewer($actor) 85 99 ->needReviewerStatus(true) 86 100 ->needActiveDiffs(true); 87 101 ··· 105 119 $should_autoclose; 106 120 107 121 if ($should_close) { 108 - $actor_phid = nonempty( 109 - $committer_phid, 110 - $author_phid, 111 - $revision->getAuthorPHID()); 112 - 113 - $actor = id(new PhabricatorUser()) 114 - ->loadOneWhere('phid = %s', $actor_phid); 115 - 116 122 $commit_name = $repository->formatCommitName( 117 123 $commit->getCommitIdentifier()); 118 124 ··· 139 145 $author_name); 140 146 } 141 147 142 - $diff = $this->generateFinalDiff($revision, $actor_phid); 148 + $diff = $this->generateFinalDiff($revision, $acting_as_phid); 143 149 144 150 $vs_diff = $this->loadChangedByCommit($revision, $diff); 145 151 $changed_uri = null; ··· 177 183 178 184 $editor = id(new DifferentialTransactionEditor()) 179 185 ->setActor($actor) 186 + ->setActingAsPHID($acting_as_phid) 180 187 ->setContinueOnMissingFields(true) 181 188 ->setContentSource($content_source) 182 189 ->setChangedPriorToCommitURI($changed_uri) ··· 195 202 } 196 203 197 204 if ($should_autoclose) { 198 - // TODO: This isn't as general as it could be. 199 - if ($user->getPHID()) { 200 - $this->closeTasks($user, $repository, $commit, $message); 201 - } 205 + $this->closeTasks( 206 + $actor, 207 + $acting_as_phid, 208 + $repository, 209 + $commit, 210 + $message); 202 211 } 203 212 204 213 $data->save(); ··· 405 414 406 415 private function closeTasks( 407 416 PhabricatorUser $actor, 417 + $acting_as, 408 418 PhabricatorRepository $repository, 409 419 PhabricatorRepositoryCommit $commit, 410 420 $message) { ··· 487 497 488 498 $editor = id(new ManiphestTransactionEditor()) 489 499 ->setActor($actor) 500 + ->setActingAsPHID($acting_as) 490 501 ->setContinueOnNoEffect(true) 491 502 ->setContinueOnMissingFields(true) 492 503 ->setContentSource($content_source);
+15 -2
src/applications/transactions/editor/PhabricatorApplicationTransactionCommentEditor.php
··· 4 4 extends PhabricatorEditor { 5 5 6 6 private $contentSource; 7 + private $actingAsPHID; 8 + 9 + public function setActingAsPHID($acting_as_phid) { 10 + $this->actingAsPHID = $acting_as_phid; 11 + return $this; 12 + } 13 + 14 + public function getActingAsPHID() { 15 + if ($this->actingAsPHID) { 16 + return $this->actingAsPHID; 17 + } 18 + return $this->getActor()->getPHID(); 19 + } 7 20 8 21 public function setContentSource(PhabricatorContentSource $content_source) { 9 22 $this->contentSource = $content_source; ··· 27 40 $actor = $this->requireActor(); 28 41 29 42 $comment->setContentSource($this->getContentSource()); 30 - $comment->setAuthorPHID($actor->getPHID()); 43 + $comment->setAuthorPHID($this->getActingAsPHID()); 31 44 32 45 // TODO: This needs to be more sophisticated once we have meta-policies. 33 46 $comment->setViewPolicy(PhabricatorPolicies::POLICY_PUBLIC); 34 - $comment->setEditPolicy($actor->getPHID()); 47 + $comment->setEditPolicy($this->getActingAsPHID()); 35 48 36 49 $xaction->openTransaction(); 37 50 $xaction->beginReadLocking();
+15 -5
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 479 479 if ($actor->isOmnipotent()) { 480 480 $xaction->setEditPolicy(PhabricatorPolicies::POLICY_NOONE); 481 481 } else { 482 - $xaction->setEditPolicy($actor->getPHID()); 482 + $xaction->setEditPolicy($this->getActingAsPHID()); 483 483 } 484 484 485 485 $xaction->setAuthorPHID($this->getActingAsPHID()); ··· 644 644 645 645 $comment_editor = id(new PhabricatorApplicationTransactionCommentEditor()) 646 646 ->setActor($actor) 647 + ->setActingAsPHID($this->getActingAsPHID()) 647 648 ->setContentSource($this->getContentSource()); 648 649 649 650 if (!$transaction_open) { ··· 1717 1718 return $xactions; 1718 1719 } 1719 1720 1720 - $actor_phid = $this->requireActor()->getPHID(); 1721 + $actor_phid = $this->getActingAsPHID(); 1722 + 1723 + $type_user = PhabricatorPeopleUserPHIDType::TYPECONST; 1724 + if (phid_get_type($actor_phid) != $type_user) { 1725 + // Transactions by application actors like Herald, Harbormaster and 1726 + // Diffusion should not CC the applications. 1727 + return $xactions; 1728 + } 1729 + 1721 1730 if ($object->isAutomaticallySubscribed($actor_phid)) { 1722 1731 // If they're auto-subscribed, don't CC them. 1723 1732 return $xactions; ··· 1827 1836 } 1828 1837 1829 1838 $template 1830 - ->setFrom($this->requireActor()->getPHID()) 1839 + ->setFrom($this->getActingAsPHID()) 1831 1840 ->setSubjectPrefix($this->getMailSubjectPrefix()) 1832 1841 ->setVarySubjectPrefix('['.$action.']') 1833 1842 ->setThreadID($this->getMailThreadID($object), $this->getIsNewObject()) ··· 2089 2098 2090 2099 return array( 2091 2100 $object->getPHID(), 2092 - $this->requireActor()->getPHID(), 2101 + $this->getActingAsPHID(), 2093 2102 ); 2094 2103 } 2095 2104 ··· 2148 2157 ->setStoryType($story_type) 2149 2158 ->setStoryData($story_data) 2150 2159 ->setStoryTime(time()) 2151 - ->setStoryAuthorPHID($this->requireActor()->getPHID()) 2160 + ->setStoryAuthorPHID($this->getActingAsPHID()) 2152 2161 ->setRelatedPHIDs($related_phids) 2153 2162 ->setPrimaryObjectPHID($object->getPHID()) 2154 2163 ->setSubscribedPHIDs($subscribed_phids) ··· 2394 2403 ->setParentMessageID($this->getParentMessageID()) 2395 2404 ->setIsInverseEdgeEditor(true) 2396 2405 ->setActor($this->requireActor()) 2406 + ->setActingAsPHID($this->getActingAsPHID()) 2397 2407 ->setContentSource($this->getContentSource()); 2398 2408 2399 2409 $editor->applyTransactions($target, array($template));