2013-03-15 12:28:43 +01:00
|
|
|
<?php
|
|
|
|
|
2014-04-14 21:06:56 +02:00
|
|
|
final class ReleephRequestEditController extends ReleephBranchController {
|
2013-03-15 12:28:43 +01:00
|
|
|
|
2014-04-14 21:06:56 +02:00
|
|
|
private $requestID;
|
|
|
|
private $branchID;
|
2013-03-15 12:28:43 +01:00
|
|
|
|
2013-04-08 17:34:21 +02:00
|
|
|
public function willProcessRequest(array $data) {
|
2014-04-14 21:06:56 +02:00
|
|
|
$this->requestID = idx($data, 'requestID');
|
|
|
|
$this->branchID = idx($data, 'branchID');
|
2013-04-08 17:34:21 +02:00
|
|
|
}
|
2013-03-15 12:28:43 +01:00
|
|
|
|
2013-04-08 17:34:21 +02:00
|
|
|
public function processRequest() {
|
|
|
|
$request = $this->getRequest();
|
2014-04-14 21:06:56 +02:00
|
|
|
$viewer = $request->getUser();
|
2013-03-15 12:28:43 +01:00
|
|
|
|
2014-04-14 21:06:56 +02:00
|
|
|
if ($this->requestID) {
|
|
|
|
$pull = id(new ReleephRequestQuery())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->withIDs(array($this->requestID))
|
2013-07-30 21:38:32 +02:00
|
|
|
->requireCapabilities(
|
|
|
|
array(
|
|
|
|
PhabricatorPolicyCapability::CAN_VIEW,
|
|
|
|
PhabricatorPolicyCapability::CAN_EDIT,
|
|
|
|
))
|
|
|
|
->executeOne();
|
2014-04-14 21:06:56 +02:00
|
|
|
if (!$pull) {
|
|
|
|
return new Aphront404Response();
|
|
|
|
}
|
|
|
|
|
|
|
|
$branch = $pull->getBranch();
|
|
|
|
|
2013-04-08 17:34:21 +02:00
|
|
|
$is_edit = true;
|
|
|
|
} else {
|
2014-04-14 21:06:56 +02:00
|
|
|
$branch = id(new ReleephBranchQuery())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->withIDs(array($this->branchID))
|
|
|
|
->executeOne();
|
|
|
|
if (!$branch) {
|
|
|
|
return new Aphront404Response();
|
|
|
|
}
|
|
|
|
|
|
|
|
$pull = id(new ReleephRequest())
|
|
|
|
->setRequestUserPHID($viewer->getPHID())
|
|
|
|
->setBranchID($branch->getID())
|
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
|
|
|
->setInBranch(0)
|
|
|
|
->attachBranch($branch);
|
2014-04-14 21:06:56 +02:00
|
|
|
|
|
|
|
$is_edit = false;
|
2013-04-08 17:34:21 +02:00
|
|
|
}
|
2014-04-14 21:06:56 +02:00
|
|
|
$this->setBranch($branch);
|
|
|
|
|
|
|
|
$product = $branch->getProduct();
|
|
|
|
|
|
|
|
$request_identifier = $request->getStr('requestIdentifierRaw');
|
|
|
|
$e_request_identifier = true;
|
2013-03-15 12:28:43 +01:00
|
|
|
|
2013-04-08 17:34:21 +02:00
|
|
|
// Load all the ReleephFieldSpecifications
|
2014-04-14 21:06:56 +02:00
|
|
|
$selector = $branch->getProduct()->getReleephFieldSelector();
|
2013-04-08 17:34:21 +02:00
|
|
|
$fields = $selector->getFieldSpecifications();
|
|
|
|
foreach ($fields as $field) {
|
|
|
|
$field
|
2014-04-14 21:06:56 +02:00
|
|
|
->setReleephProject($product)
|
|
|
|
->setReleephBranch($branch)
|
|
|
|
->setReleephRequest($pull);
|
2013-03-15 12:28:43 +01:00
|
|
|
}
|
|
|
|
|
2013-08-15 00:36:13 +02:00
|
|
|
$field_list = PhabricatorCustomField::getObjectFields(
|
2014-04-14 21:06:56 +02:00
|
|
|
$pull,
|
2013-08-15 00:36:13 +02:00
|
|
|
PhabricatorCustomField::ROLE_EDIT);
|
|
|
|
foreach ($field_list->getFields() as $field) {
|
|
|
|
$field
|
2014-04-14 21:06:56 +02:00
|
|
|
->setReleephProject($product)
|
|
|
|
->setReleephBranch($branch)
|
|
|
|
->setReleephRequest($pull);
|
2013-08-15 00:36:13 +02:00
|
|
|
}
|
2014-04-14 21:06:56 +02:00
|
|
|
$field_list->readFieldsFromStorage($pull);
|
|
|
|
|
|
|
|
|
|
|
|
if ($this->branchID) {
|
|
|
|
$cancel_uri = $this->getApplicationURI('branch/'.$this->branchID.'/');
|
|
|
|
} else {
|
|
|
|
$cancel_uri = '/'.$pull->getMonogram();
|
2013-03-15 12:28:43 +01:00
|
|
|
}
|
|
|
|
|
2013-04-08 17:34:21 +02:00
|
|
|
// Make edits
|
2013-03-15 12:28:43 +01:00
|
|
|
$errors = array();
|
2013-04-08 17:34:21 +02:00
|
|
|
if ($request->isFormPost()) {
|
|
|
|
$xactions = array();
|
2013-03-15 12:28:43 +01:00
|
|
|
|
2013-04-08 17:34:21 +02:00
|
|
|
// The commit-identifier being requested...
|
|
|
|
if (!$is_edit) {
|
|
|
|
if ($request_identifier ===
|
|
|
|
ReleephRequestTypeaheadControl::PLACEHOLDER) {
|
2013-03-15 12:28:43 +01:00
|
|
|
|
2014-06-09 20:36:49 +02:00
|
|
|
$errors[] = 'No commit ID was provided.';
|
2013-04-08 17:34:21 +02:00
|
|
|
$e_request_identifier = 'Required';
|
|
|
|
} else {
|
|
|
|
$pr_commit = null;
|
|
|
|
$finder = id(new ReleephCommitFinder())
|
2014-04-14 21:06:56 +02:00
|
|
|
->setUser($viewer)
|
|
|
|
->setReleephProject($product);
|
2013-03-15 12:28:43 +01:00
|
|
|
try {
|
2013-04-08 17:34:21 +02:00
|
|
|
$pr_commit = $finder->fromPartial($request_identifier);
|
|
|
|
} catch (Exception $e) {
|
|
|
|
$e_request_identifier = 'Invalid';
|
|
|
|
$errors[] =
|
|
|
|
"Request {$request_identifier} is probably not a valid commit";
|
|
|
|
$errors[] = $e->getMessage();
|
|
|
|
}
|
|
|
|
|
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
|
|
|
if (!$errors) {
|
|
|
|
$object_phid = $finder->getRequestedObjectPHID();
|
|
|
|
if (!$object_phid) {
|
|
|
|
$object_phid = $pr_commit->getPHID();
|
|
|
|
}
|
|
|
|
|
|
|
|
$pull->setRequestedObjectPHID($object_phid);
|
|
|
|
}
|
2013-04-08 17:34:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!$errors) {
|
|
|
|
$existing = id(new ReleephRequest())
|
|
|
|
->loadOneWhere('requestCommitPHID = %s AND branchID = %d',
|
2014-04-14 21:06:56 +02:00
|
|
|
$pr_commit->getPHID(), $branch->getID());
|
2013-04-08 17:34:21 +02:00
|
|
|
if ($existing) {
|
|
|
|
return id(new AphrontRedirectResponse())
|
|
|
|
->setURI('/releeph/request/edit/'.$existing->getID().
|
|
|
|
'?existing=1');
|
|
|
|
}
|
|
|
|
|
|
|
|
$xactions[] = id(new ReleephRequestTransaction())
|
|
|
|
->setTransactionType(ReleephRequestTransaction::TYPE_REQUEST)
|
|
|
|
->setNewValue($pr_commit->getPHID());
|
|
|
|
|
|
|
|
$xactions[] = id(new ReleephRequestTransaction())
|
|
|
|
->setTransactionType(ReleephRequestTransaction::TYPE_USER_INTENT)
|
|
|
|
// To help hide these implicit intents...
|
|
|
|
->setMetadataValue('isRQCreate', true)
|
2014-04-14 21:06:56 +02:00
|
|
|
->setMetadataValue('userPHID', $viewer->getPHID())
|
2013-04-08 17:34:21 +02:00
|
|
|
->setMetadataValue(
|
|
|
|
'isAuthoritative',
|
2014-04-14 21:06:56 +02:00
|
|
|
$product->isAuthoritative($viewer))
|
2013-04-08 17:34:21 +02:00
|
|
|
->setNewValue(ReleephRequest::INTENT_WANT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-15 00:36:13 +02:00
|
|
|
// TODO: This should happen implicitly while building transactions
|
|
|
|
// instead.
|
|
|
|
foreach ($field_list->getFields() as $field) {
|
|
|
|
$field->readValueFromRequest($request);
|
|
|
|
}
|
|
|
|
|
2013-04-08 17:34:21 +02:00
|
|
|
if (!$errors) {
|
|
|
|
foreach ($fields as $field) {
|
|
|
|
if ($field->isEditable()) {
|
|
|
|
try {
|
|
|
|
$data = $request->getRequestData();
|
|
|
|
$value = idx($data, $field->getRequiredStorageKey());
|
|
|
|
$field->validate($value);
|
|
|
|
$xactions[] = id(new ReleephRequestTransaction())
|
|
|
|
->setTransactionType(ReleephRequestTransaction::TYPE_EDIT_FIELD)
|
|
|
|
->setMetadataValue('fieldClass', get_class($field))
|
|
|
|
->setNewValue($value);
|
|
|
|
} catch (ReleephFieldParseException $ex) {
|
|
|
|
$errors[] = $ex->getMessage();
|
|
|
|
}
|
2013-03-15 12:28:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$errors) {
|
2013-04-08 17:34:21 +02:00
|
|
|
$editor = id(new ReleephRequestTransactionalEditor())
|
2014-04-14 21:06:56 +02:00
|
|
|
->setActor($viewer)
|
2013-04-08 17:34:21 +02:00
|
|
|
->setContinueOnNoEffect(true)
|
2013-05-24 19:48:34 +02:00
|
|
|
->setContentSourceFromRequest($request);
|
2014-04-14 21:06:56 +02:00
|
|
|
$editor->applyTransactions($pull, $xactions);
|
|
|
|
return id(new AphrontRedirectResponse())->setURI($cancel_uri);
|
2013-03-15 12:28:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-20 20:54:50 +02:00
|
|
|
$handle_phids = array(
|
|
|
|
$pull->getRequestUserPHID(),
|
|
|
|
$pull->getRequestCommitPHID(),
|
|
|
|
);
|
|
|
|
$handle_phids = array_filter($handle_phids);
|
|
|
|
if ($handle_phids) {
|
|
|
|
$handles = id(new PhabricatorHandleQuery())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->withPHIDs($handle_phids)
|
|
|
|
->execute();
|
|
|
|
} else {
|
|
|
|
$handles = array();
|
|
|
|
}
|
2013-04-08 17:34:21 +02:00
|
|
|
|
|
|
|
$age_string = '';
|
|
|
|
if ($is_edit) {
|
|
|
|
$age_string = phabricator_format_relative_time(
|
2014-06-10 01:03:58 +02:00
|
|
|
time() - $pull->getDateCreated()).' ago';
|
2013-04-08 17:34:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Warn the user if we've been redirected here because we tried to
|
|
|
|
// re-request something.
|
|
|
|
$notice_view = null;
|
|
|
|
if ($request->getInt('existing')) {
|
|
|
|
$notice_messages = array(
|
|
|
|
'You are editing an existing pick request!',
|
|
|
|
hsprintf(
|
2014-06-09 20:36:49 +02:00
|
|
|
'Requested %s by %s',
|
2013-04-08 17:34:21 +02:00
|
|
|
$age_string,
|
2014-04-14 21:06:56 +02:00
|
|
|
$handles[$pull->getRequestUserPHID()]->renderLink())
|
2013-04-08 17:34:21 +02:00
|
|
|
);
|
|
|
|
$notice_view = id(new AphrontErrorView())
|
|
|
|
->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
|
|
|
|
->setErrors($notice_messages);
|
|
|
|
}
|
|
|
|
|
2013-03-15 12:28:43 +01:00
|
|
|
$form = id(new AphrontFormView())
|
2014-04-14 21:06:56 +02:00
|
|
|
->setUser($viewer);
|
2013-04-08 17:34:21 +02:00
|
|
|
|
|
|
|
if ($is_edit) {
|
|
|
|
$form
|
|
|
|
->appendChild(
|
|
|
|
id(new AphrontFormMarkupControl())
|
|
|
|
->setLabel('Original Commit')
|
|
|
|
->setValue(
|
2014-04-14 21:06:56 +02:00
|
|
|
$handles[$pull->getRequestCommitPHID()]->renderLink()))
|
2013-04-08 17:34:21 +02:00
|
|
|
->appendChild(
|
|
|
|
id(new AphrontFormMarkupControl())
|
|
|
|
->setLabel('Requestor')
|
|
|
|
->setValue(hsprintf(
|
|
|
|
'%s %s',
|
2014-04-14 21:06:56 +02:00
|
|
|
$handles[$pull->getRequestUserPHID()]->renderLink(),
|
2013-04-08 17:34:21 +02:00
|
|
|
$age_string)));
|
|
|
|
} else {
|
|
|
|
$origin = null;
|
|
|
|
$diff_rev_id = $request->getStr('D');
|
|
|
|
if ($diff_rev_id) {
|
2013-09-26 21:37:19 +02:00
|
|
|
$diff_rev = id(new DifferentialRevisionQuery())
|
2014-04-14 21:06:56 +02:00
|
|
|
->setViewer($viewer)
|
2013-09-26 21:37:19 +02:00
|
|
|
->withIDs(array($diff_rev_id))
|
|
|
|
->executeOne();
|
2013-04-08 17:34:21 +02:00
|
|
|
$origin = '/D'.$diff_rev->getID();
|
|
|
|
$title = sprintf(
|
|
|
|
'D%d: %s',
|
|
|
|
$diff_rev_id,
|
|
|
|
$diff_rev->getTitle());
|
|
|
|
$form
|
|
|
|
->addHiddenInput('requestIdentifierRaw', 'D'.$diff_rev_id)
|
|
|
|
->appendChild(
|
|
|
|
id(new AphrontFormStaticControl())
|
|
|
|
->setLabel('Diff')
|
|
|
|
->setValue($title));
|
|
|
|
} else {
|
2014-04-14 21:06:56 +02:00
|
|
|
$origin = $branch->getURI();
|
2014-04-20 20:55:09 +02:00
|
|
|
$repo = $product->getRepository();
|
2013-04-08 17:34:21 +02:00
|
|
|
$branch_cut_point = id(new PhabricatorRepositoryCommit())
|
|
|
|
->loadOneWhere(
|
|
|
|
'phid = %s',
|
2014-04-14 21:06:56 +02:00
|
|
|
$branch->getCutPointCommitPHID());
|
2013-04-08 17:34:21 +02:00
|
|
|
$form->appendChild(
|
|
|
|
id(new ReleephRequestTypeaheadControl())
|
|
|
|
->setName('requestIdentifierRaw')
|
|
|
|
->setLabel('Commit ID')
|
|
|
|
->setRepo($repo)
|
|
|
|
->setValue($request_identifier)
|
|
|
|
->setError($e_request_identifier)
|
|
|
|
->setStartTime($branch_cut_point->getEpoch())
|
|
|
|
->setCaption(
|
|
|
|
'Start typing to autocomplete on commit title, '.
|
|
|
|
'or give a Phabricator commit identifier like rFOO1234'));
|
|
|
|
}
|
|
|
|
}
|
2013-03-15 12:28:43 +01:00
|
|
|
|
2013-08-15 00:36:13 +02:00
|
|
|
$field_list->appendFieldsToForm($form);
|
2013-03-15 12:28:43 +01:00
|
|
|
|
2013-07-30 21:38:32 +02:00
|
|
|
$crumbs = $this->buildApplicationCrumbs();
|
|
|
|
|
2013-04-08 17:34:21 +02:00
|
|
|
if ($is_edit) {
|
2014-04-14 21:06:56 +02:00
|
|
|
$title = pht('Edit Pull Request');
|
2013-04-08 17:34:21 +02:00
|
|
|
$submit_name = pht('Save');
|
2013-07-30 21:38:32 +02:00
|
|
|
|
2014-04-14 21:06:56 +02:00
|
|
|
$crumbs->addTextCrumb($pull->getMonogram(), '/'.$pull->getMonogram());
|
2013-12-19 02:47:34 +01:00
|
|
|
$crumbs->addTextCrumb(pht('Edit'));
|
2013-04-08 17:34:21 +02:00
|
|
|
} else {
|
2014-04-14 21:06:56 +02:00
|
|
|
$title = pht('Create Pull Request');
|
|
|
|
$submit_name = pht('Create Pull Request');
|
|
|
|
|
|
|
|
$crumbs->addTextCrumb(pht('New Pull Request'));
|
2013-04-08 17:34:21 +02:00
|
|
|
}
|
|
|
|
|
2013-07-30 21:38:32 +02:00
|
|
|
$form->appendChild(
|
|
|
|
id(new AphrontFormSubmitControl())
|
2014-04-14 21:06:56 +02:00
|
|
|
->addCancelButton($cancel_uri, 'Cancel')
|
2013-07-30 21:38:32 +02:00
|
|
|
->setValue($submit_name));
|
2013-03-15 12:28:43 +01:00
|
|
|
|
2014-04-14 21:06:56 +02:00
|
|
|
$box = id(new PHUIObjectBoxView())
|
|
|
|
->setHeaderText($title)
|
|
|
|
->setFormErrors($errors)
|
|
|
|
->appendChild($form);
|
|
|
|
|
2013-07-30 21:38:32 +02:00
|
|
|
return $this->buildApplicationPage(
|
|
|
|
array(
|
|
|
|
$crumbs,
|
|
|
|
$notice_view,
|
2014-04-14 21:06:56 +02:00
|
|
|
$box,
|
2013-07-30 21:38:32 +02:00
|
|
|
),
|
|
|
|
array(
|
|
|
|
'title' => $title,
|
|
|
|
));
|
2013-03-15 12:28:43 +01:00
|
|
|
}
|
|
|
|
}
|