mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-22 13:30:55 +01:00
Allow blocking reviewers to be added via the web UI
Summary: Ref T10939. Adds a `blocking(...)` token. This code is pretty iffy and going to get worse before it gets better, but the fix (T10967 + EditEngine) is going to be a fair chunk of work down the road. Test Plan: {F1426966} Reviewers: chad Reviewed By: chad Subscribers: scode Maniphest Tasks: T10939 Differential Revision: https://secure.phabricator.com/D15933
This commit is contained in:
parent
875b866715
commit
afec01129a
5 changed files with 221 additions and 20 deletions
|
@ -361,6 +361,7 @@ phutil_register_library_map(array(
|
||||||
'DifferentialAuthorField' => 'applications/differential/customfield/DifferentialAuthorField.php',
|
'DifferentialAuthorField' => 'applications/differential/customfield/DifferentialAuthorField.php',
|
||||||
'DifferentialBlameRevisionField' => 'applications/differential/customfield/DifferentialBlameRevisionField.php',
|
'DifferentialBlameRevisionField' => 'applications/differential/customfield/DifferentialBlameRevisionField.php',
|
||||||
'DifferentialBlockHeraldAction' => 'applications/differential/herald/DifferentialBlockHeraldAction.php',
|
'DifferentialBlockHeraldAction' => 'applications/differential/herald/DifferentialBlockHeraldAction.php',
|
||||||
|
'DifferentialBlockingReviewerDatasource' => 'applications/differential/typeahead/DifferentialBlockingReviewerDatasource.php',
|
||||||
'DifferentialBranchField' => 'applications/differential/customfield/DifferentialBranchField.php',
|
'DifferentialBranchField' => 'applications/differential/customfield/DifferentialBranchField.php',
|
||||||
'DifferentialChangeDetailMailView' => 'applications/differential/mail/DifferentialChangeDetailMailView.php',
|
'DifferentialChangeDetailMailView' => 'applications/differential/mail/DifferentialChangeDetailMailView.php',
|
||||||
'DifferentialChangeHeraldFieldGroup' => 'applications/differential/herald/DifferentialChangeHeraldFieldGroup.php',
|
'DifferentialChangeHeraldFieldGroup' => 'applications/differential/herald/DifferentialChangeHeraldFieldGroup.php',
|
||||||
|
@ -497,6 +498,7 @@ phutil_register_library_map(array(
|
||||||
'DifferentialRevertPlanField' => 'applications/differential/customfield/DifferentialRevertPlanField.php',
|
'DifferentialRevertPlanField' => 'applications/differential/customfield/DifferentialRevertPlanField.php',
|
||||||
'DifferentialReviewedByField' => 'applications/differential/customfield/DifferentialReviewedByField.php',
|
'DifferentialReviewedByField' => 'applications/differential/customfield/DifferentialReviewedByField.php',
|
||||||
'DifferentialReviewer' => 'applications/differential/storage/DifferentialReviewer.php',
|
'DifferentialReviewer' => 'applications/differential/storage/DifferentialReviewer.php',
|
||||||
|
'DifferentialReviewerDatasource' => 'applications/differential/typeahead/DifferentialReviewerDatasource.php',
|
||||||
'DifferentialReviewerForRevisionEdgeType' => 'applications/differential/edge/DifferentialReviewerForRevisionEdgeType.php',
|
'DifferentialReviewerForRevisionEdgeType' => 'applications/differential/edge/DifferentialReviewerForRevisionEdgeType.php',
|
||||||
'DifferentialReviewerStatus' => 'applications/differential/constants/DifferentialReviewerStatus.php',
|
'DifferentialReviewerStatus' => 'applications/differential/constants/DifferentialReviewerStatus.php',
|
||||||
'DifferentialReviewersAddBlockingReviewersHeraldAction' => 'applications/differential/herald/DifferentialReviewersAddBlockingReviewersHeraldAction.php',
|
'DifferentialReviewersAddBlockingReviewersHeraldAction' => 'applications/differential/herald/DifferentialReviewersAddBlockingReviewersHeraldAction.php',
|
||||||
|
@ -4561,6 +4563,7 @@ phutil_register_library_map(array(
|
||||||
'DifferentialAuthorField' => 'DifferentialCustomField',
|
'DifferentialAuthorField' => 'DifferentialCustomField',
|
||||||
'DifferentialBlameRevisionField' => 'DifferentialStoredCustomField',
|
'DifferentialBlameRevisionField' => 'DifferentialStoredCustomField',
|
||||||
'DifferentialBlockHeraldAction' => 'HeraldAction',
|
'DifferentialBlockHeraldAction' => 'HeraldAction',
|
||||||
|
'DifferentialBlockingReviewerDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||||
'DifferentialBranchField' => 'DifferentialCustomField',
|
'DifferentialBranchField' => 'DifferentialCustomField',
|
||||||
'DifferentialChangeDetailMailView' => 'DifferentialMailView',
|
'DifferentialChangeDetailMailView' => 'DifferentialMailView',
|
||||||
'DifferentialChangeHeraldFieldGroup' => 'HeraldFieldGroup',
|
'DifferentialChangeHeraldFieldGroup' => 'HeraldFieldGroup',
|
||||||
|
@ -4713,6 +4716,7 @@ phutil_register_library_map(array(
|
||||||
'DifferentialRevertPlanField' => 'DifferentialStoredCustomField',
|
'DifferentialRevertPlanField' => 'DifferentialStoredCustomField',
|
||||||
'DifferentialReviewedByField' => 'DifferentialCoreCustomField',
|
'DifferentialReviewedByField' => 'DifferentialCoreCustomField',
|
||||||
'DifferentialReviewer' => 'Phobject',
|
'DifferentialReviewer' => 'Phobject',
|
||||||
|
'DifferentialReviewerDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||||
'DifferentialReviewerForRevisionEdgeType' => 'PhabricatorEdgeType',
|
'DifferentialReviewerForRevisionEdgeType' => 'PhabricatorEdgeType',
|
||||||
'DifferentialReviewerStatus' => 'Phobject',
|
'DifferentialReviewerStatus' => 'Phobject',
|
||||||
'DifferentialReviewersAddBlockingReviewersHeraldAction' => 'DifferentialReviewersHeraldAction',
|
'DifferentialReviewersAddBlockingReviewersHeraldAction' => 'DifferentialReviewersHeraldAction',
|
||||||
|
|
|
@ -36,43 +36,83 @@ final class DifferentialReviewersField
|
||||||
}
|
}
|
||||||
|
|
||||||
public function readValueFromRequest(AphrontRequest $request) {
|
public function readValueFromRequest(AphrontRequest $request) {
|
||||||
// Compute a new set of reviewer objects. For reviewers who haven't been
|
// Compute a new set of reviewer objects. We're going to respect the new
|
||||||
// added or removed, retain their existing status. Also, respect the new
|
// reviewer order, add or remove any missing or new reviewers, and respect
|
||||||
// order.
|
// any blocking or unblocking changes. For reviewers who were there before
|
||||||
|
// and are still there, we're going to keep the current value because it
|
||||||
|
// may be something like "Accept", "Reject", etc.
|
||||||
|
|
||||||
$old_status = $this->getValue();
|
$old_status = $this->getValue();
|
||||||
$old_status = mpull($old_status, null, 'getReviewerPHID');
|
$old_status = mpull($old_status, 'getStatus', 'getReviewerPHID');
|
||||||
|
|
||||||
|
$datasource = id(new DifferentialBlockingReviewerDatasource())
|
||||||
|
->setViewer($request->getViewer());
|
||||||
|
|
||||||
$new_phids = $request->getArr($this->getFieldKey());
|
$new_phids = $request->getArr($this->getFieldKey());
|
||||||
$new_phids = array_fuse($new_phids);
|
$new_phids = $datasource->evaluateTokens($new_phids);
|
||||||
|
|
||||||
|
$status_blocking = DifferentialReviewerStatus::STATUS_BLOCKING;
|
||||||
|
|
||||||
|
$specs = array();
|
||||||
|
foreach ($new_phids as $spec) {
|
||||||
|
if (!is_array($spec)) {
|
||||||
|
$spec = array(
|
||||||
|
'type' => DifferentialReviewerStatus::STATUS_ADDED,
|
||||||
|
'phid' => $spec,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$specs[$spec['phid']] = $spec;
|
||||||
|
}
|
||||||
|
|
||||||
$new_status = array();
|
$new_status = array();
|
||||||
foreach ($new_phids as $new_phid) {
|
foreach ($specs as $phid => $spec) {
|
||||||
if (empty($old_status[$new_phid])) {
|
$new = $spec['type'];
|
||||||
$new_status[$new_phid] = new DifferentialReviewer(
|
$old = idx($old_status, $phid);
|
||||||
$new_phid,
|
|
||||||
array(
|
// If we have an old status and this didn't make the reviewer blocking
|
||||||
'status' => DifferentialReviewerStatus::STATUS_ADDED,
|
// or nonblocking, just retain the old status. This makes sure we don't
|
||||||
));
|
// throw away rejects, accepts, etc.
|
||||||
} else {
|
if ($old) {
|
||||||
$new_status[$new_phid] = $old_status[$new_phid];
|
$is_block = ($old !== $status_blocking && $new === $status_blocking);
|
||||||
|
$is_unblock = ($old === $status_blocking && $new !== $status_blocking);
|
||||||
|
if (!$is_block && !$is_unblock) {
|
||||||
|
$new_status[$phid] = $old;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$new_status[$phid] = $new;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($new_status as $phid => $status) {
|
||||||
|
$new_status[$phid] = new DifferentialReviewer(
|
||||||
|
$phid,
|
||||||
|
array(
|
||||||
|
'status' => $status,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setValue($new_status);
|
$this->setValue($new_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function renderEditControl(array $handles) {
|
public function renderEditControl(array $handles) {
|
||||||
$phids = array();
|
$status_blocking = DifferentialReviewerStatus::STATUS_BLOCKING;
|
||||||
if ($this->getValue()) {
|
|
||||||
$phids = mpull($this->getValue(), 'getReviewerPHID');
|
$value = array();
|
||||||
|
foreach ($this->getValue() as $reviewer) {
|
||||||
|
$phid = $reviewer->getReviewerPHID();
|
||||||
|
if ($reviewer->getStatus() == $status_blocking) {
|
||||||
|
$value[] = 'blocking('.$phid.')';
|
||||||
|
} else {
|
||||||
|
$value[] = $phid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return id(new AphrontFormTokenizerControl())
|
return id(new AphrontFormTokenizerControl())
|
||||||
->setUser($this->getViewer())
|
->setUser($this->getViewer())
|
||||||
->setName($this->getFieldKey())
|
->setName($this->getFieldKey())
|
||||||
->setDatasource(new DiffusionAuditorDatasource())
|
->setDatasource(new DifferentialReviewerDatasource())
|
||||||
->setValue($phids)
|
->setValue($value)
|
||||||
->setError($this->getFieldError())
|
->setError($this->getFieldError())
|
||||||
->setLabel($this->getFieldName());
|
->setLabel($this->getFieldName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DifferentialBlockingReviewerDatasource
|
||||||
|
extends PhabricatorTypeaheadCompositeDatasource {
|
||||||
|
|
||||||
|
public function getBrowseTitle() {
|
||||||
|
return pht('Browse Blocking Reviewers');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPlaceholderText() {
|
||||||
|
return pht('Type a user, project, or package name...');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDatasourceApplicationClass() {
|
||||||
|
return 'PhabricatorDifferentialApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getComponentDatasources() {
|
||||||
|
return array(
|
||||||
|
new PhabricatorPeopleDatasource(),
|
||||||
|
new PhabricatorProjectDatasource(),
|
||||||
|
new PhabricatorOwnersPackageDatasource(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDatasourceFunctions() {
|
||||||
|
return array(
|
||||||
|
'blocking' => array(
|
||||||
|
'name' => pht('Blocking: ...'),
|
||||||
|
'arguments' => pht('reviewer'),
|
||||||
|
'summary' => pht('Select a blocking reviewer.'),
|
||||||
|
'description' => pht(
|
||||||
|
"This function allows you to add a reviewer as a blocking ".
|
||||||
|
"reviewer. For example, this will add `%s` as a blocking reviewer: ".
|
||||||
|
"\n\n%s\n\n",
|
||||||
|
'alincoln',
|
||||||
|
'> blocking(alincoln)'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function didLoadResults(array $results) {
|
||||||
|
foreach ($results as $result) {
|
||||||
|
$result
|
||||||
|
->setColor('red')
|
||||||
|
->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION)
|
||||||
|
->setIcon('fa-asterisk')
|
||||||
|
->setPHID('blocking('.$result->getPHID().')')
|
||||||
|
->setDisplayName(pht('Blocking: %s', $result->getDisplayName()))
|
||||||
|
->setName($result->getName().' blocking');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function evaluateFunction($function, array $argv_list) {
|
||||||
|
$phids = array();
|
||||||
|
foreach ($argv_list as $argv) {
|
||||||
|
$phids[] = head($argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
$phids = $this->resolvePHIDs($phids);
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($phids as $phid) {
|
||||||
|
$results[] = array(
|
||||||
|
'type' => DifferentialReviewerStatus::STATUS_BLOCKING,
|
||||||
|
'phid' => $phid,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
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('Blocking: Invalid Reviewer'));
|
||||||
|
} else {
|
||||||
|
$token
|
||||||
|
->setIcon('fa-asterisk')
|
||||||
|
->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION)
|
||||||
|
->setColor('red')
|
||||||
|
->setKey('blocking('.$token->getKey().')')
|
||||||
|
->setValue(pht('Blocking: %s', $token->getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function resolvePHIDs(array $phids) {
|
||||||
|
$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,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DifferentialReviewerDatasource
|
||||||
|
extends PhabricatorTypeaheadCompositeDatasource {
|
||||||
|
|
||||||
|
public function getBrowseTitle() {
|
||||||
|
return pht('Browse Reviewers');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPlaceholderText() {
|
||||||
|
return pht('Type a user, project, or package name...');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDatasourceApplicationClass() {
|
||||||
|
return 'PhabricatorDifferentialApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getComponentDatasources() {
|
||||||
|
return array(
|
||||||
|
new PhabricatorPeopleDatasource(),
|
||||||
|
new PhabricatorProjectDatasource(),
|
||||||
|
new PhabricatorOwnersPackageDatasource(),
|
||||||
|
new DifferentialBlockingReviewerDatasource(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -69,7 +69,9 @@ final class DifferentialAddCommentView extends AphrontView {
|
||||||
);
|
);
|
||||||
|
|
||||||
$mailable_source = new PhabricatorMetaMTAMailableDatasource();
|
$mailable_source = new PhabricatorMetaMTAMailableDatasource();
|
||||||
$reviewer_source = new PhabricatorProjectOrUserDatasource();
|
|
||||||
|
// TODO: This should be a reviewers datasource, but it's a mess.
|
||||||
|
$reviewer_source = new PhabricatorMetaMTAMailableDatasource();
|
||||||
|
|
||||||
$form = new AphrontFormView();
|
$form = new AphrontFormView();
|
||||||
$form
|
$form
|
||||||
|
|
Loading…
Reference in a new issue