mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-27 01:02:42 +01:00
Modernize Audit search engine
Summary: Fixes T9279. Modernizes the SearchEngine and Query classes. User-facing changes: - Added order by commit date, default to order by commit date with newest commits first. - Added explicit "Needs Audit by". - Added new `packages(...)` typeahead function. - Picked up automatic subscribers, projects, and order fields. This changes behavior a little bit: we previously attempted to exclude, e.g., commits which a package you own needs to audit, but which you have resigned from. This is difficult in general and I think it needs a more comprehensive solution. This shouldn't impact users much, anyway. Test Plan: {F767628} Reviewers: chad Reviewed By: chad Maniphest Tasks: T9279 Differential Revision: https://secure.phabricator.com/D14013
This commit is contained in:
parent
e67c438943
commit
bce0698a0f
11 changed files with 449 additions and 206 deletions
|
@ -496,6 +496,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialUpdateRevisionConduitAPIMethod' => 'applications/differential/conduit/DifferentialUpdateRevisionConduitAPIMethod.php',
|
||||
'DifferentialViewPolicyField' => 'applications/differential/customfield/DifferentialViewPolicyField.php',
|
||||
'DiffusionAuditorDatasource' => 'applications/diffusion/typeahead/DiffusionAuditorDatasource.php',
|
||||
'DiffusionAuditorFunctionDatasource' => 'applications/diffusion/typeahead/DiffusionAuditorFunctionDatasource.php',
|
||||
'DiffusionAuditorsAddAuditorsHeraldAction' => 'applications/diffusion/herald/DiffusionAuditorsAddAuditorsHeraldAction.php',
|
||||
'DiffusionAuditorsAddSelfHeraldAction' => 'applications/diffusion/herald/DiffusionAuditorsAddSelfHeraldAction.php',
|
||||
'DiffusionAuditorsHeraldAction' => 'applications/diffusion/herald/DiffusionAuditorsHeraldAction.php',
|
||||
|
@ -2436,6 +2437,8 @@ phutil_register_library_map(array(
|
|||
'PhabricatorOwnersOwner' => 'applications/owners/storage/PhabricatorOwnersOwner.php',
|
||||
'PhabricatorOwnersPackage' => 'applications/owners/storage/PhabricatorOwnersPackage.php',
|
||||
'PhabricatorOwnersPackageDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php',
|
||||
'PhabricatorOwnersPackageFunctionDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageFunctionDatasource.php',
|
||||
'PhabricatorOwnersPackageOwnerDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageOwnerDatasource.php',
|
||||
'PhabricatorOwnersPackagePHIDType' => 'applications/owners/phid/PhabricatorOwnersPackagePHIDType.php',
|
||||
'PhabricatorOwnersPackageQuery' => 'applications/owners/query/PhabricatorOwnersPackageQuery.php',
|
||||
'PhabricatorOwnersPackageSearchEngine' => 'applications/owners/query/PhabricatorOwnersPackageSearchEngine.php',
|
||||
|
@ -2632,6 +2635,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectNoProjectsDatasource' => 'applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php',
|
||||
'PhabricatorProjectObjectHasProjectEdgeType' => 'applications/project/edge/PhabricatorProjectObjectHasProjectEdgeType.php',
|
||||
'PhabricatorProjectOrUserDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserDatasource.php',
|
||||
'PhabricatorProjectOrUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserFunctionDatasource.php',
|
||||
'PhabricatorProjectProfileController' => 'applications/project/controller/PhabricatorProjectProfileController.php',
|
||||
'PhabricatorProjectProjectHasMemberEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasMemberEdgeType.php',
|
||||
'PhabricatorProjectProjectHasObjectEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasObjectEdgeType.php',
|
||||
|
@ -2651,6 +2655,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectTransactionQuery' => 'applications/project/query/PhabricatorProjectTransactionQuery.php',
|
||||
'PhabricatorProjectUIEventListener' => 'applications/project/events/PhabricatorProjectUIEventListener.php',
|
||||
'PhabricatorProjectUpdateController' => 'applications/project/controller/PhabricatorProjectUpdateController.php',
|
||||
'PhabricatorProjectUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectUserFunctionDatasource.php',
|
||||
'PhabricatorProjectViewController' => 'applications/project/controller/PhabricatorProjectViewController.php',
|
||||
'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php',
|
||||
'PhabricatorProjectsPolicyRule' => 'applications/policy/rule/PhabricatorProjectsPolicyRule.php',
|
||||
|
@ -4158,6 +4163,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialUpdateRevisionConduitAPIMethod' => 'DifferentialConduitAPIMethod',
|
||||
'DifferentialViewPolicyField' => 'DifferentialCoreCustomField',
|
||||
'DiffusionAuditorDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'DiffusionAuditorFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'DiffusionAuditorsAddAuditorsHeraldAction' => 'DiffusionAuditorsHeraldAction',
|
||||
'DiffusionAuditorsAddSelfHeraldAction' => 'DiffusionAuditorsHeraldAction',
|
||||
'DiffusionAuditorsHeraldAction' => 'HeraldAction',
|
||||
|
@ -6407,6 +6413,8 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationTransactionInterface',
|
||||
),
|
||||
'PhabricatorOwnersPackageDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'PhabricatorOwnersPackageFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'PhabricatorOwnersPackageOwnerDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'PhabricatorOwnersPackagePHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorOwnersPackageQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorOwnersPackageSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
|
@ -6650,6 +6658,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectNoProjectsDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'PhabricatorProjectObjectHasProjectEdgeType' => 'PhabricatorEdgeType',
|
||||
'PhabricatorProjectOrUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'PhabricatorProjectOrUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectProjectHasMemberEdgeType' => 'PhabricatorEdgeType',
|
||||
'PhabricatorProjectProjectHasObjectEdgeType' => 'PhabricatorEdgeType',
|
||||
|
@ -6672,6 +6681,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorProjectUIEventListener' => 'PhabricatorEventListener',
|
||||
'PhabricatorProjectUpdateController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'PhabricatorProjectViewController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectWatchController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectsPolicyRule' => 'PhabricatorPolicyRule',
|
||||
|
|
|
@ -70,9 +70,8 @@ final class PhabricatorAuditApplication extends PhabricatorApplication {
|
|||
|
||||
$query = id(new DiffusionCommitQuery())
|
||||
->setViewer($user)
|
||||
->withAuditorPHIDs($phids)
|
||||
->withNeedsAuditByPHIDs($phids)
|
||||
->withAuditStatus(DiffusionCommitQuery::AUDIT_STATUS_OPEN)
|
||||
->withAuditAwaitingUser($user)
|
||||
->setLimit(self::MAX_STATUS_ITEMS);
|
||||
$commits = $query->execute();
|
||||
|
||||
|
|
|
@ -11,103 +11,65 @@ final class PhabricatorCommitSearchEngine
|
|||
return 'PhabricatorDiffusionApplication';
|
||||
}
|
||||
|
||||
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
||||
$saved = new PhabricatorSavedQuery();
|
||||
|
||||
$saved->setParameter(
|
||||
'auditorPHIDs',
|
||||
$this->readPHIDsFromRequest($request, 'auditorPHIDs'));
|
||||
|
||||
$saved->setParameter(
|
||||
'commitAuthorPHIDs',
|
||||
$this->readUsersFromRequest($request, 'authors'));
|
||||
|
||||
$saved->setParameter(
|
||||
'auditStatus',
|
||||
$request->getStr('auditStatus'));
|
||||
|
||||
$saved->setParameter(
|
||||
'repositoryPHIDs',
|
||||
$this->readPHIDsFromRequest($request, 'repositoryPHIDs'));
|
||||
|
||||
// -- TODO - T4173 - file location
|
||||
|
||||
return $saved;
|
||||
}
|
||||
|
||||
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
||||
$query = id(new DiffusionCommitQuery())
|
||||
public function newQuery() {
|
||||
return id(new DiffusionCommitQuery())
|
||||
->needAuditRequests(true)
|
||||
->needCommitData(true);
|
||||
}
|
||||
|
||||
$auditor_phids = $saved->getParameter('auditorPHIDs', array());
|
||||
if ($auditor_phids) {
|
||||
$query->withAuditorPHIDs($auditor_phids);
|
||||
protected function buildQueryFromParameters(array $map) {
|
||||
$query = $this->newQuery();
|
||||
|
||||
if ($map['needsAuditByPHIDs']) {
|
||||
$query->withNeedsAuditByPHIDs($map['needsAuditByPHIDs']);
|
||||
}
|
||||
|
||||
$commit_author_phids = $saved->getParameter('commitAuthorPHIDs', array());
|
||||
if ($commit_author_phids) {
|
||||
$query->withAuthorPHIDs($commit_author_phids);
|
||||
if ($map['auditorPHIDs']) {
|
||||
$query->withAuditorPHIDs($map['auditorPHIDs']);
|
||||
}
|
||||
|
||||
$audit_status = $saved->getParameter('auditStatus', null);
|
||||
if ($audit_status) {
|
||||
$query->withAuditStatus($audit_status);
|
||||
if ($map['commitAuthorPHIDs']) {
|
||||
$query->withAuthorPHIDs($map['commitAuthorPHIDs']);
|
||||
}
|
||||
|
||||
$awaiting_user_phid = $saved->getParameter('awaitingUserPHID', null);
|
||||
if ($awaiting_user_phid) {
|
||||
// This is used only for the built-in "needs attention" filter,
|
||||
// so cheat and just use the already-loaded viewer rather than reloading
|
||||
// it.
|
||||
$query->withAuditAwaitingUser($this->requireViewer());
|
||||
if ($map['auditStatus']) {
|
||||
$query->withAuditStatus($map['auditStatus']);
|
||||
}
|
||||
|
||||
$repository_phids = $saved->getParameter('repositoryPHIDs', array());
|
||||
if ($repository_phids) {
|
||||
$query->withRepositoryPHIDs($repository_phids);
|
||||
if ($map['repositoryPHIDs']) {
|
||||
$query->withRepositoryPHIDs($map['repositoryPHIDs']);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function buildSearchForm(
|
||||
AphrontFormView $form,
|
||||
PhabricatorSavedQuery $saved) {
|
||||
|
||||
$auditor_phids = $saved->getParameter('auditorPHIDs', array());
|
||||
$commit_author_phids = $saved->getParameter(
|
||||
'commitAuthorPHIDs',
|
||||
array());
|
||||
$audit_status = $saved->getParameter('auditStatus', null);
|
||||
$repository_phids = $saved->getParameter('repositoryPHIDs', array());
|
||||
|
||||
$form
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource(new DiffusionAuditorDatasource())
|
||||
->setName('auditorPHIDs')
|
||||
->setLabel(pht('Auditors'))
|
||||
->setValue($auditor_phids))
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource(new PhabricatorPeopleDatasource())
|
||||
->setName('authors')
|
||||
->setLabel(pht('Commit Authors'))
|
||||
->setValue($commit_author_phids))
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setName('auditStatus')
|
||||
->setLabel(pht('Audit Status'))
|
||||
->setOptions($this->getAuditStatusOptions())
|
||||
->setValue($audit_status))
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setLabel(pht('Repositories'))
|
||||
->setName('repositoryPHIDs')
|
||||
->setDatasource(new DiffusionRepositoryDatasource())
|
||||
->setValue($repository_phids));
|
||||
|
||||
protected function buildCustomSearchFields() {
|
||||
return array(
|
||||
id(new PhabricatorSearchDatasourceField())
|
||||
->setLabel(pht('Needs Audit By'))
|
||||
->setKey('needsAuditByPHIDs')
|
||||
->setAliases(array('needs', 'need'))
|
||||
->setDatasource(new DiffusionAuditorFunctionDatasource()),
|
||||
id(new PhabricatorSearchDatasourceField())
|
||||
->setLabel(pht('Auditors'))
|
||||
->setKey('auditorPHIDs')
|
||||
->setAliases(array('auditor', 'auditors'))
|
||||
->setDatasource(new DiffusionAuditorFunctionDatasource()),
|
||||
id(new PhabricatorUsersSearchField())
|
||||
->setLabel(pht('Authors'))
|
||||
->setKey('commitAuthorPHIDs')
|
||||
->setAliases(array('author', 'authors')),
|
||||
id(new PhabricatorSearchSelectField())
|
||||
->setLabel(pht('Audit Status'))
|
||||
->setKey('auditStatus')
|
||||
->setAliases(array('status'))
|
||||
->setOptions($this->getAuditStatusOptions()),
|
||||
id(new PhabricatorSearchDatasourceField())
|
||||
->setLabel(pht('Repositories'))
|
||||
->setKey('repositoryPHIDs')
|
||||
->setAliases(array('repository', 'repositories'))
|
||||
->setDatasource(new DiffusionRepositoryDatasource()),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getURI($path) {
|
||||
|
@ -118,7 +80,7 @@ final class PhabricatorCommitSearchEngine
|
|||
$names = array();
|
||||
|
||||
if ($this->requireViewer()->isLoggedIn()) {
|
||||
$names['need'] = pht('Need Attention');
|
||||
$names['need'] = pht('Needs Audit');
|
||||
$names['problem'] = pht('Problem Commits');
|
||||
}
|
||||
|
||||
|
@ -138,22 +100,24 @@ final class PhabricatorCommitSearchEngine
|
|||
$query->setQueryKey($query_key);
|
||||
$viewer = $this->requireViewer();
|
||||
|
||||
$viewer_phid = $viewer->getPHID();
|
||||
$status_open = DiffusionCommitQuery::AUDIT_STATUS_OPEN;
|
||||
|
||||
switch ($query_key) {
|
||||
case 'all':
|
||||
return $query;
|
||||
case 'open':
|
||||
$query->setParameter(
|
||||
'auditStatus',
|
||||
DiffusionCommitQuery::AUDIT_STATUS_OPEN);
|
||||
$query->setParameter('auditStatus', $status_open);
|
||||
return $query;
|
||||
case 'need':
|
||||
$query->setParameter('awaitingUserPHID', $viewer->getPHID());
|
||||
$query->setParameter(
|
||||
'auditStatus',
|
||||
DiffusionCommitQuery::AUDIT_STATUS_OPEN);
|
||||
$query->setParameter(
|
||||
'auditorPHIDs',
|
||||
PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($viewer));
|
||||
$needs_tokens = array(
|
||||
$viewer_phid,
|
||||
'projects('.$viewer_phid.')',
|
||||
'packages('.$viewer_phid.')',
|
||||
);
|
||||
|
||||
$query->setParameter('needsAuditByPHIDs', $needs_tokens);
|
||||
$query->setParameter('auditStatus', $status_open);
|
||||
return $query;
|
||||
case 'authored':
|
||||
$query->setParameter('commitAuthorPHIDs', array($viewer->getPHID()));
|
||||
|
|
|
@ -15,7 +15,7 @@ final class DiffusionCommitQuery
|
|||
private $needAuditRequests;
|
||||
private $auditIDs;
|
||||
private $auditorPHIDs;
|
||||
private $auditAwaitingUser;
|
||||
private $needsAuditByPHIDs;
|
||||
private $auditStatus;
|
||||
private $epochMin;
|
||||
private $epochMax;
|
||||
|
@ -103,27 +103,6 @@ final class DiffusionCommitQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if we should join the audit table, either because we're
|
||||
* interested in the information if it's available or because matching rows
|
||||
* must always have it.
|
||||
*/
|
||||
private function shouldJoinAudits() {
|
||||
return $this->auditStatus ||
|
||||
$this->rowsMustHaveAudits();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we should `JOIN` (vs `LEFT JOIN`) the audit table, because
|
||||
* matching commits will always have audit rows.
|
||||
*/
|
||||
private function rowsMustHaveAudits() {
|
||||
return
|
||||
$this->auditIDs ||
|
||||
$this->auditorPHIDs ||
|
||||
$this->auditAwaitingUser;
|
||||
}
|
||||
|
||||
public function withAuditIDs(array $ids) {
|
||||
$this->auditIDs = $ids;
|
||||
return $this;
|
||||
|
@ -134,8 +113,8 @@ final class DiffusionCommitQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withAuditAwaitingUser(PhabricatorUser $user) {
|
||||
$this->auditAwaitingUser = $user;
|
||||
public function withNeedsAuditByPHIDs(array $needs_phids) {
|
||||
$this->needsAuditByPHIDs = $needs_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -175,21 +154,12 @@ final class DiffusionCommitQuery
|
|||
}
|
||||
}
|
||||
|
||||
public function newResultObject() {
|
||||
return new PhabricatorRepositoryCommit();
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new PhabricatorRepositoryCommit();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
||||
$data = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT commit.* FROM %T commit %Q %Q %Q %Q %Q',
|
||||
$table->getTableName(),
|
||||
$this->buildJoinClause($conn_r),
|
||||
$this->buildWhereClause($conn_r),
|
||||
$this->buildGroupClause($conn_r),
|
||||
$this->buildOrderClause($conn_r),
|
||||
$this->buildLimitClause($conn_r));
|
||||
|
||||
return $table->loadAllFromArray($data);
|
||||
return $this->loadStandardPage($this->newResultObject());
|
||||
}
|
||||
|
||||
protected function willFilterPage(array $commits) {
|
||||
|
@ -296,8 +266,8 @@ final class DiffusionCommitQuery
|
|||
return $commits;
|
||||
}
|
||||
|
||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
||||
$where = array();
|
||||
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||
$where = parent::buildWhereClauseParts($conn);
|
||||
|
||||
if ($this->repositoryPHIDs !== null) {
|
||||
$map_repositories = id(new PhabricatorRepositoryQuery())
|
||||
|
@ -317,42 +287,42 @@ final class DiffusionCommitQuery
|
|||
|
||||
if ($this->ids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'commit.id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->phids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'commit.phid IN (%Ls)',
|
||||
$this->phids);
|
||||
}
|
||||
|
||||
if ($this->repositoryIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'commit.repositoryID IN (%Ld)',
|
||||
$this->repositoryIDs);
|
||||
}
|
||||
|
||||
if ($this->authorPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'commit.authorPHID IN (%Ls)',
|
||||
$this->authorPHIDs);
|
||||
}
|
||||
|
||||
if ($this->epochMin !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'commit.epoch >= %d',
|
||||
$this->epochMin);
|
||||
}
|
||||
|
||||
if ($this->epochMax !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'commit.epoch <= %d',
|
||||
$this->epochMax);
|
||||
}
|
||||
|
@ -360,13 +330,13 @@ final class DiffusionCommitQuery
|
|||
if ($this->importing !== null) {
|
||||
if ($this->importing) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'(commit.importStatus & %d) != %d',
|
||||
PhabricatorRepositoryCommit::IMPORTED_ALL,
|
||||
PhabricatorRepositoryCommit::IMPORTED_ALL);
|
||||
} else {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'(commit.importStatus & %d) = %d',
|
||||
PhabricatorRepositoryCommit::IMPORTED_ALL,
|
||||
PhabricatorRepositoryCommit::IMPORTED_ALL);
|
||||
|
@ -409,7 +379,7 @@ final class DiffusionCommitQuery
|
|||
|
||||
foreach ($bare as $identifier) {
|
||||
$sql[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'(commit.commitIdentifier LIKE %> AND '.
|
||||
'LENGTH(commit.commitIdentifier) = 40)',
|
||||
$identifier);
|
||||
|
@ -437,7 +407,7 @@ final class DiffusionCommitQuery
|
|||
continue;
|
||||
}
|
||||
$sql[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'(commit.repositoryID = %d AND commit.commitIdentifier = %s)',
|
||||
$repo->getID(),
|
||||
// NOTE: Because the 'commitIdentifier' column is a string, MySQL
|
||||
|
@ -449,7 +419,7 @@ final class DiffusionCommitQuery
|
|||
continue;
|
||||
}
|
||||
$sql[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'(commit.repositoryID = %d AND commit.commitIdentifier LIKE %>)',
|
||||
$repo->getID(),
|
||||
$ref['identifier']);
|
||||
|
@ -470,28 +440,23 @@ final class DiffusionCommitQuery
|
|||
|
||||
if ($this->auditIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'audit.id IN (%Ld)',
|
||||
$this->auditIDs);
|
||||
}
|
||||
|
||||
if ($this->auditorPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'audit.auditorPHID IN (%Ls)',
|
||||
$this->auditorPHIDs);
|
||||
}
|
||||
|
||||
if ($this->auditAwaitingUser) {
|
||||
$awaiting_user_phid = $this->auditAwaitingUser->getPHID();
|
||||
// Exclude package and project audits associated with commits where
|
||||
// the user is the author.
|
||||
if ($this->needsAuditByPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'(commit.authorPHID IS NULL OR commit.authorPHID != %s)
|
||||
OR (audit.auditorPHID = %s)',
|
||||
$awaiting_user_phid,
|
||||
$awaiting_user_phid);
|
||||
$conn,
|
||||
'needs.auditorPHID IN (%Ls)',
|
||||
$this->needsAuditByPHIDs);
|
||||
}
|
||||
|
||||
$status = $this->auditStatus;
|
||||
|
@ -499,33 +464,27 @@ final class DiffusionCommitQuery
|
|||
switch ($status) {
|
||||
case self::AUDIT_STATUS_PARTIAL:
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'commit.auditStatus = %d',
|
||||
PhabricatorAuditCommitStatusConstants::PARTIALLY_AUDITED);
|
||||
break;
|
||||
case self::AUDIT_STATUS_ACCEPTED:
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'commit.auditStatus = %d',
|
||||
PhabricatorAuditCommitStatusConstants::FULLY_AUDITED);
|
||||
break;
|
||||
case self::AUDIT_STATUS_CONCERN:
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'audit.auditStatus = %s',
|
||||
$conn,
|
||||
'status.auditStatus = %s',
|
||||
PhabricatorAuditStatusConstants::CONCERNED);
|
||||
break;
|
||||
case self::AUDIT_STATUS_OPEN:
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'audit.auditStatus in (%Ls)',
|
||||
$conn,
|
||||
'status.auditStatus in (%Ls)',
|
||||
PhabricatorAuditStatusConstants::getOpenStatusConstants());
|
||||
if ($this->auditAwaitingUser) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'awaiting.auditStatus IS NULL OR awaiting.auditStatus != %s',
|
||||
PhabricatorAuditStatusConstants::RESIGNED);
|
||||
}
|
||||
break;
|
||||
case self::AUDIT_STATUS_ANY:
|
||||
break;
|
||||
|
@ -545,9 +504,7 @@ final class DiffusionCommitQuery
|
|||
}
|
||||
}
|
||||
|
||||
$where[] = $this->buildPagingClause($conn_r);
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
return $where;
|
||||
}
|
||||
|
||||
protected function didFilterResults(array $filtered) {
|
||||
|
@ -560,56 +517,113 @@ final class DiffusionCommitQuery
|
|||
}
|
||||
}
|
||||
|
||||
protected function buildJoinClause(AphrontDatabaseConnection $conn_r) {
|
||||
$joins = array();
|
||||
private function shouldJoinStatus() {
|
||||
return $this->auditStatus;
|
||||
}
|
||||
|
||||
private function shouldJoinAudits() {
|
||||
return $this->auditIDs || $this->auditorPHIDs;
|
||||
}
|
||||
|
||||
private function shouldJoinNeeds() {
|
||||
return $this->needsAuditByPHIDs;
|
||||
}
|
||||
|
||||
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
|
||||
$join = parent::buildJoinClauseParts($conn);
|
||||
$audit_request = new PhabricatorRepositoryAuditRequest();
|
||||
|
||||
if ($this->shouldJoinAudits()) {
|
||||
$joins[] = qsprintf(
|
||||
$conn_r,
|
||||
'%Q %T audit ON commit.phid = audit.commitPHID',
|
||||
($this->rowsMustHaveAudits() ? 'JOIN' : 'LEFT JOIN'),
|
||||
if ($this->shouldJoinStatus()) {
|
||||
$join[] = qsprintf(
|
||||
$conn,
|
||||
'LEFT JOIN %T status ON commit.phid = status.commitPHID',
|
||||
$audit_request->getTableName());
|
||||
}
|
||||
|
||||
if ($this->auditAwaitingUser) {
|
||||
// Join the request table on the awaiting user's requests, so we can
|
||||
// filter out package and project requests which the user has resigned
|
||||
// from.
|
||||
$joins[] = qsprintf(
|
||||
$conn_r,
|
||||
'LEFT JOIN %T awaiting ON audit.commitPHID = awaiting.commitPHID AND
|
||||
awaiting.auditorPHID = %s',
|
||||
$audit_request->getTableName(),
|
||||
$this->auditAwaitingUser->getPHID());
|
||||
if ($this->shouldJoinAudits()) {
|
||||
$join[] = qsprintf(
|
||||
$conn,
|
||||
'JOIN %T audit ON commit.phid = audit.commitPHID',
|
||||
$audit_request->getTableName());
|
||||
}
|
||||
|
||||
if ($joins) {
|
||||
return implode(' ', $joins);
|
||||
} else {
|
||||
return '';
|
||||
if ($this->shouldJoinNeeds()) {
|
||||
$join[] = qsprintf(
|
||||
$conn,
|
||||
'JOIN %T needs ON commit.phid = needs.commitPHID
|
||||
AND needs.auditStatus IN (%Ls)',
|
||||
$audit_request->getTableName(),
|
||||
array(
|
||||
PhabricatorAuditStatusConstants::AUDIT_REQUESTED,
|
||||
PhabricatorAuditStatusConstants::AUDIT_REQUIRED,
|
||||
));
|
||||
}
|
||||
|
||||
return $join;
|
||||
}
|
||||
|
||||
protected function buildGroupClause(AphrontDatabaseConnection $conn_r) {
|
||||
$should_group = $this->shouldJoinAudits();
|
||||
|
||||
// TODO: Currently, the audit table is missing a unique key, so we may
|
||||
// require a GROUP BY if we perform this join. See T1768. This can be
|
||||
// removed once the table has the key.
|
||||
if ($this->auditAwaitingUser) {
|
||||
$should_group = true;
|
||||
protected function shouldGroupQueryResultRows() {
|
||||
if ($this->shouldJoinStatus()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($should_group) {
|
||||
return 'GROUP BY commit.id';
|
||||
} else {
|
||||
return '';
|
||||
if ($this->shouldJoinAudits()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->shouldJoinNeeds()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return parent::shouldGroupQueryResultRows();
|
||||
}
|
||||
|
||||
public function getQueryApplicationClass() {
|
||||
return 'PhabricatorDiffusionApplication';
|
||||
}
|
||||
|
||||
public function getOrderableColumns() {
|
||||
return parent::getOrderableColumns() + array(
|
||||
'epoch' => array(
|
||||
'table' => $this->getPrimaryTableAlias(),
|
||||
'column' => 'epoch',
|
||||
'type' => 'int',
|
||||
'reverse' => false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getPagingValueMap($cursor, array $keys) {
|
||||
$commit = $this->loadCursorObject($cursor);
|
||||
return array(
|
||||
'id' => $commit->getID(),
|
||||
'epoch' => $commit->getEpoch(),
|
||||
);
|
||||
}
|
||||
|
||||
public function getBuiltinOrders() {
|
||||
$parent = parent::getBuiltinOrders();
|
||||
|
||||
// Rename the default ID-based orders.
|
||||
$parent['importnew'] = array(
|
||||
'name' => pht('Import Date (Newest First)'),
|
||||
) + $parent['newest'];
|
||||
|
||||
$parent['importold'] = array(
|
||||
'name' => pht('Import Date (Oldest First)'),
|
||||
) + $parent['oldest'];
|
||||
|
||||
return array(
|
||||
'newest' => array(
|
||||
'vector' => array('epoch', 'id'),
|
||||
'name' => pht('Commit Date (Newest First)'),
|
||||
),
|
||||
'oldest' => array(
|
||||
'vector' => array('-epoch', '-id'),
|
||||
'name' => pht('Commit Date (Oldest First)'),
|
||||
),
|
||||
) + $parent;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionAuditorFunctionDatasource
|
||||
extends PhabricatorTypeaheadCompositeDatasource {
|
||||
|
||||
public function getBrowseTitle() {
|
||||
return pht('Browse Auditors');
|
||||
}
|
||||
|
||||
public function getPlaceholderText() {
|
||||
return pht('Type a user, project, package name or function...');
|
||||
}
|
||||
|
||||
public function getDatasourceApplicationClass() {
|
||||
return 'PhabricatorDiffusionApplication';
|
||||
}
|
||||
|
||||
public function getComponentDatasources() {
|
||||
return array(
|
||||
new PhabricatorProjectOrUserFunctionDatasource(),
|
||||
new PhabricatorOwnersPackageFunctionDatasource(),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -349,9 +349,8 @@ final class PhabricatorHomeMainController extends PhabricatorHomeController {
|
|||
|
||||
$query = id(new DiffusionCommitQuery())
|
||||
->setViewer($user)
|
||||
->withAuditorPHIDs($phids)
|
||||
->withNeedsAuditByPHIDs($phids)
|
||||
->withAuditStatus(DiffusionCommitQuery::AUDIT_STATUS_OPEN)
|
||||
->withAuditAwaitingUser($user)
|
||||
->needAuditRequests(true)
|
||||
->needCommitData(true)
|
||||
->setLimit(10);
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersPackageFunctionDatasource
|
||||
extends PhabricatorTypeaheadCompositeDatasource {
|
||||
|
||||
public function getBrowseTitle() {
|
||||
return pht('Browse Packages');
|
||||
}
|
||||
|
||||
public function getPlaceholderText() {
|
||||
return pht('Type a package name or function...');
|
||||
}
|
||||
|
||||
public function getDatasourceApplicationClass() {
|
||||
return 'PhabricatorOwnersApplication';
|
||||
}
|
||||
|
||||
public function getComponentDatasources() {
|
||||
return array(
|
||||
new PhabricatorOwnersPackageDatasource(),
|
||||
new PhabricatorOwnersPackageOwnerDatasource(),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersPackageOwnerDatasource
|
||||
extends PhabricatorTypeaheadCompositeDatasource {
|
||||
|
||||
public function getBrowseTitle() {
|
||||
return pht('Browse Packages by Owner');
|
||||
}
|
||||
|
||||
public function getPlaceholderText() {
|
||||
return pht('Type packages(<user>) or packages(<project>)...');
|
||||
}
|
||||
|
||||
public function getDatasourceApplicationClass() {
|
||||
return 'PhabricatorOwnersApplication';
|
||||
}
|
||||
|
||||
public function getComponentDatasources() {
|
||||
return array(
|
||||
new PhabricatorPeopleDatasource(),
|
||||
new PhabricatorProjectDatasource(),
|
||||
);
|
||||
}
|
||||
|
||||
public function getDatasourceFunctions() {
|
||||
return array(
|
||||
'packages' => array(
|
||||
'name' => pht('Packages: ...'),
|
||||
'arguments' => pht('owner'),
|
||||
'summary' => pht("Find results in any of an owner's projects."),
|
||||
'description' => pht(
|
||||
"This function allows you to find results associated with any ".
|
||||
"of the packages a specified user or project is an owner of. ".
|
||||
"For example, this will find results associated with all of ".
|
||||
"the projects `%s` owns:\n\n%s\n\n",
|
||||
'alincoln',
|
||||
'> packages(alincoln)'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
protected function didLoadResults(array $results) {
|
||||
foreach ($results as $result) {
|
||||
$result
|
||||
->setColor(null)
|
||||
->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION)
|
||||
->setIcon('fa-asterisk')
|
||||
->setPHID('packages('.$result->getPHID().')')
|
||||
->setDisplayName(pht('Packages: %s', $result->getDisplayName()))
|
||||
->setName($result->getName().' packages');
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
protected function evaluateFunction($function, array $argv_list) {
|
||||
$phids = array();
|
||||
foreach ($argv_list as $argv) {
|
||||
$phids[] = head($argv);
|
||||
}
|
||||
|
||||
$phids = $this->resolvePHIDs($phids);
|
||||
|
||||
$user_phids = array();
|
||||
foreach ($phids as $phid) {
|
||||
if (phid_get_type($phid) == PhabricatorPeopleUserPHIDType::TYPECONST) {
|
||||
$user_phids[] = $phid;
|
||||
}
|
||||
}
|
||||
|
||||
if ($user_phids) {
|
||||
$projects = id(new PhabricatorProjectQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withMemberPHIDs($user_phids)
|
||||
->execute();
|
||||
foreach ($projects as $project) {
|
||||
$phids[] = $project->getPHID();
|
||||
}
|
||||
}
|
||||
|
||||
return $phids;
|
||||
}
|
||||
|
||||
public function renderFunctionTokens($function, array $argv_list) {
|
||||
$phids = array();
|
||||
foreach ($argv_list as $argv) {
|
||||
$phids[] = head($argv);
|
||||
}
|
||||
|
||||
$phids = $this->resolvePHIDs($phids);
|
||||
|
||||
$tokens = $this->renderTokens($phids);
|
||||
foreach ($tokens as $token) {
|
||||
$token->setColor(null);
|
||||
if ($token->isInvalid()) {
|
||||
$token
|
||||
->setValue(pht('Packages: Invalid Owner'));
|
||||
} else {
|
||||
$token
|
||||
->setIcon('fa-asterisk')
|
||||
->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION)
|
||||
->setKey('packages('.$token->getKey().')')
|
||||
->setValue(pht('Packages: %s', $token->getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
private function resolvePHIDs(array $phids) {
|
||||
|
||||
// TODO: It would be nice for this to handle `packages(#project)` from a
|
||||
// query string or eventually via Conduit. This could also share code with
|
||||
// PhabricatorProjectLogicalUserDatasource.
|
||||
|
||||
$usernames = array();
|
||||
foreach ($phids as $key => $phid) {
|
||||
if (phid_get_type($phid) != PhabricatorPeopleUserPHIDType::TYPECONST) {
|
||||
$usernames[$key] = $phid;
|
||||
}
|
||||
}
|
||||
|
||||
if ($usernames) {
|
||||
$users = id(new PhabricatorPeopleQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withUsernames($usernames)
|
||||
->execute();
|
||||
$users = mpull($users, null, 'getUsername');
|
||||
foreach ($usernames as $key => $username) {
|
||||
$user = idx($users, $username);
|
||||
if ($user) {
|
||||
$phids[$key] = $user->getPHID();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $phids;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectOrUserFunctionDatasource
|
||||
extends PhabricatorTypeaheadCompositeDatasource {
|
||||
|
||||
public function getBrowseTitle() {
|
||||
return pht('Browse Users and Projects');
|
||||
}
|
||||
|
||||
public function getPlaceholderText() {
|
||||
return pht('Type a user, project name, or function...');
|
||||
}
|
||||
|
||||
public function getComponentDatasources() {
|
||||
return array(
|
||||
new PhabricatorViewerDatasource(),
|
||||
new PhabricatorPeopleDatasource(),
|
||||
new PhabricatorProjectDatasource(),
|
||||
new PhabricatorProjectMembersDatasource(),
|
||||
new PhabricatorProjectUserFunctionDatasource(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectUserFunctionDatasource
|
||||
extends PhabricatorTypeaheadCompositeDatasource {
|
||||
|
||||
public function getBrowseTitle() {
|
||||
return pht('Browse User Projects');
|
||||
}
|
||||
|
||||
public function getPlaceholderText() {
|
||||
return pht('Type projects(<user>)...');
|
||||
}
|
||||
|
||||
public function getDatasourceApplicationClass() {
|
||||
return 'PhabricatorProjectApplication';
|
||||
}
|
||||
|
||||
public function getComponentDatasources() {
|
||||
return array(
|
||||
new PhabricatorProjectLogicalUserDatasource(),
|
||||
);
|
||||
}
|
||||
|
||||
protected function evaluateFunction($function, array $argv_list) {
|
||||
$result = parent::evaluateFunction($function, $argv_list);
|
||||
|
||||
foreach ($result as $k => $v) {
|
||||
if ($v instanceof PhabricatorQueryConstraint) {
|
||||
$result[$k] = $v->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
|
@ -98,6 +98,12 @@ final class PhabricatorRepositoryCommit
|
|||
'columns' => array('commitIdentifier', 'repositoryID'),
|
||||
'unique' => true,
|
||||
),
|
||||
'key_epoch' => array(
|
||||
'columns' => array('epoch'),
|
||||
),
|
||||
'key_author' => array(
|
||||
'columns' => array('authorPHID', 'epoch'),
|
||||
),
|
||||
),
|
||||
self::CONFIG_NO_MUTATE => array(
|
||||
'importStatus',
|
||||
|
|
Loading…
Reference in a new issue