diff --git a/src/applications/diffusion/controller/commit/DiffusionCommitController.php b/src/applications/diffusion/controller/commit/DiffusionCommitController.php index 414f0494b8..73e8a8d3c0 100644 --- a/src/applications/diffusion/controller/commit/DiffusionCommitController.php +++ b/src/applications/diffusion/controller/commit/DiffusionCommitController.php @@ -270,7 +270,11 @@ final class DiffusionCommitController extends DiffusionController { assert_instances_of($parents, 'PhabricatorRepositoryCommit'); $user = $this->getRequest()->getUser(); - $phids = array(); + $task_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( + $commit->getPHID(), + PhabricatorEdgeConfig::TYPE_COMMIT_HAS_TASK); + + $phids = $task_phids; if ($data->getCommitDetail('authorPHID')) { $phids[] = $data->getCommitDetail('authorPHID'); } @@ -333,6 +337,7 @@ final class DiffusionCommitController extends DiffusionController { $props['Parents'] = implode(' · ', $parent_links); } + $request = $this->getDiffusionRequest(); $contains = DiffusionContainsQuery::newFromDiffusionRequest($request); @@ -345,6 +350,15 @@ final class DiffusionCommitController extends DiffusionController { $props['Branches'] = $branches; } + if ($task_phids) { + $task_list = array(); + foreach ($task_phids as $phid) { + $task_list[] = $handles[$phid]->renderLink(); + } + $task_list = implode('
', $task_list); + $props['Tasks'] = $task_list; + } + return $props; } @@ -634,18 +648,13 @@ final class DiffusionCommitController extends DiffusionController { require_celerity_resource('phabricator-object-selector-css'); require_celerity_resource('javelin-behavior-phabricator-object-selector'); - /* - TODO: Implement this. - $action = new AphrontHeadsupActionView(); $action->setName('Edit Maniphest Tasks'); - $action->setURI('/search/attach/'.$commit->getPHID().'/TASK/'); + $action->setURI('/search/attach/'.$commit->getPHID().'/TASK/edge/'); $action->setWorkflow(true); $action->setClass('attach-maniphest'); $actions[] = $action; - */ - if ($user->getIsAdmin()) { $action = new AphrontHeadsupActionView(); $action->setName('MetaMTA Transcripts'); diff --git a/src/applications/diffusion/controller/commit/__init__.php b/src/applications/diffusion/controller/commit/__init__.php index b90af27377..cfcfa786cb 100644 --- a/src/applications/diffusion/controller/commit/__init__.php +++ b/src/applications/diffusion/controller/commit/__init__.php @@ -36,6 +36,8 @@ phutil_require_module('phabricator', 'applications/phid/handle/data'); phutil_require_module('phabricator', 'applications/repository/constants/repositorytype'); phutil_require_module('phabricator', 'applications/repository/storage/repository'); phutil_require_module('phabricator', 'infrastructure/celerity/api'); +phutil_require_module('phabricator', 'infrastructure/edges/constants/config'); +phutil_require_module('phabricator', 'infrastructure/edges/query/edge'); phutil_require_module('phabricator', 'infrastructure/env'); phutil_require_module('phabricator', 'infrastructure/javelin/api'); phutil_require_module('phabricator', 'storage/queryfx'); diff --git a/src/applications/maniphest/controller/taskdetail/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/taskdetail/ManiphestTaskDetailController.php index 582a80a1c0..ffa02ccbaa 100644 --- a/src/applications/maniphest/controller/taskdetail/ManiphestTaskDetailController.php +++ b/src/applications/maniphest/controller/taskdetail/ManiphestTaskDetailController.php @@ -51,7 +51,11 @@ final class ManiphestTaskDetailController extends ManiphestController { 'taskID = %d ORDER BY id ASC', $task->getID()); - $phids = array(); + $commit_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( + $task->getPHID(), + PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT); + + $phids = array_fill_keys($commit_phids, true); foreach ($transactions as $transaction) { foreach ($transaction->extractPHIDs() as $phid) { $phids[$phid] = true; @@ -168,6 +172,15 @@ final class ManiphestTaskDetailController extends ManiphestController { $dict['Revisions'] = $rev_links; } + if ($commit_phids) { + $commit_links = array(); + foreach ($commit_phids as $phid) { + $commit_links[] = $handles[$phid]->renderLink(); + } + $commit_links = implode('
', $commit_links); + $dict['Commits'] = $commit_links; + } + $file_infos = idx($attached, PhabricatorPHIDConstants::PHID_TYPE_FILE); if ($file_infos) { $file_phids = array_keys($file_infos); diff --git a/src/applications/maniphest/controller/taskdetail/__init__.php b/src/applications/maniphest/controller/taskdetail/__init__.php index 4bd8605259..a2e37fc8bd 100644 --- a/src/applications/maniphest/controller/taskdetail/__init__.php +++ b/src/applications/maniphest/controller/taskdetail/__init__.php @@ -23,6 +23,8 @@ phutil_require_module('phabricator', 'applications/markup/engine'); phutil_require_module('phabricator', 'applications/phid/constants'); phutil_require_module('phabricator', 'applications/phid/handle/data'); phutil_require_module('phabricator', 'infrastructure/celerity/api'); +phutil_require_module('phabricator', 'infrastructure/edges/constants/config'); +phutil_require_module('phabricator', 'infrastructure/edges/query/edge'); phutil_require_module('phabricator', 'infrastructure/env'); phutil_require_module('phabricator', 'infrastructure/javelin/api'); phutil_require_module('phabricator', 'view/form/base'); diff --git a/src/applications/search/controller/attach/PhabricatorSearchAttachController.php b/src/applications/search/controller/attach/PhabricatorSearchAttachController.php index 97ae5a8bb0..9037b40567 100644 --- a/src/applications/search/controller/attach/PhabricatorSearchAttachController.php +++ b/src/applications/search/controller/attach/PhabricatorSearchAttachController.php @@ -29,6 +29,7 @@ final class PhabricatorSearchAttachController const ACTION_ATTACH = 'attach'; const ACTION_MERGE = 'merge'; const ACTION_DEPENDENCIES = 'dependencies'; + const ACTION_EDGE = 'edge'; public function willProcessRequest(array $data) { $this->phid = $data['phid']; @@ -64,6 +65,16 @@ final class PhabricatorSearchAttachController case self::ACTION_MERGE: return $this->performMerge($object, $handle, $phids); + case self::ACTION_EDGE: + $edge_type = $this->getEdgeType($object_type, $attach_type); + + $editor = id(new PhabricatorEdgeEditor()); + foreach ($phids as $phid) { + $editor->addEdge($this->phid, $edge_type, $phid); + } + $editor->save(); + + return id(new AphrontReloadResponse())->setURI($handle->getURI()); case self::ACTION_DEPENDENCIES: case self::ACTION_ATTACH: $two_way = true; @@ -94,6 +105,13 @@ final class PhabricatorSearchAttachController case self::ACTION_DEPENDENCIES: $phids = $object->getAttachedPHIDs($attach_type); break; + case self::ACTION_EDGE: + $edge_type = $this->getEdgeType($object_type, $attach_type); + + $phids = PhabricatorEdgeQuery::loadDestinationPHIDs( + $this->phid, + $edge_type); + break; default: $phids = array(); break; @@ -202,9 +220,14 @@ final class PhabricatorSearchAttachController $noun = 'Tasks'; $selected = 'assigned'; break; + case PhabricatorPHIDConstants::PHID_TYPE_CMIT: + $noun = 'Commits'; + $selected = 'created'; + break; } switch ($this->action) { + case self::ACTION_EDGE: case self::ACTION_ATTACH: $dialog_title = "Manage Attached {$noun}"; $header_text = "Currently Attached {$noun}"; @@ -272,4 +295,24 @@ final class PhabricatorSearchAttachController } } + private function getEdgeType($src_type, $dst_type) { + $t_cmit = PhabricatorPHIDConstants::PHID_TYPE_CMIT; + $t_task = PhabricatorPHIDConstants::PHID_TYPE_TASK; + + $map = array( + $t_cmit => array( + $t_task => PhabricatorEdgeConfig::TYPE_COMMIT_HAS_TASK, + ), + $t_task => array( + $t_cmit => PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT, + ), + ); + + if (empty($map[$src_type][$dst_type])) { + throw new Exception("Unknown edge type!"); + } + + return $map[$src_type][$dst_type]; + } + } diff --git a/src/applications/search/controller/attach/__init__.php b/src/applications/search/controller/attach/__init__.php index 95997943f5..6ebca02a96 100644 --- a/src/applications/search/controller/attach/__init__.php +++ b/src/applications/search/controller/attach/__init__.php @@ -19,6 +19,9 @@ phutil_require_module('phabricator', 'applications/phid/graph'); phutil_require_module('phabricator', 'applications/phid/handle/data'); phutil_require_module('phabricator', 'applications/search/controller/base'); phutil_require_module('phabricator', 'applications/search/editor/attach'); +phutil_require_module('phabricator', 'infrastructure/edges/constants/config'); +phutil_require_module('phabricator', 'infrastructure/edges/editor/edge'); +phutil_require_module('phabricator', 'infrastructure/edges/query/edge'); phutil_require_module('phabricator', 'view/control/objectselector'); phutil_require_module('phutil', 'utils'); diff --git a/src/infrastructure/edges/query/edge/PhabricatorEdgeQuery.php b/src/infrastructure/edges/query/edge/PhabricatorEdgeQuery.php index bef97ebd9a..fdeb8fda8b 100644 --- a/src/infrastructure/edges/query/edge/PhabricatorEdgeQuery.php +++ b/src/infrastructure/edges/query/edge/PhabricatorEdgeQuery.php @@ -92,6 +92,24 @@ final class PhabricatorEdgeQuery extends PhabricatorQuery { /* -( Executing the Query )------------------------------------------------ */ + /** + * Convenience method for loading destination PHIDs with one source and one + * edge type. Equivalent to building a full query, but simplifies a common + * use case. + * + * @param phid Source PHID. + * @param const Edge type. + * @return list List of destination PHIDs. + */ + public static function loadDestinationPHIDs($src_phid, $edge_type) { + $edges = id(new PhabricatorEdgeQuery()) + ->withSourcePHIDs(array($src_phid)) + ->withEdgeTypes(array($edge_type)) + ->execute(); + return array_keys($edges[$src_phid][$edge_type]); + } + + /** * Load specified edges. *