1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-18 12:52:42 +01:00

Provide a basic search engine for builds

Summary:
This supports a few basic use cases that aren't served by the buildable search engine:

 - I'm trying to discover when the last time that this particular build plan failed was.
 - I want to know if any builds have deadlocked.
 - At a glance, I'm more interested in what build plans are running, not which buildables are being built. This is more often than not the case.

Test Plan: {F1744003}

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: Korvin, epriestley

Differential Revision: https://secure.phabricator.com/D16347
This commit is contained in:
Mike Riley 2016-07-31 13:35:31 +00:00 committed by yelirekim
parent bbc2ae7858
commit 2c55a4ad72
7 changed files with 218 additions and 22 deletions

View file

@ -1107,6 +1107,7 @@ phutil_register_library_map(array(
'HarbormasterBuildFailureException' => 'applications/harbormaster/exception/HarbormasterBuildFailureException.php',
'HarbormasterBuildGraph' => 'applications/harbormaster/engine/HarbormasterBuildGraph.php',
'HarbormasterBuildLintMessage' => 'applications/harbormaster/storage/build/HarbormasterBuildLintMessage.php',
'HarbormasterBuildListController' => 'applications/harbormaster/controller/HarbormasterBuildListController.php',
'HarbormasterBuildLog' => 'applications/harbormaster/storage/build/HarbormasterBuildLog.php',
'HarbormasterBuildLogChunk' => 'applications/harbormaster/storage/build/HarbormasterBuildLogChunk.php',
'HarbormasterBuildLogChunkIterator' => 'applications/harbormaster/storage/build/HarbormasterBuildLogChunkIterator.php',
@ -1129,6 +1130,8 @@ phutil_register_library_map(array(
'HarbormasterBuildPlanTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildPlanTransactionQuery.php',
'HarbormasterBuildQuery' => 'applications/harbormaster/query/HarbormasterBuildQuery.php',
'HarbormasterBuildRequest' => 'applications/harbormaster/engine/HarbormasterBuildRequest.php',
'HarbormasterBuildSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildSearchEngine.php',
'HarbormasterBuildStatusDatasource' => 'applications/harbormaster/typeahead/HarbormasterBuildStatusDatasource.php',
'HarbormasterBuildStep' => 'applications/harbormaster/storage/configuration/HarbormasterBuildStep.php',
'HarbormasterBuildStepCoreCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCoreCustomField.php',
'HarbormasterBuildStepCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCustomField.php',
@ -5647,6 +5650,7 @@ phutil_register_library_map(array(
'HarbormasterBuildFailureException' => 'Exception',
'HarbormasterBuildGraph' => 'AbstractDirectedGraph',
'HarbormasterBuildLintMessage' => 'HarbormasterDAO',
'HarbormasterBuildListController' => 'HarbormasterController',
'HarbormasterBuildLog' => array(
'HarbormasterDAO',
'PhabricatorPolicyInterface',
@ -5682,6 +5686,8 @@ phutil_register_library_map(array(
'HarbormasterBuildPlanTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'HarbormasterBuildQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'HarbormasterBuildRequest' => 'Phobject',
'HarbormasterBuildSearchEngine' => 'PhabricatorApplicationSearchEngine',
'HarbormasterBuildStatusDatasource' => 'PhabricatorTypeaheadDatasource',
'HarbormasterBuildStep' => array(
'HarbormasterDAO',
'PhabricatorApplicationTransactionInterface',

View file

@ -70,6 +70,7 @@ final class PhabricatorHarbormasterApplication extends PhabricatorApplication {
=> 'HarbormasterBuildableActionController',
),
'build/' => array(
$this->getQueryRoutePattern() => 'HarbormasterBuildListController',
'(?P<id>\d+)/' => 'HarbormasterBuildViewController',
'(?P<action>pause|resume|restart|abort)/'.
'(?P<id>\d+)/(?:(?P<via>[^/]+)/)?'

View file

@ -0,0 +1,15 @@
<?php
final class HarbormasterBuildListController extends HarbormasterController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
return id(new HarbormasterBuildSearchEngine())
->setController($this)
->buildResponse();
}
}

View file

@ -9,6 +9,15 @@ final class HarbormasterBuildableListController extends HarbormasterController {
public function handleRequest(AphrontRequest $request) {
$items = array();
$items[] = id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_LABEL)
->setName(pht('Builds'));
$items[] = id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_LINK)
->setName(pht('Browse Builds'))
->setHref($this->getApplicationURI('build/'));
$items[] = id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_LABEL)
->setName(pht('Build Plans'));

View file

@ -0,0 +1,126 @@
<?php
final class HarbormasterBuildSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Harbormaster Builds');
}
public function getApplicationClassName() {
return 'PhabricatorHarbormasterApplication';
}
public function newQuery() {
return new HarbormasterBuildQuery();
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Build Plans'))
->setKey('plans')
->setAliases(array('plan'))
->setDescription(
pht('Search for builds running a given build plan.'))
->setDatasource(new HarbormasterBuildPlanDatasource()),
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Statuses'))
->setKey('statuses')
->setAliases(array('status'))
->setDescription(
pht('Search for builds with given statuses.'))
->setDatasource(new HarbormasterBuildStatusDatasource()),
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['plans']) {
$query->withBuildPlanPHIDs($map['plans']);
}
if ($map['statuses']) {
$query->withBuildStatuses($map['statuses']);
}
return $query;
}
protected function getURI($path) {
return '/harbormaster/build/'.$path;
}
protected function getBuiltinQueryNames() {
return array(
'all' => pht('All Builds'),
);
}
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 $builds,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($builds, 'HarbormasterBuild');
$viewer = $this->requireViewer();
$buildables = mpull($builds, 'getBuildable');
$object_phids = mpull($buildables, 'getBuildablePHID');
$initiator_phids = mpull($builds, 'getInitiatorPHID');
$phids = array_mergev(array($initiator_phids, $object_phids));
$phids = array_unique(array_filter($phids));
$handles = $viewer->loadHandles($phids);
$list = new PHUIObjectItemListView();
foreach ($builds as $build) {
$id = $build->getID();
$initiator = $handles[$build->getInitiatorPHID()];
$buildable_object = $handles[$build->getBuildable()->getBuildablePHID()];
$item = id(new PHUIObjectItemView())
->setViewer($viewer)
->setObject($build)
->setObjectName(pht('Build %d', $build->getID()))
->setHeader($build->getName())
->setHref($build->getURI())
->setEpoch($build->getDateCreated())
->addAttribute($buildable_object->getName());
if ($initiator) {
$item->addHandleIcon($initiator, $initiator->getName());
}
$status = $build->getBuildStatus();
$status_icon = HarbormasterBuild::getBuildStatusIcon($status);
$status_color = HarbormasterBuild::getBuildStatusColor($status);
$status_label = HarbormasterBuild::getBuildStatusName($status);
$item->setStatusIcon("{$status_icon} {$status_color}", $status_label);
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No builds found.'));
return $result;
}
}

View file

@ -71,28 +71,22 @@ final class HarbormasterBuild extends HarbormasterDAO
* @return string Human-readable name.
*/
public static function getBuildStatusName($status) {
switch ($status) {
case self::STATUS_INACTIVE:
return pht('Inactive');
case self::STATUS_PENDING:
return pht('Pending');
case self::STATUS_BUILDING:
return pht('Building');
case self::STATUS_PASSED:
return pht('Passed');
case self::STATUS_FAILED:
return pht('Failed');
case self::STATUS_ABORTED:
return pht('Aborted');
case self::STATUS_ERROR:
return pht('Unexpected Error');
case self::STATUS_PAUSED:
return pht('Paused');
case self::STATUS_DEADLOCKED:
return pht('Deadlocked');
default:
return pht('Unknown');
$map = self::getBuildStatusMap();
return idx($map, $status, pht('Unknown ("%s")', $status));
}
public static function getBuildStatusMap() {
return array(
self::STATUS_INACTIVE => pht('Inactive'),
self::STATUS_PENDING => pht('Pending'),
self::STATUS_BUILDING => pht('Building'),
self::STATUS_PASSED => pht('Passed'),
self::STATUS_FAILED => pht('Failed'),
self::STATUS_ABORTED => pht('Aborted'),
self::STATUS_ERROR => pht('Unexpected Error'),
self::STATUS_PAUSED => pht('Paused'),
self::STATUS_DEADLOCKED => pht('Deadlocked'),
);
}
public static function getBuildStatusIcon($status) {

View file

@ -0,0 +1,45 @@
<?php
final class HarbormasterBuildStatusDatasource
extends PhabricatorTypeaheadDatasource {
public function getBrowseTitle() {
return pht('Choose Build Statuses');
}
public function getPlaceholderText() {
return pht('Type a build status name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorHarbormasterApplication';
}
public function loadResults() {
$results = $this->buildResults();
return $this->filterResultsAgainstTokens($results);
}
public function renderTokens(array $values) {
return $this->renderTokensFromResults($this->buildResults(), $values);
}
private function buildResults() {
$results = array();
$status_map = HarbormasterBuild::getBuildStatusMap();
foreach ($status_map as $value => $name) {
$result = id(new PhabricatorTypeaheadResult())
->setIcon(HarbormasterBuild::getBuildStatusIcon($value))
->setColor(HarbormasterBuild::getBuildStatusColor($value))
->setPHID($value)
->setName($name)
->addAttribute(pht('Status'));
$results[$value] = $result;
}
return $results;
}
}