Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2895961
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
16 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/applications/differential/application/PhabricatorDifferentialApplication.php b/src/applications/differential/application/PhabricatorDifferentialApplication.php
index 52b222301a..c27d0da820 100644
--- a/src/applications/differential/application/PhabricatorDifferentialApplication.php
+++ b/src/applications/differential/application/PhabricatorDifferentialApplication.php
@@ -1,149 +1,149 @@
<?php
-final class PhabricatorDifferentialApplication extends PhabricatorApplication {
+final class PhabricatorDifferentialApplication
+ extends PhabricatorApplication {
public function getBaseURI() {
return '/differential/';
}
public function getName() {
return pht('Differential');
}
public function getShortDescription() {
return pht('Pre-Commit Review');
}
public function getIcon() {
return 'fa-cog';
}
public function isPinnedByDefault(PhabricatorUser $viewer) {
return true;
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Differential User Guide'),
'href' => PhabricatorEnv::getDoclink('Differential User Guide'),
),
);
}
public function getTitleGlyph() {
return "\xE2\x9A\x99";
}
public function getOverview() {
return pht(
'Differential is a **code review application** which allows '.
'engineers to review, discuss and approve changes to software.');
}
public function getRoutes() {
return array(
'/D(?P<id>[1-9]\d*)' => array(
'' => 'DifferentialRevisionViewController',
'/(?P<filter>new)/' => 'DifferentialRevisionViewController',
),
'/differential/' => array(
- '(?:query/(?P<queryKey>[^/]+)/)?'
- => 'DifferentialRevisionListController',
+ $this->getQueryRoutePattern() => 'DifferentialRevisionListController',
'diff/' => array(
'(?P<id>[1-9]\d*)/' => array(
'' => 'DifferentialDiffViewController',
'changesets/' => array(
$this->getQueryRoutePattern()
=> 'DifferentialChangesetListController',
),
),
'create/' => 'DifferentialDiffCreateController',
),
'changeset/' => 'DifferentialChangesetViewController',
'revision/' => array(
$this->getEditRoutePattern('edit/')
=> 'DifferentialRevisionEditController',
$this->getEditRoutePattern('attach/(?P<diffID>[^/]+)/to/')
=> 'DifferentialRevisionEditController',
'closedetails/(?P<phid>[^/]+)/'
=> 'DifferentialRevisionCloseDetailsController',
'update/(?P<revisionID>[1-9]\d*)/'
=> 'DifferentialDiffCreateController',
'operation/(?P<id>[1-9]\d*)/'
=> 'DifferentialRevisionOperationController',
'inlines/(?P<id>[1-9]\d*)/'
=> 'DifferentialRevisionInlinesController',
),
'comment/' => array(
'preview/(?P<id>[1-9]\d*)/' => 'DifferentialCommentPreviewController',
'save/(?P<id>[1-9]\d*)/' => 'DifferentialCommentSaveController',
'inline/' => array(
'preview/(?P<id>[1-9]\d*)/'
=> 'DifferentialInlineCommentPreviewController',
'edit/(?P<id>[1-9]\d*)/'
=> 'DifferentialInlineCommentEditController',
),
),
'preview/' => 'PhabricatorMarkupPreviewController',
),
);
}
public function getApplicationOrder() {
return 0.100;
}
public function getRemarkupRules() {
return array(
new DifferentialRemarkupRule(),
);
}
public function supportsEmailIntegration() {
return true;
}
public function getAppEmailBlurb() {
return pht(
'Send email to these addresses to create revisions. The body of the '.
'message and / or one or more attachments should be the output of a '.
'"diff" command. %s',
phutil_tag(
'a',
array(
'href' => $this->getInboundEmailSupportLink(),
),
pht('Learn More')));
}
protected function getCustomCapabilities() {
return array(
DifferentialDefaultViewCapability::CAPABILITY => array(
'caption' => pht('Default view policy for newly created revisions.'),
'template' => DifferentialRevisionPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
);
}
public function getMailCommandObjects() {
return array(
'revision' => array(
'name' => pht('Email Commands: Revisions'),
'header' => pht('Interacting with Differential Revisions'),
'object' => new DifferentialRevision(),
'summary' => pht(
'This page documents the commands you can use to interact with '.
'revisions in Differential.'),
),
);
}
public function getApplicationSearchDocumentTypes() {
return array(
DifferentialRevisionPHIDType::TYPECONST,
);
}
}
diff --git a/src/applications/differential/query/DifferentialRevisionSearchEngine.php b/src/applications/differential/query/DifferentialRevisionSearchEngine.php
index 557ca23078..be753c5e17 100644
--- a/src/applications/differential/query/DifferentialRevisionSearchEngine.php
+++ b/src/applications/differential/query/DifferentialRevisionSearchEngine.php
@@ -1,292 +1,365 @@
<?php
final class DifferentialRevisionSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Differential Revisions');
}
public function getApplicationClassName() {
return 'PhabricatorDifferentialApplication';
}
protected function newResultBuckets() {
return DifferentialRevisionResultBucket::getAllResultBuckets();
}
public function newQuery() {
return id(new DifferentialRevisionQuery())
->needFlags(true)
->needDrafts(true)
->needReviewers(true);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['responsiblePHIDs']) {
$query->withResponsibleUsers($map['responsiblePHIDs']);
}
if ($map['authorPHIDs']) {
$query->withAuthors($map['authorPHIDs']);
}
if ($map['reviewerPHIDs']) {
$query->withReviewers($map['reviewerPHIDs']);
}
if ($map['repositoryPHIDs']) {
$query->withRepositoryPHIDs($map['repositoryPHIDs']);
}
if ($map['statuses']) {
$query->withStatuses($map['statuses']);
}
if ($map['createdStart'] || $map['createdEnd']) {
$query->withCreatedEpochBetween(
$map['createdStart'],
$map['createdEnd']);
}
return $query;
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Responsible Users'))
->setKey('responsiblePHIDs')
->setAliases(array('responsiblePHID', 'responsibles', 'responsible'))
->setDatasource(new DifferentialResponsibleDatasource())
->setDescription(
pht('Find revisions that a given user is responsible for.')),
id(new PhabricatorUsersSearchField())
->setLabel(pht('Authors'))
->setKey('authorPHIDs')
->setAliases(array('author', 'authors', 'authorPHID'))
->setDescription(
pht('Find revisions with specific authors.')),
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Reviewers'))
->setKey('reviewerPHIDs')
->setAliases(array('reviewer', 'reviewers', 'reviewerPHID'))
->setDatasource(new DiffusionAuditorFunctionDatasource())
->setDescription(
pht('Find revisions with specific reviewers.')),
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Repositories'))
->setKey('repositoryPHIDs')
->setAliases(array('repository', 'repositories', 'repositoryPHID'))
->setDatasource(new DiffusionRepositoryFunctionDatasource())
->setDescription(
pht('Find revisions from specific repositories.')),
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Statuses'))
->setKey('statuses')
->setAliases(array('status'))
->setDatasource(new DifferentialRevisionStatusFunctionDatasource())
->setDescription(
pht('Find revisions with particular statuses.')),
id(new PhabricatorSearchDateField())
->setLabel(pht('Created After'))
->setKey('createdStart')
->setDescription(
pht('Find revisions created at or after a particular time.')),
id(new PhabricatorSearchDateField())
->setLabel(pht('Created Before'))
->setKey('createdEnd')
->setDescription(
pht('Find revisions created at or before a particular time.')),
);
}
protected function getURI($path) {
return '/differential/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array();
if ($this->requireViewer()->isLoggedIn()) {
$names['active'] = pht('Active Revisions');
$names['authored'] = pht('Authored');
}
$names['all'] = pht('All Revisions');
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
$viewer = $this->requireViewer();
switch ($query_key) {
case 'active':
$bucket_key = DifferentialRevisionRequiredActionResultBucket::BUCKETKEY;
return $query
->setParameter('responsiblePHIDs', array($viewer->getPHID()))
->setParameter('statuses', array('open()'))
->setParameter('bucket', $bucket_key);
case 'authored':
return $query
->setParameter('authorPHIDs', array($viewer->getPHID()));
case 'all':
return $query;
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
private function getStatusOptions() {
return array(
DifferentialLegacyQuery::STATUS_ANY => pht('All'),
DifferentialLegacyQuery::STATUS_OPEN => pht('Open'),
DifferentialLegacyQuery::STATUS_ACCEPTED => pht('Accepted'),
DifferentialLegacyQuery::STATUS_NEEDS_REVIEW => pht('Needs Review'),
DifferentialLegacyQuery::STATUS_NEEDS_REVISION => pht('Needs Revision'),
DifferentialLegacyQuery::STATUS_CLOSED => pht('Closed'),
DifferentialLegacyQuery::STATUS_ABANDONED => pht('Abandoned'),
);
}
protected function renderResultList(
array $revisions,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($revisions, 'DifferentialRevision');
$viewer = $this->requireViewer();
$template = id(new DifferentialRevisionListView())
->setViewer($viewer)
->setNoBox($this->isPanelContext());
$bucket = $this->getResultBucket($query);
$unlanded = $this->loadUnlandedDependencies($revisions);
$views = array();
if ($bucket) {
$bucket->setViewer($viewer);
try {
$groups = $bucket->newResultGroups($query, $revisions);
foreach ($groups as $group) {
// Don't show groups in Dashboard Panels
if ($group->getObjects() || !$this->isPanelContext()) {
$views[] = id(clone $template)
->setHeader($group->getName())
->setNoDataString($group->getNoDataString())
->setRevisions($group->getObjects());
}
}
} catch (Exception $ex) {
$this->addError($ex->getMessage());
}
} else {
$views[] = id(clone $template)
->setRevisions($revisions);
}
if (!$views) {
$views[] = id(new DifferentialRevisionListView())
->setViewer($viewer)
->setNoDataString(pht('No revisions found.'));
}
foreach ($views as $view) {
$view->setUnlandedDependencies($unlanded);
}
if (count($views) == 1) {
// Reduce this to a PHUIObjectItemListView so we can get the free
// support from ApplicationSearch.
$list = head($views)->render();
} else {
$list = $views;
}
$result = new PhabricatorApplicationSearchResultView();
$result->setContent($list);
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Diff'))
->setHref('/differential/diff/create/')
->setColor(PHUIButtonView::GREEN);
$icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Pre-commit code review. Revisions that are waiting on your input '.
'will appear here.'))
->addAction($create_button);
return $view;
}
private function loadUnlandedDependencies(array $revisions) {
$phids = array();
foreach ($revisions as $revision) {
if (!$revision->isAccepted()) {
continue;
}
$phids[] = $revision->getPHID();
}
if (!$phids) {
return array();
}
$query = id(new PhabricatorEdgeQuery())
->withSourcePHIDs($phids)
->withEdgeTypes(
array(
DifferentialRevisionDependsOnRevisionEdgeType::EDGECONST,
));
$query->execute();
$revision_phids = $query->getDestinationPHIDs();
if (!$revision_phids) {
return array();
}
$viewer = $this->requireViewer();
$blocking_revisions = id(new DifferentialRevisionQuery())
->setViewer($viewer)
->withPHIDs($revision_phids)
->withIsOpen(true)
->execute();
$blocking_revisions = mpull($blocking_revisions, null, 'getPHID');
$result = array();
foreach ($revisions as $revision) {
$revision_phid = $revision->getPHID();
$blocking_phids = $query->getDestinationPHIDs(array($revision_phid));
$blocking = array_select_keys($blocking_revisions, $blocking_phids);
if ($blocking) {
$result[$revision_phid] = $blocking;
}
}
return $result;
}
+ protected function newExportFields() {
+ $fields = array(
+ id(new PhabricatorStringExportField())
+ ->setKey('monogram')
+ ->setLabel(pht('Monogram')),
+ id(new PhabricatorPHIDExportField())
+ ->setKey('authorPHID')
+ ->setLabel(pht('Author PHID')),
+ id(new PhabricatorStringExportField())
+ ->setKey('author')
+ ->setLabel(pht('Author')),
+ id(new PhabricatorStringExportField())
+ ->setKey('status')
+ ->setLabel(pht('Status')),
+ id(new PhabricatorStringExportField())
+ ->setKey('statusName')
+ ->setLabel(pht('Status Name')),
+ id(new PhabricatorURIExportField())
+ ->setKey('uri')
+ ->setLabel(pht('URI')),
+ id(new PhabricatorStringExportField())
+ ->setKey('title')
+ ->setLabel(pht('Title')),
+ id(new PhabricatorStringExportField())
+ ->setKey('summary')
+ ->setLabel(pht('Summary')),
+ id(new PhabricatorStringExportField())
+ ->setKey('testPlan')
+ ->setLabel(pht('Test Plan')),
+ );
+
+ return $fields;
+ }
+
+ protected function newExportData(array $revisions) {
+ $viewer = $this->requireViewer();
+
+ $phids = array();
+ foreach ($revisions as $revision) {
+ $phids[] = $revision->getAuthorPHID();
+ }
+ $handles = $viewer->loadHandles($phids);
+
+ $export = array();
+ foreach ($revisions as $revision) {
+
+ $author_phid = $revision->getAuthorPHID();
+ if ($author_phid) {
+ $author_name = $handles[$author_phid]->getName();
+ } else {
+ $author_name = null;
+ }
+
+ $status = $revision->getStatusObject();
+ $status_name = $status->getDisplayName();
+ $status_value = $status->getKey();
+
+ $export[] = array(
+ 'monogram' => $revision->getMonogram(),
+ 'authorPHID' => $author_phid,
+ 'author' => $author_name,
+ 'status' => $status_value,
+ 'statusName' => $status_name,
+ 'uri' => PhabricatorEnv::getProductionURI($revision->getURI()),
+ 'title' => (string)$revision->getTitle(),
+ 'summary' => (string)$revision->getSummary(),
+ 'testPlan' => (string)$revision->getTestPlan(),
+ );
+ }
+
+ return $export;
+ }
+
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Jan 19 2025, 22:21 (6 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1129335
Default Alt Text
(16 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment