Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15376239
D15330.id36973.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
15 KB
Referenced Files
None
Subscribers
None
D15330.id36973.diff
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -600,6 +600,7 @@
'DiffusionCommitRevisionReviewersHeraldField' => 'applications/diffusion/herald/DiffusionCommitRevisionReviewersHeraldField.php',
'DiffusionCommitRevisionSubscribersHeraldField' => 'applications/diffusion/herald/DiffusionCommitRevisionSubscribersHeraldField.php',
'DiffusionCommitTagsController' => 'applications/diffusion/controller/DiffusionCommitTagsController.php',
+ 'DiffusionCompareController' => 'applications/diffusion/controller/DiffusionCompareController.php',
'DiffusionConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionConduitAPIMethod.php',
'DiffusionController' => 'applications/diffusion/controller/DiffusionController.php',
'DiffusionCreateCommentConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionCreateCommentConduitAPIMethod.php',
@@ -757,6 +758,7 @@
'DiffusionRequest' => 'applications/diffusion/request/DiffusionRequest.php',
'DiffusionResolveRefsConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionResolveRefsConduitAPIMethod.php',
'DiffusionResolveUserQuery' => 'applications/diffusion/query/DiffusionResolveUserQuery.php',
+ 'DiffusionRevlistConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRevlistConduitAPIMethod.php',
'DiffusionSSHWorkflow' => 'applications/diffusion/ssh/DiffusionSSHWorkflow.php',
'DiffusionSearchQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionSearchQueryConduitAPIMethod.php',
'DiffusionServeController' => 'applications/diffusion/controller/DiffusionServeController.php',
@@ -4675,6 +4677,7 @@
'DiffusionCommitRevisionReviewersHeraldField' => 'DiffusionCommitHeraldField',
'DiffusionCommitRevisionSubscribersHeraldField' => 'DiffusionCommitHeraldField',
'DiffusionCommitTagsController' => 'DiffusionController',
+ 'DiffusionCompareController' => 'DiffusionController',
'DiffusionConduitAPIMethod' => 'ConduitAPIMethod',
'DiffusionController' => 'PhabricatorController',
'DiffusionCreateCommentConduitAPIMethod' => 'DiffusionConduitAPIMethod',
@@ -4832,6 +4835,7 @@
'DiffusionRequest' => 'Phobject',
'DiffusionResolveRefsConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
'DiffusionResolveUserQuery' => 'Phobject',
+ 'DiffusionRevlistConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
'DiffusionSSHWorkflow' => 'PhabricatorSSHWorkflow',
'DiffusionSearchQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
'DiffusionServeController' => 'DiffusionController',
diff --git a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php
--- a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php
+++ b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php
@@ -77,6 +77,7 @@
'browse/(?P<dblob>.*)' => 'DiffusionBrowseController',
'lastmodified/(?P<dblob>.*)' => 'DiffusionLastModifiedController',
'diff/' => 'DiffusionDiffController',
+ 'compare/' => 'DiffusionCompareController',
'tags/(?P<dblob>.*)' => 'DiffusionTagListController',
'branches/(?P<dblob>.*)' => 'DiffusionBranchTableController',
'refs/(?P<dblob>.*)' => 'DiffusionRefTableController',
diff --git a/src/applications/diffusion/conduit/DiffusionRevlistConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionRevlistConduitAPIMethod.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/conduit/DiffusionRevlistConduitAPIMethod.php
@@ -0,0 +1,115 @@
+<?php
+
+final class DiffusionRevlistConduitAPIMethod
+ extends DiffusionQueryConduitAPIMethod {
+
+ private $parents = array();
+ private $cherryPicked = array();
+ private $mergeBase;
+ private $listCount;
+ private $reverseListCount;
+
+ public function getAPIMethodName() {
+ return 'diffusion.revlist';
+ }
+
+ public function getMethodDescription() {
+ return pht('Returns list of commites between two branches.');
+ }
+
+ protected function defineReturnType() {
+ return 'array';
+ }
+
+ protected function defineCustomParamTypes() {
+ return array(
+ 'from' => 'required string',
+ 'onto' => 'required string',
+ 'path' => 'optional string',
+ 'offset' => 'required int',
+ 'limit' => 'required int',
+ );
+ }
+
+ protected function getResult(ConduitAPIRequest $request) {
+ $path_changes = parent::getResult($request);
+
+ return array(
+ 'pathChanges' => mpull($path_changes, 'toDictionary'),
+ 'parents' => $this->parents,
+ 'cherryPicked' => $this->cherryPicked,
+ 'mergeBase' => $this->mergeBase,
+ 'commitsCount' => $this->listCount,
+ 'reversedComparisonSize' => $this->reverseListCount,
+ );
+ }
+
+ protected function getGitResult(ConduitAPIRequest $request) {
+ $drequest = $this->getDiffusionRequest();
+ $repository = $drequest->getRepository();
+ $from = $request->getValue('from');
+ $onto = $request->getValue('onto');
+ $path = $request->getValue('path', '');
+ $offset = $request->getValue('offset');
+ $limit = $request->getValue('limit');
+
+
+ list($stdout) = $repository->execxLocalCommand(
+ 'rev-list '.
+ '--skip=%d '.
+ '-n %d '.
+ '--parents '.
+ '--left-only '.
+ '%s...%s -- %C',
+ $offset,
+ $limit,
+ $from,
+ $onto,
+ // Git omits merge commits if the path is provided, even if it is empty.
+ (strlen($path) ? csprintf('%s', $path) : ''));
+
+ $lines = explode("\n", trim($stdout));
+ $lines = array_filter($lines);
+ if (!$lines) {
+ return array();
+ }
+
+ $hash_list = array();
+ $parent_map = array();
+ $cherry_picked = array();
+ foreach ($lines as $line) {
+ list($hash, $parents) = explode(' ', $line, 2);
+ $hash_list[] = $hash;
+ $parent_map[$hash] = preg_split('/\s+/', $parents);
+ }
+
+ $this->parents = $parent_map;
+ $this->cherryPicked = $cherry_picked;
+
+ list($stdout) = $repository->execxLocalCommand(
+ 'rev-list '.
+ '--count '.
+ '--left-right '.
+ '%s...%s -- %C',
+ $from,
+ $onto,
+ // Git omits merge commits if the path is provided, even if it is empty.
+ (strlen($path) ? csprintf('%s', $path) : ''));
+
+ list($count, $reverse_count) = preg_split('/\s+/', $stdout, 2);
+ $this->listCount = $count;
+ $this->reverseListCount = $reverse_count;
+
+ list($stdout) = $repository->execxLocalCommand(
+ 'merge-base '.
+ '%s %s',
+ $from,
+ $onto);
+
+ $this->mergeBase = $stdout;
+
+ return DiffusionQuery::loadHistoryForCommitIdentifiers(
+ $hash_list,
+ $drequest);
+ }
+}
diff --git a/src/applications/diffusion/controller/DiffusionCompareController.php b/src/applications/diffusion/controller/DiffusionCompareController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/controller/DiffusionCompareController.php
@@ -0,0 +1,251 @@
+<?php
+
+final class DiffusionCompareController extends DiffusionController {
+
+ public function shouldAllowPublic() {
+ return true;
+ }
+
+ public function handleRequest(AphrontRequest $request) {
+ $response = $this->loadDiffusionContext();
+ if ($response) {
+ return $response;
+ }
+
+ $viewer = $this->getViewer();
+ $drequest = $this->getDiffusionRequest();
+ $repository = $drequest->getRepository();
+
+ $content = array();
+
+ $crumbs = $this->buildCrumbs(array('view' => 'compare'));
+
+ $empty_title = null;
+ $error_message = null;
+
+ if ($repository->getVersionControlSystem() !=
+ PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) {
+ $empty_title = pht('Not supported');
+ $error_message = pht(
+ 'This feature is not yet supported for %s repositories.',
+ $repository->getVersionControlSystem());
+ $content[] = id(new PHUIInfoView())
+ ->setTitle($empty_title)
+ ->setSeverity(PHUIInfoView::SEVERITY_WARNING)
+ ->setErrors(array($error_message));
+ }
+
+ $from_ref = $request->getStr('from');
+ $onto_ref = $request->getStr('onto');
+
+ $refs = id(new DiffusionCachedResolveRefsQuery())
+ ->setRepository($repository)
+ ->withRefs(array($from_ref, $onto_ref))
+ ->execute();
+
+
+ if (count($refs) == 2) {
+ $content[] = $this->buildCompareContent($drequest);
+ } else {
+ $content[] = $this->buildCompareForm($request, $refs);
+ }
+
+
+ return $this->newPage()
+ ->setTitle(
+ array(
+ $repository->getName(),
+ $repository->getDisplayName(),
+ ))
+ ->setCrumbs($crumbs)
+ ->appendChild($content);
+ }
+
+ private function buildCompareForm(AphrontRequest $request, array $resolved) {
+ $viewer = $this->getViewer();
+
+ $from_ref = $request->getStr('from');
+ $onto_ref = $request->getStr('onto');
+
+ if (idx($resolved, $from_ref)) {
+ $e_from = null;
+ } else {
+ $e_from = 'Not Found';
+ }
+
+ if (idx($resolved, $onto_ref)) {
+ $e_onto = null;
+ } else {
+ $e_onto = 'Not Found';
+ }
+
+
+ $form = id(new AphrontFormView())
+ ->setUser($viewer)
+ ->setMethod('GET')
+ ->appendControl(
+ id(new AphrontFormTextControl())
+ ->setLabel(pht('From'))
+ ->setName('from')
+ ->setError($e_from)
+ ->setValue($from_ref))
+ ->appendControl(
+ id(new AphrontFormTextControl())
+ ->setLabel(pht('Onto'))
+ ->setName('onto')
+ ->setError($e_onto)
+ ->setValue($onto_ref))
+ ->appendControl(
+ id(new AphrontFormSubmitControl())
+ ->setValue('Compare'));
+
+ return $form;
+ }
+
+ private function buildCompareContent(DiffusionRequest $drequest) {
+ $request = $this->getRequest();
+ $repository = $drequest->getRepository();
+
+ $from_ref = $request->getStr('from');
+ $onto_ref = $request->getStr('onto');
+
+ $content = array();
+
+ try {
+ $revlist = $this->callConduitWithDiffusionRequest(
+ 'diffusion.revlist',
+ array(
+ 'from' => $from_ref,
+ 'onto' => $onto_ref,
+ 'path' => $drequest->getPath(),
+ 'offset' => 0,
+ 'limit' => 100,
+ ));
+ $history = DiffusionPathChange::newFromConduit(
+ $revlist['pathChanges']);
+
+ $history_exception = null;
+ } catch (Exception $ex) {
+ $revlist = null;
+ $history = null;
+ $history_exception = $ex;
+ }
+
+
+ $content[] = $this->buildCompareProperties($drequest, $revlist);
+ $content[] = $this->buildCompareForm(
+ $request,
+ array($from_ref => true, $onto_ref => true));
+
+ $content[] = $this->buildHistoryTable(
+ $revlist,
+ $history,
+ $history_exception);
+
+ return $content;
+ }
+
+ private function buildCompareProperties($drequest, $revlist) {
+ $viewer = $this->getViewer();
+
+ $request = $this->getRequest();
+ $repository = $drequest->getRepository();
+
+ $from_ref = $request->getStr('from');
+ $onto_ref = $request->getStr('onto');
+
+ $reverse_uri = $repository->getPathURI(
+ "compare/?from=${onto_ref}&onto=${from_ref}");
+ $actions = id(new PhabricatorActionListView());
+ $actions->setUser($viewer);
+
+
+ $actions->addAction(id(new PhabricatorActionView())
+ ->setName(pht('Reverse Comparison'))
+ ->setHref($reverse_uri)
+ ->setIcon('fa-list'));
+
+ $view = id(new PHUIPropertyListView())
+ ->setUser($viewer)
+ ->setActionList($actions);
+
+ $readme =
+ 'These are the commits that will be added to **Onto** if you merge '.
+ '**From** onto it.';
+ $readme = new PHUIRemarkupView($viewer, $readme);
+ $view->addTextContent($readme);
+
+ $view->addProperty(pht('From'), $from_ref);
+ $view->addProperty(pht('Onto'), $onto_ref);
+ $view->addProperty(
+ pht('merge-base'),
+ new PHUIRemarkupView($viewer, idx($revlist, 'mergeBase')));
+
+ $compare_text = pht(
+ '%d Commits (Reverse comparison is %d commits)',
+ idx($revlist, 'commitsCount'),
+ idx($revlist, 'reversedComparisonSize'));
+ $view->addProperty(pht('Comparison size'), $compare_text);
+
+ $merge_instructions = "`git checkout ${onto_ref} && git merge ${from_ref}`";
+ $merge_instructions = new PHUIRemarkupView($viewer, $merge_instructions);
+ $view->addProperty(pht('To Merge'), $merge_instructions);
+
+ $header = id(new PHUIHeaderView())
+ ->setUser($viewer)
+ ->setPolicyObject($drequest->getRepository());
+
+ $box = id(new PHUIObjectBoxView())
+ ->setUser($viewer)
+ ->setHeader($header)
+ ->addPropertyList($view);
+ return $box;
+ }
+
+ private function buildHistoryTable(
+ $revlist,
+ $history,
+ $history_exception) {
+
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+ $drequest = $this->getDiffusionRequest();
+ $repository = $drequest->getRepository();
+
+ if ($history_exception) {
+ if ($repository->isImporting()) {
+ return $this->renderStatusMessage(
+ pht('Still Importing...'),
+ pht(
+ 'This repository is still importing. History is not yet '.
+ 'available.'));
+ } else {
+ return $this->renderStatusMessage(
+ pht('Unable to Retrieve History'),
+ $history_exception->getMessage());
+ }
+ }
+
+ $history_table = id(new DiffusionHistoryTableView())
+ ->setUser($viewer)
+ ->setDiffusionRequest($drequest)
+ ->setHistory($history);
+
+ // TODO: Super sketchy?
+ $history_table->loadRevisions();
+
+ if ($revlist) {
+ $history_table->setParents($revlist['parents']);
+ }
+
+ // TODO also expose diff.
+
+ $panel = new PHUIObjectBoxView();
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('Missing Commits'));
+ $panel->setHeader($header);
+ $panel->setTable($history_table);
+
+ return $panel;
+ }
+}
diff --git a/src/applications/diffusion/controller/DiffusionController.php b/src/applications/diffusion/controller/DiffusionController.php
--- a/src/applications/diffusion/controller/DiffusionController.php
+++ b/src/applications/diffusion/controller/DiffusionController.php
@@ -206,6 +206,9 @@
case 'change':
$view_name = pht('Change');
break;
+ case 'compare':
+ $view_name = pht('Compare');
+ break;
}
$crumb = id(new PHUICrumbView())
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryController.php b/src/applications/diffusion/controller/DiffusionRepositoryController.php
--- a/src/applications/diffusion/controller/DiffusionRepositoryController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryController.php
@@ -506,6 +506,12 @@
->setHref($push_uri));
}
+ $view->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Compare Branches'))
+ ->setIcon('fa-usb')
+ ->setHref($repository->getPathURI('compare/')));
+
return $view;
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Mar 14, 2:19 AM (1 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7640971
Default Alt Text
D15330.id36973.diff (15 KB)
Attached To
Mode
D15330: Compare two branches
Attached
Detach File
Event Timeline
Log In to Comment