diff --git a/src/applications/differential/editor/DifferentialTransactionEditor.php b/src/applications/differential/editor/DifferentialTransactionEditor.php --- a/src/applications/differential/editor/DifferentialTransactionEditor.php +++ b/src/applications/differential/editor/DifferentialTransactionEditor.php @@ -288,16 +288,26 @@ $downgrade_accepts = true; } break; + case DifferentialRevisionRequestReviewTransaction::TRANSACTIONTYPE: + $downgrade_rejects = true; + if ((!$is_sticky_accept) || + ($object->getStatus() != $status_plan)) { + // If the old state isn't "changes planned", downgrade the accepts. + // This exception allows an accepted revision to go through + // "Plan Changes" -> "Request Review" and return to "accepted" if + // the author didn't update the revision, essentially undoing the + // "Plan Changes". + $downgrade_accepts = true; + } + break; + + // TODO: Remove this, obsoleted by ModularTransactions above. case DifferentialTransaction::TYPE_ACTION: switch ($xaction->getNewValue()) { case DifferentialAction::ACTION_REQUEST: $downgrade_rejects = true; if ((!$is_sticky_accept) || ($object->getStatus() != $status_plan)) { - // If the old state isn't "changes planned", downgrade the - // accepts. This exception allows an accepted revision to - // go through Plan Changes -> Request Review to return to - // "accepted" if the author didn't update the revision. $downgrade_accepts = true; } break; @@ -353,6 +363,7 @@ } } + $is_commandeer = false; switch ($xaction->getTransactionType()) { case DifferentialTransaction::TYPE_UPDATE: if ($this->getIsCloseByCommit()) { @@ -424,6 +435,10 @@ } break; + case DifferentialRevisionCommandeerTransaction::TRANSACTIONTYPE: + $is_commandeer = true; + break; + case DifferentialTransaction::TYPE_ACTION: $action_type = $xaction->getNewValue(); @@ -463,41 +478,7 @@ break; case DifferentialAction::ACTION_CLAIM: - // If the user is commandeering, add the previous owner as a - // reviewer and remove the actor. - - $edits = array( - '-' => array( - $actor_phid => $actor_phid, - ), - ); - - $owner_phid = $object->getAuthorPHID(); - if ($owner_phid) { - $reviewer = new DifferentialReviewerProxy( - $owner_phid, - array( - 'status' => DifferentialReviewerStatus::STATUS_ADDED, - )); - - $edits['+'] = array( - $owner_phid => array( - 'data' => $reviewer->getEdgeData(), - ), - ); - } - - // NOTE: We're setting setIsCommandeerSideEffect() on this because - // normally you can't add a revision's author as a reviewer, but - // this action swaps them after validation executes. - - $results[] = id(new DifferentialTransaction()) - ->setTransactionType($type_edge) - ->setMetadataValue('edge:type', $edge_reviewer) - ->setIgnoreOnNoEffect(true) - ->setIsCommandeerSideEffect(true) - ->setNewValue($edits); - + $is_commandeer = true; break; case DifferentialAction::ACTION_RESIGN: // If the user is resigning, add a separate reviewer edit @@ -519,6 +500,10 @@ break; } + if ($is_commandeer) { + $results[] = $this->newCommandeerReviewerTransaction($object); + } + if (!$this->didExpandInlineState) { switch ($xaction->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: @@ -1499,6 +1484,10 @@ return true; } break; + case DifferentialRevisionCommandeerTransaction::TRANSACTIONTYPE: + // When users commandeer revisions, we may need to trigger + // signatures or author-based rules. + return true; case DifferentialTransaction::TYPE_ACTION: switch ($xaction->getNewValue()) { case DifferentialAction::ACTION_CLAIM: @@ -1922,4 +1911,35 @@ return $this; } + private function newCommandeerReviewerTransaction( + DifferentialRevision $revision) { + + $actor_phid = $this->getActingAsPHID(); + $owner_phid = $revision->getAuthorPHID(); + + // If the user is commandeering, add the previous owner as a + // reviewer and remove the actor. + + $edits = array( + '-' => array( + $actor_phid, + ), + '+' => array( + $owner_phid, + ), + ); + + // NOTE: We're setting setIsCommandeerSideEffect() on this because normally + // you can't add a revision's author as a reviewer, but this action swaps + // them after validation executes. + + $xaction_type = DifferentialRevisionReviewersTransaction::TRANSACTIONTYPE; + + return id(new DifferentialTransaction()) + ->setTransactionType($xaction_type) + ->setIgnoreOnNoEffect(true) + ->setIsCommandeerSideEffect(true) + ->setNewValue($edits); + } + } diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php --- a/src/applications/transactions/editengine/PhabricatorEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php @@ -1805,6 +1805,10 @@ try { $xactions = $editor->applyTransactions($object, $xactions); + } catch (PhabricatorApplicationTransactionValidationException $ex) { + return id(new PhabricatorApplicationTransactionValidationResponse()) + ->setCancelURI($view_uri) + ->setException($ex); } catch (PhabricatorApplicationTransactionNoEffectException $ex) { return id(new PhabricatorApplicationTransactionNoEffectResponse()) ->setCancelURI($view_uri)