2016-12-28 13:05:04 -08:00
|
|
|
<?php
|
|
|
|
|
|
|
|
final class DifferentialRevisionCloseTransaction
|
|
|
|
extends DifferentialRevisionActionTransaction {
|
|
|
|
|
|
|
|
const TRANSACTIONTYPE = 'differential.revision.close';
|
|
|
|
const ACTIONKEY = 'close';
|
|
|
|
|
|
|
|
protected function getRevisionActionLabel() {
|
|
|
|
return pht('Close Revision');
|
|
|
|
}
|
|
|
|
|
2017-09-18 14:14:52 -07:00
|
|
|
protected function getRevisionActionDescription(
|
|
|
|
DifferentialRevision $revision) {
|
2016-12-28 13:05:04 -08:00
|
|
|
return pht('This revision will be closed.');
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getIcon() {
|
|
|
|
return 'fa-check';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getColor() {
|
|
|
|
return 'indigo';
|
|
|
|
}
|
|
|
|
|
Order actions sensibly within Differential revision comment action groups
Summary:
Ref T11114. See D17114 for some discussion.
For review actions: accept, reject, resign.
For revision actions, order is basically least-severe to most-severe action pairs: plan changes, request review, close, reopen, abandon, reclaim, commandeer.
Test Plan: Viewed revisions as an author and a reviewer, saw sensible action order within action groups.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T11114
Differential Revision: https://secure.phabricator.com/D17115
2016-12-29 13:36:36 -08:00
|
|
|
protected function getRevisionActionOrder() {
|
|
|
|
return 300;
|
|
|
|
}
|
|
|
|
|
2017-01-12 07:40:48 -08:00
|
|
|
public function getActionName() {
|
|
|
|
return pht('Closed');
|
|
|
|
}
|
|
|
|
|
2016-12-28 13:05:04 -08:00
|
|
|
public function generateOldValue($object) {
|
|
|
|
return $object->isClosed();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function applyInternalEffects($object, $value) {
|
2017-08-11 13:23:41 -07:00
|
|
|
$was_accepted = $object->isAccepted();
|
2016-12-28 13:05:04 -08:00
|
|
|
|
2017-08-11 15:49:05 -07:00
|
|
|
$status_published = DifferentialRevisionStatus::PUBLISHED;
|
|
|
|
$object->setModernRevisionStatus($status_published);
|
2016-12-28 13:05:04 -08:00
|
|
|
|
|
|
|
$object->setProperty(
|
|
|
|
DifferentialRevision::PROPERTY_CLOSED_FROM_ACCEPTED,
|
|
|
|
$was_accepted);
|
2019-05-31 06:15:28 -07:00
|
|
|
|
|
|
|
// See T13300. When a revision is closed, we promote it out of "Draft"
|
|
|
|
// immediately. This usually happens when a user creates a draft revision
|
|
|
|
// and then lands the associated commit before the revision leaves draft.
|
|
|
|
$object->setShouldBroadcast(true);
|
2016-12-28 13:05:04 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function validateAction($object, PhabricatorUser $viewer) {
|
2017-08-29 09:54:03 -07:00
|
|
|
if ($this->hasEditor()) {
|
|
|
|
if ($this->getEditor()->getIsCloseByCommit()) {
|
|
|
|
// If we're closing a revision because we discovered a commit, we don't
|
|
|
|
// care what state it was in.
|
|
|
|
return;
|
|
|
|
}
|
2017-08-11 14:47:39 -07:00
|
|
|
}
|
|
|
|
|
2016-12-28 13:05:04 -08:00
|
|
|
if ($object->isClosed()) {
|
|
|
|
throw new Exception(
|
|
|
|
pht(
|
|
|
|
'You can not close this revision because it has already been '.
|
|
|
|
'closed. Only open revisions can be closed.'));
|
|
|
|
}
|
|
|
|
|
Order actions sensibly within Differential revision comment action groups
Summary:
Ref T11114. See D17114 for some discussion.
For review actions: accept, reject, resign.
For revision actions, order is basically least-severe to most-severe action pairs: plan changes, request review, close, reopen, abandon, reclaim, commandeer.
Test Plan: Viewed revisions as an author and a reviewer, saw sensible action order within action groups.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T11114
Differential Revision: https://secure.phabricator.com/D17115
2016-12-29 13:36:36 -08:00
|
|
|
if (!$object->isAccepted()) {
|
|
|
|
throw new Exception(
|
|
|
|
pht(
|
|
|
|
'You can not close this revision because it has not been accepted. '.
|
|
|
|
'Revisions must be accepted before they can be closed.'));
|
|
|
|
}
|
|
|
|
|
2016-12-28 13:05:04 -08:00
|
|
|
$config_key = 'differential.always-allow-close';
|
|
|
|
if (!PhabricatorEnv::getEnvConfig($config_key)) {
|
|
|
|
if (!$this->isViewerRevisionAuthor($object, $viewer)) {
|
|
|
|
throw new Exception(
|
|
|
|
pht(
|
|
|
|
'You can not close this revision because you are not the '.
|
|
|
|
'author. You can only close revisions you own. You can change '.
|
|
|
|
'this behavior by adjusting the "%s" setting in Config.',
|
|
|
|
$config_key));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getTitle() {
|
2017-08-11 14:47:39 -07:00
|
|
|
$commit_phid = $this->getMetadataValue('commitPHID');
|
2019-04-14 10:46:20 -07:00
|
|
|
if ($commit_phid) {
|
|
|
|
$commit = id(new DiffusionCommitQuery())
|
|
|
|
->setViewer($this->getViewer())
|
|
|
|
->withPHIDs(array($commit_phid))
|
|
|
|
->needIdentities(true)
|
|
|
|
->executeOne();
|
2017-08-11 14:47:39 -07:00
|
|
|
} else {
|
2019-04-14 10:46:20 -07:00
|
|
|
$commit = null;
|
2017-08-11 14:47:39 -07:00
|
|
|
}
|
|
|
|
|
2019-04-14 10:46:20 -07:00
|
|
|
if (!$commit) {
|
|
|
|
return pht(
|
|
|
|
'%s closed this revision.',
|
|
|
|
$this->renderAuthor());
|
2017-08-11 14:47:39 -07:00
|
|
|
}
|
|
|
|
|
2019-04-22 12:42:39 -07:00
|
|
|
$author_phid = null;
|
|
|
|
if ($commit->hasAuthorIdentity()) {
|
|
|
|
$identity = $commit->getAuthorIdentity();
|
|
|
|
$author_phid = $identity->getIdentityDisplayPHID();
|
|
|
|
}
|
|
|
|
|
|
|
|
$committer_phid = null;
|
|
|
|
if ($commit->hasCommitterIdentity()) {
|
|
|
|
$identity = $commit->getCommitterIdentity();
|
|
|
|
$committer_phid = $identity->getIdentityDisplayPHID();
|
|
|
|
}
|
2017-08-11 14:47:39 -07:00
|
|
|
|
2019-04-14 10:46:20 -07:00
|
|
|
if (!$author_phid) {
|
|
|
|
return pht(
|
|
|
|
'Closed by commit %s.',
|
|
|
|
$this->renderHandle($commit_phid));
|
|
|
|
} else if (!$committer_phid || ($committer_phid === $author_phid)) {
|
2017-08-11 14:47:39 -07:00
|
|
|
return pht(
|
|
|
|
'Closed by commit %s (authored by %s).',
|
|
|
|
$this->renderHandle($commit_phid),
|
2019-04-14 10:46:20 -07:00
|
|
|
$this->renderHandle($author_phid));
|
2017-08-11 14:47:39 -07:00
|
|
|
} else {
|
|
|
|
return pht(
|
|
|
|
'Closed by commit %s (authored by %s, committed by %s).',
|
|
|
|
$this->renderHandle($commit_phid),
|
2019-04-14 10:46:20 -07:00
|
|
|
$this->renderHandle($author_phid),
|
|
|
|
$this->renderHandle($committer_phid));
|
2017-08-11 14:47:39 -07:00
|
|
|
}
|
2016-12-28 13:05:04 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getTitleForFeed() {
|
|
|
|
return pht(
|
|
|
|
'%s closed %s.',
|
|
|
|
$this->renderAuthor(),
|
|
|
|
$this->renderObject());
|
|
|
|
}
|
|
|
|
|
2018-03-06 08:40:34 -08:00
|
|
|
public function getTransactionTypeForConduit($xaction) {
|
|
|
|
return 'close';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getFieldValuesForConduit($object, $data) {
|
|
|
|
$commit_phid = $object->getMetadataValue('commitPHID');
|
|
|
|
|
|
|
|
if ($commit_phid) {
|
|
|
|
$commit_phids = array($commit_phid);
|
|
|
|
} else {
|
|
|
|
$commit_phids = array();
|
|
|
|
}
|
|
|
|
|
|
|
|
return array(
|
|
|
|
'commitPHIDs' => $commit_phids,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-12-28 13:05:04 -08:00
|
|
|
}
|