diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 0446053a30..8475bf720d 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -302,6 +302,7 @@ phutil_register_library_map(array( 'DifferentialUnitTestResult' => 'applications/differential/constants/unittestresult', 'DiffusionBranchInformation' => 'applications/diffusion/data/branch', 'DiffusionBranchQuery' => 'applications/diffusion/query/branch/base', + 'DiffusionBranchTableController' => 'applications/diffusion/controller/branchtable', 'DiffusionBranchTableView' => 'applications/diffusion/view/branchtable', 'DiffusionBrowseController' => 'applications/diffusion/controller/browse', 'DiffusionBrowseFileController' => 'applications/diffusion/controller/file', @@ -1297,6 +1298,7 @@ phutil_register_library_map(array( 'DifferentialTestPlanFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialTitleFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialUnitFieldSpecification' => 'DifferentialFieldSpecification', + 'DiffusionBranchTableController' => 'DiffusionController', 'DiffusionBranchTableView' => 'DiffusionView', 'DiffusionBrowseController' => 'DiffusionController', 'DiffusionBrowseFileController' => 'DiffusionController', diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php index 417d62d265..3a528095a1 100644 --- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php @@ -248,6 +248,7 @@ class AphrontDefaultApplicationConfiguration 'lastmodified/(?P.*)' => 'DiffusionLastModifiedController', 'diff/' => 'DiffusionDiffController', 'tags/(?P.*)' => 'DiffusionTagListController', + 'branches/(?P.*)' => 'DiffusionBranchTableController', ), 'inline/(?P[^/]+)/' => 'DiffusionInlineCommentController', 'services/' => array( diff --git a/src/applications/diffusion/controller/base/DiffusionController.php b/src/applications/diffusion/controller/base/DiffusionController.php index c541806f18..862f3d69f7 100644 --- a/src/applications/diffusion/controller/base/DiffusionController.php +++ b/src/applications/diffusion/controller/base/DiffusionController.php @@ -164,6 +164,7 @@ abstract class DiffusionController extends PhabricatorController { $spec = $spec + array( 'commit' => null, 'tags' => null, + 'branches' => null, 'view' => null, ); @@ -193,16 +194,17 @@ abstract class DiffusionController extends PhabricatorController { $callsign = $repository->getCallsign(); $repository_name = phutil_escape_html($repository->getName()).' Repository'; - if (!$spec['commit'] && !$spec['tags']) { + if (!$spec['commit'] && !$spec['tags'] && !$spec['branches']) { $branch_name = $drequest->getBranch(); if ($branch_name) { $repository_name .= ' ('.phutil_escape_html($branch_name).')'; } } - if (!$spec['view'] && !$spec['commit'] && !$spec['tags']) { - $crumb_list[] = $repository_name; - return $crumb_list; + if (!$spec['view'] && !$spec['commit'] + && !$spec['tags'] && !$spec['branches']) { + $crumb_list[] = $repository_name; + return $crumb_list; } $crumb_list[] = phutil_render_tag( @@ -232,6 +234,11 @@ abstract class DiffusionController extends PhabricatorController { return $crumb_list; } + if ($spec['branches']) { + $crumb_list[] = 'Branches'; + return $crumb_list; + } + if ($spec['commit']) { $crumb_list[] = "r{$callsign}{$raw_commit}"; return $crumb_list; diff --git a/src/applications/diffusion/controller/branchtable/DiffusionBranchTableController.php b/src/applications/diffusion/controller/branchtable/DiffusionBranchTableController.php new file mode 100644 index 0000000000..be9a135dca --- /dev/null +++ b/src/applications/diffusion/controller/branchtable/DiffusionBranchTableController.php @@ -0,0 +1,85 @@ +getDiffusionRequest(); + $request = $this->getRequest(); + $user = $request->getUser(); + + $repository = $drequest->getRepository(); + + $pager = new AphrontPagerView(); + $pager->setURI($request->getRequestURI(), 'offset'); + $pager->setOffset($request->getInt('offset')); + + // TODO: Add support for branches that contain commit + $query = DiffusionBranchQuery::newFromDiffusionRequest($drequest); + $query->setOffset($pager->getOffset()); + // we add 2 here, because of removed HEAD branch + $query->setLimit($pager->getPageSize() + 2); + $branches = $query->loadBranches(); + + $branches = $pager->sliceResults($branches); + + $content = null; + if (!$branches) { + $content = new AphrontErrorView(); + $content->setTitle('No Branches'); + $content->appendChild('This repository has no branches.'); + $content->setSeverity(AphrontErrorView::SEVERITY_NODATA); + } else { + $commits = id(new PhabricatorAuditCommitQuery()) + ->withIdentifiers( + $drequest->getRepository()->getID(), + mpull($branches, 'getHeadCommitIdentifier')) + ->needCommitData(true) + ->execute(); + + $view = id(new DiffusionBranchTableView()) + ->setBranches($branches) + ->setUser($user) + ->setCommits($commits) + ->setDiffusionRequest($drequest); + + $panel = id(new AphrontPanelView()) + ->setHeader('Branches') + ->appendChild($view) + ->appendChild($pager); + + $content = $panel; + } + + return $this->buildStandardPageResponse( + array( + $this->buildCrumbs( + array( + 'branches' => true, + )), + $content, + ), + array( + 'title' => array( + 'Branches', + $repository->getCallsign().' Repository', + ), + )); + } + +} diff --git a/src/applications/diffusion/controller/branchtable/__init__.php b/src/applications/diffusion/controller/branchtable/__init__.php new file mode 100644 index 0000000000..3d369c0f84 --- /dev/null +++ b/src/applications/diffusion/controller/branchtable/__init__.php @@ -0,0 +1,20 @@ +buildTagListTable($drequest); - if ($drequest->getBranch() !== null) { - $branch_query = DiffusionBranchQuery::newFromDiffusionRequest($drequest); - $branches = $branch_query->loadBranches(); - - $commits = id(new PhabricatorAuditCommitQuery()) - ->withIdentifiers( - $drequest->getRepository()->getID(), - mpull($branches, 'getHeadCommitIdentifier')) - ->needCommitData(true) - ->execute(); - - $branch_table = new DiffusionBranchTableView(); - $branch_table->setDiffusionRequest($drequest); - $branch_table->setBranches($branches); - $branch_table->setCommits($commits); - $branch_table->setUser($this->getRequest()->getUser()); - - $branch_panel = new AphrontPanelView(); - $branch_panel->setHeader('Branches'); - $branch_panel->appendChild($branch_table); - - $content[] = $branch_panel; - } + $content[] = $this->buildBranchListTable($drequest); $readme = $browse_query->renderReadme($browse_results); if ($readme) { @@ -171,8 +149,64 @@ final class DiffusionRepositoryController extends DiffusionController { return $panel; } + private function buildBranchListTable(DiffusionRequest $drequest) { + if ($drequest->getBranch() !== null) { + $limit = 15; + + $branch_query = DiffusionBranchQuery::newFromDiffusionRequest($drequest); + // we add 2 here, because of removed HEAD branch + $branch_query->setLimit($limit + 2); + $branches = $branch_query->loadBranches(); + + if (!$branches) { + return null; + } + + $more_branches = (count($branches) > $limit); + $branches = array_slice($branches, 0, $limit); + + $commits = id(new PhabricatorAuditCommitQuery()) + ->withIdentifiers( + $drequest->getRepository()->getID(), + mpull($branches, 'getHeadCommitIdentifier')) + ->needCommitData(true) + ->execute(); + + $table = new DiffusionBranchTableView(); + $table->setDiffusionRequest($drequest); + $table->setBranches($branches); + $table->setCommits($commits); + $table->setUser($this->getRequest()->getUser()); + + $panel = new AphrontPanelView(); + $panel->setHeader('Branches'); + + if ($more_branches) { + $panel->setCaption('Showing the ' . $limit . ' most recent branches.'); + } + + $panel->addButton( + phutil_render_tag( + 'a', + array( + 'href' => $drequest->generateURI( + array( + 'action' => 'branches', + )), + 'class' => 'grey button', + ), + "Show All Branches \xC2\xBB")); + + $panel->appendChild($table); + + return $panel; + } + + return null; + } + private function buildTagListTable(DiffusionRequest $drequest) { - $tag_limit = 25; + $tag_limit = 15; $query = DiffusionTagListQuery::newFromDiffusionRequest($drequest); $query->setLimit($tag_limit + 1); diff --git a/src/applications/diffusion/query/branch/base/DiffusionBranchQuery.php b/src/applications/diffusion/query/branch/base/DiffusionBranchQuery.php index a7b598ecd7..84703d6ce7 100644 --- a/src/applications/diffusion/query/branch/base/DiffusionBranchQuery.php +++ b/src/applications/diffusion/query/branch/base/DiffusionBranchQuery.php @@ -1,7 +1,7 @@ offset = $offset; + return $this; + } + + public function getOffset() { + return $this->offset; + } + + public function setLimit($limit) { + $this->limit = $limit; + return $this; + } + + protected function getLimit() { + return $this->limit; + } final private function __construct() { // diff --git a/src/applications/diffusion/query/branch/git/DiffusionGitBranchQuery.php b/src/applications/diffusion/query/branch/git/DiffusionGitBranchQuery.php index dc58784ebc..34fb8f9e64 100644 --- a/src/applications/diffusion/query/branch/git/DiffusionGitBranchQuery.php +++ b/src/applications/diffusion/query/branch/git/DiffusionGitBranchQuery.php @@ -21,11 +21,13 @@ final class DiffusionGitBranchQuery extends DiffusionBranchQuery { protected function executeQuery() { $drequest = $this->getRequest(); $repository = $drequest->getRepository(); - - $local_path = $repository->getDetail('local-path'); + $count = $this->getOffset() + $this->getLimit(); list($stdout) = $repository->execxLocalCommand( - 'branch -r --verbose --no-abbrev'); + 'for-each-ref %C --sort=-creatordate --format=%s refs/remotes', + $count ? '--count='.(int)$count : null, + '%(refname:short) %(objectname)' + ); $branch_list = self::parseGitRemoteBranchOutput( $stdout, @@ -43,6 +45,11 @@ final class DiffusionGitBranchQuery extends DiffusionBranchQuery { $branches[] = $branch; } + $offset = $this->getOffset(); + if ($offset) { + $branches = array_slice($branches, $offset); + } + return $branches; } @@ -75,22 +82,27 @@ final class DiffusionGitBranchQuery extends DiffusionBranchQuery { foreach ($lines as $line) { $matches = null; if (preg_match('/^ (\S+)\s+-> (\S+)$/', $line, $matches)) { - // This is a line like: - // - // origin/HEAD -> origin/master - // - // ...which we don't currently do anything interesting with, although - // in theory we could use it to automatically choose the default - // branch. - continue; + // This is a line like: + // + // origin/HEAD -> origin/master + // + // ...which we don't currently do anything interesting with, although + // in theory we could use it to automatically choose the default + // branch. + continue; } - if (!preg_match('/^[ *] (\S+)\s+([a-z0-9]{40}) /', $line, $matches)) { + if (!preg_match('/^ *(\S+)\s+([a-z0-9]{40})/', $line, $matches)) { throw new Exception("Failed to parse {$line}!"); } $remote_branch = $matches[1]; $branch_head = $matches[2]; + if (strpos($remote_branch, 'HEAD') !== false) { + // let's assume that no one will call their remote or branch HEAD + continue; + } + if ($only_this_remote) { $matches = null; if (!preg_match('#^([^/]+)/(.*)$#', $remote_branch, $matches)) { diff --git a/src/applications/diffusion/query/branch/git/__tests__/DiffusionGitBranchQueryTestCase.php b/src/applications/diffusion/query/branch/git/__tests__/DiffusionGitBranchQueryTestCase.php index 1111679c5b..8a2f864ff0 100644 --- a/src/applications/diffusion/query/branch/git/__tests__/DiffusionGitBranchQueryTestCase.php +++ b/src/applications/diffusion/query/branch/git/__tests__/DiffusionGitBranchQueryTestCase.php @@ -1,7 +1,7 @@ assertEqual( array( - 'origin/accent-folding' => 'bfaea2e72197506e028c604cd1a294b6e37aa17d', - 'origin/eventordering' => '185a90a3c1b0556015e5f318fb86ccf8f7a6f3e3', - 'origin/master' => '713f1fc54f9cfc830acbf6bbdb46a2883f772896', - 'alternate/stuff' => '4444444444444444444444444444444444444444', + 'origin/accent-folding' => 'bfaea2e72197506e028c604cd1a294b6e37aa17d', + 'origin/eventordering' => '185a90a3c1b0556015e5f318fb86ccf8f7a6f3e3', + 'origin/master' => '713f1fc54f9cfc830acbf6bbdb46a2883f772896', + 'alternate/stuff' => '4444444444444444444444444444444444444444', + 'origin/weekend-refactoring' => '6e947ab0498b82075ca6195ac168385a11326c4b', + 'alternate/release-1.0.0' => '9ddd5d67962dd89fa167f9989954468b6c517b87', ), DiffusionGitBranchQuery::parseGitRemoteBranchOutput($output)); $this->assertEqual( array( - 'accent-folding' => 'bfaea2e72197506e028c604cd1a294b6e37aa17d', - 'eventordering' => '185a90a3c1b0556015e5f318fb86ccf8f7a6f3e3', - 'master' => '713f1fc54f9cfc830acbf6bbdb46a2883f772896', + 'accent-folding' => 'bfaea2e72197506e028c604cd1a294b6e37aa17d', + 'eventordering' => '185a90a3c1b0556015e5f318fb86ccf8f7a6f3e3', + 'master' => '713f1fc54f9cfc830acbf6bbdb46a2883f772896', + 'weekend-refactoring' => '6e947ab0498b82075ca6195ac168385a11326c4b', ), DiffusionGitBranchQuery::parseGitRemoteBranchOutput($output, 'origin')); } diff --git a/src/applications/diffusion/request/base/DiffusionRequest.php b/src/applications/diffusion/request/base/DiffusionRequest.php index 5b418da562..0c41f7c89f 100644 --- a/src/applications/diffusion/request/base/DiffusionRequest.php +++ b/src/applications/diffusion/request/base/DiffusionRequest.php @@ -369,6 +369,7 @@ abstract class DiffusionRequest { case 'change': case 'lastmodified': case 'tags': + case 'branches': $req_callsign = true; break; case 'branch': @@ -402,6 +403,7 @@ abstract class DiffusionRequest { case 'browse': case 'lastmodified': case 'tags': + case 'branches': $uri = "/diffusion/{$callsign}{$action}/{$path}{$commit}{$line}"; break; case 'branch': diff --git a/src/applications/diffusion/view/branchtable/DiffusionBranchTableView.php b/src/applications/diffusion/view/branchtable/DiffusionBranchTableView.php index eb6b0bf97c..61076776fc 100644 --- a/src/applications/diffusion/view/branchtable/DiffusionBranchTableView.php +++ b/src/applications/diffusion/view/branchtable/DiffusionBranchTableView.php @@ -19,6 +19,8 @@ final class DiffusionBranchTableView extends DiffusionView { private $branches; + private $user; + private $commits = array(); public function setBranches(array $branches) { assert_instances_of($branches, 'DiffusionBranchInformation');