diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 22bbb98756..b23f9cbadd 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -577,6 +577,7 @@ phutil_register_library_map(array( 'DiffusionRawDiffQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRawDiffQueryConduitAPIMethod.php', 'DiffusionReadmeView' => 'applications/diffusion/view/DiffusionReadmeView.php', 'DiffusionRefNotFoundException' => 'applications/diffusion/exception/DiffusionRefNotFoundException.php', + 'DiffusionRefTableController' => 'applications/diffusion/controller/DiffusionRefTableController.php', 'DiffusionRefsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRefsQueryConduitAPIMethod.php', 'DiffusionRenameHistoryQuery' => 'applications/diffusion/query/DiffusionRenameHistoryQuery.php', 'DiffusionRepositoryByIDRemarkupRule' => 'applications/diffusion/remarkup/DiffusionRepositoryByIDRemarkupRule.php', @@ -3789,6 +3790,7 @@ phutil_register_library_map(array( 'DiffusionRawDiffQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionReadmeView' => 'DiffusionView', 'DiffusionRefNotFoundException' => 'Exception', + 'DiffusionRefTableController' => 'DiffusionController', 'DiffusionRefsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionRepositoryByIDRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'DiffusionRepositoryController' => 'DiffusionController', diff --git a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php index 92b433a48a..7771b8a03d 100644 --- a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php +++ b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php @@ -76,6 +76,7 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication { 'diff/' => 'DiffusionDiffController', 'tags/(?P.*)' => 'DiffusionTagListController', 'branches/(?P.*)' => 'DiffusionBranchTableController', + 'refs/(?P.*)' => 'DiffusionRefTableController', 'lint/(?P.*)' => 'DiffusionLintController', 'commit/(?P[a-z0-9]+)/branches/' => 'DiffusionCommitBranchesController', diff --git a/src/applications/diffusion/controller/DiffusionRefTableController.php b/src/applications/diffusion/controller/DiffusionRefTableController.php new file mode 100644 index 0000000000..2f113e225b --- /dev/null +++ b/src/applications/diffusion/controller/DiffusionRefTableController.php @@ -0,0 +1,131 @@ +getViewer(); + + $drequest = $this->getDiffusionRequest(); + $repository = $drequest->getRepository(); + + if (!$drequest->supportsBranches()) { + return $this->newDialog() + ->setTitle(pht('No Ref Support')) + ->appendParagraph( + pht( + 'The version control system this repository uses does not '. + 'support named references, so you can not resolve or list '. + 'repository refs in this repository.')) + ->addCancelButton($repository->getURI()); + } + + $ref_name = $drequest->getBranch(); + + $cache_query = id(new DiffusionCachedResolveRefsQuery()) + ->setRepository($repository); + if ($ref_name !== null) { + $cache_query->withRefs(array($ref_name)); + } + $cache_refs = $cache_query->execute(); + + $vcs_refs = DiffusionQuery::callConduitWithDiffusionRequest( + $viewer, + $drequest, + 'diffusion.resolverefs', + array( + 'refs' => array($ref_name), + )); + + $all = array(); + foreach ($cache_refs as $ref => $results) { + foreach ($results as $result) { + $id = $result['type'].'/'.$result['identifier']; + $all[$ref][$id]['cache'] = $result; + } + } + + foreach ($vcs_refs as $ref => $results) { + foreach ($results as $result) { + $id = $result['type'].'/'.$result['identifier']; + $all[$ref][$id]['vcs'] = $result; + } + } + + $rows = array(); + foreach ($all as $ref => $results) { + foreach ($results as $info) { + $cache = idx($info, 'cache', array()); + $vcs = idx($info, 'vcs', array()); + + $type = idx($vcs, 'type'); + if (!$type) { + $type = idx($cache, 'type'); + } + + $identifier = idx($vcs, 'identifier'); + if ($identifier !== null) { + $identifier = DiffusionView::linkCommit( + $repository, + $identifier); + } + + $cache_identifier = idx($cache, 'identifier'); + if ($cache_identifier !== null) { + $cache_identifier = DiffusionView::linkCommit( + $repository, + $cache_identifier); + } + + $alternate = idx($vcs, 'alternate'); + if ($alternate !== null) { + $alternate = DiffusionView::linkCommit( + $repository, + $alternate); + } + + $rows[] = array( + $ref, + $type, + $identifier, + $cache_identifier, + $alternate, + ); + } + } + + $table = id(new AphrontTableView($rows)) + ->setHeaders( + array( + pht('Ref'), + pht('Type'), + pht('Identifier'), + pht('Cached'), + pht('Alternate'), + )); + + $content = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Ref "%s"', $ref_name)) + ->appendChild($table); + + $crumbs = $this->buildCrumbs(array()); + $crumbs->addTextCrumb(pht('Refs')); + + return $this->buildApplicationPage( + array( + $crumbs, + $content, + ), + array( + 'title' => array( + pht('Refs'), + $repository->getMonogram(), + $ref_name, + ), + )); + } + +} diff --git a/src/applications/diffusion/controller/DiffusionRepositoryController.php b/src/applications/diffusion/controller/DiffusionRepositoryController.php index 9b1936ca0e..46707f8430 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryController.php @@ -303,10 +303,40 @@ final class DiffusionRepositoryController extends DiffusionController { $view->setActionList($actions); - return id(new PHUIObjectBoxView()) + $box = id(new PHUIObjectBoxView()) ->setHeader($header) ->addPropertyList($view); + $info = null; + $drequest = $this->getDiffusionRequest(); + if ($drequest->getRefAlternatives()) { + $message = array( + pht( + 'The ref "%s" is ambiguous in this repository.', + $drequest->getBranch()), + ' ', + phutil_tag( + 'a', + array( + 'href' => $drequest->generateURI( + array( + 'action' => 'refs', + )), + ), + pht('View Alternatives')), + ); + + $messages = array($message); + + $info = id(new PHUIInfoView()) + ->setSeverity(PHUIInfoView::SEVERITY_WARNING) + ->setErrors(array($message)); + + $box->setInfoView($info); + } + + + return $box; } private function buildBranchListTable(DiffusionRequest $drequest) { diff --git a/src/applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php b/src/applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php index 7470f9b40a..a187077832 100644 --- a/src/applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php +++ b/src/applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php @@ -45,6 +45,8 @@ final class DiffusionLowLevelResolveRefsQuery private function resolveGitRefs() { $repository = $this->getRepository(); + // TODO: When refs are ambiguous (for example, tags and branches with + // the same name) this will only resolve one of them. $future = $repository->getLocalCommandFuture('cat-file --batch-check'); $future->write(implode("\n", $this->refs)); list($stdout) = $future->resolvex(); diff --git a/src/applications/diffusion/request/DiffusionRequest.php b/src/applications/diffusion/request/DiffusionRequest.php index 3e8b4a8b19..9ffd67ac07 100644 --- a/src/applications/diffusion/request/DiffusionRequest.php +++ b/src/applications/diffusion/request/DiffusionRequest.php @@ -28,6 +28,7 @@ abstract class DiffusionRequest { private $initFromConduit = true; private $user; private $branchObject = false; + private $refAlternatives; abstract public function supportsBranches(); abstract protected function isStableCommit($symbol); @@ -528,6 +529,7 @@ abstract class DiffusionRequest { case 'tags': case 'branches': case 'lint': + case 'refs': $req_callsign = true; break; case 'branch': @@ -559,6 +561,7 @@ abstract class DiffusionRequest { case 'branches': case 'lint': case 'pathtree': + case 'refs': $uri = "/diffusion/{$callsign}{$action}/{$path}{$commit}{$line}"; break; case 'branch': @@ -728,18 +731,41 @@ abstract class DiffusionRequest { $results = $this->resolveRefs(array($ref)); $matches = idx($results, $ref, array()); - if (count($matches) !== 1) { - $message = pht('Ref "%s" is ambiguous or does not exist.', $ref); + if (!$matches) { + $message = pht( + 'Ref "%s" does not exist in this repository.', + $ref); throw id(new DiffusionRefNotFoundException($message)) ->setRef($ref); } - $match = head($matches); + if (count($matches) > 1) { + $match = $this->chooseBestRefMatch($ref, $matches); + } else { + $match = head($matches); + } $this->stableCommit = $match['identifier']; $this->symbolicType = $match['type']; } + public function getRefAlternatives() { + // Make sure we've resolved the reference into a stable commit first. + $this->getStableCommit(); + return $this->refAlternatives; + } + + private function chooseBestRefMatch($ref, array $results) { + // TODO: Do a better job of selecting the best match. + $match = head($results); + + // After choosing the best alternative, save all the alternatives so the + // UI can show them to the user. + $this->refAlternatives = $results; + + return $match; + } + protected function getResolvableBranchName($branch) { return $branch; }