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

Mark reviewers as "commented" when they leave a comment

Summary:
Ref T2222. This requires one new trick:

- When merging edge transactions which both add/update an edge, the Editor gets to control how the edge data is merged.

Specifically, we pick the "strongest" state to keep, so "accept + comment" leaves you with an accept instead of a comment.

Test Plan: Accepted, commented on, and comment + accepted revisions. Added some debugging dumps to verify that the merging was getting hit and working correctly.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T2222

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

+139 -8
+26
src/applications/differential/constants/DifferentialReviewerStatus.php
··· 8 8 const STATUS_REJECTED = 'rejected'; 9 9 const STATUS_COMMENTED = 'commented'; 10 10 11 + /** 12 + * Returns the relative strength of a status, used to pick a winner when a 13 + * transaction group makes several status changes to a particular reviewer. 14 + * 15 + * For example, if you accept a revision and leave a comment, the transactions 16 + * will attempt to update you to both "commented" and "accepted". We want 17 + * "accepted" to win, because it's the stronger of the two. 18 + * 19 + * @param const Reviewer status constant. 20 + * @return int Relative strength (higher is stronger). 21 + */ 22 + public static function getStatusStrength($constant) { 23 + $map = array( 24 + self::STATUS_ADDED => 1, 25 + 26 + self::STATUS_COMMENTED => 2, 27 + 28 + self::STATUS_BLOCKING => 3, 29 + 30 + self::STATUS_ACCEPTED => 4, 31 + self::STATUS_REJECTED => 4, 32 + ); 33 + 34 + return idx($map, $constant, 0); 35 + } 36 + 11 37 }
+65 -7
src/applications/differential/editor/DifferentialTransactionEditor.php
··· 190 190 PhabricatorLiskDAO $object, 191 191 PhabricatorApplicationTransaction $xaction) { 192 192 193 + $actor = $this->getActor(); 194 + $actor_phid = $actor->getPHID(); 195 + $type_edge = PhabricatorTransactions::TYPE_EDGE; 196 + $edge_reviewer = PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER; 197 + 193 198 $results = parent::expandTransaction($object, $xaction); 194 199 switch ($xaction->getTransactionType()) { 195 - // TODO: If the user comments and is a reviewer, we should upgrade their 196 - // edge metadata to STATUS_COMMENTED. 200 + case PhabricatorTransactions::TYPE_COMMENT: 201 + // When a user leaves a comment, upgrade their reviewer status from 202 + // "added" to "commented" if they're also a reviewer. We may further 203 + // upgrade this based on other actions in the transaction group. 204 + 205 + $status_added = DifferentialReviewerStatus::STATUS_ADDED; 206 + $status_commented = DifferentialReviewerStatus::STATUS_COMMENTED; 207 + 208 + $data = array( 209 + 'status' => $status_commented, 210 + ); 211 + 212 + $edits = array(); 213 + foreach ($object->getReviewerStatus() as $reviewer) { 214 + if ($reviewer->getReviewerPHID() == $actor_phid) { 215 + if ($reviewer->getStatus() == $status_added) { 216 + $edits[$actor_phid] = array( 217 + 'data' => $data, 218 + ); 219 + } 220 + } 221 + } 222 + 223 + if ($edits) { 224 + $results[] = id(new DifferentialTransaction()) 225 + ->setTransactionType($type_edge) 226 + ->setMetadataValue('edge:type', $edge_reviewer) 227 + ->setIgnoreOnNoEffect(true) 228 + ->setNewValue(array('+' => $edits)); 229 + } 230 + break; 197 231 198 232 case DifferentialTransaction::TYPE_ACTION: 199 - 200 - $actor = $this->getActor(); 201 - $actor_phid = $actor->getPHID(); 202 - $type_edge = PhabricatorTransactions::TYPE_EDGE; 203 - $edge_reviewer = PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER; 204 233 $action_type = $xaction->getNewValue(); 205 234 206 235 switch ($action_type) { ··· 311 340 312 341 return parent::applyCustomExternalTransaction($object, $xaction); 313 342 } 343 + 344 + protected function mergeEdgeData($type, array $u, array $v) { 345 + $result = parent::mergeEdgeData($type, $u, $v); 346 + 347 + switch ($type) { 348 + case PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER: 349 + // When the same reviewer has their status updated by multiple 350 + // transactions, we want the strongest status to win. An example of 351 + // this is when a user adds a comment and also accepts a revision which 352 + // they are a reviewer on. The comment creates a "commented" status, 353 + // while the accept creates an "accepted" status. Since accept is 354 + // stronger, it should win and persist. 355 + 356 + $u_status = idx($u, 'status'); 357 + $v_status = idx($v, 'status'); 358 + $u_str = DifferentialReviewerStatus::getStatusStrength($u_status); 359 + $v_str = DifferentialReviewerStatus::getStatusStrength($v_status); 360 + if ($u_str > $v_str) { 361 + $result['status'] = $u_status; 362 + } else { 363 + $result['status'] = $v_status; 364 + } 365 + break; 366 + } 367 + 368 + return $result; 369 + } 370 + 371 + 314 372 315 373 protected function applyFinalEffects( 316 374 PhabricatorLiskDAO $object,
+48 -1
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 953 953 954 954 $result = $u->getNewValue(); 955 955 foreach ($v->getNewValue() as $key => $value) { 956 - $result[$key] = array_merge($value, idx($result, $key, array())); 956 + if ($u->getTransactionType() == PhabricatorTransactions::TYPE_EDGE) { 957 + if (empty($result[$key])) { 958 + $result[$key] = $value; 959 + } else { 960 + // We're merging two lists of edge adds, sets, or removes. Merge 961 + // them by merging individual PHIDs within them. 962 + $merged = $result[$key]; 963 + 964 + foreach ($value as $dst => $v_spec) { 965 + if (empty($merged[$dst])) { 966 + $merged[$dst] = $v_spec; 967 + } else { 968 + // Two transactions are trying to perform the same operation on 969 + // the same edge. Normalize the edge data and then merge it. This 970 + // allows transactions to specify how data merges execute in a 971 + // precise way. 972 + 973 + $u_spec = $merged[$dst]; 974 + 975 + if (!is_array($u_spec)) { 976 + $u_spec = array('dst' => $u_spec); 977 + } 978 + if (!is_array($v_spec)) { 979 + $v_spec = array('dst' => $v_spec); 980 + } 981 + 982 + $ux_data = idx($u_spec, 'data', array()); 983 + $vx_data = idx($v_spec, 'data', array()); 984 + 985 + $merged_data = $this->mergeEdgeData( 986 + $u->getMetadataValue('edge:type'), 987 + $ux_data, 988 + $vx_data); 989 + 990 + $u_spec['data'] = $merged_data; 991 + $merged[$dst] = $u_spec; 992 + } 993 + } 994 + 995 + $result[$key] = $merged; 996 + } 997 + } else { 998 + $result[$key] = array_merge($value, idx($result, $key, array())); 999 + } 957 1000 } 958 1001 $u->setNewValue($result); 959 1002 ··· 964 1007 } 965 1008 966 1009 return $u; 1010 + } 1011 + 1012 + protected function mergeEdgeData($type, array $u, array $v) { 1013 + return $v + $u; 967 1014 } 968 1015 969 1016 protected function getPHIDTransactionNewValue(