1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-26 16:52:41 +01:00

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
This commit is contained in:
epriestley 2018-01-22 20:09:52 -08:00
parent 2914613444
commit e6a9db56a9
11 changed files with 304 additions and 25 deletions

View file

@ -764,6 +764,7 @@ phutil_register_library_map(array(
'DiffusionLintCountQuery' => 'applications/diffusion/query/DiffusionLintCountQuery.php', 'DiffusionLintCountQuery' => 'applications/diffusion/query/DiffusionLintCountQuery.php',
'DiffusionLintSaveRunner' => 'applications/diffusion/DiffusionLintSaveRunner.php', 'DiffusionLintSaveRunner' => 'applications/diffusion/DiffusionLintSaveRunner.php',
'DiffusionLocalRepositoryFilter' => 'applications/diffusion/data/DiffusionLocalRepositoryFilter.php', 'DiffusionLocalRepositoryFilter' => 'applications/diffusion/data/DiffusionLocalRepositoryFilter.php',
'DiffusionLogController' => 'applications/diffusion/controller/DiffusionLogController.php',
'DiffusionLookSoonConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionLookSoonConduitAPIMethod.php', 'DiffusionLookSoonConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionLookSoonConduitAPIMethod.php',
'DiffusionLowLevelCommitFieldsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelCommitFieldsQuery.php', 'DiffusionLowLevelCommitFieldsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelCommitFieldsQuery.php',
'DiffusionLowLevelCommitQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelCommitQuery.php', 'DiffusionLowLevelCommitQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelCommitQuery.php',
@ -831,9 +832,11 @@ phutil_register_library_map(array(
'DiffusionPreCommitRefTypeHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitRefTypeHeraldField.php', 'DiffusionPreCommitRefTypeHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitRefTypeHeraldField.php',
'DiffusionPreCommitUsesGitLFSHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitUsesGitLFSHeraldField.php', 'DiffusionPreCommitUsesGitLFSHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitUsesGitLFSHeraldField.php',
'DiffusionPullEventGarbageCollector' => 'applications/diffusion/garbagecollector/DiffusionPullEventGarbageCollector.php', 'DiffusionPullEventGarbageCollector' => 'applications/diffusion/garbagecollector/DiffusionPullEventGarbageCollector.php',
'DiffusionPullLogListController' => 'applications/diffusion/controller/DiffusionPullLogListController.php',
'DiffusionPullLogListView' => 'applications/diffusion/view/DiffusionPullLogListView.php',
'DiffusionPullLogSearchEngine' => 'applications/diffusion/query/DiffusionPullLogSearchEngine.php',
'DiffusionPushCapability' => 'applications/diffusion/capability/DiffusionPushCapability.php', 'DiffusionPushCapability' => 'applications/diffusion/capability/DiffusionPushCapability.php',
'DiffusionPushEventViewController' => 'applications/diffusion/controller/DiffusionPushEventViewController.php', 'DiffusionPushEventViewController' => 'applications/diffusion/controller/DiffusionPushEventViewController.php',
'DiffusionPushLogController' => 'applications/diffusion/controller/DiffusionPushLogController.php',
'DiffusionPushLogListController' => 'applications/diffusion/controller/DiffusionPushLogListController.php', 'DiffusionPushLogListController' => 'applications/diffusion/controller/DiffusionPushLogListController.php',
'DiffusionPushLogListView' => 'applications/diffusion/view/DiffusionPushLogListView.php', 'DiffusionPushLogListView' => 'applications/diffusion/view/DiffusionPushLogListView.php',
'DiffusionPythonExternalSymbolsSource' => 'applications/diffusion/symbol/DiffusionPythonExternalSymbolsSource.php', 'DiffusionPythonExternalSymbolsSource' => 'applications/diffusion/symbol/DiffusionPythonExternalSymbolsSource.php',
@ -5864,6 +5867,7 @@ phutil_register_library_map(array(
'DiffusionLintCountQuery' => 'PhabricatorQuery', 'DiffusionLintCountQuery' => 'PhabricatorQuery',
'DiffusionLintSaveRunner' => 'Phobject', 'DiffusionLintSaveRunner' => 'Phobject',
'DiffusionLocalRepositoryFilter' => 'Phobject', 'DiffusionLocalRepositoryFilter' => 'Phobject',
'DiffusionLogController' => 'DiffusionController',
'DiffusionLookSoonConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionLookSoonConduitAPIMethod' => 'DiffusionConduitAPIMethod',
'DiffusionLowLevelCommitFieldsQuery' => 'DiffusionLowLevelQuery', 'DiffusionLowLevelCommitFieldsQuery' => 'DiffusionLowLevelQuery',
'DiffusionLowLevelCommitQuery' => 'DiffusionLowLevelQuery', 'DiffusionLowLevelCommitQuery' => 'DiffusionLowLevelQuery',
@ -5931,10 +5935,12 @@ phutil_register_library_map(array(
'DiffusionPreCommitRefTypeHeraldField' => 'DiffusionPreCommitRefHeraldField', 'DiffusionPreCommitRefTypeHeraldField' => 'DiffusionPreCommitRefHeraldField',
'DiffusionPreCommitUsesGitLFSHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitUsesGitLFSHeraldField' => 'DiffusionPreCommitContentHeraldField',
'DiffusionPullEventGarbageCollector' => 'PhabricatorGarbageCollector', 'DiffusionPullEventGarbageCollector' => 'PhabricatorGarbageCollector',
'DiffusionPullLogListController' => 'DiffusionLogController',
'DiffusionPullLogListView' => 'AphrontView',
'DiffusionPullLogSearchEngine' => 'PhabricatorApplicationSearchEngine',
'DiffusionPushCapability' => 'PhabricatorPolicyCapability', 'DiffusionPushCapability' => 'PhabricatorPolicyCapability',
'DiffusionPushEventViewController' => 'DiffusionPushLogController', 'DiffusionPushEventViewController' => 'DiffusionLogController',
'DiffusionPushLogController' => 'DiffusionController', 'DiffusionPushLogListController' => 'DiffusionLogController',
'DiffusionPushLogListController' => 'DiffusionPushLogController',
'DiffusionPushLogListView' => 'AphrontView', 'DiffusionPushLogListView' => 'AphrontView',
'DiffusionPythonExternalSymbolsSource' => 'DiffusionExternalSymbolsSource', 'DiffusionPythonExternalSymbolsSource' => 'DiffusionExternalSymbolsSource',
'DiffusionQuery' => 'PhabricatorQuery', 'DiffusionQuery' => 'PhabricatorQuery',

View file

@ -124,6 +124,9 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
'(?:query/(?P<queryKey>[^/]+)/)?' => 'DiffusionPushLogListController', '(?:query/(?P<queryKey>[^/]+)/)?' => 'DiffusionPushLogListController',
'view/(?P<id>\d+)/' => 'DiffusionPushEventViewController', 'view/(?P<id>\d+)/' => 'DiffusionPushEventViewController',
), ),
'pulllog/' => array(
$this->getQueryRoutePattern() => 'DiffusionPullLogListController',
),
'(?P<repositoryCallsign>[A-Z]+)' => $repository_routes, '(?P<repositoryCallsign>[A-Z]+)' => $repository_routes,
'(?P<repositoryID>[1-9]\d*)' => $repository_routes, '(?P<repositoryID>[1-9]\d*)' => $repository_routes,

View file

@ -1,6 +1,6 @@
<?php <?php
abstract class DiffusionPushLogController extends DiffusionController { abstract class DiffusionLogController extends DiffusionController {
protected function shouldLoadDiffusionRequest() { protected function shouldLoadDiffusionRequest() {
return false; return false;

View file

@ -0,0 +1,12 @@
<?php
final class DiffusionPullLogListController
extends DiffusionLogController {
public function handleRequest(AphrontRequest $request) {
return id(new DiffusionPullLogSearchEngine())
->setController($this)
->buildResponse();
}
}

View file

@ -1,11 +1,7 @@
<?php <?php
final class DiffusionPushEventViewController final class DiffusionPushEventViewController
extends DiffusionPushLogController { extends DiffusionLogController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) { public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();

View file

@ -1,10 +1,7 @@
<?php <?php
final class DiffusionPushLogListController extends DiffusionPushLogController { final class DiffusionPushLogListController
extends DiffusionLogController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) { public function handleRequest(AphrontRequest $request) {
return id(new PhabricatorRepositoryPushLogSearchEngine()) return id(new PhabricatorRepositoryPushLogSearchEngine())

View file

@ -365,7 +365,7 @@ final class DiffusionRepositoryController extends DiffusionController {
if ($repository->isHosted()) { if ($repository->isHosted()) {
$push_uri = $this->getApplicationURI( $push_uri = $this->getApplicationURI(
'pushlog/?repositories='.$repository->getMonogram()); 'pushlog/?repositories='.$repository->getPHID());
$action_view->addAction( $action_view->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
@ -374,6 +374,15 @@ final class DiffusionRepositoryController extends DiffusionController {
->setHref($push_uri)); ->setHref($push_uri));
} }
$pull_uri = $this->getApplicationURI(
'pulllog/?repositories='.$repository->getPHID());
$action_view->addAction(
id(new PhabricatorActionView())
->setName(pht('View Pull Logs'))
->setIcon('fa-list-alt')
->setHref($pull_uri));
return $action_view; return $action_view;
} }

View file

@ -0,0 +1,85 @@
<?php
final class DiffusionPullLogSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Pull Logs');
}
public function getApplicationClassName() {
return 'PhabricatorDiffusionApplication';
}
public function newQuery() {
return new PhabricatorRepositoryPullEventQuery();
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['repositoryPHIDs']) {
$query->withRepositoryPHIDs($map['repositoryPHIDs']);
}
if ($map['pullerPHIDs']) {
$query->withPullerPHIDs($map['pullerPHIDs']);
}
return $query;
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorSearchDatasourceField())
->setDatasource(new DiffusionRepositoryDatasource())
->setKey('repositoryPHIDs')
->setAliases(array('repository', 'repositories', 'repositoryPHID'))
->setLabel(pht('Repositories'))
->setDescription(
pht('Search for pull logs for specific repositories.')),
id(new PhabricatorUsersSearchField())
->setKey('pullerPHIDs')
->setAliases(array('puller', 'pullers', 'pullerPHID'))
->setLabel(pht('Pullers'))
->setDescription(
pht('Search for pull logs by specific users.')),
);
}
protected function getURI($path) {
return '/diffusion/pulllog/'.$path;
}
protected function getBuiltinQueryNames() {
return array(
'all' => pht('All Pull Logs'),
);
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
return $query;
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function renderResultList(
array $logs,
PhabricatorSavedQuery $query,
array $handles) {
$table = id(new DiffusionPullLogListView())
->setViewer($this->requireViewer())
->setLogs($logs);
return id(new PhabricatorApplicationSearchResultView())
->setTable($table);
}
}

View file

@ -0,0 +1,115 @@
<?php
final class DiffusionPullLogListView extends AphrontView {
private $logs;
public function setLogs(array $logs) {
assert_instances_of($logs, 'PhabricatorRepositoryPullEvent');
$this->logs = $logs;
return $this;
}
public function render() {
$events = $this->logs;
$viewer = $this->getViewer();
$handle_phids = array();
foreach ($events as $event) {
if ($event->getPullerPHID()) {
$handle_phids[] = $event->getPullerPHID();
}
}
$handles = $viewer->loadHandles($handle_phids);
// Figure out which repositories are editable. We only let you see remote
// IPs if you have edit capability on a repository.
$editable_repos = array();
if ($events) {
$editable_repos = id(new PhabricatorRepositoryQuery())
->setViewer($viewer)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->withPHIDs(mpull($events, 'getRepositoryPHID'))
->execute();
$editable_repos = mpull($editable_repos, null, 'getPHID');
}
$rows = array();
$any_host = false;
foreach ($events as $event) {
if ($event->getRepositoryPHID()) {
$repository = $event->getRepository();
} else {
$repository = null;
}
// Reveal this if it's valid and the user can edit the repository. For
// invalid requests you currently have to go fishing in the database.
$remote_address = '-';
if ($repository) {
if (isset($editable_repos[$event->getRepositoryPHID()])) {
$remote_address = $event->getRemoteAddress();
}
}
$event_id = $event->getID();
$repository_link = null;
if ($repository) {
$repository_link = phutil_tag(
'a',
array(
'href' => $repository->getURI(),
),
$repository->getDisplayName());
}
$puller_link = null;
if ($event->getPullerPHID()) {
$puller_link = $viewer->renderHandle($event->getPullerPHID());
}
$rows[] = array(
$event_id,
$repository_link,
$puller_link,
$remote_address,
$event->getRemoteProtocolDisplayName(),
$event->newResultIcon(),
$event->getResultCode(),
phabricator_datetime($event->getEpoch(), $viewer),
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
pht('Pull'),
pht('Repository'),
pht('Puller'),
pht('From'),
pht('Via'),
null,
pht('Error'),
pht('Date'),
))
->setColumnClasses(
array(
'n',
'',
'',
'n',
'wide',
'',
'n',
'right',
));
return $table;
}
}

View file

@ -37,19 +37,35 @@ final class PhabricatorRepositoryPullEventQuery
} }
protected function willFilterPage(array $events) { protected function willFilterPage(array $events) {
// If a pull targets an invalid repository or fails before authenticating,
// it may not have an associated repository.
$repository_phids = mpull($events, 'getRepositoryPHID'); $repository_phids = mpull($events, 'getRepositoryPHID');
$repository_phids = array_filter($repository_phids);
if ($repository_phids) {
$repositories = id(new PhabricatorRepositoryQuery()) $repositories = id(new PhabricatorRepositoryQuery())
->setViewer($this->getViewer()) ->setViewer($this->getViewer())
->withPHIDs($repository_phids) ->withPHIDs($repository_phids)
->execute(); ->execute();
$repositories = mpull($repositories, null, 'getPHID'); $repositories = mpull($repositories, null, 'getPHID');
} else {
$repositories = array();
}
foreach ($events as $key => $event) { foreach ($events as $key => $event) {
$phid = $event->getRepositoryPHID(); $phid = $event->getRepositoryPHID();
if (empty($repositories[$phid])) { if (!$phid) {
unset($events[$key]); $event->attachRepository(null);
continue; continue;
} }
if (empty($repositories[$phid])) {
unset($events[$key]);
$this->didRejectResult($event);
continue;
}
$event->attachRepository($repositories[$phid]); $event->attachRepository($repositories[$phid]);
} }

View file

@ -51,7 +51,7 @@ final class PhabricatorRepositoryPullEvent
PhabricatorRepositoryPullEventPHIDType::TYPECONST); PhabricatorRepositoryPullEventPHIDType::TYPECONST);
} }
public function attachRepository(PhabricatorRepository $repository) { public function attachRepository(PhabricatorRepository $repository = null) {
$this->repository = $repository; $this->repository = $repository;
return $this; return $this;
} }
@ -60,6 +60,38 @@ final class PhabricatorRepositoryPullEvent
return $this->assertAttached($this->repository); return $this->assertAttached($this->repository);
} }
public function getRemoteProtocolDisplayName() {
$map = array(
'ssh' => pht('SSH'),
'http' => pht('HTTP'),
);
$protocol = $this->getRemoteProtocol();
return idx($map, $protocol, $protocol);
}
public function newResultIcon() {
$icon = new PHUIIconView();
$type = $this->getResultType();
switch ($type) {
case 'wild':
$icon
->setIcon('fa-question indigo')
->setTooltip(pht('Unknown ("%s")', $type));
break;
case 'pull':
$icon
->setIcon('fa-download green')
->setTooltip(pht('Pull'));
break;
}
return $icon;
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */ /* -( PhabricatorPolicyInterface )----------------------------------------- */
@ -71,10 +103,18 @@ final class PhabricatorRepositoryPullEvent
} }
public function getPolicy($capability) { public function getPolicy($capability) {
if ($this->getRepository()) {
return $this->getRepository()->getPolicy($capability); return $this->getRepository()->getPolicy($capability);
} }
return PhabricatorPolicies::POLICY_ADMIN;
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
if (!$this->getRepository()) {
return false;
}
return $this->getRepository()->hasAutomaticCapability($capability, $viewer); return $this->getRepository()->hasAutomaticCapability($capability, $viewer);
} }