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

Modularize remaining TYPE_ACTION transactions in Differential, reducing calls to ArcanistDifferentialRevisionStatus

Summary:
Ref T2543. This cleans up a couple of remaining rough edges:

- We could do an older TYPE_ACTION "close" via the daemons.
- We could do an older TYPE_ACTION "close" via `arc close-revision`, explicitly or implicitly in `arc land`, via API (`differential.close`).
- We could do an older TYPE_ACTION "rethink" ("Plan Changes") via the API, via `arc diff --plan-changes` (`differential.createcomment`).

Move these to modern modular transactions, then get rid of all the validation and application logic for them. This nukes a bunch of `ArcanistDifferentialRevision::...` junk.

Test Plan:
- Used `bin/repository reparse --message rXYZ...` to reparse a commit, closing a corresponding revision.
- Used `differential.close` to close a revision.
- Used `differential.createcomment` to plan changes to a revision.
- Reviewed transaction log for full "closed by commit" message (linking to commit and mentioning author).
- Grepped for `::TYPE_ACTION` to look for remaining callsites, didn't find any.
- Grepped for `differential.close` and `differential.createcomment` in `arcanist/` to look for anything suspicious, seemed clean.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T2543

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

+63 -250
+3 -2
src/applications/differential/conduit/DifferentialCloseConduitAPIMethod.php
··· 52 52 53 53 $xactions = array(); 54 54 $xactions[] = id(new DifferentialTransaction()) 55 - ->setTransactionType(DifferentialTransaction::TYPE_ACTION) 56 - ->setNewValue(DifferentialAction::ACTION_CLOSE); 55 + ->setTransactionType( 56 + DifferentialRevisionCloseTransaction::TRANSACTIONTYPE) 57 + ->setNewValue(true); 57 58 58 59 $content_source = $request->newContentSource(); 59 60
+5 -3
src/applications/differential/conduit/DifferentialCreateCommentConduitAPIMethod.php
··· 63 63 'resign' => DifferentialRevisionResignTransaction::TRANSACTIONTYPE, 64 64 'request_review' => 65 65 DifferentialRevisionRequestReviewTransaction::TRANSACTIONTYPE, 66 + 'rethink' => DifferentialRevisionPlanChangesTransaction::TRANSACTIONTYPE, 66 67 ); 67 68 68 69 $action = $request->getValue('action'); ··· 76 77 case 'none': 77 78 break; 78 79 default: 79 - $xactions[] = id(new DifferentialTransaction()) 80 - ->setTransactionType(DifferentialTransaction::TYPE_ACTION) 81 - ->setNewValue($action); 80 + throw new Exception( 81 + pht( 82 + 'Unsupported action "%s".', 83 + $action)); 82 84 break; 83 85 } 84 86 }
-239
src/applications/differential/editor/DifferentialTransactionEditor.php
··· 69 69 $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; 70 70 $types[] = PhabricatorTransactions::TYPE_INLINESTATE; 71 71 72 - $types[] = DifferentialTransaction::TYPE_ACTION; 73 72 $types[] = DifferentialTransaction::TYPE_INLINE; 74 73 $types[] = DifferentialTransaction::TYPE_UPDATE; 75 74 ··· 81 80 PhabricatorApplicationTransaction $xaction) { 82 81 83 82 switch ($xaction->getTransactionType()) { 84 - case DifferentialTransaction::TYPE_ACTION: 85 - return null; 86 83 case DifferentialTransaction::TYPE_INLINE: 87 84 return null; 88 85 case DifferentialTransaction::TYPE_UPDATE: ··· 101 98 PhabricatorApplicationTransaction $xaction) { 102 99 103 100 switch ($xaction->getTransactionType()) { 104 - case DifferentialTransaction::TYPE_ACTION: 105 101 case DifferentialTransaction::TYPE_UPDATE: 106 102 return $xaction->getNewValue(); 107 103 case DifferentialTransaction::TYPE_INLINE: ··· 120 116 switch ($xaction->getTransactionType()) { 121 117 case DifferentialTransaction::TYPE_INLINE: 122 118 return $xaction->hasComment(); 123 - case DifferentialTransaction::TYPE_ACTION: 124 - $status_closed = ArcanistDifferentialRevisionStatus::CLOSED; 125 - $status_abandoned = ArcanistDifferentialRevisionStatus::ABANDONED; 126 - $status_review = ArcanistDifferentialRevisionStatus::NEEDS_REVIEW; 127 - $status_revision = ArcanistDifferentialRevisionStatus::NEEDS_REVISION; 128 - $status_plan = ArcanistDifferentialRevisionStatus::CHANGES_PLANNED; 129 - 130 - $action_type = $xaction->getNewValue(); 131 - switch ($action_type) { 132 - case DifferentialAction::ACTION_CLOSE: 133 - return ($object->getStatus() != $status_closed); 134 - case DifferentialAction::ACTION_ABANDON: 135 - return ($object->getStatus() != $status_abandoned); 136 - case DifferentialAction::ACTION_RECLAIM: 137 - return ($object->getStatus() == $status_abandoned); 138 - case DifferentialAction::ACTION_REOPEN: 139 - return ($object->getStatus() == $status_closed); 140 - case DifferentialAction::ACTION_RETHINK: 141 - return ($object->getStatus() != $status_plan); 142 - case DifferentialAction::ACTION_CLAIM: 143 - return ($actor_phid != $object->getAuthorPHID()); 144 - } 145 119 } 146 120 147 121 return parent::transactionHasEffect($object, $xaction); ··· 183 157 184 158 // TODO: Update the `diffPHID` once we add that. 185 159 return; 186 - case DifferentialTransaction::TYPE_ACTION: 187 - switch ($xaction->getNewValue()) { 188 - case DifferentialAction::ACTION_ABANDON: 189 - $object->setStatus(ArcanistDifferentialRevisionStatus::ABANDONED); 190 - return; 191 - case DifferentialAction::ACTION_RETHINK: 192 - $object->setStatus($status_plan); 193 - return; 194 - case DifferentialAction::ACTION_RECLAIM: 195 - $object->setStatus($status_review); 196 - return; 197 - case DifferentialAction::ACTION_REOPEN: 198 - $object->setStatus($status_review); 199 - return; 200 - case DifferentialAction::ACTION_CLOSE: 201 - $old_status = $object->getStatus(); 202 - $object->setStatus(ArcanistDifferentialRevisionStatus::CLOSED); 203 - $was_accepted = ($old_status == $status_accepted); 204 - $object->setProperty( 205 - DifferentialRevision::PROPERTY_CLOSED_FROM_ACCEPTED, 206 - $was_accepted); 207 - return; 208 - case DifferentialAction::ACTION_CLAIM: 209 - $object->setAuthorPHID($this->getActingAsPHID()); 210 - return; 211 - default: 212 - throw new Exception( 213 - pht( 214 - 'Differential action "%s" is not a valid action!', 215 - $xaction->getNewValue())); 216 - } 217 - break; 218 160 } 219 161 220 162 return parent::applyCustomInternalTransaction($object, $xaction); ··· 356 298 case DifferentialRevisionCommandeerTransaction::TRANSACTIONTYPE: 357 299 $is_commandeer = true; 358 300 break; 359 - 360 - case DifferentialTransaction::TYPE_ACTION: 361 - $action_type = $xaction->getNewValue(); 362 - 363 - switch ($action_type) { 364 - case DifferentialAction::ACTION_CLAIM: 365 - $is_commandeer = true; 366 - break; 367 - } 368 - break; 369 301 } 370 302 371 303 if ($is_commandeer) { ··· 375 307 if (!$this->didExpandInlineState) { 376 308 switch ($xaction->getTransactionType()) { 377 309 case PhabricatorTransactions::TYPE_COMMENT: 378 - case DifferentialTransaction::TYPE_ACTION: 379 310 case DifferentialTransaction::TYPE_UPDATE: 380 311 case DifferentialTransaction::TYPE_INLINE: 381 312 $this->didExpandInlineState = true; ··· 421 352 PhabricatorApplicationTransaction $xaction) { 422 353 423 354 switch ($xaction->getTransactionType()) { 424 - case DifferentialTransaction::TYPE_ACTION: 425 - return; 426 355 case DifferentialTransaction::TYPE_INLINE: 427 356 $reply = $xaction->getComment()->getReplyToComment(); 428 357 if ($reply && !$reply->getHasReplies()) { ··· 660 589 $xaction); 661 590 } 662 591 break; 663 - case DifferentialTransaction::TYPE_ACTION: 664 - $error = $this->validateDifferentialAction( 665 - $object, 666 - $type, 667 - $xaction, 668 - $xaction->getNewValue()); 669 - if ($error) { 670 - $errors[] = new PhabricatorApplicationTransactionValidationError( 671 - $type, 672 - pht('Invalid'), 673 - $error, 674 - $xaction); 675 - } 676 - break; 677 592 } 678 593 } 679 594 680 595 return $errors; 681 596 } 682 597 683 - private function validateDifferentialAction( 684 - DifferentialRevision $revision, 685 - $type, 686 - DifferentialTransaction $xaction, 687 - $action) { 688 - 689 - $author_phid = $revision->getAuthorPHID(); 690 - $actor_phid = $this->getActingAsPHID(); 691 - $actor_is_author = ($author_phid == $actor_phid); 692 - 693 - $config_abandon_key = 'differential.always-allow-abandon'; 694 - $always_allow_abandon = PhabricatorEnv::getEnvConfig($config_abandon_key); 695 - 696 - $config_close_key = 'differential.always-allow-close'; 697 - $always_allow_close = PhabricatorEnv::getEnvConfig($config_close_key); 698 - 699 - $config_reopen_key = 'differential.allow-reopen'; 700 - $allow_reopen = PhabricatorEnv::getEnvConfig($config_reopen_key); 701 - 702 - $config_self_accept_key = 'differential.allow-self-accept'; 703 - $allow_self_accept = PhabricatorEnv::getEnvConfig($config_self_accept_key); 704 - 705 - $revision_status = $revision->getStatus(); 706 - 707 - $status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED; 708 - $status_abandoned = ArcanistDifferentialRevisionStatus::ABANDONED; 709 - $status_closed = ArcanistDifferentialRevisionStatus::CLOSED; 710 - 711 - switch ($action) { 712 - case DifferentialAction::ACTION_CLAIM: 713 - // You can claim a revision if you're not the owner. If you are, this 714 - // is a no-op rather than invalid. 715 - 716 - if ($revision_status == $status_closed) { 717 - return pht( 718 - 'You can not commandeer this revision because it has already been '. 719 - 'closed.'); 720 - } 721 - break; 722 - 723 - case DifferentialAction::ACTION_ABANDON: 724 - if (!$actor_is_author && !$always_allow_abandon) { 725 - return pht( 726 - 'You can not abandon this revision because you do not own it. '. 727 - 'You can only abandon revisions you own.'); 728 - } 729 - 730 - if ($revision_status == $status_closed) { 731 - return pht( 732 - 'You can not abandon this revision because it has already been '. 733 - 'closed.'); 734 - } 735 - 736 - // NOTE: Abandons of already-abandoned revisions are treated as no-op 737 - // instead of invalid. Other abandons are OK. 738 - 739 - break; 740 - 741 - case DifferentialAction::ACTION_RECLAIM: 742 - if (!$actor_is_author) { 743 - return pht( 744 - 'You can not reclaim this revision because you do not own '. 745 - 'it. You can only reclaim revisions you own.'); 746 - } 747 - 748 - if ($revision_status == $status_closed) { 749 - return pht( 750 - 'You can not reclaim this revision because it has already been '. 751 - 'closed.'); 752 - } 753 - 754 - // NOTE: Reclaims of other non-abandoned revisions are treated as no-op 755 - // instead of invalid. 756 - 757 - break; 758 - 759 - case DifferentialAction::ACTION_REOPEN: 760 - if (!$allow_reopen) { 761 - return pht( 762 - 'The reopen action is not enabled on this Phabricator install. '. 763 - 'Adjust your configuration to enable it.'); 764 - } 765 - 766 - // NOTE: If the revision is not closed, this is caught as a no-op 767 - // instead of an invalid transaction. 768 - 769 - break; 770 - 771 - case DifferentialAction::ACTION_RETHINK: 772 - if (!$actor_is_author) { 773 - return pht( 774 - 'You can not plan changes to this revision because you do not '. 775 - 'own it. To plan changes to a revision, you must be its owner.'); 776 - } 777 - 778 - switch ($revision_status) { 779 - case ArcanistDifferentialRevisionStatus::ACCEPTED: 780 - case ArcanistDifferentialRevisionStatus::NEEDS_REVISION: 781 - case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW: 782 - // These are OK. 783 - break; 784 - case ArcanistDifferentialRevisionStatus::CHANGES_PLANNED: 785 - // Let this through, it's a no-op. 786 - break; 787 - case ArcanistDifferentialRevisionStatus::ABANDONED: 788 - return pht( 789 - 'You can not plan changes to this revision because it has '. 790 - 'been abandoned.'); 791 - case ArcanistDifferentialRevisionStatus::CLOSED: 792 - return pht( 793 - 'You can not plan changes to this revision because it has '. 794 - 'already been closed.'); 795 - default: 796 - throw new Exception( 797 - pht( 798 - 'Encountered unexpected revision status ("%s") when '. 799 - 'validating "%s" action.', 800 - $revision_status, 801 - $action)); 802 - } 803 - break; 804 - 805 - case DifferentialAction::ACTION_CLOSE: 806 - // We force revisions closed when we discover a corresponding commit. 807 - // In this case, revisions are allowed to transition to closed from 808 - // any state. This is an automated action taken by the daemons. 809 - 810 - if (!$this->getIsCloseByCommit()) { 811 - if (!$actor_is_author && !$always_allow_close) { 812 - return pht( 813 - 'You can not close this revision because you do not own it. To '. 814 - 'close a revision, you must be its owner.'); 815 - } 816 - 817 - if ($revision_status != $status_accepted) { 818 - return pht( 819 - 'You can not close this revision because it has not been '. 820 - 'accepted. You can only close accepted revisions.'); 821 - } 822 - } 823 - break; 824 - } 825 - 826 - return null; 827 - } 828 - 829 598 protected function sortTransactions(array $xactions) { 830 599 $xactions = parent::sortTransactions($xactions); 831 600 ··· 1233 1002 // When users commandeer revisions, we may need to trigger 1234 1003 // signatures or author-based rules. 1235 1004 return true; 1236 - case DifferentialTransaction::TYPE_ACTION: 1237 - switch ($xaction->getNewValue()) { 1238 - case DifferentialAction::ACTION_CLAIM: 1239 - // When users commandeer revisions, we may need to trigger 1240 - // signatures or author-based rules. 1241 - return true; 1242 - } 1243 - break; 1244 1005 } 1245 1006 } 1246 1007
+50 -3
src/applications/differential/xaction/DifferentialRevisionCloseTransaction.php
··· 46 46 } 47 47 48 48 protected function validateAction($object, PhabricatorUser $viewer) { 49 + if ($this->getEditor()->getIsCloseByCommit()) { 50 + // If we're closing a revision because we discovered a commit, we don't 51 + // care what state it was in. 52 + return; 53 + } 54 + 49 55 if ($object->isClosed()) { 50 56 throw new Exception( 51 57 pht( ··· 74 80 } 75 81 76 82 public function getTitle() { 77 - return pht( 78 - '%s closed this revision.', 79 - $this->renderAuthor()); 83 + if (!$this->getMetadataValue('isCommitClose')) { 84 + return pht( 85 + '%s closed this revision.', 86 + $this->renderAuthor()); 87 + } 88 + 89 + $commit_phid = $this->getMetadataValue('commitPHID'); 90 + $committer_phid = $this->getMetadataValue('committerPHID'); 91 + $author_phid = $this->getMetadataValue('authorPHID'); 92 + 93 + if ($committer_phid) { 94 + $committer_name = $this->renderHandle($committer_phid); 95 + } else { 96 + $committer_name = $this->getMetadataValue('committerName'); 97 + } 98 + 99 + if ($author_phid) { 100 + $author_name = $this->renderHandle($author_phid); 101 + } else { 102 + $author_name = $this->getMetadatavalue('authorName'); 103 + } 104 + 105 + $same_phid = 106 + strlen($committer_phid) && 107 + strlen($author_phid) && 108 + ($committer_phid == $author_phid); 109 + 110 + $same_name = 111 + !strlen($committer_phid) && 112 + !strlen($author_phid) && 113 + ($committer_name == $author_name); 114 + 115 + if ($same_name || $same_phid) { 116 + return pht( 117 + 'Closed by commit %s (authored by %s).', 118 + $this->renderHandle($commit_phid), 119 + $author_name); 120 + } else { 121 + return pht( 122 + 'Closed by commit %s (authored by %s, committed by %s).', 123 + $this->renderHandle($commit_phid), 124 + $author_name, 125 + $committer_name); 126 + } 80 127 } 81 128 82 129 public function getTitleForFeed() {
+5 -3
src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php
··· 205 205 206 206 $should_close = !$revision->isPublished() && $should_autoclose; 207 207 if ($should_close) { 208 - $commit_close_xaction = id(new DifferentialTransaction()) 209 - ->setTransactionType(DifferentialTransaction::TYPE_ACTION) 210 - ->setNewValue(DifferentialAction::ACTION_CLOSE) 208 + $type_close = DifferentialRevisionCloseTransaction::TRANSACTIONTYPE; 209 + 210 + $commit_close_xaction = id(new DifferentialTransaction()) 211 + ->setTransactionType($type_close) 212 + ->setNewValue(true) 211 213 ->setMetadataValue('isCommitClose', true); 212 214 213 215 $commit_close_xaction->setMetadataValue(