@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 an issue where "Request Review" of a fully-accepted revision would transition to "Accepted"

Summary:
Ref T10967. This is explained in more detail in T10967#217125

When an author does "Request Review" on an accepted revision, void (in the sense of "cancel out", like a bank check) any "accepted" reviewers on the current diff.

Test Plan:
- Create a revision with author A and reviewer B.
- Accept as B.
- "Request Review" as A.
- (With sticky accepts enabled.)
- Before patch: revision swithced back to "accepted".
- After patch: the earlier review is "voided" by te "Request Review", and the revision switches to "Review Requested".

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10967

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

+109 -21
+2
resources/sql/autopatches/20170328.reviewers.01.void.sql
··· 1 + ALTER TABLE {$NAMESPACE}_differential.differential_reviewer 2 + ADD voidedPHID VARBINARY(64);
+2
src/__phutil_library_map__.php
··· 571 571 'DifferentialRevisionTransactionType' => 'applications/differential/xaction/DifferentialRevisionTransactionType.php', 572 572 'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/DifferentialRevisionUpdateHistoryView.php', 573 573 'DifferentialRevisionViewController' => 'applications/differential/controller/DifferentialRevisionViewController.php', 574 + 'DifferentialRevisionVoidTransaction' => 'applications/differential/xaction/DifferentialRevisionVoidTransaction.php', 574 575 'DifferentialSchemaSpec' => 'applications/differential/storage/DifferentialSchemaSpec.php', 575 576 'DifferentialSetDiffPropertyConduitAPIMethod' => 'applications/differential/conduit/DifferentialSetDiffPropertyConduitAPIMethod.php', 576 577 'DifferentialStoredCustomField' => 'applications/differential/customfield/DifferentialStoredCustomField.php', ··· 5357 5358 'DifferentialRevisionTransactionType' => 'PhabricatorModularTransactionType', 5358 5359 'DifferentialRevisionUpdateHistoryView' => 'AphrontView', 5359 5360 'DifferentialRevisionViewController' => 'DifferentialController', 5361 + 'DifferentialRevisionVoidTransaction' => 'DifferentialRevisionTransactionType', 5360 5362 'DifferentialSchemaSpec' => 'PhabricatorConfigSchemaSpec', 5361 5363 'DifferentialSetDiffPropertyConduitAPIMethod' => 'DifferentialConduitAPIMethod', 5362 5364 'DifferentialStoredCustomField' => 'DifferentialCustomField',
+9 -4
src/applications/differential/editor/DifferentialTransactionEditor.php
··· 357 357 } 358 358 } 359 359 360 + if ($downgrade_accepts) { 361 + $void_type = DifferentialRevisionVoidTransaction::TRANSACTIONTYPE; 362 + $results[] = id(new DifferentialTransaction()) 363 + ->setTransactionType($void_type) 364 + ->setIgnoreOnNoEffect(true) 365 + ->setNewValue(true); 366 + } 367 + 360 368 $is_commandeer = false; 361 369 switch ($xaction->getTransactionType()) { 362 370 case DifferentialTransaction::TYPE_UPDATE: ··· 685 693 break; 686 694 case DifferentialReviewerStatus::STATUS_ACCEPTED: 687 695 if ($reviewer->isUser()) { 688 - $action_phid = $reviewer->getLastActionDiffPHID(); 689 696 $active_phid = $active_diff->getPHID(); 690 - $is_current = ($action_phid == $active_phid); 691 - 692 - if ($is_sticky_accept || $is_current) { 697 + if ($reviewer->isAccepted($active_phid)) { 693 698 $has_accepting_user = true; 694 699 } 695 700 }
+9
src/applications/differential/storage/DifferentialReviewer.php
··· 9 9 protected $lastActionDiffPHID; 10 10 protected $lastCommentDiffPHID; 11 11 protected $lastActorPHID; 12 + protected $voidedPHID; 12 13 13 14 private $authority = array(); 14 15 ··· 19 20 'lastActionDiffPHID' => 'phid?', 20 21 'lastCommentDiffPHID' => 'phid?', 21 22 'lastActorPHID' => 'phid?', 23 + 'voidedPHID' => 'phid?', 22 24 ), 23 25 self::CONFIG_KEY_SCHEMA => array( 24 26 'key_revision' => array( ··· 56 58 $status_accepted = DifferentialReviewerStatus::STATUS_ACCEPTED; 57 59 58 60 if ($this->getReviewerStatus() != $status_accepted) { 61 + return false; 62 + } 63 + 64 + // If this accept has been voided (for example, but a reviewer using 65 + // "Request Review"), don't count it as a real "Accept" even if it is 66 + // against the current diff PHID. 67 + if ($this->getVoidedPHID()) { 59 68 return false; 60 69 } 61 70
+24 -17
src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php
··· 50 50 protected function isViewerFullyAccepted( 51 51 DifferentialRevision $revision, 52 52 PhabricatorUser $viewer) { 53 - return $this->isViewerReviewerStatusFullyAmong( 53 + return $this->isViewerReviewerStatusFully( 54 54 $revision, 55 55 $viewer, 56 - array( 57 - DifferentialReviewerStatus::STATUS_ACCEPTED, 58 - ), 59 - true); 56 + DifferentialReviewerStatus::STATUS_ACCEPTED); 60 57 } 61 58 62 59 protected function isViewerFullyRejected( 63 60 DifferentialRevision $revision, 64 61 PhabricatorUser $viewer) { 65 - return $this->isViewerReviewerStatusFullyAmong( 62 + return $this->isViewerReviewerStatusFully( 66 63 $revision, 67 64 $viewer, 68 - array( 69 - DifferentialReviewerStatus::STATUS_REJECTED, 70 - ), 71 - true); 65 + DifferentialReviewerStatus::STATUS_REJECTED); 72 66 } 73 67 74 68 protected function getViewerReviewerStatus( ··· 90 84 return null; 91 85 } 92 86 93 - protected function isViewerReviewerStatusFullyAmong( 87 + private function isViewerReviewerStatusFully( 94 88 DifferentialRevision $revision, 95 89 PhabricatorUser $viewer, 96 - array $status_list, 97 - $require_current) { 90 + $require_status) { 98 91 99 92 // If the user themselves is not a reviewer, the reviews they have 100 93 // authority over can not all be in any set of states since their own ··· 106 99 107 100 $active_phid = $this->getActiveDiffPHID($revision); 108 101 102 + $status_accepted = DifferentialReviewerStatus::STATUS_ACCEPTED; 103 + $is_accepted = ($require_status == $status_accepted); 104 + 109 105 // Otherwise, check that all reviews they have authority over are in 110 106 // the desired set of states. 111 - $status_map = array_fuse($status_list); 112 107 foreach ($revision->getReviewers() as $reviewer) { 113 108 if (!$reviewer->hasAuthority($viewer)) { 114 109 continue; 115 110 } 116 111 117 112 $status = $reviewer->getReviewerStatus(); 118 - if (!isset($status_map[$status])) { 113 + if ($status != $require_status) { 119 114 return false; 120 115 } 121 116 122 - if ($require_current) { 123 - if ($reviewer->getLastActionDiffPHID() != $active_phid) { 117 + // Here, we're primarily testing if we can remove a void on the review. 118 + if ($is_accepted) { 119 + if (!$reviewer->isAccepted($active_phid)) { 124 120 return false; 125 121 } 122 + } 123 + 124 + // This is a broader check to see if we can update the diff where the 125 + // last action occurred. 126 + if ($reviewer->getLastActionDiffPHID() != $active_phid) { 127 + return false; 126 128 } 127 129 } 128 130 ··· 222 224 if ($old_status !== $status) { 223 225 $reviewer->setLastActorPHID($this->getActingAsPHID()); 224 226 } 227 + 228 + // Clear any outstanding void on this reviewer. A void may be placed 229 + // by the author using "Request Review" when a reviewer has already 230 + // accepted. 231 + $reviewer->setVoidedPHID(null); 225 232 226 233 try { 227 234 $reviewer->save();
+63
src/applications/differential/xaction/DifferentialRevisionVoidTransaction.php
··· 1 + <?php 2 + 3 + /** 4 + * This is an internal transaction type used to void reviews. 5 + * 6 + * For example, "Request Review" voids any open accepts, so they no longer 7 + * act as current accepts. 8 + */ 9 + final class DifferentialRevisionVoidTransaction 10 + extends DifferentialRevisionTransactionType { 11 + 12 + const TRANSACTIONTYPE = 'differential.revision.void'; 13 + 14 + public function generateOldValue($object) { 15 + return false; 16 + } 17 + 18 + public function generateNewValue($object, $value) { 19 + $table = new DifferentialReviewer(); 20 + $table_name = $table->getTableName(); 21 + $conn = $table->establishConnection('w'); 22 + 23 + $rows = queryfx_all( 24 + $conn, 25 + 'SELECT reviewerPHID FROM %T 26 + WHERE revisionPHID = %s 27 + AND voidedPHID IS NULL 28 + AND reviewerStatus = %s', 29 + $table_name, 30 + $object->getPHID(), 31 + DifferentialReviewerStatus::STATUS_ACCEPTED); 32 + 33 + return ipull($rows, 'reviewerPHID'); 34 + } 35 + 36 + public function getTransactionHasEffect($object, $old, $new) { 37 + return (bool)$new; 38 + } 39 + 40 + public function applyExternalEffects($object, $value) { 41 + $table = new DifferentialReviewer(); 42 + $table_name = $table->getTableName(); 43 + $conn = $table->establishConnection('w'); 44 + 45 + queryfx( 46 + $conn, 47 + 'UPDATE %T SET voidedPHID = %s 48 + WHERE revisionPHID = %s 49 + AND voidedPHID IS NULL 50 + AND reviewerStatus = %s', 51 + $table_name, 52 + $this->getActingAsPHID(), 53 + $object->getPHID(), 54 + DifferentialReviewerStatus::STATUS_ACCEPTED); 55 + } 56 + 57 + public function shouldHide() { 58 + // This is an internal transaction, so don't show it in feeds or 59 + // transaction logs. 60 + return true; 61 + } 62 + 63 + }