mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 00:42:41 +01:00
Allow custom actions in Differential to explicitly override "accept" stickiness
Summary: See PHI431. Ref T13102. An install is interested in a custom "non-sticky" accept action, roughly. On the one hand, this is a pretty hacky patch. However, I suspect it inches us closer to T731, and I'm generally comfortable with exploring the realms of "Accept Next Update", "Unblock Without Accepting", etc., as long as most of it doesn't end up enabled by default in the upstream. Test Plan: - Accepted and updated revisions normally, saw accepts respect global stickiness. - Modified the "Accept" action to explicitly be unsticky, saw nonsticky accept behavior after update. Maniphest Tasks: T13102 Differential Revision: https://secure.phabricator.com/D19211
This commit is contained in:
parent
df8d4dff67
commit
1e93b49b1b
6 changed files with 78 additions and 48 deletions
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_differential.differential_reviewer
|
||||||
|
ADD options LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT};
|
|
@ -0,0 +1,2 @@
|
||||||
|
UPDATE {$NAMESPACE}_differential.differential_reviewer
|
||||||
|
SET options = '{}' WHERE options = '';
|
|
@ -154,59 +154,41 @@ final class DifferentialTransactionEditor
|
||||||
|
|
||||||
$edge_ref_task = DifferentialRevisionHasTaskEdgeType::EDGECONST;
|
$edge_ref_task = DifferentialRevisionHasTaskEdgeType::EDGECONST;
|
||||||
|
|
||||||
$is_sticky_accept = PhabricatorEnv::getEnvConfig(
|
$want_downgrade = array();
|
||||||
'differential.sticky-accept');
|
$must_downgrade = array();
|
||||||
|
|
||||||
$downgrade_rejects = false;
|
|
||||||
$downgrade_accepts = false;
|
|
||||||
if ($this->getIsCloseByCommit()) {
|
if ($this->getIsCloseByCommit()) {
|
||||||
// Never downgrade reviewers when we're closing a revision after a
|
// Never downgrade reviewers when we're closing a revision after a
|
||||||
// commit.
|
// commit.
|
||||||
} else {
|
} else {
|
||||||
switch ($xaction->getTransactionType()) {
|
switch ($xaction->getTransactionType()) {
|
||||||
case DifferentialRevisionUpdateTransaction::TRANSACTIONTYPE:
|
case DifferentialRevisionUpdateTransaction::TRANSACTIONTYPE:
|
||||||
$downgrade_rejects = true;
|
$want_downgrade[] = DifferentialReviewerStatus::STATUS_ACCEPTED;
|
||||||
if (!$is_sticky_accept) {
|
$want_downgrade[] = DifferentialReviewerStatus::STATUS_REJECTED;
|
||||||
// If "sticky accept" is disabled, also downgrade the accepts.
|
|
||||||
$downgrade_accepts = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case DifferentialRevisionRequestReviewTransaction::TRANSACTIONTYPE:
|
case DifferentialRevisionRequestReviewTransaction::TRANSACTIONTYPE:
|
||||||
$downgrade_rejects = true;
|
if (!$object->isChangePlanned()) {
|
||||||
if ((!$is_sticky_accept) ||
|
// If the old state isn't "Changes Planned", downgrade the accepts
|
||||||
(!$object->isChangePlanned())) {
|
// even if they're sticky.
|
||||||
// If the old state isn't "changes planned", downgrade the accepts.
|
|
||||||
// This exception allows an accepted revision to go through
|
// We don't downgrade for "Changes Planned" to allow an author to
|
||||||
// "Plan Changes" -> "Request Review" and return to "accepted" if
|
// undo a "Plan Changes" by immediately following it up with a
|
||||||
// the author didn't update the revision, essentially undoing the
|
// "Request Review".
|
||||||
// "Plan Changes".
|
$want_downgrade[] = DifferentialReviewerStatus::STATUS_ACCEPTED;
|
||||||
$downgrade_accepts = true;
|
$must_downgrade[] = DifferentialReviewerStatus::STATUS_ACCEPTED;
|
||||||
}
|
}
|
||||||
|
$want_downgrade[] = DifferentialReviewerStatus::STATUS_REJECTED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$new_accept = DifferentialReviewerStatus::STATUS_ACCEPTED;
|
if ($want_downgrade) {
|
||||||
$new_reject = DifferentialReviewerStatus::STATUS_REJECTED;
|
|
||||||
$old_accept = DifferentialReviewerStatus::STATUS_ACCEPTED_OLDER;
|
|
||||||
$old_reject = DifferentialReviewerStatus::STATUS_REJECTED_OLDER;
|
|
||||||
|
|
||||||
$downgrade = array();
|
|
||||||
if ($downgrade_accepts) {
|
|
||||||
$downgrade[] = DifferentialReviewerStatus::STATUS_ACCEPTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($downgrade_rejects) {
|
|
||||||
$downgrade[] = DifferentialReviewerStatus::STATUS_REJECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($downgrade) {
|
|
||||||
$void_type = DifferentialRevisionVoidTransaction::TRANSACTIONTYPE;
|
$void_type = DifferentialRevisionVoidTransaction::TRANSACTIONTYPE;
|
||||||
|
|
||||||
$results[] = id(new DifferentialTransaction())
|
$results[] = id(new DifferentialTransaction())
|
||||||
->setTransactionType($void_type)
|
->setTransactionType($void_type)
|
||||||
->setIgnoreOnNoEffect(true)
|
->setIgnoreOnNoEffect(true)
|
||||||
->setNewValue($downgrade);
|
->setMetadataValue('void.force', $must_downgrade)
|
||||||
|
->setNewValue($want_downgrade);
|
||||||
}
|
}
|
||||||
|
|
||||||
$is_commandeer = false;
|
$is_commandeer = false;
|
||||||
|
|
|
@ -10,12 +10,16 @@ final class DifferentialReviewer
|
||||||
protected $lastCommentDiffPHID;
|
protected $lastCommentDiffPHID;
|
||||||
protected $lastActorPHID;
|
protected $lastActorPHID;
|
||||||
protected $voidedPHID;
|
protected $voidedPHID;
|
||||||
|
protected $options = array();
|
||||||
|
|
||||||
private $authority = array();
|
private $authority = array();
|
||||||
private $changesets = self::ATTACHABLE;
|
private $changesets = self::ATTACHABLE;
|
||||||
|
|
||||||
protected function getConfiguration() {
|
protected function getConfiguration() {
|
||||||
return array(
|
return array(
|
||||||
|
self::CONFIG_SERIALIZATION => array(
|
||||||
|
'options' => self::SERIALIZATION_JSON,
|
||||||
|
),
|
||||||
self::CONFIG_COLUMN_SCHEMA => array(
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
'reviewerStatus' => 'text64',
|
'reviewerStatus' => 'text64',
|
||||||
'lastActionDiffPHID' => 'phid?',
|
'lastActionDiffPHID' => 'phid?',
|
||||||
|
@ -64,6 +68,15 @@ final class DifferentialReviewer
|
||||||
return $this->assertAttached($this->changesets);
|
return $this->assertAttached($this->changesets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setOption($key, $value) {
|
||||||
|
$this->options[$key] = $value;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOption($key, $default = null) {
|
||||||
|
return idx($this->options, $key, $default);
|
||||||
|
}
|
||||||
|
|
||||||
public function isResigned() {
|
public function isResigned() {
|
||||||
$status_resigned = DifferentialReviewerStatus::STATUS_RESIGNED;
|
$status_resigned = DifferentialReviewerStatus::STATUS_RESIGNED;
|
||||||
return ($this->getReviewerStatus() == $status_resigned);
|
return ($this->getReviewerStatus() == $status_resigned);
|
||||||
|
|
|
@ -164,7 +164,14 @@ abstract class DifferentialRevisionReviewTransaction
|
||||||
DifferentialRevision $revision,
|
DifferentialRevision $revision,
|
||||||
PhabricatorUser $viewer,
|
PhabricatorUser $viewer,
|
||||||
$value,
|
$value,
|
||||||
$status) {
|
$status,
|
||||||
|
array $reviewer_options = array()) {
|
||||||
|
|
||||||
|
PhutilTypeSpec::checkMap(
|
||||||
|
$reviewer_options,
|
||||||
|
array(
|
||||||
|
'sticky' => 'optional bool',
|
||||||
|
));
|
||||||
|
|
||||||
$map = array();
|
$map = array();
|
||||||
|
|
||||||
|
@ -253,6 +260,8 @@ abstract class DifferentialRevisionReviewTransaction
|
||||||
// accepted.
|
// accepted.
|
||||||
$reviewer->setVoidedPHID(null);
|
$reviewer->setVoidedPHID(null);
|
||||||
|
|
||||||
|
$reviewer->setOption('sticky', idx($reviewer_options, 'sticky'));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$reviewer->save();
|
$reviewer->save();
|
||||||
} catch (AphrontDuplicateKeyQueryException $ex) {
|
} catch (AphrontDuplicateKeyQueryException $ex) {
|
||||||
|
|
|
@ -16,21 +16,43 @@ final class DifferentialRevisionVoidTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateNewValue($object, $value) {
|
public function generateNewValue($object, $value) {
|
||||||
$table = new DifferentialReviewer();
|
$reviewers = id(new DifferentialReviewer())->loadAllWhere(
|
||||||
$table_name = $table->getTableName();
|
'revisionPHID = %s
|
||||||
$conn = $table->establishConnection('w');
|
|
||||||
|
|
||||||
$rows = queryfx_all(
|
|
||||||
$conn,
|
|
||||||
'SELECT reviewerPHID FROM %T
|
|
||||||
WHERE revisionPHID = %s
|
|
||||||
AND voidedPHID IS NULL
|
AND voidedPHID IS NULL
|
||||||
AND reviewerStatus IN (%Ls)',
|
AND reviewerStatus IN (%Ls)',
|
||||||
$table_name,
|
|
||||||
$object->getPHID(),
|
$object->getPHID(),
|
||||||
$value);
|
$value);
|
||||||
|
|
||||||
return ipull($rows, 'reviewerPHID');
|
$must_downgrade = $this->getMetadataValue('void.force', array());
|
||||||
|
$must_downgrade = array_fuse($must_downgrade);
|
||||||
|
|
||||||
|
$default = PhabricatorEnv::getEnvConfig('differential.sticky-accept');
|
||||||
|
foreach ($reviewers as $key => $reviewer) {
|
||||||
|
$status = $reviewer->getReviewerStatus();
|
||||||
|
|
||||||
|
// If this void is forced, always downgrade. For example, this happens
|
||||||
|
// when an author chooses "Request Review": existing reviews are always
|
||||||
|
// voided, even if they're sticky.
|
||||||
|
if (isset($must_downgrade[$status])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, if this is a sticky accept, don't void it. Accepts may be
|
||||||
|
// explicitly sticky or unsticky, or they'll use the default value if
|
||||||
|
// no value is specified.
|
||||||
|
$is_sticky = $reviewer->getOption('sticky');
|
||||||
|
$is_sticky = coalesce($is_sticky, $default);
|
||||||
|
|
||||||
|
if ($status === DifferentialReviewerStatus::STATUS_ACCEPTED) {
|
||||||
|
if ($is_sticky) {
|
||||||
|
unset($reviewers[$key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return mpull($reviewers, 'getReviewerPHID');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTransactionHasEffect($object, $old, $new) {
|
public function getTransactionHasEffect($object, $old, $new) {
|
||||||
|
|
Loading…
Reference in a new issue