diff --git a/resources/sql/autopatches/20170528.maniphestdupes.php b/resources/sql/autopatches/20170528.maniphestdupes.php new file mode 100644 index 0000000000..aea8ae93d2 --- /dev/null +++ b/resources/sql/autopatches/20170528.maniphestdupes.php @@ -0,0 +1,68 @@ +getTransactionType(); + + if ($txn_type == 'mergedinto') { + // dupe handling as implemented in D10427, which creates a specific txn + $add_edges[] = array( + 'src' => $txn->getObjectPHID(), + 'dst' => $txn->getNewValue(), + ); + } else if ($txn_type == 'status' && $txn->getNewValue() == 'duplicate') { + // dupe handling as originally implemented, which just changes the status + // and adds a comment + $src_phid = $txn->getObjectPHID(); + + // get all the comment transactions associated with this task + $viewer = PhabricatorUser::getOmnipotentUser(); + $comment_txns = id(new ManiphestTransactionQuery()) + ->setViewer($viewer) + ->withObjectPHIDs(array($src_phid)) + ->needComments(true) + ->execute(); + + // check each comment, looking for the "Merged Into" message + foreach ($comment_txns as $comment_txn) { + if ($comment_txn->hasComment()) { + $comment = $comment_txn->getComment()->getContent(); + $pattern = '/^\xE2\x9C\x98 Merged into T(\d+)\.$/'; + $matches = array(); + + if (preg_match($pattern, $comment, $matches)) { + $dst_task = id(new ManiphestTaskQuery()) + ->setViewer($viewer) + ->withIDs(array($matches[1])) + ->executeOne(); + + if ($dst_task) { + $dst_phid = $dst_task->getPHID(); + $add_edges[] = array( + 'src' => $src_phid, + 'dst' => $dst_phid, + ); + } + } + } + } + } +} + +if ($add_edges) { + foreach ($add_edges as $edge) { + $src_phid = $edge['src']; + $dst_phid = $edge['dst']; + + $type = ManiphestTaskIsDuplicateOfTaskEdgeType::EDGECONST; + try { + $editor = id(new PhabricatorEdgeEditor()) + ->addEdge($src_phid, $type, $dst_phid) + ->save(); + } catch (PhabricatorEdgeCycleException $ex) { + // Some earlier or later merge made this invalid, just skip it. + } + } +} diff --git a/src/applications/maniphest/controller/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/ManiphestTaskDetailController.php index 92fe703f91..ecfb723f97 100644 --- a/src/applications/maniphest/controller/ManiphestTaskDetailController.php +++ b/src/applications/maniphest/controller/ManiphestTaskDetailController.php @@ -36,6 +36,7 @@ final class ManiphestTaskDetailController extends ManiphestController { ManiphestTaskHasMockEdgeType::EDGECONST, PhabricatorObjectMentionedByObjectEdgeType::EDGECONST, PhabricatorObjectMentionsObjectEdgeType::EDGECONST, + ManiphestTaskHasDuplicateTaskEdgeType::EDGECONST, ); $phid = $task->getPHID(); @@ -159,6 +160,7 @@ final class ManiphestTaskDetailController extends ManiphestController { $related_tabs[] = $this->newMocksTab($task, $query); $related_tabs[] = $this->newMentionsTab($task, $query); + $related_tabs[] = $this->newDuplicatesTab($task, $query); $tab_view = null; @@ -553,6 +555,32 @@ final class ManiphestTaskDetailController extends ManiphestController { ->appendChild($view); } + private function newDuplicatesTab( + ManiphestTask $task, + PhabricatorEdgeQuery $edge_query) { + + $in_type = ManiphestTaskHasDuplicateTaskEdgeType::EDGECONST; + $in_phids = $edge_query->getDestinationPHIDs(array(), array($in_type)); + + $viewer = $this->getViewer(); + $in_handles = $viewer->loadHandles($in_phids); + $in_handles = $this->getCompleteHandles($in_handles); + + $view = new PHUIPropertyListView(); + + if (!count($in_handles)) { + return null; + } + + $view->addProperty( + pht('Duplicates Merged Here'), $in_handles->renderList()); + + return id(new PHUITabView()) + ->setName(pht('Duplicates')) + ->setKey('duplicates') + ->appendChild($view); + } + private function getCompleteHandles(PhabricatorHandleList $handles) { $phids = array();