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

Allow auditors to be added and removed from commits in a modern way

Summary: Ref T10978. Ref T7676. Make auditors work more like reviewers, so they can be freely added or removed.

Test Plan:
- Interacted with auditors via "Edit Commit" and API.
- Comment area is still oldschool and doesn't work yet.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10978, T7676

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

+267 -4
+5 -1
src/__phutil_library_map__.php
··· 613 613 'DiffusionCommandEngine' => 'applications/diffusion/protocol/DiffusionCommandEngine.php', 614 614 'DiffusionCommandEngineTestCase' => 'applications/diffusion/protocol/__tests__/DiffusionCommandEngineTestCase.php', 615 615 'DiffusionCommitAffectedFilesHeraldField' => 'applications/diffusion/herald/DiffusionCommitAffectedFilesHeraldField.php', 616 + 'DiffusionCommitAuditorsTransaction' => 'applications/diffusion/xaction/DiffusionCommitAuditorsTransaction.php', 616 617 'DiffusionCommitAuthorHeraldField' => 'applications/diffusion/herald/DiffusionCommitAuthorHeraldField.php', 617 618 'DiffusionCommitAutocloseHeraldField' => 'applications/diffusion/herald/DiffusionCommitAutocloseHeraldField.php', 618 619 'DiffusionCommitBranchesController' => 'applications/diffusion/controller/DiffusionCommitBranchesController.php', ··· 659 660 'DiffusionCommitRevisionReviewersHeraldField' => 'applications/diffusion/herald/DiffusionCommitRevisionReviewersHeraldField.php', 660 661 'DiffusionCommitRevisionSubscribersHeraldField' => 'applications/diffusion/herald/DiffusionCommitRevisionSubscribersHeraldField.php', 661 662 'DiffusionCommitTagsController' => 'applications/diffusion/controller/DiffusionCommitTagsController.php', 663 + 'DiffusionCommitTransactionType' => 'applications/diffusion/xaction/DiffusionCommitTransactionType.php', 662 664 'DiffusionCompareController' => 'applications/diffusion/controller/DiffusionCompareController.php', 663 665 'DiffusionConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionConduitAPIMethod.php', 664 666 'DiffusionController' => 'applications/diffusion/controller/DiffusionController.php', ··· 5312 5314 'DiffusionCommandEngine' => 'Phobject', 5313 5315 'DiffusionCommandEngineTestCase' => 'PhabricatorTestCase', 5314 5316 'DiffusionCommitAffectedFilesHeraldField' => 'DiffusionCommitHeraldField', 5317 + 'DiffusionCommitAuditorsTransaction' => 'DiffusionCommitTransactionType', 5315 5318 'DiffusionCommitAuthorHeraldField' => 'DiffusionCommitHeraldField', 5316 5319 'DiffusionCommitAutocloseHeraldField' => 'DiffusionCommitHeraldField', 5317 5320 'DiffusionCommitBranchesController' => 'DiffusionController', ··· 5358 5361 'DiffusionCommitRevisionReviewersHeraldField' => 'DiffusionCommitHeraldField', 5359 5362 'DiffusionCommitRevisionSubscribersHeraldField' => 'DiffusionCommitHeraldField', 5360 5363 'DiffusionCommitTagsController' => 'DiffusionController', 5364 + 'DiffusionCommitTransactionType' => 'PhabricatorModularTransactionType', 5361 5365 'DiffusionCompareController' => 'DiffusionController', 5362 5366 'DiffusionConduitAPIMethod' => 'ConduitAPIMethod', 5363 5367 'DiffusionController' => 'PhabricatorController', ··· 6761 6765 'PhabricatorAuditPreviewController' => 'PhabricatorAuditController', 6762 6766 'PhabricatorAuditReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 6763 6767 'PhabricatorAuditStatusConstants' => 'Phobject', 6764 - 'PhabricatorAuditTransaction' => 'PhabricatorApplicationTransaction', 6768 + 'PhabricatorAuditTransaction' => 'PhabricatorModularTransaction', 6765 6769 'PhabricatorAuditTransactionComment' => 'PhabricatorApplicationTransactionComment', 6766 6770 'PhabricatorAuditTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 6767 6771 'PhabricatorAuditTransactionView' => 'PhabricatorApplicationTransactionView',
+5 -1
src/applications/audit/storage/PhabricatorAuditTransaction.php
··· 1 1 <?php 2 2 3 3 final class PhabricatorAuditTransaction 4 - extends PhabricatorApplicationTransaction { 4 + extends PhabricatorModularTransaction { 5 5 6 6 const TYPE_COMMIT = 'audit:commit'; 7 7 ··· 18 18 19 19 public function getApplicationName() { 20 20 return 'audit'; 21 + } 22 + 23 + public function getBaseTransactionClass() { 24 + return 'DiffusionCommitTransactionType'; 21 25 } 22 26 23 27 public function getApplicationTransactionType() {
+17 -2
src/applications/diffusion/editor/DiffusionCommitEditEngine.php
··· 35 35 36 36 return id(new PhabricatorRepositoryCommit()) 37 37 ->attachRepository($repository) 38 - ->attachCommitData($data); 38 + ->attachCommitData($data) 39 + ->attachAudits(array()); 39 40 } 40 41 41 42 protected function newObjectQuery() { 42 43 return id(new DiffusionCommitQuery()) 43 - ->needCommitData(true); 44 + ->needCommitData(true) 45 + ->needAuditRequests(true); 44 46 } 45 47 46 48 protected function getObjectCreateTitleText($object) { ··· 76 78 $data = $object->getCommitData(); 77 79 78 80 $fields = array(); 81 + 82 + $fields[] = id(new PhabricatorDatasourceEditField()) 83 + ->setKey('auditors') 84 + ->setLabel(pht('Auditors')) 85 + ->setDatasource(new DiffusionAuditorDatasource()) 86 + ->setUseEdgeTransactions(true) 87 + ->setTransactionType( 88 + DiffusionCommitAuditorsTransaction::TRANSACTIONTYPE) 89 + ->setCommentActionLabel(pht('Change Auditors')) 90 + ->setDescription(pht('Auditors for this commit.')) 91 + ->setConduitDescription(pht('Change the auditors for this commit.')) 92 + ->setConduitTypeDescription(pht('New auditors.')) 93 + ->setValue($object->getAuditorPHIDsForEdit()); 79 94 80 95 $reason = $data->getCommitDetail('autocloseReason', false); 81 96 $reason = PhabricatorRepository::BECAUSE_AUTOCLOSE_FORCED;
+231
src/applications/diffusion/xaction/DiffusionCommitAuditorsTransaction.php
··· 1 + <?php 2 + 3 + final class DiffusionCommitAuditorsTransaction 4 + extends DiffusionCommitTransactionType { 5 + 6 + const TRANSACTIONTYPE = 'diffusion.commit.auditors'; 7 + 8 + public function generateOldValue($object) { 9 + $auditors = $object->getAudits(); 10 + return mpull($auditors, 'getAuditStatus', 'getAuditorPHID'); 11 + } 12 + 13 + public function generateNewValue($object, $value) { 14 + $actor = $this->getActor(); 15 + 16 + $auditors = $this->generateOldValue($object); 17 + $old_auditors = $auditors; 18 + 19 + $request_status = PhabricatorAuditStatusConstants::AUDIT_REQUESTED; 20 + 21 + $rem = idx($value, '-', array()); 22 + foreach ($rem as $phid) { 23 + unset($auditors[$phid]); 24 + } 25 + 26 + $add = idx($value, '+', array()); 27 + $add_map = array(); 28 + foreach ($add as $phid) { 29 + $add_map[$phid] = $request_status; 30 + } 31 + 32 + $set = idx($value, '=', null); 33 + if ($set !== null) { 34 + foreach ($set as $phid) { 35 + $add_map[$phid] = $request_status; 36 + } 37 + 38 + $auditors = array(); 39 + } 40 + 41 + foreach ($add_map as $phid => $new_status) { 42 + $old_status = idx($old_auditors, $phid); 43 + 44 + if ($old_status) { 45 + $auditors[$phid] = $old_status; 46 + continue; 47 + } 48 + 49 + $auditors[$phid] = $new_status; 50 + } 51 + 52 + return $auditors; 53 + } 54 + 55 + public function getTransactionHasEffect($object, $old, $new) { 56 + ksort($old); 57 + ksort($new); 58 + return ($old !== $new); 59 + } 60 + 61 + public function applyExternalEffects($object, $value) { 62 + $src_phid = $object->getPHID(); 63 + 64 + $old = $this->generateOldValue($object); 65 + $new = $value; 66 + 67 + $auditors = $object->getAudits(); 68 + $auditors = mpull($auditors, null, 'getAuditorPHID'); 69 + 70 + $rem = array_diff_key($old, $new); 71 + foreach ($rem as $phid => $status) { 72 + $auditor = idx($auditors, $phid); 73 + if ($auditor) { 74 + $auditor->delete(); 75 + } 76 + } 77 + 78 + foreach ($new as $phid => $status) { 79 + $auditor = idx($auditors, $phid); 80 + if (!$auditor) { 81 + $auditor = id(new PhabricatorRepositoryAuditRequest()) 82 + ->setAuditorPHID($phid) 83 + ->setCommitPHID($object->getPHID()); 84 + } else { 85 + if ($auditor->getAuditStatus() === $status) { 86 + continue; 87 + } 88 + } 89 + 90 + $auditor 91 + ->setAuditStatus($status) 92 + ->save(); 93 + } 94 + } 95 + 96 + public function getTitle() { 97 + $old = $this->getOldValue(); 98 + $new = $this->getNewValue(); 99 + 100 + $rem = array_diff_key($old, $new); 101 + $add = array_diff_key($new, $old); 102 + $rem_phids = array_keys($rem); 103 + $add_phids = array_keys($add); 104 + $total_count = count($rem) + count($add); 105 + 106 + if ($rem && $add) { 107 + return pht( 108 + '%s edited %s auditor(s), removed %s: %s; added %s: %s.', 109 + $this->renderAuthor(), 110 + new PhutilNumber($total_count), 111 + phutil_count($rem_phids), 112 + $this->renderHandleList($rem_phids), 113 + phutil_count($add_phids), 114 + $this->renderHandleList($add_phids)); 115 + } else if ($add) { 116 + return pht( 117 + '%s added %s auditor(s): %s.', 118 + $this->renderAuthor(), 119 + phutil_count($add_phids), 120 + $this->renderHandleList($add_phids)); 121 + } else { 122 + return pht( 123 + '%s removed %s auditor(s): %s.', 124 + $this->renderAuthor(), 125 + phutil_count($rem_phids), 126 + $this->renderHandleList($rem_phids)); 127 + } 128 + } 129 + 130 + public function getTitleForFeed() { 131 + $old = $this->getOldValue(); 132 + $new = $this->getNewValue(); 133 + 134 + $rem = array_diff_key($old, $new); 135 + $add = array_diff_key($new, $old); 136 + $rem_phids = array_keys($rem); 137 + $add_phids = array_keys($add); 138 + $total_count = count($rem) + count($add); 139 + 140 + if ($rem && $add) { 141 + return pht( 142 + '%s edited %s auditor(s) for %s, removed %s: %s; added %s: %s.', 143 + $this->renderAuthor(), 144 + new PhutilNumber($total_count), 145 + $this->renderObject(), 146 + phutil_count($rem_phids), 147 + $this->renderHandleList($rem_phids), 148 + phutil_count($add_phids), 149 + $this->renderHandleList($add_phids)); 150 + } else if ($add) { 151 + return pht( 152 + '%s added %s auditor(s) for %s: %s.', 153 + $this->renderAuthor(), 154 + phutil_count($add_phids), 155 + $this->renderObject(), 156 + $this->renderHandleList($add_phids)); 157 + } else { 158 + return pht( 159 + '%s removed %s auditor(s) for %s: %s.', 160 + $this->renderAuthor(), 161 + phutil_count($rem_phids), 162 + $this->renderObject(), 163 + $this->renderHandleList($rem_phids)); 164 + } 165 + } 166 + 167 + public function validateTransactions($object, array $xactions) { 168 + $actor = $this->getActor(); 169 + $errors = array(); 170 + 171 + if (!$xactions) { 172 + return $errors; 173 + } 174 + 175 + $author_phid = $object->getAuthorPHID(); 176 + $can_author_close_key = 'audit.can-author-close-audit'; 177 + $can_author_close = PhabricatorEnv::getEnvConfig($can_author_close_key); 178 + 179 + $old = $this->generateOldValue($object); 180 + foreach ($xactions as $xaction) { 181 + $new = $this->generateNewValue($object, $xaction->getNewValue()); 182 + 183 + $add = array_diff_key($new, $old); 184 + if (!$add) { 185 + continue; 186 + } 187 + 188 + $objects = id(new PhabricatorObjectQuery()) 189 + ->setViewer($actor) 190 + ->withPHIDs(array_keys($add)) 191 + ->execute(); 192 + $objects = mpull($objects, null, 'getPHID'); 193 + 194 + foreach ($add as $phid => $status) { 195 + if (!isset($objects[$phid])) { 196 + $errors[] = $this->newInvalidError( 197 + pht( 198 + 'Auditor "%s" is not a valid object.', 199 + $phid), 200 + $xaction); 201 + continue; 202 + } 203 + 204 + switch (phid_get_type($phid)) { 205 + case PhabricatorPeopleUserPHIDType::TYPECONST: 206 + case PhabricatorOwnersPackagePHIDType::TYPECONST: 207 + case PhabricatorProjectProjectPHIDType::TYPECONST: 208 + break; 209 + default: 210 + $errors[] = $this->newInvalidError( 211 + pht( 212 + 'Auditor "%s" must be a user, a package, or a project.', 213 + $phid), 214 + $xaction); 215 + continue 2; 216 + } 217 + 218 + $is_self = ($phid === $author_phid); 219 + if ($is_self && !$can_author_close) { 220 + $errors[] = $this->newInvalidError( 221 + pht('The author of a commit can not be an auditor.'), 222 + $xaction); 223 + continue; 224 + } 225 + } 226 + } 227 + 228 + return $errors; 229 + } 230 + 231 + }
+4
src/applications/diffusion/xaction/DiffusionCommitTransactionType.php
··· 1 + <?php 2 + 3 + abstract class DiffusionCommitTransactionType 4 + extends PhabricatorModularTransactionType {}
+5
src/applications/repository/storage/PhabricatorRepositoryCommit.php
··· 203 203 return $authority_audits; 204 204 } 205 205 206 + public function getAuditorPHIDsForEdit() { 207 + $audits = $this->getAudits(); 208 + return mpull($audits, 'getAuditorPHID'); 209 + } 210 + 206 211 public function save() { 207 212 if (!$this->mailKey) { 208 213 $this->mailKey = Filesystem::readRandomCharacters(20);