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

Move "close tasks on commit" code out of field specification stuff

Summary: Ref T2222. There's some magic here, just port it forward in a mostly-reasonable way. This could use some refinement eventually.

Test Plan: Pushed commits with "Fixes" and "Ref" language, used `reparse.php` to trigger the new code. Saw expected updates in Maniphest.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T2222

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

+110 -196
-19
src/applications/differential/field/specification/DifferentialFieldSpecification.php
··· 578 578 } 579 579 580 580 581 - /** 582 - * This method allows you to take action when a commit appears in a tracked 583 - * branch (for example, by closing tasks associated with the commit). 584 - * 585 - * @param PhabricatorRepository The repository the commit appeared in. 586 - * @param PhabricatorRepositoryCommit The commit itself. 587 - * @param PhabricatorRepostioryCommitData Commit data. 588 - * @return void 589 - * 590 - * @task commit 591 - */ 592 - public function didParseCommit( 593 - PhabricatorRepository $repo, 594 - PhabricatorRepositoryCommit $commit, 595 - PhabricatorRepositoryCommitData $data) { 596 - return; 597 - } 598 - 599 - 600 581 601 582 /* -( Loading Additional Data )-------------------------------------------- */ 602 583
-158
src/applications/differential/field/specification/DifferentialFreeformFieldSpecification.php
··· 3 3 abstract class DifferentialFreeformFieldSpecification 4 4 extends DifferentialFieldSpecification { 5 5 6 - private function findMentionedTasks($message) { 7 - $maniphest = 'PhabricatorApplicationManiphest'; 8 - if (!PhabricatorApplication::isClassInstalled($maniphest)) { 9 - return array(); 10 - } 11 - 12 - $prefixes = ManiphestTaskStatus::getStatusPrefixMap(); 13 - $suffixes = ManiphestTaskStatus::getStatusSuffixMap(); 14 - 15 - $matches = id(new ManiphestCustomFieldStatusParser()) 16 - ->parseCorpus($message); 17 - 18 - $task_statuses = array(); 19 - foreach ($matches as $match) { 20 - $prefix = phutil_utf8_strtolower($match['prefix']); 21 - $suffix = phutil_utf8_strtolower($match['suffix']); 22 - 23 - $status = idx($suffixes, $suffix); 24 - if (!$status) { 25 - $status = idx($prefixes, $prefix); 26 - } 27 - 28 - foreach ($match['monograms'] as $task_monogram) { 29 - $task_id = (int)trim($task_monogram, 'tT'); 30 - $task_statuses[$task_id] = $status; 31 - } 32 - } 33 - 34 - return $task_statuses; 35 - } 36 - 37 - private function findDependentRevisions($message) { 38 - $matches = id(new DifferentialCustomFieldDependsOnParser()) 39 - ->parseCorpus($message); 40 - 41 - $dependents = array(); 42 - foreach ($matches as $match) { 43 - foreach ($match['monograms'] as $monogram) { 44 - $id = (int)trim($monogram, 'dD'); 45 - $dependents[$id] = $id; 46 - } 47 - } 48 - 49 - return $dependents; 50 - } 51 - 52 - public static function findRevertedCommits($message) { 53 - $matches = id(new DifferentialCustomFieldRevertsParser()) 54 - ->parseCorpus($message); 55 - 56 - $result = array(); 57 - foreach ($matches as $match) { 58 - foreach ($match['monograms'] as $monogram) { 59 - $result[$monogram] = $monogram; 60 - } 61 - } 62 - 63 - return $result; 64 - } 65 - 66 - private function saveFieldEdges( 67 - DifferentialRevision $revision, 68 - $edge_type, 69 - array $add_phids) { 70 - 71 - $revision_phid = $revision->getPHID(); 72 - 73 - $old_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( 74 - $revision_phid, 75 - $edge_type); 76 - 77 - $add_phids = array_diff($add_phids, $old_phids); 78 - if (!$add_phids) { 79 - return; 80 - } 81 - 82 - $edge_editor = id(new PhabricatorEdgeEditor())->setActor($this->getUser()); 83 - foreach ($add_phids as $phid) { 84 - $edge_editor->addEdge($revision_phid, $edge_type, $phid); 85 - } 86 - // NOTE: Deletes only through the fields. 87 - $edge_editor->save(); 88 - } 89 - 90 - public function didParseCommit( 91 - PhabricatorRepository $repository, 92 - PhabricatorRepositoryCommit $commit, 93 - PhabricatorRepositoryCommitData $data) { 94 - 95 - $message = $this->renderValueForCommitMessage($is_edit = false); 96 - 97 - $user = id(new PhabricatorUser())->loadOneWhere( 98 - 'phid = %s', 99 - $data->getCommitDetail('authorPHID')); 100 - if (!$user) { 101 - // TODO: Maybe after grey users, we should find a way to proceed even 102 - // if we don't know who the author is. 103 - return; 104 - } 105 - 106 - $commit_names = self::findRevertedCommits($message); 107 - if ($commit_names) { 108 - $reverts = id(new DiffusionCommitQuery()) 109 - ->setViewer($user) 110 - ->withIdentifiers($commit_names) 111 - ->withDefaultRepository($repository) 112 - ->execute(); 113 - foreach ($reverts as $revert) { 114 - // TODO: Do interesting things here. 115 - } 116 - } 117 - 118 - $tasks_statuses = $this->findMentionedTasks($message); 119 - if (!$tasks_statuses) { 120 - return; 121 - } 122 - 123 - $tasks = id(new ManiphestTaskQuery()) 124 - ->setViewer($user) 125 - ->withIDs(array_keys($tasks_statuses)) 126 - ->execute(); 127 - 128 - foreach ($tasks as $task_id => $task) { 129 - id(new PhabricatorEdgeEditor()) 130 - ->setActor($user) 131 - ->addEdge( 132 - $task->getPHID(), 133 - PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT, 134 - $commit->getPHID()) 135 - ->save(); 136 - 137 - $status = $tasks_statuses[$task_id]; 138 - if (!$status) { 139 - // Text like "Ref T123", don't change the task status. 140 - continue; 141 - } 142 - 143 - if ($task->getStatus() == $status) { 144 - // Task is already in the specified status, so skip updating it. 145 - continue; 146 - } 147 - 148 - $commit_name = $repository->formatCommitName( 149 - $commit->getCommitIdentifier()); 150 - 151 - $call = new ConduitCall( 152 - 'maniphest.update', 153 - array( 154 - 'id' => $task->getID(), 155 - 'status' => $status, 156 - 'comments' => "Closed by commit {$commit_name}.", 157 - )); 158 - 159 - $call->setUser($user); 160 - $call->execute(); 161 - } 162 - } 163 - 164 6 }
+2
src/applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php
··· 243 243 PhabricatorRepositoryCommit $commit, 244 244 PhabricatorRepositoryCommitData $data) { 245 245 246 + // NOTE: This is currently dead code. See T2222. 247 + 246 248 $releeph_requests = $this->loadReleephRequests(); 247 249 248 250 if (!$releeph_requests) {
+108 -19
src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php
··· 85 85 ->needReviewerStatus(true) 86 86 ->needActiveDiffs(true); 87 87 88 - // TODO: Remove this once we swap to new CustomFields. This is only 89 - // required by the old FieldSpecifications, lower on in this worker. 90 - $revision_query->needRelationships(true); 91 - 92 88 $revision = $revision_query->executeOne(); 93 89 94 90 if ($revision) { ··· 200 196 } 201 197 202 198 if ($should_autoclose) { 203 - // TODO: When this is moved to CustomFields, remove the additional 204 - // call above in query construction. 205 - $fields = DifferentialFieldSelector::newSelector() 206 - ->getFieldSpecifications(); 207 - foreach ($fields as $key => $field) { 208 - if (!$field->shouldAppearOnCommitMessage()) { 209 - continue; 210 - } 211 - $field->setUser($user); 212 - $value = idx($field_values, $field->getCommitMessageKey()); 213 - $field->setValueFromParsedCommitMessage($value); 214 - if ($revision) { 215 - $field->setRevision($revision); 216 - } 217 - $field->didParseCommit($repository, $commit, $data); 199 + // TODO: This isn't as general as it could be. 200 + if ($user->getPHID()) { 201 + $this->closeTasks($user, $repository, $commit, $message); 218 202 } 219 203 } 220 204 ··· 416 400 ->withCommit($commit) 417 401 ->withName($user_name) 418 402 ->execute(); 403 + } 404 + 405 + private function closeTasks( 406 + PhabricatorUser $actor, 407 + PhabricatorRepository $repository, 408 + PhabricatorRepositoryCommit $commit, 409 + $message) { 410 + 411 + $maniphest = 'PhabricatorApplicationManiphest'; 412 + if (!PhabricatorApplication::isClassInstalled($maniphest)) { 413 + return; 414 + } 415 + 416 + $prefixes = ManiphestTaskStatus::getStatusPrefixMap(); 417 + $suffixes = ManiphestTaskStatus::getStatusSuffixMap(); 418 + 419 + $matches = id(new ManiphestCustomFieldStatusParser()) 420 + ->parseCorpus($message); 421 + 422 + $task_statuses = array(); 423 + foreach ($matches as $match) { 424 + $prefix = phutil_utf8_strtolower($match['prefix']); 425 + $suffix = phutil_utf8_strtolower($match['suffix']); 426 + 427 + $status = idx($suffixes, $suffix); 428 + if (!$status) { 429 + $status = idx($prefixes, $prefix); 430 + } 431 + 432 + foreach ($match['monograms'] as $task_monogram) { 433 + $task_id = (int)trim($task_monogram, 'tT'); 434 + $task_statuses[$task_id] = $status; 435 + } 436 + } 437 + 438 + if (!$task_statuses) { 439 + return; 440 + } 441 + 442 + $tasks = id(new ManiphestTaskQuery()) 443 + ->setViewer($actor) 444 + ->withIDs(array_keys($task_statuses)) 445 + ->execute(); 446 + 447 + foreach ($tasks as $task_id => $task) { 448 + $xactions = array(); 449 + 450 + // TODO: Swap this for a real edge transaction once the weirdness in 451 + // Maniphest edges is sorted out. Currently, Maniphest reacts to an edge 452 + // edit on this edge. 453 + id(new PhabricatorEdgeEditor()) 454 + ->setActor($actor) 455 + ->addEdge( 456 + $task->getPHID(), 457 + PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT, 458 + $commit->getPHID()) 459 + ->save(); 460 + 461 + /* TODO: Do this instead of the above. 462 + 463 + $xactions[] = id(new ManiphestTransaction()) 464 + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 465 + ->setMetadataValue('edge:type', $edge_task_has_commit) 466 + ->setNewValue( 467 + array( 468 + '+' => array( 469 + $commit->getPHID() => $commit->getPHID(), 470 + ), 471 + )); 472 + */ 473 + 474 + $status = $task_statuses[$task_id]; 475 + if ($status) { 476 + if ($task->getStatus() != $status) { 477 + $xactions[] = id(new ManiphestTransaction()) 478 + ->setTransactionType(ManiphestTransaction::TYPE_STATUS) 479 + ->setNewValue($status); 480 + 481 + $commit_name = $repository->formatCommitName( 482 + $commit->getCommitIdentifier()); 483 + 484 + $status_message = pht( 485 + 'Closed by commit %s.', 486 + $commit_name); 487 + 488 + $xactions[] = id(new ManiphestTransaction()) 489 + ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) 490 + ->attachComment( 491 + id(new ManiphestTransactionComment()) 492 + ->setContent($status_message)); 493 + } 494 + } 495 + 496 + $content_source = PhabricatorContentSource::newForSource( 497 + PhabricatorContentSource::SOURCE_DAEMON, 498 + array()); 499 + 500 + $editor = id(new ManiphestTransactionEditor()) 501 + ->setActor($actor) 502 + ->setContinueOnNoEffect(true) 503 + ->setContinueOnMissingFields(true) 504 + ->setContentSource($content_source); 505 + 506 + $editor->applyTransactions($task, $xactions); 507 + } 419 508 } 420 509 421 510 }