mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-19 13:22:42 +01:00
Provide an "event" page for push logs, which shows details on all events in a given push
Summary: Ref T4677. This shows a more detailed view of an entire "git push", "hg push", or "svn commit". This is mostly to give push summary emails a reasonable, stable URI to link to for T4677. Test Plan: - Pushed into SVN, Git and Mercurial. - Viewed partial and imported event records. {F134864} Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T4677 Differential Revision: https://secure.phabricator.com/D8616
This commit is contained in:
parent
a5f55d506f
commit
75c47c6ae0
8 changed files with 356 additions and 100 deletions
|
@ -520,6 +520,8 @@ phutil_register_library_map(array(
|
|||
'DiffusionPathQuery' => 'applications/diffusion/query/DiffusionPathQuery.php',
|
||||
'DiffusionPathQueryTestCase' => 'applications/diffusion/query/pathid/__tests__/DiffusionPathQueryTestCase.php',
|
||||
'DiffusionPathValidateController' => 'applications/diffusion/controller/DiffusionPathValidateController.php',
|
||||
'DiffusionPushEventViewController' => 'applications/diffusion/controller/DiffusionPushEventViewController.php',
|
||||
'DiffusionPushLogController' => 'applications/diffusion/controller/DiffusionPushLogController.php',
|
||||
'DiffusionPushLogListController' => 'applications/diffusion/controller/DiffusionPushLogListController.php',
|
||||
'DiffusionQuery' => 'applications/diffusion/query/DiffusionQuery.php',
|
||||
'DiffusionRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionRawDiffQuery.php',
|
||||
|
@ -3070,9 +3072,11 @@ phutil_register_library_map(array(
|
|||
'DiffusionPathCompleteController' => 'DiffusionController',
|
||||
'DiffusionPathQueryTestCase' => 'PhabricatorTestCase',
|
||||
'DiffusionPathValidateController' => 'DiffusionController',
|
||||
'DiffusionPushEventViewController' => 'DiffusionPushLogController',
|
||||
'DiffusionPushLogController' => 'DiffusionController',
|
||||
'DiffusionPushLogListController' =>
|
||||
array(
|
||||
0 => 'DiffusionController',
|
||||
0 => 'DiffusionPushLogController',
|
||||
1 => 'PhabricatorApplicationSearchResultsControllerInterface',
|
||||
),
|
||||
'DiffusionQuery' => 'PhabricatorQuery',
|
||||
|
|
|
@ -47,9 +47,10 @@ final class PhabricatorApplicationDiffusion extends PhabricatorApplication {
|
|||
'new/' => 'DiffusionRepositoryNewController',
|
||||
'(?P<edit>create)/' => 'DiffusionRepositoryCreateController',
|
||||
'(?P<edit>import)/' => 'DiffusionRepositoryCreateController',
|
||||
'pushlog/(?:query/(?P<queryKey>[^/]+)/)?'
|
||||
=> 'DiffusionPushLogListController',
|
||||
|
||||
'pushlog/' => array(
|
||||
'(?:query/(?P<queryKey>[^/]+)/)?' => 'DiffusionPushLogListController',
|
||||
'view/(?P<id>\d+)/' => 'DiffusionPushEventViewController',
|
||||
),
|
||||
'(?P<callsign>[A-Z]+)/' => array(
|
||||
'' => 'DiffusionRepositoryController',
|
||||
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionPushEventViewController
|
||||
extends DiffusionPushLogController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = idx($data, 'id');
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$event = id(new PhabricatorRepositoryPushEventQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($this->id))
|
||||
->needLogs(true)
|
||||
->executeOne();
|
||||
if (!$event) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$repository = $event->getRepository();
|
||||
$title = pht('Push %d', $event->getID());
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(
|
||||
$repository->getName(),
|
||||
$this->getApplicationURI($repository->getCallsign().'/'));
|
||||
$crumbs->addTextCrumb(
|
||||
pht('Push Logs'),
|
||||
$this->getApplicationURI(
|
||||
'pushlog/?repositories='.$repository->getMonogram()));
|
||||
$crumbs->addTextCrumb($title);
|
||||
|
||||
$event_properties = $this->buildPropertyList($event);
|
||||
|
||||
$detail_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText($title)
|
||||
->addPropertyList($event_properties);
|
||||
|
||||
$commits = $this->loadCommits($event);
|
||||
$commits_table = $this->renderCommitsTable($event, $commits);
|
||||
|
||||
$commits_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Pushed Commits'))
|
||||
->appendChild($commits_table);
|
||||
|
||||
$updates_table = $this->renderPushLogTable($event->getLogs());
|
||||
|
||||
$update_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('All Pushed Updates'))
|
||||
->appendChild($updates_table);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$detail_box,
|
||||
$commits_box,
|
||||
$update_box,
|
||||
),
|
||||
array(
|
||||
'title' => $title,
|
||||
'device' => true,
|
||||
));
|
||||
}
|
||||
|
||||
private function buildPropertyList(PhabricatorRepositoryPushEvent $event) {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$this->loadHandles(array($event->getPusherPHID()));
|
||||
|
||||
$view = new PHUIPropertyListView();
|
||||
|
||||
$view->addProperty(
|
||||
pht('Pushed At'),
|
||||
phabricator_datetime($event->getEpoch(), $viewer));
|
||||
|
||||
$view->addProperty(
|
||||
pht('Pushed By'),
|
||||
$this->getHandle($event->getPusherPHID())->renderLink());
|
||||
|
||||
$view->addProperty(
|
||||
pht('Pushed Via'),
|
||||
$event->getRemoteProtocol());
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
private function loadCommits(PhabricatorRepositoryPushEvent $event) {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$identifiers = array();
|
||||
foreach ($event->getLogs() as $log) {
|
||||
if ($log->getRefType() == PhabricatorRepositoryPushLog::REFTYPE_COMMIT) {
|
||||
$identifiers[] = $log->getRefNew();
|
||||
}
|
||||
}
|
||||
|
||||
if (!$identifiers) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// NOTE: Commits may not have been parsed/discovered yet. We need to return
|
||||
// the identifiers no matter what. If possible, we'll also return the
|
||||
// corresponding commits.
|
||||
|
||||
$commits = id(new DiffusionCommitQuery())
|
||||
->setViewer($viewer)
|
||||
->withRepository($event->getRepository())
|
||||
->withIdentifiers($identifiers)
|
||||
->execute();
|
||||
|
||||
$commits = mpull($commits, null, 'getCommitIdentifier');
|
||||
|
||||
$results = array();
|
||||
foreach ($identifiers as $identifier) {
|
||||
$results[$identifier] = idx($commits, $identifier);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
private function renderCommitsTable(
|
||||
PhabricatorRepositoryPushEvent $event,
|
||||
array $commits) {
|
||||
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
$repository = $event->getRepository();
|
||||
|
||||
$rows = array();
|
||||
foreach ($commits as $identifier => $commit) {
|
||||
if ($commit) {
|
||||
$partial_import = PhabricatorRepositoryCommit::IMPORTED_MESSAGE |
|
||||
PhabricatorRepositoryCommit::IMPORTED_CHANGE;
|
||||
if ($commit->isPartiallyImported($partial_import)) {
|
||||
$summary = AphrontTableView::renderSingleDisplayLine(
|
||||
$commit->getSummary());
|
||||
} else {
|
||||
$summary = phutil_tag('em', array(), pht('Importing...'));
|
||||
}
|
||||
} else {
|
||||
$summary = phutil_tag('em', array(), pht('Discovering...'));
|
||||
}
|
||||
|
||||
$commit_name = $repository->formatCommitName($identifier);
|
||||
if ($commit) {
|
||||
$commit_name = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/'.$commit_name,
|
||||
),
|
||||
$commit_name);
|
||||
}
|
||||
|
||||
$rows[] = array(
|
||||
$commit_name,
|
||||
$summary,
|
||||
);
|
||||
}
|
||||
|
||||
$table = id(new AphrontTableView($rows))
|
||||
->setNoDataString(pht("This push didn't push any new commits."))
|
||||
->setHeaders(
|
||||
array(
|
||||
pht('Commit'),
|
||||
pht('Summary'),
|
||||
))
|
||||
->setColumnClasses(
|
||||
array(
|
||||
'n',
|
||||
'wide',
|
||||
));
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
|
||||
abstract class DiffusionPushLogController extends DiffusionController {
|
||||
|
||||
public function renderPushLogTable(array $logs) {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$this->loadHandles(mpull($logs, 'getPusherPHID'));
|
||||
|
||||
// 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 ($logs) {
|
||||
$editable_repos = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($viewer)
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->withPHIDs(mpull($logs, 'getRepositoryPHID'))
|
||||
->execute();
|
||||
$editable_repos = mpull($editable_repos, null, 'getPHID');
|
||||
}
|
||||
|
||||
$rows = array();
|
||||
foreach ($logs as $log) {
|
||||
|
||||
// Reveal this if it's valid and the user can edit the repository.
|
||||
$remote_addr = '-';
|
||||
if (isset($editable_repos[$log->getRepositoryPHID()])) {
|
||||
$remote_long = $log->getPushEvent()->getRemoteAddress();
|
||||
if ($remote_long) {
|
||||
$remote_addr = long2ip($remote_long);
|
||||
}
|
||||
}
|
||||
|
||||
$event_id = $log->getPushEvent()->getID();
|
||||
|
||||
$callsign = $log->getRepository()->getCallsign();
|
||||
$rows[] = array(
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $this->getApplicationURI('pushlog/view/'.$event_id.'/'),
|
||||
),
|
||||
$event_id),
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $this->getApplicationURI($callsign.'/'),
|
||||
),
|
||||
$callsign),
|
||||
$this->getHandle($log->getPusherPHID())->renderLink(),
|
||||
$remote_addr,
|
||||
$log->getPushEvent()->getRemoteProtocol(),
|
||||
$log->getRefType(),
|
||||
$log->getRefName(),
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/r'.$callsign.$log->getRefOld(),
|
||||
),
|
||||
$log->getRefOldShort()),
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/r'.$callsign.$log->getRefNew(),
|
||||
),
|
||||
$log->getRefNewShort()),
|
||||
|
||||
// TODO: Make these human-readable.
|
||||
$log->getChangeFlags(),
|
||||
$log->getPushEvent()->getRejectCode(),
|
||||
phabricator_datetime($log->getEpoch(), $viewer),
|
||||
);
|
||||
}
|
||||
|
||||
$table = id(new AphrontTableView($rows))
|
||||
->setHeaders(
|
||||
array(
|
||||
pht('Push'),
|
||||
pht('Repository'),
|
||||
pht('Pusher'),
|
||||
pht('From'),
|
||||
pht('Via'),
|
||||
pht('Type'),
|
||||
pht('Name'),
|
||||
pht('Old'),
|
||||
pht('New'),
|
||||
pht('Flags'),
|
||||
pht('Code'),
|
||||
pht('Date'),
|
||||
))
|
||||
->setColumnClasses(
|
||||
array(
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'wide',
|
||||
'n',
|
||||
'n',
|
||||
'date',
|
||||
));
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionPushLogListController extends DiffusionController
|
||||
final class DiffusionPushLogListController extends DiffusionPushLogController
|
||||
implements PhabricatorApplicationSearchResultsControllerInterface {
|
||||
|
||||
private $queryKey;
|
||||
|
@ -26,101 +26,8 @@ final class DiffusionPushLogListController extends DiffusionController
|
|||
public function renderResultsList(
|
||||
array $logs,
|
||||
PhabricatorSavedQuery $query) {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$this->loadHandles(mpull($logs, 'getPusherPHID'));
|
||||
|
||||
// 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 ($logs) {
|
||||
$editable_repos = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($viewer)
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->withPHIDs(mpull($logs, 'getRepositoryPHID'))
|
||||
->execute();
|
||||
$editable_repos = mpull($editable_repos, null, 'getPHID');
|
||||
}
|
||||
|
||||
$rows = array();
|
||||
foreach ($logs as $log) {
|
||||
|
||||
// Reveal this if it's valid and the user can edit the repository.
|
||||
$remote_addr = '-';
|
||||
if (isset($editable_repos[$log->getRepositoryPHID()])) {
|
||||
$remote_long = $log->getPushEvent()->getRemoteAddress();
|
||||
if ($remote_long) {
|
||||
$remote_addr = long2ip($remote_long);
|
||||
}
|
||||
}
|
||||
|
||||
$callsign = $log->getRepository()->getCallsign();
|
||||
$rows[] = array(
|
||||
$log->getPushEvent()->getID(),
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $this->getApplicationURI($callsign.'/'),
|
||||
),
|
||||
$callsign),
|
||||
$this->getHandle($log->getPusherPHID())->renderLink(),
|
||||
$remote_addr,
|
||||
$log->getPushEvent()->getRemoteProtocol(),
|
||||
$log->getRefType(),
|
||||
$log->getRefName(),
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/r'.$callsign.$log->getRefOld(),
|
||||
),
|
||||
$log->getRefOldShort()),
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/r'.$callsign.$log->getRefNew(),
|
||||
),
|
||||
$log->getRefNewShort()),
|
||||
|
||||
// TODO: Make these human-readable.
|
||||
$log->getChangeFlags(),
|
||||
$log->getPushEvent()->getRejectCode(),
|
||||
phabricator_datetime($log->getEpoch(), $viewer),
|
||||
);
|
||||
}
|
||||
|
||||
$table = id(new AphrontTableView($rows))
|
||||
->setHeaders(
|
||||
array(
|
||||
pht('Push'),
|
||||
pht('Repository'),
|
||||
pht('Pusher'),
|
||||
pht('From'),
|
||||
pht('Via'),
|
||||
pht('Type'),
|
||||
pht('Name'),
|
||||
pht('Old'),
|
||||
pht('New'),
|
||||
pht('Flags'),
|
||||
pht('Code'),
|
||||
pht('Date'),
|
||||
))
|
||||
->setColumnClasses(
|
||||
array(
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'wide',
|
||||
'n',
|
||||
'n',
|
||||
'date',
|
||||
));
|
||||
$table = $this->renderPushLogTable($logs);
|
||||
|
||||
$box = id(new PHUIBoxView())
|
||||
->addMargin(PHUI::MARGIN_LARGE)
|
||||
|
|
|
@ -7,6 +7,7 @@ final class PhabricatorRepositoryPushEventQuery
|
|||
private $phids;
|
||||
private $repositoryPHIDs;
|
||||
private $pusherPHIDs;
|
||||
private $needLogs;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -28,6 +29,11 @@ final class PhabricatorRepositoryPushEventQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function needLogs($need_logs) {
|
||||
$this->needLogs = $need_logs;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new PhabricatorRepositoryPushEvent();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
@ -63,6 +69,24 @@ final class PhabricatorRepositoryPushEventQuery
|
|||
return $events;
|
||||
}
|
||||
|
||||
public function didFilterPage(array $events) {
|
||||
$phids = mpull($events, 'getPHID');
|
||||
|
||||
if ($this->needLogs) {
|
||||
$logs = id(new PhabricatorRepositoryPushLogQuery())
|
||||
->setParentQuery($this)
|
||||
->setViewer($this->getViewer())
|
||||
->withPushEventPHIDs($phids)
|
||||
->execute();
|
||||
$logs = mgroup($logs, 'getPushEventPHID');
|
||||
foreach ($events as $key => $event) {
|
||||
$event_logs = idx($logs, $event->getPHID(), array());
|
||||
$event->attachLogs($event_logs);
|
||||
}
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
private function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
||||
$where = array();
|
||||
|
|
|
@ -9,6 +9,7 @@ final class PhabricatorRepositoryPushLogQuery
|
|||
private $pusherPHIDs;
|
||||
private $refTypes;
|
||||
private $newRefs;
|
||||
private $pushEventPHIDs;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -40,6 +41,11 @@ final class PhabricatorRepositoryPushLogQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withPushEventPHIDs(array $phids) {
|
||||
$this->pushEventPHIDs = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new PhabricatorRepositoryPushLog();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
@ -57,7 +63,8 @@ final class PhabricatorRepositoryPushLogQuery
|
|||
|
||||
public function willFilterPage(array $logs) {
|
||||
$event_phids = mpull($logs, 'getPushEventPHID');
|
||||
$events = id(new PhabricatorRepositoryPushEventQuery())
|
||||
$events = id(new PhabricatorObjectQuery())
|
||||
->setParentQuery($this)
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs($event_phids)
|
||||
->execute();
|
||||
|
@ -107,6 +114,13 @@ final class PhabricatorRepositoryPushLogQuery
|
|||
$this->pusherPHIDs);
|
||||
}
|
||||
|
||||
if ($this->pushEventPHIDs) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'pushEventPHID in (%Ls)',
|
||||
$this->pushEventPHIDs);
|
||||
}
|
||||
|
||||
if ($this->refTypes) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
|
|
|
@ -17,6 +17,7 @@ final class PhabricatorRepositoryPushEvent
|
|||
protected $rejectDetails;
|
||||
|
||||
private $repository = self::ATTACHABLE;
|
||||
private $logs = self::ATTACHABLE;
|
||||
|
||||
public static function initializeNewEvent(PhabricatorUser $viewer) {
|
||||
return id(new PhabricatorRepositoryPushEvent())
|
||||
|
@ -44,6 +45,15 @@ final class PhabricatorRepositoryPushEvent
|
|||
return $this->assertAttached($this->repository);
|
||||
}
|
||||
|
||||
public function attachLogs(array $logs) {
|
||||
$this->logs = $logs;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLogs() {
|
||||
return $this->assertAttached($this->logs);
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
||||
|
|
Loading…
Reference in a new issue