public static function indexRevision(DifferentialRevision $rev) { $doc = new PhabricatorSearchAbstractDocument(); $doc->setPHID($rev->getPHID()); $doc->setDocumentType(PhabricatorPHIDConstants::PHID_TYPE_DREV); $doc->setDocumentTitle($rev->getTitle()); $doc->setDocumentCreated($rev->getDateCreated()); $doc->setDocumentModified($rev->getDateModified()); $doc->addField(PhabricatorSearchField::FIELD_BODY, $rev->getSummary()); $doc->addField(PhabricatorSearchField::FIELD_TEST_PLAN, $rev->getTestPlan()); $doc->addRelationship(PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR, $rev->getAuthorPHID(), PhabricatorPHIDConstants::PHID_TYPE_USER, $rev->getDateCreated()); if ($rev->getStatus() != ArcanistDifferentialRevisionStatus::CLOSED && $rev->getStatus() != ArcanistDifferentialRevisionStatus::ABANDONED) { $doc->addRelationship(PhabricatorSearchRelationship::RELATIONSHIP_OPEN, $rev->getPHID(), PhabricatorPHIDConstants::PHID_TYPE_DREV, time()); } $comments = id(new DifferentialComment())->loadAllWhere('revisionID = %d', $rev->getID()); $inlines = id(new DifferentialInlineComment())->loadAllWhere('revisionID = %d AND commentID IS NOT NULL', $rev->getID()); $touches = array(); foreach (array_merge($comments, $inlines) as $comment) { if (strlen($comment->getContent())) { $doc->addField(PhabricatorSearchField::FIELD_COMMENT, $comment->getContent()); } $author = $comment->getAuthorPHID(); $touches[$author] = $comment->getDateCreated(); } foreach ($touches as $touch => $time) { $doc->addRelationship(PhabricatorSearchRelationship::RELATIONSHIP_TOUCH, $touch, PhabricatorPHIDConstants::PHID_TYPE_USER, $time); } $rev->loadRelationships(); // If a revision needs review, the owners are the reviewers. Otherwise, the // owner is the author (e.g., accepted, rejected, closed). if ($rev->getStatus() == ArcanistDifferentialRevisionStatus::NEEDS_REVIEW) { foreach ($rev->getReviewers() as $phid) { $doc->addRelationship(PhabricatorSearchRelationship::RELATIONSHIP_OWNER, $phid, PhabricatorPHIDConstants::PHID_TYPE_USER, $rev->getDateModified()); // Bogus timestamp. } } else { $doc->addRelationship(PhabricatorSearchRelationship::RELATIONSHIP_OWNER, $rev->getAuthorPHID(), PhabricatorPHIDConstants::PHID_TYPE_USER, $rev->getDateCreated()); } $ccphids = $rev->getCCPHIDs(); $handles = id(new PhabricatorObjectHandleData($ccphids))->loadHandles(); foreach ($handles as $phid => $handle) { $doc->addRelationship(PhabricatorSearchRelationship::RELATIONSHIP_SUBSCRIBER, $phid, $handle->getType(), $rev->getDateModified()); // Bogus timestamp. } self::reindexAbstractDocument($doc); }
public function commitRevisionToWorkspace(DifferentialRevision $revision, ArcanistRepositoryAPI $workspace, PhabricatorUser $user) { $diff_id = $revision->loadActiveDiff()->getID(); $call = new ConduitCall('differential.getrawdiff', array('diffID' => $diff_id)); $call->setUser($user); $raw_diff = $call->execute(); $future = $workspace->execFutureLocal('patch --no-commit -'); $future->write($raw_diff); $future->resolvex(); $workspace->reloadWorkingCopy(); $call = new ConduitCall('differential.getcommitmessage', array('revision_id' => $revision->getID())); $call->setUser($user); $message = $call->execute(); $author = id(new PhabricatorUser())->loadOneWhere('phid = %s', $revision->getAuthorPHID()); $author_string = sprintf('%s <%s>', $author->getRealName(), $author->loadPrimaryEmailAddress()); $author_date = $revision->getDateCreated(); $workspace->execxLocal('commit --date=%s --user=%s ' . '--message=%s', $author_date . ' 0', $author_string, $message); }
public function commitRevisionToWorkspace(DifferentialRevision $revision, ArcanistRepositoryAPI $workspace, PhabricatorUser $user) { $diff_id = $revision->loadActiveDiff()->getID(); $call = new ConduitCall('differential.getrawdiff', array('diffID' => $diff_id)); $call->setUser($user); $raw_diff = $call->execute(); $missing_binary = "\nindex " . "0000000000000000000000000000000000000000.." . "0000000000000000000000000000000000000000\n"; if (strpos($raw_diff, $missing_binary) !== false) { throw new Exception(pht('Patch is missing content for a binary file')); } $future = $workspace->execFutureLocal('apply --index -'); $future->write($raw_diff); $future->resolvex(); $workspace->reloadWorkingCopy(); $call = new ConduitCall('differential.getcommitmessage', array('revision_id' => $revision->getID())); $call->setUser($user); $message = $call->execute(); $author = id(new PhabricatorUser())->loadOneWhere('phid = %s', $revision->getAuthorPHID()); $author_string = sprintf('%s <%s>', $author->getRealName(), $author->loadPrimaryEmailAddress()); $author_date = $revision->getDateCreated(); $workspace->execxLocal('-c user.name=%s -c user.email=%s ' . 'commit --date=%s --author=%s ' . '--message=%s', $user->getRealName(), $user->loadPrimaryEmailAddress(), $author_date, $author_string, $message); }
private function getRevisionCommentActions(DifferentialRevision $revision) { $actions = array(DifferentialAction::ACTION_COMMENT => true); $viewer = $this->getRequest()->getUser(); $viewer_phid = $viewer->getPHID(); $viewer_is_owner = $viewer_phid == $revision->getAuthorPHID(); $viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers()); $status = $revision->getStatus(); $viewer_has_accepted = false; $viewer_has_rejected = false; $status_accepted = DifferentialReviewerStatus::STATUS_ACCEPTED; $status_rejected = DifferentialReviewerStatus::STATUS_REJECTED; foreach ($revision->getReviewerStatus() as $reviewer) { if ($reviewer->getReviewerPHID() == $viewer_phid) { if ($reviewer->getStatus() == $status_accepted) { $viewer_has_accepted = true; } if ($reviewer->getStatus() == $status_rejected) { $viewer_has_rejected = true; } break; } } $allow_self_accept = PhabricatorEnv::getEnvConfig('differential.allow-self-accept'); $always_allow_abandon = PhabricatorEnv::getEnvConfig('differential.always-allow-abandon'); $always_allow_close = PhabricatorEnv::getEnvConfig('differential.always-allow-close'); $allow_reopen = PhabricatorEnv::getEnvConfig('differential.allow-reopen'); if ($viewer_is_owner) { switch ($status) { case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW: $actions[DifferentialAction::ACTION_ACCEPT] = $allow_self_accept; $actions[DifferentialAction::ACTION_ABANDON] = true; $actions[DifferentialAction::ACTION_RETHINK] = true; break; case ArcanistDifferentialRevisionStatus::NEEDS_REVISION: case ArcanistDifferentialRevisionStatus::CHANGES_PLANNED: $actions[DifferentialAction::ACTION_ACCEPT] = $allow_self_accept; $actions[DifferentialAction::ACTION_ABANDON] = true; $actions[DifferentialAction::ACTION_REQUEST] = true; break; case ArcanistDifferentialRevisionStatus::ACCEPTED: $actions[DifferentialAction::ACTION_ABANDON] = true; $actions[DifferentialAction::ACTION_REQUEST] = true; $actions[DifferentialAction::ACTION_RETHINK] = true; $actions[DifferentialAction::ACTION_CLOSE] = true; break; case ArcanistDifferentialRevisionStatus::CLOSED: break; case ArcanistDifferentialRevisionStatus::ABANDONED: $actions[DifferentialAction::ACTION_RECLAIM] = true; break; } } else { switch ($status) { case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW: $actions[DifferentialAction::ACTION_ABANDON] = $always_allow_abandon; $actions[DifferentialAction::ACTION_ACCEPT] = true; $actions[DifferentialAction::ACTION_REJECT] = true; $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer; break; case ArcanistDifferentialRevisionStatus::NEEDS_REVISION: case ArcanistDifferentialRevisionStatus::CHANGES_PLANNED: $actions[DifferentialAction::ACTION_ABANDON] = $always_allow_abandon; $actions[DifferentialAction::ACTION_ACCEPT] = true; $actions[DifferentialAction::ACTION_REJECT] = !$viewer_has_rejected; $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer; break; case ArcanistDifferentialRevisionStatus::ACCEPTED: $actions[DifferentialAction::ACTION_ABANDON] = $always_allow_abandon; $actions[DifferentialAction::ACTION_ACCEPT] = !$viewer_has_accepted; $actions[DifferentialAction::ACTION_REJECT] = true; $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer; break; case ArcanistDifferentialRevisionStatus::CLOSED: case ArcanistDifferentialRevisionStatus::ABANDONED: break; } if ($status != ArcanistDifferentialRevisionStatus::CLOSED) { $actions[DifferentialAction::ACTION_CLAIM] = true; $actions[DifferentialAction::ACTION_CLOSE] = $always_allow_close; } } $actions[DifferentialAction::ACTION_ADDREVIEWERS] = true; $actions[DifferentialAction::ACTION_ADDCCS] = true; $actions[DifferentialAction::ACTION_REOPEN] = $allow_reopen && $status == ArcanistDifferentialRevisionStatus::CLOSED; $actions = array_keys(array_filter($actions)); $actions_dict = array(); foreach ($actions as $action) { $actions_dict[$action] = DifferentialAction::getActionVerb($action); } return $actions_dict; }
private function validateDifferentialAction(DifferentialRevision $revision, $type, DifferentialTransaction $xaction, $action) { $author_phid = $revision->getAuthorPHID(); $actor_phid = $this->getActingAsPHID(); $actor_is_author = $author_phid == $actor_phid; $config_abandon_key = 'differential.always-allow-abandon'; $always_allow_abandon = PhabricatorEnv::getEnvConfig($config_abandon_key); $config_close_key = 'differential.always-allow-close'; $always_allow_close = PhabricatorEnv::getEnvConfig($config_close_key); $config_reopen_key = 'differential.allow-reopen'; $allow_reopen = PhabricatorEnv::getEnvConfig($config_reopen_key); $config_self_accept_key = 'differential.allow-self-accept'; $allow_self_accept = PhabricatorEnv::getEnvConfig($config_self_accept_key); $revision_status = $revision->getStatus(); $status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED; $status_abandoned = ArcanistDifferentialRevisionStatus::ABANDONED; $status_closed = ArcanistDifferentialRevisionStatus::CLOSED; switch ($action) { case DifferentialAction::ACTION_ACCEPT: if ($actor_is_author && !$allow_self_accept) { return pht('You can not accept this revision because you are the owner.'); } if ($revision_status == $status_abandoned) { return pht('You can not accept this revision because it has been ' . 'abandoned.'); } if ($revision_status == $status_closed) { return pht('You can not accept this revision because it has already been ' . 'closed.'); } // TODO: It would be nice to make this generic at some point. $signatures = DifferentialRequiredSignaturesField::loadForRevision($revision); foreach ($signatures as $phid => $signed) { if (!$signed) { return pht('You can not accept this revision because the author has ' . 'not signed all of the required legal documents.'); } } break; case DifferentialAction::ACTION_REJECT: if ($actor_is_author) { return pht('You can not request changes to your own revision.'); } if ($revision_status == $status_abandoned) { return pht('You can not request changes to this revision because it has been ' . 'abandoned.'); } if ($revision_status == $status_closed) { return pht('You can not request changes to this revision because it has ' . 'already been closed.'); } break; case DifferentialAction::ACTION_RESIGN: // You can always resign from a revision if you're a reviewer. If you // aren't, this is a no-op rather than invalid. break; case DifferentialAction::ACTION_CLAIM: // You can claim a revision if you're not the owner. If you are, this // is a no-op rather than invalid. if ($revision_status == $status_closed) { return pht('You can not commandeer this revision because it has already been ' . 'closed.'); } break; case DifferentialAction::ACTION_ABANDON: if (!$actor_is_author && !$always_allow_abandon) { return pht('You can not abandon this revision because you do not own it. ' . 'You can only abandon revisions you own.'); } if ($revision_status == $status_closed) { return pht('You can not abandon this revision because it has already been ' . 'closed.'); } // NOTE: Abandons of already-abandoned revisions are treated as no-op // instead of invalid. Other abandons are OK. break; case DifferentialAction::ACTION_RECLAIM: if (!$actor_is_author) { return pht('You can not reclaim this revision because you do not own ' . 'it. You can only reclaim revisions you own.'); } if ($revision_status == $status_closed) { return pht('You can not reclaim this revision because it has already been ' . 'closed.'); } // NOTE: Reclaims of other non-abandoned revisions are treated as no-op // instead of invalid. break; case DifferentialAction::ACTION_REOPEN: if (!$allow_reopen) { return pht('The reopen action is not enabled on this Phabricator install. ' . 'Adjust your configuration to enable it.'); } // NOTE: If the revision is not closed, this is caught as a no-op // instead of an invalid transaction. break; case DifferentialAction::ACTION_RETHINK: if (!$actor_is_author) { return pht('You can not plan changes to this revision because you do not ' . 'own it. To plan changes to a revision, you must be its owner.'); } switch ($revision_status) { case ArcanistDifferentialRevisionStatus::ACCEPTED: case ArcanistDifferentialRevisionStatus::NEEDS_REVISION: case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW: // These are OK. break; case ArcanistDifferentialRevisionStatus::CHANGES_PLANNED: // Let this through, it's a no-op. break; case ArcanistDifferentialRevisionStatus::ABANDONED: return pht('You can not plan changes to this revision because it has ' . 'been abandoned.'); case ArcanistDifferentialRevisionStatus::CLOSED: return pht('You can not plan changes to this revision because it has ' . 'already been closed.'); default: throw new Exception(pht('Encountered unexpected revision status ("%s") when ' . 'validating "%s" action.', $revision_status, $action)); } break; case DifferentialAction::ACTION_REQUEST: if (!$actor_is_author) { return pht('You can not request review of this revision because you do ' . 'not own it. To request review of a revision, you must be its ' . 'owner.'); } switch ($revision_status) { case ArcanistDifferentialRevisionStatus::ACCEPTED: case ArcanistDifferentialRevisionStatus::NEEDS_REVISION: case ArcanistDifferentialRevisionStatus::CHANGES_PLANNED: // These are OK. break; case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW: // This will be caught as "no effect" later on. break; case ArcanistDifferentialRevisionStatus::ABANDONED: return pht('You can not request review of this revision because it has ' . 'been abandoned. Instead, reclaim it.'); case ArcanistDifferentialRevisionStatus::CLOSED: return pht('You can not request review of this revision because it has ' . 'already been closed.'); default: throw new Exception(pht('Encountered unexpected revision status ("%s") when ' . 'validating "%s" action.', $revision_status, $action)); } break; case DifferentialAction::ACTION_CLOSE: // We force revisions closed when we discover a corresponding commit. // In this case, revisions are allowed to transition to closed from // any state. This is an automated action taken by the daemons. if (!$this->getIsCloseByCommit()) { if (!$actor_is_author && !$always_allow_close) { return pht('You can not close this revision because you do not own it. To ' . 'close a revision, you must be its owner.'); } if ($revision_status != $status_accepted) { return pht('You can not close this revision because it has not been ' . 'accepted. You can only close accepted revisions.'); } } break; } return null; }
private function renderRevisionTooltip(DifferentialRevision $revision, $handles) { $viewer = $this->getRequest()->getUser(); $date = phabricator_date($revision->getDateModified(), $viewer); $id = $revision->getID(); $title = $revision->getTitle(); $header = "D{$id} {$title}"; $author = $handles[$revision->getAuthorPHID()]->getName(); return "{$header}\n{$date} · {$author}"; }
private function getRevisionCommentActions(DifferentialRevision $revision) { $actions = array(DifferentialAction::ACTION_COMMENT => true); $viewer = $this->getRequest()->getUser(); $viewer_phid = $viewer->getPHID(); $viewer_is_owner = $viewer_phid == $revision->getAuthorPHID(); $viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers()); $viewer_did_accept = $viewer_phid === $revision->loadReviewedBy(); $status = $revision->getStatus(); $allow_self_accept = PhabricatorEnv::getEnvConfig('differential.allow-self-accept', false); if ($viewer_is_owner) { switch ($status) { case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW: $actions[DifferentialAction::ACTION_ACCEPT] = $allow_self_accept; $actions[DifferentialAction::ACTION_ABANDON] = true; $actions[DifferentialAction::ACTION_RETHINK] = true; break; case ArcanistDifferentialRevisionStatus::NEEDS_REVISION: $actions[DifferentialAction::ACTION_ACCEPT] = $allow_self_accept; $actions[DifferentialAction::ACTION_ABANDON] = true; $actions[DifferentialAction::ACTION_REQUEST] = true; break; case ArcanistDifferentialRevisionStatus::ACCEPTED: $actions[DifferentialAction::ACTION_ABANDON] = true; $actions[DifferentialAction::ACTION_REQUEST] = true; $actions[DifferentialAction::ACTION_RETHINK] = true; $actions[DifferentialAction::ACTION_CLOSE] = true; break; case ArcanistDifferentialRevisionStatus::CLOSED: break; case ArcanistDifferentialRevisionStatus::ABANDONED: $actions[DifferentialAction::ACTION_RECLAIM] = true; break; } } else { switch ($status) { case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW: $actions[DifferentialAction::ACTION_ACCEPT] = true; $actions[DifferentialAction::ACTION_REJECT] = true; $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer; break; case ArcanistDifferentialRevisionStatus::NEEDS_REVISION: $actions[DifferentialAction::ACTION_ACCEPT] = true; $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer; break; case ArcanistDifferentialRevisionStatus::ACCEPTED: $actions[DifferentialAction::ACTION_REJECT] = true; $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer && !$viewer_did_accept; break; case ArcanistDifferentialRevisionStatus::CLOSED: case ArcanistDifferentialRevisionStatus::ABANDONED: break; } if ($status != ArcanistDifferentialRevisionStatus::CLOSED) { $actions[DifferentialAction::ACTION_CLAIM] = true; } } $actions[DifferentialAction::ACTION_ADDREVIEWERS] = true; $actions[DifferentialAction::ACTION_ADDCCS] = true; $actions = array_keys(array_filter($actions)); $actions_dict = array(); foreach ($actions as $action) { $actions_dict[$action] = DifferentialAction::getActionVerb($action); } return $actions_dict; }
private function initializeNewRevision(DifferentialRevision $revision) { // These fields aren't nullable; set them to sensible defaults if they // haven't been configured. We're just doing this so we can generate an // ID for the revision if we don't have one already. $revision->setLineCount(0); if ($revision->getStatus() === null) { $revision->setStatus(ArcanistDifferentialRevisionStatus::NEEDS_REVIEW); } if ($revision->getTitle() === null) { $revision->setTitle('Untitled Revision'); } if ($revision->getAuthorPHID() === null) { $revision->setAuthorPHID($this->getActorPHID()); } if ($revision->getSummary() === null) { $revision->setSummary(''); } if ($revision->getTestPlan() === null) { $revision->setTestPlan(''); } }
public function getRequiredHandlePHIDsForRevisionList(DifferentialRevision $revision) { return array($revision->getAuthorPHID()); }
private function getRevisionCommentActions(DifferentialRevision $revision) { $actions = array(DifferentialAction::ACTION_COMMENT => true); $admin_actions = array(); $viewer = $this->getRequest()->getUser(); $viewer_phid = $viewer->getPHID(); $viewer_is_admin = $viewer->getIsAdmin(); $viewer_is_owner = $viewer_phid == $revision->getAuthorPHID(); $viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers()); $viewer_did_accept = $viewer_phid === $revision->loadReviewedBy(); if ($viewer_is_owner) { switch ($revision->getStatus()) { case DifferentialRevisionStatus::NEEDS_REVIEW: $actions[DifferentialAction::ACTION_ABANDON] = true; $actions[DifferentialAction::ACTION_RETHINK] = true; break; case DifferentialRevisionStatus::NEEDS_REVISION: $actions[DifferentialAction::ACTION_ABANDON] = true; $actions[DifferentialAction::ACTION_REQUEST] = true; break; case DifferentialRevisionStatus::ACCEPTED: $actions[DifferentialAction::ACTION_ABANDON] = true; $actions[DifferentialAction::ACTION_REQUEST] = true; $actions[DifferentialAction::ACTION_RETHINK] = true; break; case DifferentialRevisionStatus::COMMITTED: break; case DifferentialRevisionStatus::ABANDONED: $actions[DifferentialAction::ACTION_RECLAIM] = true; break; } } else { switch ($revision->getStatus()) { case DifferentialRevisionStatus::NEEDS_REVIEW: $admin_actions[DifferentialAction::ACTION_ABANDON] = $viewer_is_admin; $actions[DifferentialAction::ACTION_ACCEPT] = true; $actions[DifferentialAction::ACTION_REJECT] = true; $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer; break; case DifferentialRevisionStatus::NEEDS_REVISION: $admin_actions[DifferentialAction::ACTION_ABANDON] = $viewer_is_admin; $actions[DifferentialAction::ACTION_ACCEPT] = true; $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer; break; case DifferentialRevisionStatus::ACCEPTED: $admin_actions[DifferentialAction::ACTION_ABANDON] = $viewer_is_admin; $actions[DifferentialAction::ACTION_REJECT] = true; $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer && !$viewer_did_accept; break; case DifferentialRevisionStatus::COMMITTED: case DifferentialRevisionStatus::ABANDONED: break; } } $actions[DifferentialAction::ACTION_ADDREVIEWERS] = true; $actions[DifferentialAction::ACTION_ADDCCS] = true; $actions = array_keys(array_filter($actions)); $admin_actions = array_keys(array_filter($admin_actions)); $actions_dict = array(); foreach ($actions as $action) { $actions_dict[$action] = DifferentialAction::getActionVerb($action); } foreach ($admin_actions as $action) { $actions_dict[$action] = '(Admin) ' . DifferentialAction::getActionVerb($action); } return $actions_dict; }
private function getRevisionCommentActions(DifferentialRevision $revision) { $actions = array(DifferentialAction::ACTION_COMMENT => true); $viewer_phid = $this->getRequest()->getUser()->getPHID(); $viewer_is_owner = $viewer_phid == $revision->getAuthorPHID(); $viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers()); if ($viewer_is_owner) { switch ($revision->getStatus()) { case DifferentialRevisionStatus::NEEDS_REVIEW: $actions[DifferentialAction::ACTION_ABANDON] = true; $actions[DifferentialAction::ACTION_RETHINK] = true; break; case DifferentialRevisionStatus::NEEDS_REVISION: $actions[DifferentialAction::ACTION_ABANDON] = true; $actions[DifferentialAction::ACTION_REQUEST] = true; break; case DifferentialRevisionStatus::ACCEPTED: $actions[DifferentialAction::ACTION_ABANDON] = true; $actions[DifferentialAction::ACTION_REQUEST] = true; $actions[DifferentialAction::ACTION_RETHINK] = true; break; case DifferentialRevisionStatus::COMMITTED: break; case DifferentialRevisionStatus::ABANDONED: $actions[DifferentialAction::ACTION_RECLAIM] = true; break; } } else { switch ($revision->getStatus()) { case DifferentialRevisionStatus::NEEDS_REVIEW: $actions[DifferentialAction::ACTION_ACCEPT] = true; $actions[DifferentialAction::ACTION_REJECT] = true; $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer; break; case DifferentialRevisionStatus::NEEDS_REVISION: $actions[DifferentialAction::ACTION_ACCEPT] = true; $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer; break; case DifferentialRevisionStatus::ACCEPTED: $actions[DifferentialAction::ACTION_REJECT] = true; break; case DifferentialRevisionStatus::COMMITTED: case DifferentialRevisionStatus::ABANDONED: break; } } $actions[DifferentialAction::ACTION_ADDREVIEWERS] = true; $actions[DifferentialAction::ACTION_ADDCCS] = true; return array_keys(array_filter($actions)); }