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

Add a "Needs Verification" state to Audit

Summary:
Fixes T2393. This allows authors to explicitly say "I think I fixed everything, please accept my commit now thank you".

Also improves behavior of "re-accept" and "re-reject" after new auditors you have authority over get added.

Test Plan:
- Kicked a commit back and forth between an author and auditor by alternately using "Request Verification" and "Raise Concern".
- Verified it showed up properly in bucketing for both users.
- Accepted, added a project, accepted again (works now; didn't before).
- Audited on behalf of projects / packages.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T2393

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

+191 -32
+2
src/__phutil_library_map__.php
··· 674 674 'DiffusionCommitStateTransaction' => 'applications/diffusion/xaction/DiffusionCommitStateTransaction.php', 675 675 'DiffusionCommitTagsController' => 'applications/diffusion/controller/DiffusionCommitTagsController.php', 676 676 'DiffusionCommitTransactionType' => 'applications/diffusion/xaction/DiffusionCommitTransactionType.php', 677 + 'DiffusionCommitVerifyTransaction' => 'applications/diffusion/xaction/DiffusionCommitVerifyTransaction.php', 677 678 'DiffusionCompareController' => 'applications/diffusion/controller/DiffusionCompareController.php', 678 679 'DiffusionConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionConduitAPIMethod.php', 679 680 'DiffusionController' => 'applications/diffusion/controller/DiffusionController.php', ··· 5382 5383 'DiffusionCommitStateTransaction' => 'DiffusionCommitTransactionType', 5383 5384 'DiffusionCommitTagsController' => 'DiffusionController', 5384 5385 'DiffusionCommitTransactionType' => 'PhabricatorModularTransactionType', 5386 + 'DiffusionCommitVerifyTransaction' => 'DiffusionCommitAuditTransaction', 5385 5387 'DiffusionCompareController' => 'DiffusionController', 5386 5388 'DiffusionConduitAPIMethod' => 'ConduitAPIMethod', 5387 5389 'DiffusionController' => 'PhabricatorController',
+10 -1
src/applications/audit/constants/PhabricatorAuditCommitStatusConstants.php
··· 7 7 const CONCERN_RAISED = 2; 8 8 const PARTIALLY_AUDITED = 3; 9 9 const FULLY_AUDITED = 4; 10 + const NEEDS_VERIFICATION = 5; 10 11 11 12 public static function getStatusNameMap() { 12 13 $map = array( 13 14 self::NONE => pht('No Audits'), 14 15 self::NEEDS_AUDIT => pht('Audit Required'), 15 16 self::CONCERN_RAISED => pht('Concern Raised'), 17 + self::NEEDS_VERIFICATION => pht('Needs Verification'), 16 18 self::PARTIALLY_AUDITED => pht('Partially Audited'), 17 19 self::FULLY_AUDITED => pht('Audited'), 18 20 ); ··· 28 30 return array( 29 31 self::CONCERN_RAISED, 30 32 self::NEEDS_AUDIT, 33 + self::NEEDS_VERIFICATION, 31 34 self::PARTIALLY_AUDITED, 32 35 ); 33 36 } ··· 48 51 break; 49 52 case self::NONE: 50 53 $color = 'bluegrey'; 54 + break; 55 + case self::NEEDS_VERIFICATION: 56 + $color = 'indigo'; 51 57 break; 52 58 default: 53 59 $color = null; ··· 56 62 return $color; 57 63 } 58 64 59 - public static function getStatusIcon($code) { 65 + public static function getStatusIcon($code) { 60 66 switch ($code) { 61 67 case self::CONCERN_RAISED: 62 68 $icon = 'fa-times-circle'; ··· 72 78 break; 73 79 case self::NONE: 74 80 $icon = 'fa-check'; 81 + break; 82 + case self::NEEDS_VERIFICATION: 83 + $icon = 'fa-refresh'; 75 84 break; 76 85 default: 77 86 $icon = null;
+4 -1
src/applications/audit/editor/PhabricatorAuditEditor.php
··· 11 11 private $auditorPHIDs = array(); 12 12 13 13 private $didExpandInlineState = false; 14 + private $oldAuditStatus = null; 14 15 15 16 public function addAuditReason($phid, $reason) { 16 17 if (!isset($this->auditReasonMap[$phid])) { ··· 77 78 break; 78 79 } 79 80 } 81 + 82 + $this->oldAuditStatus = $object->getAuditStatus(); 80 83 81 84 $object->loadAndAttachAuditAuthority( 82 85 $this->getActor(), ··· 269 272 } 270 273 } 271 274 272 - $old_status = $object->getAuditStatus(); 275 + $old_status = $this->oldAuditStatus; 273 276 274 277 $requests = $object->getAudits(); 275 278 $object->updateAuditStatus($requests);
+36
src/applications/diffusion/query/DiffusionCommitRequiredActionResultBucket.php
··· 34 34 ->setObjects($this->filterConcernRaised($phids)); 35 35 36 36 $groups[] = $this->newGroup() 37 + ->setName(pht('Needs Verification')) 38 + ->setNoDataString(pht('No commits are awaiting your verification.')) 39 + ->setObjects($this->filterNeedsVerification($phids)); 40 + 41 + $groups[] = $this->newGroup() 37 42 ->setName(pht('Ready to Audit')) 38 43 ->setNoDataString(pht('No commits are waiting for you to audit them.')) 39 44 ->setObjects($this->filterShouldAudit($phids)); ··· 82 87 return $results; 83 88 } 84 89 90 + private function filterNeedsVerification(array $phids) { 91 + $results = array(); 92 + $objects = $this->objects; 93 + 94 + $status_verify = PhabricatorAuditCommitStatusConstants::NEEDS_VERIFICATION; 95 + $has_concern = array( 96 + PhabricatorAuditStatusConstants::CONCERNED, 97 + ); 98 + $has_concern = array_fuse($has_concern); 99 + 100 + foreach ($objects as $key => $object) { 101 + if (isset($phids[$object->getAuthorPHID()])) { 102 + continue; 103 + } 104 + 105 + if ($object->getAuditStatus() != $status_verify) { 106 + continue; 107 + } 108 + 109 + if (!$this->hasAuditorsWithStatus($object, $phids, $has_concern)) { 110 + continue; 111 + } 112 + 113 + $results[$key] = $object; 114 + unset($this->objects[$key]); 115 + } 116 + 117 + return $results; 118 + } 119 + 85 120 private function filterShouldAudit(array $phids) { 86 121 $results = array(); 87 122 $objects = $this->objects; ··· 132 167 133 168 $status_waiting = array( 134 169 PhabricatorAuditCommitStatusConstants::NEEDS_AUDIT, 170 + PhabricatorAuditCommitStatusConstants::NEEDS_VERIFICATION, 135 171 PhabricatorAuditCommitStatusConstants::PARTIALLY_AUDITED, 136 172 ); 137 173 $status_waiting = array_fuse($status_waiting);
+1 -6
src/applications/diffusion/xaction/DiffusionCommitAcceptTransaction.php
··· 30 30 return pht('Accepted'); 31 31 } 32 32 33 - public function generateOldValue($object) { 34 - $actor = $this->getActor(); 35 - return $this->isViewerAcceptingAuditor($object, $actor); 36 - } 37 - 38 33 public function applyExternalEffects($object, $value) { 39 34 $status = PhabricatorAuditStatusConstants::ACCEPTED; 40 35 $actor = $this->getActor(); ··· 54 49 } 55 50 } 56 51 57 - if ($this->isViewerAcceptingAuditor($object, $viewer)) { 52 + if ($this->isViewerFullyAccepted($object, $viewer)) { 58 53 throw new Exception( 59 54 pht( 60 55 'You can not accept this commit because you have already '.
+33 -15
src/applications/diffusion/xaction/DiffusionCommitAuditTransaction.php
··· 7 7 return DiffusionCommitEditEngine::ACTIONGROUP_AUDIT; 8 8 } 9 9 10 + public function generateOldValue($object) { 11 + return false; 12 + } 13 + 10 14 protected function isViewerAnyAuditor( 11 15 PhabricatorRepositoryCommit $commit, 12 16 PhabricatorUser $viewer) { ··· 18 22 PhabricatorUser $viewer) { 19 23 20 24 // This omits various inactive states like "Resigned" and "Not Required". 25 + $active = array( 26 + PhabricatorAuditStatusConstants::AUDIT_REQUIRED, 27 + PhabricatorAuditStatusConstants::CONCERNED, 28 + PhabricatorAuditStatusConstants::ACCEPTED, 29 + PhabricatorAuditStatusConstants::AUDIT_REQUESTED, 30 + ); 31 + $active = array_fuse($active); 21 32 22 - return $this->isViewerAuditStatusAmong( 23 - $commit, 24 - $viewer, 25 - array( 26 - PhabricatorAuditStatusConstants::AUDIT_REQUIRED, 27 - PhabricatorAuditStatusConstants::CONCERNED, 28 - PhabricatorAuditStatusConstants::ACCEPTED, 29 - PhabricatorAuditStatusConstants::AUDIT_REQUESTED, 30 - )); 33 + $viewer_status = $this->getViewerAuditStatus($commit, $viewer); 34 + 35 + return isset($active[$viewer_status]); 31 36 } 32 37 33 - protected function isViewerAcceptingAuditor( 38 + protected function isViewerFullyAccepted( 34 39 PhabricatorRepositoryCommit $commit, 35 40 PhabricatorUser $viewer) { 36 - return $this->isViewerAuditStatusAmong( 41 + return $this->isViewerAuditStatusFullyAmong( 37 42 $commit, 38 43 $viewer, 39 44 array( ··· 41 46 )); 42 47 } 43 48 44 - protected function isViewerRejectingAuditor( 49 + protected function isViewerFullyRejected( 45 50 PhabricatorRepositoryCommit $commit, 46 51 PhabricatorUser $viewer) { 47 - return $this->isViewerAuditStatusAmong( 52 + return $this->isViewerAuditStatusFullyAmong( 48 53 $commit, 49 54 $viewer, 50 55 array( ··· 71 76 return null; 72 77 } 73 78 74 - protected function isViewerAuditStatusAmong( 79 + protected function isViewerAuditStatusFullyAmong( 75 80 PhabricatorRepositoryCommit $commit, 76 81 PhabricatorUser $viewer, 77 82 array $status_list) { ··· 82 87 } 83 88 84 89 $status_map = array_fuse($status_list); 85 - return isset($status_map[$status]); 90 + foreach ($commit->getAudits() as $audit) { 91 + if (!$commit->hasAuditAuthority($viewer, $audit)) { 92 + continue; 93 + } 94 + 95 + $status = $audit->getAuditStatus(); 96 + if (isset($status_map[$status])) { 97 + continue; 98 + } 99 + 100 + return false; 101 + } 102 + 103 + return true; 86 104 } 87 105 88 106 protected function applyAuditorEffect(
+16 -8
src/applications/diffusion/xaction/DiffusionCommitConcernTransaction.php
··· 30 30 return pht('Raised Concern'); 31 31 } 32 32 33 - public function generateOldValue($object) { 34 - $actor = $this->getActor(); 35 - return $this->isViewerRejectingAuditor($object, $actor); 33 + public function applyInternalEffects($object, $value) { 34 + // NOTE: We force the commit directly into "Concern Raised" so that we 35 + // override a possible "Needs Verification" state. 36 + $object->setAuditStatus( 37 + PhabricatorAuditCommitStatusConstants::CONCERN_RAISED); 36 38 } 37 39 38 40 public function applyExternalEffects($object, $value) { ··· 50 52 'you did not author.')); 51 53 } 52 54 53 - if ($this->isViewerRejectingAuditor($object, $viewer)) { 54 - throw new Exception( 55 - pht( 56 - 'You can not raise a concern with this commit because you have '. 57 - 'already raised a concern with it.')); 55 + // Even if you've already raised a concern, you can raise again as long 56 + // as the author requsted you verify. 57 + $state_verify = PhabricatorAuditCommitStatusConstants::NEEDS_VERIFICATION; 58 + 59 + if ($this->isViewerFullyRejected($object, $viewer)) { 60 + if ($object->getAuditStatus() != $state_verify) { 61 + throw new Exception( 62 + pht( 63 + 'You can not raise a concern with this commit because you have '. 64 + 'already raised a concern with it.')); 65 + } 58 66 } 59 67 } 60 68
+6
src/applications/diffusion/xaction/DiffusionCommitStateTransaction.php
··· 31 31 return pht('This commit now requires audit.'); 32 32 case PhabricatorAuditCommitStatusConstants::CONCERN_RAISED: 33 33 return pht('This commit now has outstanding concerns.'); 34 + case PhabricatorAuditCommitStatusConstants::NEEDS_VERIFICATION: 35 + return pht('This commit now requires verification by auditors.'); 34 36 case PhabricatorAuditCommitStatusConstants::FULLY_AUDITED: 35 37 return pht('All concerns with this commit have now been addressed.'); 36 38 } ··· 53 55 case PhabricatorAuditCommitStatusConstants::CONCERN_RAISED: 54 56 return pht( 55 57 '%s now has outstanding concerns.', 58 + $this->renderObject()); 59 + case PhabricatorAuditCommitStatusConstants::NEEDS_VERIFICATION: 60 + return pht( 61 + '%s now requires verification by auditors.', 56 62 $this->renderObject()); 57 63 case PhabricatorAuditCommitStatusConstants::FULLY_AUDITED: 58 64 return pht(
+73
src/applications/diffusion/xaction/DiffusionCommitVerifyTransaction.php
··· 1 + <?php 2 + 3 + final class DiffusionCommitVerifyTransaction 4 + extends DiffusionCommitAuditTransaction { 5 + 6 + const TRANSACTIONTYPE = 'diffusion.commit.verify'; 7 + const ACTIONKEY = 'verify'; 8 + 9 + protected function getCommitActionLabel() { 10 + return pht('Request Verification'); 11 + } 12 + 13 + protected function getCommitActionDescription() { 14 + return pht( 15 + 'Auditors will be asked to verify that concerns have been addressed.'); 16 + } 17 + 18 + protected function getCommitActionGroupKey() { 19 + return DiffusionCommitEditEngine::ACTIONGROUP_COMMIT; 20 + } 21 + 22 + public function getIcon() { 23 + return 'fa-refresh'; 24 + } 25 + 26 + public function getColor() { 27 + return 'indigo'; 28 + } 29 + 30 + protected function getCommitActionOrder() { 31 + return 600; 32 + } 33 + 34 + public function getActionName() { 35 + return pht('Requested Verification'); 36 + } 37 + 38 + public function applyInternalEffects($object, $value) { 39 + $object->setAuditStatus( 40 + PhabricatorAuditCommitStatusConstants::NEEDS_VERIFICATION); 41 + } 42 + 43 + protected function validateAction($object, PhabricatorUser $viewer) { 44 + if (!$this->isViewerCommitAuthor($object, $viewer)) { 45 + throw new Exception( 46 + pht( 47 + 'You can not request verification of this commit because you '. 48 + 'are not the author.')); 49 + } 50 + 51 + $status = $object->getAuditStatus(); 52 + if ($status != PhabricatorAuditCommitStatusConstants::CONCERN_RAISED) { 53 + throw new Exception( 54 + pht( 55 + 'You can not request verification of this commit because no '. 56 + 'auditors have raised conerns with it.')); 57 + } 58 + } 59 + 60 + public function getTitle() { 61 + return pht( 62 + '%s requested verification of this commit.', 63 + $this->renderAuthor()); 64 + } 65 + 66 + public function getTitleForFeed() { 67 + return pht( 68 + '%s requested verification of %s.', 69 + $this->renderAuthor(), 70 + $this->renderObject()); 71 + } 72 + 73 + }
+10 -1
src/applications/repository/storage/PhabricatorRepositoryCommit.php
··· 327 327 } 328 328 } 329 329 330 + $current_status = $this->getAuditStatus(); 331 + $status_verify = PhabricatorAuditCommitStatusConstants::NEEDS_VERIFICATION; 332 + 330 333 if ($any_concern) { 331 - $status = PhabricatorAuditCommitStatusConstants::CONCERN_RAISED; 334 + if ($current_status == $status_verify) { 335 + // If the change is in "Needs Verification", we keep it there as 336 + // long as any auditors still have concerns. 337 + $status = $status_verify; 338 + } else { 339 + $status = PhabricatorAuditCommitStatusConstants::CONCERN_RAISED; 340 + } 332 341 } else if ($any_accept) { 333 342 if ($any_need) { 334 343 $status = PhabricatorAuditCommitStatusConstants::PARTIALLY_AUDITED;