2013-03-15 12:28:43 +01:00
|
|
|
<?php
|
|
|
|
|
2013-04-26 18:07:38 +02:00
|
|
|
final class ReleephRequest extends ReleephDAO
|
2013-08-14 19:04:18 +02:00
|
|
|
implements
|
|
|
|
PhabricatorPolicyInterface,
|
|
|
|
PhabricatorCustomFieldInterface {
|
2013-03-15 12:28:43 +01:00
|
|
|
|
|
|
|
protected $branchID;
|
|
|
|
protected $requestUserPHID;
|
|
|
|
protected $details = array();
|
|
|
|
protected $userIntents = array();
|
|
|
|
protected $inBranch;
|
|
|
|
protected $pickStatus;
|
2013-05-08 11:38:07 +02:00
|
|
|
protected $mailKey;
|
2013-03-15 12:28:43 +01:00
|
|
|
|
Add "requestedObjectPHID" to ReleephRequest
Summary:
Ref T3551. Currently, ReleephRequests don't have a direct concept of the //object// being requested. You can request `D123`, but that is just a convenient way to write `rXyyyy`.
When the UI wants to display information about a revision, it deduces it by examining the commit.
This is primarily an attack on T3551, so we don't need to load <commit -> edge -> revision> (in an ad-hoc way) to get revisions. Instead, when you request a revision we keep track of it and can load it directly later.
Later, this will let us do more things: for example, if you request a branch, we can automatically update the commits (as GitHub does), etc. (Repository branches will need PHIDs first, of course.)
This adds and populates the column but doesn't use it yet. The second part of the migration could safely be run while Phabricator is up, although even for Facebook this table is probably quite small.
Test Plan:
- Ran migration.
- Verified existing requests associated sensibly.
- Created a new commit request.
- Created a new revision request.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T3551
Differential Revision: https://secure.phabricator.com/D8822
2014-04-20 20:55:18 +02:00
|
|
|
/**
|
|
|
|
* The object which is being requested. Normally this is a commit, but it
|
|
|
|
* might also be a revision. In the future, it could be a repository branch
|
|
|
|
* or an external object (like a GitHub pull request).
|
|
|
|
*/
|
|
|
|
protected $requestedObjectPHID;
|
|
|
|
|
2013-03-15 12:28:43 +01:00
|
|
|
// Information about the thing being requested
|
|
|
|
protected $requestCommitPHID;
|
|
|
|
|
|
|
|
// Information about the last commit to the releeph branch
|
|
|
|
protected $commitIdentifier;
|
|
|
|
protected $commitPHID;
|
|
|
|
|
Add "requestedObjectPHID" to ReleephRequest
Summary:
Ref T3551. Currently, ReleephRequests don't have a direct concept of the //object// being requested. You can request `D123`, but that is just a convenient way to write `rXyyyy`.
When the UI wants to display information about a revision, it deduces it by examining the commit.
This is primarily an attack on T3551, so we don't need to load <commit -> edge -> revision> (in an ad-hoc way) to get revisions. Instead, when you request a revision we keep track of it and can load it directly later.
Later, this will let us do more things: for example, if you request a branch, we can automatically update the commits (as GitHub does), etc. (Repository branches will need PHIDs first, of course.)
This adds and populates the column but doesn't use it yet. The second part of the migration could safely be run while Phabricator is up, although even for Facebook this table is probably quite small.
Test Plan:
- Ran migration.
- Verified existing requests associated sensibly.
- Created a new commit request.
- Created a new revision request.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T3551
Differential Revision: https://secure.phabricator.com/D8822
2014-04-20 20:55:18 +02:00
|
|
|
|
2013-08-14 19:04:18 +02:00
|
|
|
private $customFields = self::ATTACHABLE;
|
2014-04-14 21:06:56 +02:00
|
|
|
private $branch = self::ATTACHABLE;
|
2014-04-20 20:55:47 +02:00
|
|
|
private $requestedObject = self::ATTACHABLE;
|
2013-08-14 19:04:18 +02:00
|
|
|
|
2013-03-15 12:28:43 +01:00
|
|
|
|
|
|
|
/* -( Constants and helper methods )--------------------------------------- */
|
|
|
|
|
|
|
|
const INTENT_WANT = 'want';
|
|
|
|
const INTENT_PASS = 'pass';
|
|
|
|
|
|
|
|
const PICK_PENDING = 1; // old
|
|
|
|
const PICK_FAILED = 2;
|
|
|
|
const PICK_OK = 3;
|
|
|
|
const PICK_MANUAL = 4; // old
|
|
|
|
const REVERT_OK = 5;
|
|
|
|
const REVERT_FAILED = 6;
|
|
|
|
|
|
|
|
public function shouldBeInBranch() {
|
|
|
|
return
|
|
|
|
$this->getPusherIntent() == self::INTENT_WANT &&
|
|
|
|
/**
|
|
|
|
* We use "!= pass" instead of "== want" in case the requestor intent is
|
2014-07-10 00:12:48 +02:00
|
|
|
* not present. In other words, only revert if the requestor explicitly
|
2013-03-15 12:28:43 +01:00
|
|
|
* passed.
|
|
|
|
*/
|
|
|
|
$this->getRequestorIntent() != self::INTENT_PASS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Will return INTENT_WANT if any pusher wants this request, and no pusher
|
|
|
|
* passes on this request.
|
|
|
|
*/
|
|
|
|
public function getPusherIntent() {
|
2014-04-20 20:54:58 +02:00
|
|
|
$product = $this->getBranch()->getProduct();
|
2013-10-15 01:07:17 +02:00
|
|
|
|
2014-04-20 20:54:58 +02:00
|
|
|
if (!$product->getPushers()) {
|
2013-03-15 12:28:43 +01:00
|
|
|
return self::INTENT_WANT;
|
|
|
|
}
|
|
|
|
|
|
|
|
$found_pusher_want = false;
|
|
|
|
foreach ($this->userIntents as $phid => $intent) {
|
2014-04-20 20:54:58 +02:00
|
|
|
if ($product->isAuthoritativePHID($phid)) {
|
2013-03-15 12:28:43 +01:00
|
|
|
if ($intent == self::INTENT_PASS) {
|
|
|
|
return self::INTENT_PASS;
|
|
|
|
}
|
|
|
|
|
|
|
|
$found_pusher_want = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($found_pusher_want) {
|
|
|
|
return self::INTENT_WANT;
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getRequestorIntent() {
|
|
|
|
return idx($this->userIntents, $this->requestUserPHID);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getStatus() {
|
|
|
|
return $this->calculateStatus();
|
|
|
|
}
|
|
|
|
|
2014-04-14 21:06:56 +02:00
|
|
|
public function getMonogram() {
|
|
|
|
return 'Y'.$this->getID();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getBranch() {
|
|
|
|
return $this->assertAttached($this->branch);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function attachBranch(ReleephBranch $branch) {
|
|
|
|
$this->branch = $branch;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2014-04-20 20:55:47 +02:00
|
|
|
public function getRequestedObject() {
|
|
|
|
return $this->assertAttached($this->requestedObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function attachRequestedObject($object) {
|
|
|
|
$this->requestedObject = $object;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2013-03-15 12:28:43 +01:00
|
|
|
private function calculateStatus() {
|
|
|
|
if ($this->shouldBeInBranch()) {
|
|
|
|
if ($this->getInBranch()) {
|
2013-05-10 18:07:33 +02:00
|
|
|
return ReleephRequestStatus::STATUS_PICKED;
|
2013-03-15 12:28:43 +01:00
|
|
|
} else {
|
2013-05-10 18:07:33 +02:00
|
|
|
return ReleephRequestStatus::STATUS_NEEDS_PICK;
|
2013-03-15 12:28:43 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ($this->getInBranch()) {
|
2013-05-10 18:07:33 +02:00
|
|
|
return ReleephRequestStatus::STATUS_NEEDS_REVERT;
|
2013-03-15 12:28:43 +01:00
|
|
|
} else {
|
|
|
|
$has_been_in_branch = $this->getCommitIdentifier();
|
|
|
|
// Regardless of why we reverted something, always say reverted if it
|
|
|
|
// was once in the branch.
|
|
|
|
if ($has_been_in_branch) {
|
2013-05-10 18:07:33 +02:00
|
|
|
return ReleephRequestStatus::STATUS_REVERTED;
|
2014-06-09 20:36:49 +02:00
|
|
|
} else if ($this->getPusherIntent() === ReleephRequest::INTENT_PASS) {
|
2013-03-15 12:28:43 +01:00
|
|
|
// Otherwise, if it has never been in the branch, explicitly say why:
|
2013-05-10 18:07:33 +02:00
|
|
|
return ReleephRequestStatus::STATUS_REJECTED;
|
2014-06-09 20:36:49 +02:00
|
|
|
} else if ($this->getRequestorIntent() === ReleephRequest::INTENT_WANT) {
|
2013-05-10 18:07:33 +02:00
|
|
|
return ReleephRequestStatus::STATUS_REQUESTED;
|
2013-03-15 12:28:43 +01:00
|
|
|
} else {
|
2013-05-10 18:07:33 +02:00
|
|
|
return ReleephRequestStatus::STATUS_ABANDONED;
|
2013-03-15 12:28:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* -( Lisk mechanics )----------------------------------------------------- */
|
|
|
|
|
|
|
|
public function getConfiguration() {
|
|
|
|
return array(
|
|
|
|
self::CONFIG_AUX_PHID => true,
|
|
|
|
self::CONFIG_SERIALIZATION => array(
|
|
|
|
'details' => self::SERIALIZATION_JSON,
|
|
|
|
'userIntents' => self::SERIALIZATION_JSON,
|
|
|
|
),
|
|
|
|
) + parent::getConfiguration();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function generatePHID() {
|
|
|
|
return PhabricatorPHID::generateNewPHID(
|
2014-07-24 00:05:46 +02:00
|
|
|
ReleephRequestPHIDType::TYPECONST);
|
2013-03-15 12:28:43 +01:00
|
|
|
}
|
|
|
|
|
2013-05-08 11:38:07 +02:00
|
|
|
public function save() {
|
|
|
|
if (!$this->getMailKey()) {
|
|
|
|
$this->setMailKey(Filesystem::readRandomCharacters(20));
|
|
|
|
}
|
|
|
|
return parent::save();
|
|
|
|
}
|
|
|
|
|
2013-03-15 12:28:43 +01:00
|
|
|
|
|
|
|
/* -( Helpful accessors )--------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function getDetail($key, $default = null) {
|
|
|
|
return idx($this->getDetails(), $key, $default);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setDetail($key, $value) {
|
|
|
|
$this->details[$key] = $value;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
Add "requestedObjectPHID" to ReleephRequest
Summary:
Ref T3551. Currently, ReleephRequests don't have a direct concept of the //object// being requested. You can request `D123`, but that is just a convenient way to write `rXyyyy`.
When the UI wants to display information about a revision, it deduces it by examining the commit.
This is primarily an attack on T3551, so we don't need to load <commit -> edge -> revision> (in an ad-hoc way) to get revisions. Instead, when you request a revision we keep track of it and can load it directly later.
Later, this will let us do more things: for example, if you request a branch, we can automatically update the commits (as GitHub does), etc. (Repository branches will need PHIDs first, of course.)
This adds and populates the column but doesn't use it yet. The second part of the migration could safely be run while Phabricator is up, although even for Facebook this table is probably quite small.
Test Plan:
- Ran migration.
- Verified existing requests associated sensibly.
- Created a new commit request.
- Created a new revision request.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T3551
Differential Revision: https://secure.phabricator.com/D8822
2014-04-20 20:55:18 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the commit PHIDs this request is requesting.
|
|
|
|
*
|
|
|
|
* NOTE: For now, this always returns one PHID.
|
|
|
|
*
|
|
|
|
* @return list<phid> Commit PHIDs requested by this request.
|
|
|
|
*/
|
|
|
|
public function getCommitPHIDs() {
|
|
|
|
return array(
|
|
|
|
$this->requestCommitPHID,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2013-03-15 12:28:43 +01:00
|
|
|
public function getReason() {
|
|
|
|
// Backward compatibility: reason used to be called comments
|
|
|
|
$reason = $this->getDetail('reason');
|
|
|
|
if (!$reason) {
|
|
|
|
return $this->getDetail('comments');
|
|
|
|
}
|
|
|
|
return $reason;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Allow a null summary, and fall back to the title of the commit.
|
|
|
|
*/
|
|
|
|
public function getSummaryForDisplay() {
|
|
|
|
$summary = $this->getDetail('summary');
|
|
|
|
|
2014-04-18 15:44:45 +02:00
|
|
|
if (!strlen($summary)) {
|
|
|
|
$commit = $this->loadPhabricatorRepositoryCommit();
|
|
|
|
if ($commit) {
|
|
|
|
$summary = $commit->getSummary();
|
2013-03-15 12:28:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-18 15:44:45 +02:00
|
|
|
if (!strlen($summary)) {
|
|
|
|
$summary = pht('None');
|
2013-03-15 12:28:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return $summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -( Loading external objects )------------------------------------------- */
|
|
|
|
|
|
|
|
public function loadPhabricatorRepositoryCommit() {
|
|
|
|
return $this->loadOneRelative(
|
|
|
|
new PhabricatorRepositoryCommit(),
|
|
|
|
'phid',
|
|
|
|
'getRequestCommitPHID');
|
|
|
|
}
|
|
|
|
|
|
|
|
public function loadPhabricatorRepositoryCommitData() {
|
2013-04-12 01:54:51 +02:00
|
|
|
$commit = $this->loadPhabricatorRepositoryCommit();
|
|
|
|
if ($commit) {
|
|
|
|
return $commit->loadOneRelative(
|
|
|
|
new PhabricatorRepositoryCommitData(),
|
|
|
|
'commitID');
|
|
|
|
}
|
2013-03-15 12:28:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* -( State change helpers )----------------------------------------------- */
|
|
|
|
|
|
|
|
public function setUserIntent(PhabricatorUser $user, $intent) {
|
|
|
|
$this->userIntents[$user->getPHID()] = $intent;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* -( Migrating to status-less ReleephRequests )--------------------------- */
|
|
|
|
|
|
|
|
protected function didReadData() {
|
|
|
|
if ($this->userIntents === null) {
|
|
|
|
$this->userIntents = array();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setStatus($value) {
|
|
|
|
throw new Exception('`status` is now deprecated!');
|
|
|
|
}
|
|
|
|
|
2013-04-26 18:07:38 +02:00
|
|
|
/* -( Make magic Lisk methods private )------------------------------------ */
|
|
|
|
|
|
|
|
private function setUserIntents(array $ar) {
|
|
|
|
return parent::setUserIntents($ar);
|
|
|
|
}
|
|
|
|
|
2013-08-14 19:04:18 +02:00
|
|
|
|
2013-04-26 18:07:38 +02:00
|
|
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
|
|
|
|
2013-08-14 19:04:18 +02:00
|
|
|
|
2013-04-26 18:07:38 +02:00
|
|
|
public function getCapabilities() {
|
|
|
|
return array(
|
|
|
|
PhabricatorPolicyCapability::CAN_VIEW,
|
2013-07-30 21:38:32 +02:00
|
|
|
PhabricatorPolicyCapability::CAN_EDIT,
|
2013-04-26 18:07:38 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getPolicy($capability) {
|
2014-04-14 21:06:56 +02:00
|
|
|
return $this->getBranch()->getPolicy($capability);
|
2013-04-26 18:07:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
2014-04-14 21:06:56 +02:00
|
|
|
return $this->getBranch()->hasAutomaticCapability($capability, $viewer);
|
2013-04-26 18:07:38 +02:00
|
|
|
}
|
|
|
|
|
2013-09-27 17:43:41 +02:00
|
|
|
public function describeAutomaticCapability($capability) {
|
2014-04-14 21:06:56 +02:00
|
|
|
return pht(
|
|
|
|
'Pull requests have the same policies as the branches they are '.
|
|
|
|
'requested against.');
|
2013-09-27 17:43:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-14 19:04:18 +02:00
|
|
|
|
|
|
|
/* -( PhabricatorCustomFieldInterface )------------------------------------ */
|
|
|
|
|
|
|
|
|
|
|
|
public function getCustomFieldSpecificationForRole($role) {
|
|
|
|
return PhabricatorEnv::getEnvConfig('releeph.fields');
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCustomFieldBaseClass() {
|
|
|
|
return 'ReleephFieldSpecification';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCustomFields() {
|
|
|
|
return $this->assertAttached($this->customFields);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) {
|
|
|
|
$this->customFields = $fields;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-15 12:28:43 +01:00
|
|
|
}
|