@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add a basic view for repository pull logs

Summary:
Depends on D18912. Ref T13046. Add a UI to browse the existing pull log table.

The actual log still has some significant flaws, but get the basics working.

Test Plan: {F5391909}

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13046

Differential Revision: https://secure.phabricator.com/D18914

+310 -31
+10 -4
src/__phutil_library_map__.php
··· 764 764 'DiffusionLintCountQuery' => 'applications/diffusion/query/DiffusionLintCountQuery.php', 765 765 'DiffusionLintSaveRunner' => 'applications/diffusion/DiffusionLintSaveRunner.php', 766 766 'DiffusionLocalRepositoryFilter' => 'applications/diffusion/data/DiffusionLocalRepositoryFilter.php', 767 + 'DiffusionLogController' => 'applications/diffusion/controller/DiffusionLogController.php', 767 768 'DiffusionLookSoonConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionLookSoonConduitAPIMethod.php', 768 769 'DiffusionLowLevelCommitFieldsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelCommitFieldsQuery.php', 769 770 'DiffusionLowLevelCommitQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelCommitQuery.php', ··· 831 832 'DiffusionPreCommitRefTypeHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitRefTypeHeraldField.php', 832 833 'DiffusionPreCommitUsesGitLFSHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitUsesGitLFSHeraldField.php', 833 834 'DiffusionPullEventGarbageCollector' => 'applications/diffusion/garbagecollector/DiffusionPullEventGarbageCollector.php', 835 + 'DiffusionPullLogListController' => 'applications/diffusion/controller/DiffusionPullLogListController.php', 836 + 'DiffusionPullLogListView' => 'applications/diffusion/view/DiffusionPullLogListView.php', 837 + 'DiffusionPullLogSearchEngine' => 'applications/diffusion/query/DiffusionPullLogSearchEngine.php', 834 838 'DiffusionPushCapability' => 'applications/diffusion/capability/DiffusionPushCapability.php', 835 839 'DiffusionPushEventViewController' => 'applications/diffusion/controller/DiffusionPushEventViewController.php', 836 - 'DiffusionPushLogController' => 'applications/diffusion/controller/DiffusionPushLogController.php', 837 840 'DiffusionPushLogListController' => 'applications/diffusion/controller/DiffusionPushLogListController.php', 838 841 'DiffusionPushLogListView' => 'applications/diffusion/view/DiffusionPushLogListView.php', 839 842 'DiffusionPythonExternalSymbolsSource' => 'applications/diffusion/symbol/DiffusionPythonExternalSymbolsSource.php', ··· 5864 5867 'DiffusionLintCountQuery' => 'PhabricatorQuery', 5865 5868 'DiffusionLintSaveRunner' => 'Phobject', 5866 5869 'DiffusionLocalRepositoryFilter' => 'Phobject', 5870 + 'DiffusionLogController' => 'DiffusionController', 5867 5871 'DiffusionLookSoonConduitAPIMethod' => 'DiffusionConduitAPIMethod', 5868 5872 'DiffusionLowLevelCommitFieldsQuery' => 'DiffusionLowLevelQuery', 5869 5873 'DiffusionLowLevelCommitQuery' => 'DiffusionLowLevelQuery', ··· 5931 5935 'DiffusionPreCommitRefTypeHeraldField' => 'DiffusionPreCommitRefHeraldField', 5932 5936 'DiffusionPreCommitUsesGitLFSHeraldField' => 'DiffusionPreCommitContentHeraldField', 5933 5937 'DiffusionPullEventGarbageCollector' => 'PhabricatorGarbageCollector', 5938 + 'DiffusionPullLogListController' => 'DiffusionLogController', 5939 + 'DiffusionPullLogListView' => 'AphrontView', 5940 + 'DiffusionPullLogSearchEngine' => 'PhabricatorApplicationSearchEngine', 5934 5941 'DiffusionPushCapability' => 'PhabricatorPolicyCapability', 5935 - 'DiffusionPushEventViewController' => 'DiffusionPushLogController', 5936 - 'DiffusionPushLogController' => 'DiffusionController', 5937 - 'DiffusionPushLogListController' => 'DiffusionPushLogController', 5942 + 'DiffusionPushEventViewController' => 'DiffusionLogController', 5943 + 'DiffusionPushLogListController' => 'DiffusionLogController', 5938 5944 'DiffusionPushLogListView' => 'AphrontView', 5939 5945 'DiffusionPythonExternalSymbolsSource' => 'DiffusionExternalSymbolsSource', 5940 5946 'DiffusionQuery' => 'PhabricatorQuery',
+3
src/applications/diffusion/application/PhabricatorDiffusionApplication.php
··· 124 124 '(?:query/(?P<queryKey>[^/]+)/)?' => 'DiffusionPushLogListController', 125 125 'view/(?P<id>\d+)/' => 'DiffusionPushEventViewController', 126 126 ), 127 + 'pulllog/' => array( 128 + $this->getQueryRoutePattern() => 'DiffusionPullLogListController', 129 + ), 127 130 '(?P<repositoryCallsign>[A-Z]+)' => $repository_routes, 128 131 '(?P<repositoryID>[1-9]\d*)' => $repository_routes, 129 132
+9
src/applications/diffusion/controller/DiffusionLogController.php
··· 1 + <?php 2 + 3 + abstract class DiffusionLogController extends DiffusionController { 4 + 5 + protected function shouldLoadDiffusionRequest() { 6 + return false; 7 + } 8 + 9 + }
+12
src/applications/diffusion/controller/DiffusionPullLogListController.php
··· 1 + <?php 2 + 3 + final class DiffusionPullLogListController 4 + extends DiffusionLogController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + return id(new DiffusionPullLogSearchEngine()) 8 + ->setController($this) 9 + ->buildResponse(); 10 + } 11 + 12 + }
+1 -5
src/applications/diffusion/controller/DiffusionPushEventViewController.php
··· 1 1 <?php 2 2 3 3 final class DiffusionPushEventViewController 4 - extends DiffusionPushLogController { 5 - 6 - public function shouldAllowPublic() { 7 - return true; 8 - } 4 + extends DiffusionLogController { 9 5 10 6 public function handleRequest(AphrontRequest $request) { 11 7 $viewer = $this->getViewer();
-9
src/applications/diffusion/controller/DiffusionPushLogController.php
··· 1 - <?php 2 - 3 - abstract class DiffusionPushLogController extends DiffusionController { 4 - 5 - protected function shouldLoadDiffusionRequest() { 6 - return false; 7 - } 8 - 9 - }
+2 -5
src/applications/diffusion/controller/DiffusionPushLogListController.php
··· 1 1 <?php 2 2 3 - final class DiffusionPushLogListController extends DiffusionPushLogController { 4 - 5 - public function shouldAllowPublic() { 6 - return true; 7 - } 3 + final class DiffusionPushLogListController 4 + extends DiffusionLogController { 8 5 9 6 public function handleRequest(AphrontRequest $request) { 10 7 return id(new PhabricatorRepositoryPushLogSearchEngine())
+10 -1
src/applications/diffusion/controller/DiffusionRepositoryController.php
··· 365 365 366 366 if ($repository->isHosted()) { 367 367 $push_uri = $this->getApplicationURI( 368 - 'pushlog/?repositories='.$repository->getMonogram()); 368 + 'pushlog/?repositories='.$repository->getPHID()); 369 369 370 370 $action_view->addAction( 371 371 id(new PhabricatorActionView()) ··· 373 373 ->setIcon('fa-list-alt') 374 374 ->setHref($push_uri)); 375 375 } 376 + 377 + $pull_uri = $this->getApplicationURI( 378 + 'pulllog/?repositories='.$repository->getPHID()); 379 + 380 + $action_view->addAction( 381 + id(new PhabricatorActionView()) 382 + ->setName(pht('View Pull Logs')) 383 + ->setIcon('fa-list-alt') 384 + ->setHref($pull_uri)); 376 385 377 386 return $action_view; 378 387 }
+85
src/applications/diffusion/query/DiffusionPullLogSearchEngine.php
··· 1 + <?php 2 + 3 + final class DiffusionPullLogSearchEngine 4 + extends PhabricatorApplicationSearchEngine { 5 + 6 + public function getResultTypeDescription() { 7 + return pht('Pull Logs'); 8 + } 9 + 10 + public function getApplicationClassName() { 11 + return 'PhabricatorDiffusionApplication'; 12 + } 13 + 14 + public function newQuery() { 15 + return new PhabricatorRepositoryPullEventQuery(); 16 + } 17 + 18 + protected function buildQueryFromParameters(array $map) { 19 + $query = $this->newQuery(); 20 + 21 + if ($map['repositoryPHIDs']) { 22 + $query->withRepositoryPHIDs($map['repositoryPHIDs']); 23 + } 24 + 25 + if ($map['pullerPHIDs']) { 26 + $query->withPullerPHIDs($map['pullerPHIDs']); 27 + } 28 + 29 + return $query; 30 + } 31 + 32 + protected function buildCustomSearchFields() { 33 + return array( 34 + id(new PhabricatorSearchDatasourceField()) 35 + ->setDatasource(new DiffusionRepositoryDatasource()) 36 + ->setKey('repositoryPHIDs') 37 + ->setAliases(array('repository', 'repositories', 'repositoryPHID')) 38 + ->setLabel(pht('Repositories')) 39 + ->setDescription( 40 + pht('Search for pull logs for specific repositories.')), 41 + id(new PhabricatorUsersSearchField()) 42 + ->setKey('pullerPHIDs') 43 + ->setAliases(array('puller', 'pullers', 'pullerPHID')) 44 + ->setLabel(pht('Pullers')) 45 + ->setDescription( 46 + pht('Search for pull logs by specific users.')), 47 + ); 48 + } 49 + 50 + protected function getURI($path) { 51 + return '/diffusion/pulllog/'.$path; 52 + } 53 + 54 + protected function getBuiltinQueryNames() { 55 + return array( 56 + 'all' => pht('All Pull Logs'), 57 + ); 58 + } 59 + 60 + public function buildSavedQueryFromBuiltin($query_key) { 61 + $query = $this->newSavedQuery(); 62 + $query->setQueryKey($query_key); 63 + 64 + switch ($query_key) { 65 + case 'all': 66 + return $query; 67 + } 68 + 69 + return parent::buildSavedQueryFromBuiltin($query_key); 70 + } 71 + 72 + protected function renderResultList( 73 + array $logs, 74 + PhabricatorSavedQuery $query, 75 + array $handles) { 76 + 77 + $table = id(new DiffusionPullLogListView()) 78 + ->setViewer($this->requireViewer()) 79 + ->setLogs($logs); 80 + 81 + return id(new PhabricatorApplicationSearchResultView()) 82 + ->setTable($table); 83 + } 84 + 85 + }
+115
src/applications/diffusion/view/DiffusionPullLogListView.php
··· 1 + <?php 2 + 3 + final class DiffusionPullLogListView extends AphrontView { 4 + 5 + private $logs; 6 + 7 + public function setLogs(array $logs) { 8 + assert_instances_of($logs, 'PhabricatorRepositoryPullEvent'); 9 + $this->logs = $logs; 10 + return $this; 11 + } 12 + 13 + public function render() { 14 + $events = $this->logs; 15 + $viewer = $this->getViewer(); 16 + 17 + $handle_phids = array(); 18 + foreach ($events as $event) { 19 + if ($event->getPullerPHID()) { 20 + $handle_phids[] = $event->getPullerPHID(); 21 + } 22 + } 23 + $handles = $viewer->loadHandles($handle_phids); 24 + 25 + // Figure out which repositories are editable. We only let you see remote 26 + // IPs if you have edit capability on a repository. 27 + $editable_repos = array(); 28 + if ($events) { 29 + $editable_repos = id(new PhabricatorRepositoryQuery()) 30 + ->setViewer($viewer) 31 + ->requireCapabilities( 32 + array( 33 + PhabricatorPolicyCapability::CAN_VIEW, 34 + PhabricatorPolicyCapability::CAN_EDIT, 35 + )) 36 + ->withPHIDs(mpull($events, 'getRepositoryPHID')) 37 + ->execute(); 38 + $editable_repos = mpull($editable_repos, null, 'getPHID'); 39 + } 40 + 41 + $rows = array(); 42 + $any_host = false; 43 + foreach ($events as $event) { 44 + if ($event->getRepositoryPHID()) { 45 + $repository = $event->getRepository(); 46 + } else { 47 + $repository = null; 48 + } 49 + 50 + // Reveal this if it's valid and the user can edit the repository. For 51 + // invalid requests you currently have to go fishing in the database. 52 + $remote_address = '-'; 53 + if ($repository) { 54 + if (isset($editable_repos[$event->getRepositoryPHID()])) { 55 + $remote_address = $event->getRemoteAddress(); 56 + } 57 + } 58 + 59 + $event_id = $event->getID(); 60 + 61 + $repository_link = null; 62 + if ($repository) { 63 + $repository_link = phutil_tag( 64 + 'a', 65 + array( 66 + 'href' => $repository->getURI(), 67 + ), 68 + $repository->getDisplayName()); 69 + } 70 + 71 + $puller_link = null; 72 + if ($event->getPullerPHID()) { 73 + $puller_link = $viewer->renderHandle($event->getPullerPHID()); 74 + } 75 + 76 + $rows[] = array( 77 + $event_id, 78 + $repository_link, 79 + $puller_link, 80 + $remote_address, 81 + $event->getRemoteProtocolDisplayName(), 82 + $event->newResultIcon(), 83 + $event->getResultCode(), 84 + phabricator_datetime($event->getEpoch(), $viewer), 85 + ); 86 + } 87 + 88 + $table = id(new AphrontTableView($rows)) 89 + ->setHeaders( 90 + array( 91 + pht('Pull'), 92 + pht('Repository'), 93 + pht('Puller'), 94 + pht('From'), 95 + pht('Via'), 96 + null, 97 + pht('Error'), 98 + pht('Date'), 99 + )) 100 + ->setColumnClasses( 101 + array( 102 + 'n', 103 + '', 104 + '', 105 + 'n', 106 + 'wide', 107 + '', 108 + 'n', 109 + 'right', 110 + )); 111 + 112 + return $table; 113 + } 114 + 115 + }
+21 -5
src/applications/repository/query/PhabricatorRepositoryPullEventQuery.php
··· 37 37 } 38 38 39 39 protected function willFilterPage(array $events) { 40 + // If a pull targets an invalid repository or fails before authenticating, 41 + // it may not have an associated repository. 42 + 40 43 $repository_phids = mpull($events, 'getRepositoryPHID'); 41 - $repositories = id(new PhabricatorRepositoryQuery()) 42 - ->setViewer($this->getViewer()) 43 - ->withPHIDs($repository_phids) 44 - ->execute(); 45 - $repositories = mpull($repositories, null, 'getPHID'); 44 + $repository_phids = array_filter($repository_phids); 45 + 46 + if ($repository_phids) { 47 + $repositories = id(new PhabricatorRepositoryQuery()) 48 + ->setViewer($this->getViewer()) 49 + ->withPHIDs($repository_phids) 50 + ->execute(); 51 + $repositories = mpull($repositories, null, 'getPHID'); 52 + } else { 53 + $repositories = array(); 54 + } 46 55 47 56 foreach ($events as $key => $event) { 48 57 $phid = $event->getRepositoryPHID(); 58 + if (!$phid) { 59 + $event->attachRepository(null); 60 + continue; 61 + } 62 + 49 63 if (empty($repositories[$phid])) { 50 64 unset($events[$key]); 65 + $this->didRejectResult($event); 51 66 continue; 52 67 } 68 + 53 69 $event->attachRepository($repositories[$phid]); 54 70 } 55 71
+42 -2
src/applications/repository/storage/PhabricatorRepositoryPullEvent.php
··· 51 51 PhabricatorRepositoryPullEventPHIDType::TYPECONST); 52 52 } 53 53 54 - public function attachRepository(PhabricatorRepository $repository) { 54 + public function attachRepository(PhabricatorRepository $repository = null) { 55 55 $this->repository = $repository; 56 56 return $this; 57 57 } ··· 60 60 return $this->assertAttached($this->repository); 61 61 } 62 62 63 + public function getRemoteProtocolDisplayName() { 64 + $map = array( 65 + 'ssh' => pht('SSH'), 66 + 'http' => pht('HTTP'), 67 + ); 68 + 69 + $protocol = $this->getRemoteProtocol(); 70 + 71 + return idx($map, $protocol, $protocol); 72 + } 73 + 74 + public function newResultIcon() { 75 + $icon = new PHUIIconView(); 76 + $type = $this->getResultType(); 77 + 78 + switch ($type) { 79 + case 'wild': 80 + $icon 81 + ->setIcon('fa-question indigo') 82 + ->setTooltip(pht('Unknown ("%s")', $type)); 83 + break; 84 + case 'pull': 85 + $icon 86 + ->setIcon('fa-download green') 87 + ->setTooltip(pht('Pull')); 88 + break; 89 + } 90 + 91 + return $icon; 92 + } 93 + 94 + 63 95 64 96 /* -( PhabricatorPolicyInterface )----------------------------------------- */ 65 97 ··· 71 103 } 72 104 73 105 public function getPolicy($capability) { 74 - return $this->getRepository()->getPolicy($capability); 106 + if ($this->getRepository()) { 107 + return $this->getRepository()->getPolicy($capability); 108 + } 109 + 110 + return PhabricatorPolicies::POLICY_ADMIN; 75 111 } 76 112 77 113 public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 114 + if (!$this->getRepository()) { 115 + return false; 116 + } 117 + 78 118 return $this->getRepository()->hasAutomaticCapability($capability, $viewer); 79 119 } 80 120