1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-04-07 18:08:31 +02:00

Implement a "Reviewers" CustomField

Summary:
Ref T3886:

  - Adds a "Reviewers" field as a modern CustomField.

Ref T418:

  - Allows CustomFields to emit transaction metadata.

Test Plan: {F116254}

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T418, T3886

Differential Revision: https://secure.phabricator.com/D8291
This commit is contained in:
epriestley 2014-02-21 11:54:32 -08:00
parent aa7ba4c6e6
commit c5ba75ee9e
8 changed files with 165 additions and 18 deletions

View file

@ -441,6 +441,7 @@ phutil_register_library_map(array(
'DifferentialReviewedByFieldSpecification' => 'applications/differential/field/specification/DifferentialReviewedByFieldSpecification.php', 'DifferentialReviewedByFieldSpecification' => 'applications/differential/field/specification/DifferentialReviewedByFieldSpecification.php',
'DifferentialReviewer' => 'applications/differential/storage/DifferentialReviewer.php', 'DifferentialReviewer' => 'applications/differential/storage/DifferentialReviewer.php',
'DifferentialReviewerStatus' => 'applications/differential/constants/DifferentialReviewerStatus.php', 'DifferentialReviewerStatus' => 'applications/differential/constants/DifferentialReviewerStatus.php',
'DifferentialReviewersField' => 'applications/differential/customfield/DifferentialReviewersField.php',
'DifferentialReviewersFieldSpecification' => 'applications/differential/field/specification/DifferentialReviewersFieldSpecification.php', 'DifferentialReviewersFieldSpecification' => 'applications/differential/field/specification/DifferentialReviewersFieldSpecification.php',
'DifferentialReviewersView' => 'applications/differential/view/DifferentialReviewersView.php', 'DifferentialReviewersView' => 'applications/differential/view/DifferentialReviewersView.php',
'DifferentialRevision' => 'applications/differential/storage/DifferentialRevision.php', 'DifferentialRevision' => 'applications/differential/storage/DifferentialRevision.php',
@ -2979,6 +2980,7 @@ phutil_register_library_map(array(
'DifferentialRevertPlanFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialRevertPlanFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialReviewRequestMail' => 'DifferentialMail', 'DifferentialReviewRequestMail' => 'DifferentialMail',
'DifferentialReviewedByFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialReviewedByFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialReviewersField' => 'DifferentialCoreCustomField',
'DifferentialReviewersFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialReviewersFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialReviewersView' => 'AphrontView', 'DifferentialReviewersView' => 'AphrontView',
'DifferentialRevision' => 'DifferentialRevision' =>

View file

@ -0,0 +1,84 @@
<?php
final class DifferentialReviewersField
extends DifferentialCoreCustomField {
public function getFieldKey() {
return 'differential:reviewers';
}
public function getFieldName() {
return pht('Reviewers');
}
public function getFieldDescription() {
return pht('Manage reviewers.');
}
protected function readValueFromRevision(
DifferentialRevision $revision) {
return $revision->getReviewerStatus();
}
public function getNewValueForApplicationTransactions() {
$specs = array();
foreach ($this->getValue() as $reviewer) {
$specs[$reviewer->getReviewerPHID()] = array(
'data' => $reviewer->getEdgeData(),
);
}
return array('=' => $specs);
}
public function readValueFromRequest(AphrontRequest $request) {
// Compute a new set of reviewer objects. For reviewers who haven't been
// added or removed, retain their existing status. Also, respect the new
// order.
$old_status = $this->getValue();
$old_status = mpull($old_status, null, 'getReviewerPHID');
$new_phids = $request->getArr($this->getFieldKey());
$new_phids = array_fuse($new_phids);
$new_status = array();
foreach ($new_phids as $new_phid) {
if (empty($old_status[$new_phid])) {
$new_status[$new_phid] = new DifferentialReviewer(
$new_phid,
array(
'status' => DifferentialReviewerStatus::STATUS_ADDED,
));
} else {
$new_status[$new_phid] = $old_status[$new_phid];
}
}
$this->setValue($new_status);
}
public function getRequiredHandlePHIDsForEdit() {
return mpull($this->getValue(), 'getReviewerPHID');
}
public function renderEditControl(array $handles) {
return id(new AphrontFormTokenizerControl())
->setName($this->getFieldKey())
->setDatasource('/typeahead/common/usersorprojects/')
->setValue($handles)
->setError($this->getFieldError())
->setLabel($this->getFieldName());
}
public function getApplicationTransactionType() {
return PhabricatorTransactions::TYPE_EDGE;
}
public function getApplicationTransactionMetadata() {
return array(
'edge:type' => PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER,
);
}
}

View file

@ -6,11 +6,11 @@ final class DifferentialTransactionEditor
public function getTransactionTypes() { public function getTransactionTypes() {
$types = parent::getTransactionTypes(); $types = parent::getTransactionTypes();
$types[] = PhabricatorTransactions::TYPE_EDGE;
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
/* /*
$types[] = PhabricatorTransactions::TYPE_EDGE;
$types[] = DifferentialTransaction::TYPE_INLINE; $types[] = DifferentialTransaction::TYPE_INLINE;
$types[] = DifferentialTransaction::TYPE_UPDATE; $types[] = DifferentialTransaction::TYPE_UPDATE;
@ -59,6 +59,9 @@ final class DifferentialTransactionEditor
$object->setEditPolicy($xaction->getNewValue()); $object->setEditPolicy($xaction->getNewValue());
return; return;
case PhabricatorTransactions::TYPE_SUBSCRIBERS: case PhabricatorTransactions::TYPE_SUBSCRIBERS:
case PhabricatorTransactions::TYPE_EDGE:
// TODO: When removing reviewers, we may be able to move the revision
// to "Accepted".
return; return;
} }
@ -74,6 +77,7 @@ final class DifferentialTransactionEditor
case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY:
return; return;
case PhabricatorTransactions::TYPE_SUBSCRIBERS: case PhabricatorTransactions::TYPE_SUBSCRIBERS:
case PhabricatorTransactions::TYPE_EDGE:
return; return;
} }
@ -93,7 +97,6 @@ final class DifferentialTransactionEditor
return $errors; return $errors;
} }
protected function requireCapabilities( protected function requireCapabilities(
PhabricatorLiskDAO $object, PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) { PhabricatorApplicationTransaction $xaction) {

View file

@ -46,4 +46,11 @@ final class DifferentialReviewer {
return $this->authority[$viewer_phid]; return $this->authority[$viewer_phid];
} }
public function getEdgeData() {
return array(
'status' => $this->status,
'diffID' => $this->diffID,
);
}
} }

View file

@ -469,6 +469,7 @@ final class DifferentialRevision extends DifferentialDAO
new DifferentialTitleField(), new DifferentialTitleField(),
new DifferentialSummaryField(), new DifferentialSummaryField(),
new DifferentialTestPlanField(), new DifferentialTestPlanField(),
new DifferentialReviewersField(),
new DifferentialSubscribersField(), new DifferentialSubscribersField(),
new DifferentialRepositoryField(), new DifferentialRepositoryField(),
new DifferentialViewPolicyField(), new DifferentialViewPolicyField(),

View file

@ -990,21 +990,24 @@ abstract class PhabricatorApplicationTransactionEditor
} }
$result[$dst_phid] = $this->normalizeEdgeTransactionValue( $result[$dst_phid] = $this->normalizeEdgeTransactionValue(
$xaction, $xaction,
$edge); $edge,
$dst_phid);
} }
if ($new_set !== null) { if ($new_set !== null) {
foreach ($new_set as $dst_phid => $edge) { foreach ($new_set as $dst_phid => $edge) {
$result[$dst_phid] = $this->normalizeEdgeTransactionValue( $result[$dst_phid] = $this->normalizeEdgeTransactionValue(
$xaction, $xaction,
$edge); $edge,
$dst_phid);
} }
} }
foreach ($new_add as $dst_phid => $edge) { foreach ($new_add as $dst_phid => $edge) {
$result[$dst_phid] = $this->normalizeEdgeTransactionValue( $result[$dst_phid] = $this->normalizeEdgeTransactionValue(
$xaction, $xaction,
$edge); $edge,
$dst_phid);
} }
foreach ($new_rem as $dst_phid => $edge) { foreach ($new_rem as $dst_phid => $edge) {
@ -1032,18 +1035,44 @@ abstract class PhabricatorApplicationTransactionEditor
} }
} }
protected function normalizeEdgeTransactionValue( private function normalizeEdgeTransactionValue(
PhabricatorApplicationTransaction $xaction, PhabricatorApplicationTransaction $xaction,
$edge) { $edge,
$dst_phid) {
if (!is_array($edge)) { if (!is_array($edge)) {
$edge = array( if ($edge != $dst_phid) {
'dst' => $edge, throw new Exception(
); pht(
'Transaction edge data must either be the edge PHID or an edge '.
'specification dictionary.'));
}
$edge = array();
} else {
foreach ($edge as $key => $value) {
switch ($key) {
case 'src':
case 'dst':
case 'type':
case 'data':
case 'dateCreated':
case 'dateModified':
case 'seq':
case 'dataID':
break;
default:
throw new Exception(
pht(
'Transaction edge specification contains unexpected key '.
'"%s".',
$key));
}
}
} }
$edge_type = $xaction->getMetadataValue('edge:type'); $edge['dst'] = $dst_phid;
$edge_type = $xaction->getMetadataValue('edge:type');
if (empty($edge['type'])) { if (empty($edge['type'])) {
$edge['type'] = $edge_type; $edge['type'] = $edge_type;
} else { } else {

View file

@ -744,6 +744,17 @@ abstract class PhabricatorCustomField {
} }
/**
* @task appxaction
*/
public function getApplicationTransactionMetadata() {
if ($this->proxy) {
return $this->proxy->getApplicationTransactionMetadata();
}
return array();
}
/** /**
* @task appxaction * @task appxaction
*/ */

View file

@ -199,22 +199,32 @@ final class PhabricatorCustomFieldList extends Phobject {
continue; continue;
} }
$old_value = $field->getOldValueForApplicationTransactions();
$field->readValueFromRequest($request);
$transaction_type = $field->getApplicationTransactionType(); $transaction_type = $field->getApplicationTransactionType();
$xaction = id(clone $template) $xaction = id(clone $template)
->setTransactionType($transaction_type) ->setTransactionType($transaction_type);
->setMetadataValue('customfield:key', $field->getFieldKey())
->setNewValue($field->getNewValueForApplicationTransactions());
if ($transaction_type == PhabricatorTransactions::TYPE_CUSTOMFIELD) { if ($transaction_type == PhabricatorTransactions::TYPE_CUSTOMFIELD) {
// For TYPE_CUSTOMFIELD transactions only, we provide the old value // For TYPE_CUSTOMFIELD transactions only, we provide the old value
// as an input. // as an input.
$old_value = $field->getOldValueForApplicationTransactions();
$xaction->setOldValue($old_value); $xaction->setOldValue($old_value);
} }
$field->readValueFromRequest($request);
$xaction
->setNewValue($field->getNewValueForApplicationTransactions());
if ($transaction_type == PhabricatorTransactions::TYPE_CUSTOMFIELD) {
// For TYPE_CUSTOMFIELD transactions, add the field key in metadata.
$xaction->setMetadataValue('customfield:key', $field->getFieldKey());
}
$metadata = $field->getApplicationTransactionMetadata();
foreach ($metadata as $key => $value) {
$xaction->setMetadataValue($key, $value);
}
$xactions[] = $xaction; $xactions[] = $xaction;
} }