diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 11be8a50f0..35be621604 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1004,6 +1004,7 @@ phutil_register_library_map(array( 'DrydockBlueprintCustomField' => 'applications/drydock/customfield/DrydockBlueprintCustomField.php', 'DrydockBlueprintDatasource' => 'applications/drydock/typeahead/DrydockBlueprintDatasource.php', 'DrydockBlueprintDisableController' => 'applications/drydock/controller/DrydockBlueprintDisableController.php', + 'DrydockBlueprintEditConduitAPIMethod' => 'applications/drydock/conduit/DrydockBlueprintEditConduitAPIMethod.php', 'DrydockBlueprintEditController' => 'applications/drydock/controller/DrydockBlueprintEditController.php', 'DrydockBlueprintEditEngine' => 'applications/drydock/editor/DrydockBlueprintEditEngine.php', 'DrydockBlueprintEditor' => 'applications/drydock/editor/DrydockBlueprintEditor.php', @@ -6090,6 +6091,7 @@ phutil_register_library_map(array( 'DrydockBlueprintCustomField' => 'PhabricatorCustomField', 'DrydockBlueprintDatasource' => 'PhabricatorTypeaheadDatasource', 'DrydockBlueprintDisableController' => 'DrydockBlueprintController', + 'DrydockBlueprintEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'DrydockBlueprintEditController' => 'DrydockBlueprintController', 'DrydockBlueprintEditEngine' => 'PhabricatorEditEngine', 'DrydockBlueprintEditor' => 'PhabricatorApplicationTransactionEditor', diff --git a/src/applications/differential/editor/DifferentialTransactionEditor.php b/src/applications/differential/editor/DifferentialTransactionEditor.php index ae652ba0ec..b2fc179002 100644 --- a/src/applications/differential/editor/DifferentialTransactionEditor.php +++ b/src/applications/differential/editor/DifferentialTransactionEditor.php @@ -1588,11 +1588,8 @@ final class DifferentialTransactionEditor ->setAuthorPHID($author_phid) ->setTransactionType( DifferentialRevisionRequestReviewTransaction::TRANSACTIONTYPE) - ->setOldValue(false) ->setNewValue(true); - $xaction = $this->populateTransaction($object, $xaction); - // If we're creating this revision and immediately moving it out of // the draft state, mark this as a create transaction so it gets // hidden in the timeline and mail, since it isn't interesting: it @@ -1601,15 +1598,10 @@ final class DifferentialTransactionEditor $xaction->setIsCreateTransaction(true); } - $object->openTransaction(); - $object - ->setStatus(DifferentialRevisionStatus::NEEDS_REVIEW) - ->save(); - - $xaction->save(); - $object->saveTransaction(); - - $xactions[] = $xaction; + // Queue this transaction and apply it separately after the current + // batch of transactions finishes so that Herald can fire on the new + // revision state. See T13027 for discussion. + $this->queueTransaction($xaction); } } diff --git a/src/applications/differential/xaction/DifferentialRevisionRequestReviewTransaction.php b/src/applications/differential/xaction/DifferentialRevisionRequestReviewTransaction.php index 465b5234d5..ed0d20a0b6 100644 --- a/src/applications/differential/xaction/DifferentialRevisionRequestReviewTransaction.php +++ b/src/applications/differential/xaction/DifferentialRevisionRequestReviewTransaction.php @@ -57,11 +57,15 @@ final class DifferentialRevisionRequestReviewTransaction 'revisions.')); } - if (!$this->isViewerRevisionAuthor($object, $viewer)) { - throw new Exception( - pht( - 'You can not request review of this revision because you are not '. - 'the author of the revision.')); + // When revisions automatically promote out of "Draft" after builds finish, + // the viewer may be acting as the Harbormaster application. + if (!$viewer->isOmnipotent()) { + if (!$this->isViewerRevisionAuthor($object, $viewer)) { + throw new Exception( + pht( + 'You can not request review of this revision because you are not '. + 'the author of the revision.')); + } } } diff --git a/src/applications/diffusion/controller/DiffusionCommitController.php b/src/applications/diffusion/controller/DiffusionCommitController.php index cdce8702ca..11463ef97d 100644 --- a/src/applications/diffusion/controller/DiffusionCommitController.php +++ b/src/applications/diffusion/controller/DiffusionCommitController.php @@ -39,20 +39,23 @@ final class DiffusionCommitController extends DiffusionController { return $this->buildRawDiffResponse($drequest); } - $commit = id(new DiffusionCommitQuery()) + $commits = id(new DiffusionCommitQuery()) ->setViewer($viewer) ->withRepository($repository) ->withIdentifiers(array($commit_identifier)) ->needCommitData(true) ->needAuditRequests(true) - ->executeOne(); + ->setLimit(100) + ->execute(); + + $multiple_results = count($commits) > 1; $crumbs = $this->buildCrumbs(array( - 'commit' => true, + 'commit' => !$multiple_results, )); $crumbs->setBorder(true); - if (!$commit) { + if (!$commits) { if (!$this->getCommitExists()) { return new Aphront404Response(); } @@ -70,7 +73,40 @@ final class DiffusionCommitController extends DiffusionController { ->setTitle($title) ->setCrumbs($crumbs) ->appendChild($error); + } else if ($multiple_results) { + $warning_message = + pht( + 'The identifier %s is ambiguous and matches more than one commit.', + phutil_tag( + 'strong', + array(), + $commit_identifier)); + + $error = id(new PHUIInfoView()) + ->setTitle(pht('Ambiguous Commit')) + ->setSeverity(PHUIInfoView::SEVERITY_WARNING) + ->appendChild($warning_message); + + $list = id(new DiffusionCommitListView()) + ->setViewer($viewer) + ->setCommits($commits) + ->setNoDataString(pht('No recent commits.')); + + $crumbs->addTextCrumb(pht('Ambiguous Commit')); + + $matched_commits = id(new PHUITwoColumnView()) + ->setFooter(array( + $error, + $list, + )); + + return $this->newPage() + ->setTitle(pht('Ambiguous Commit')) + ->setCrumbs($crumbs) + ->appendChild($matched_commits); + } else { + $commit = head($commits); } $audit_requests = $commit->getAudits(); diff --git a/src/applications/drydock/conduit/DrydockBlueprintEditConduitAPIMethod.php b/src/applications/drydock/conduit/DrydockBlueprintEditConduitAPIMethod.php new file mode 100644 index 0000000000..764c077d87 --- /dev/null +++ b/src/applications/drydock/conduit/DrydockBlueprintEditConduitAPIMethod.php @@ -0,0 +1,20 @@ +setBlueprintImplementation($impl); + return $this->newEditableObject(); + } + protected function newObjectQuery() { return new DrydockBlueprintQuery(); } diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php index 6c9cb5e201..8ba49f4d77 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php @@ -630,6 +630,15 @@ abstract class PhabricatorEditEngine return $this->isCreate; } + /** + * Initialize a new object for documentation creation. + * + * @return object Newly initialized object. + * @task load + */ + protected function newEditableObjectForDocumentation() { + return $this->newEditableObject(); + } /** * Flag this workflow as a create or edit. @@ -2198,7 +2207,7 @@ abstract class PhabricatorEditEngine return array(); } - $object = $this->newEditableObject(); + $object = $this->newEditableObjectForDocumentation(); $fields = $this->buildEditFields($object); return $this->getConduitEditTypesFromFields($fields); } diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php index 175a5775ee..8e6d816769 100644 --- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php +++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php @@ -70,6 +70,8 @@ abstract class PhabricatorApplicationTransactionEditor private $feedRelatedPHIDs = array(); private $modularTypes; + private $transactionQueue = array(); + const STORAGE_ENCODING_BINARY = 'binary'; /** @@ -1174,6 +1176,8 @@ abstract class PhabricatorApplicationTransactionEditor 'priority' => PhabricatorWorker::PRIORITY_ALERTS, )); + $this->flushTransactionQueue($object); + return $xactions; } @@ -3864,4 +3868,39 @@ abstract class PhabricatorApplicationTransactionEditor return pht('%s created an object: %s.', $author, $object); } +/* -( Queue )-------------------------------------------------------------- */ + + protected function queueTransaction( + PhabricatorApplicationTransaction $xaction) { + $this->transactionQueue[] = $xaction; + return $this; + } + + private function flushTransactionQueue($object) { + if (!$this->transactionQueue) { + return; + } + + $xactions = $this->transactionQueue; + $this->transactionQueue = array(); + + $editor = $this->newQueueEditor(); + + return $editor->applyTransactions($object, $xactions); + } + + private function newQueueEditor() { + $editor = id(newv(get_class($this), array())) + ->setActor($this->getActor()) + ->setContentSource($this->getContentSource()) + ->setContinueOnNoEffect($this->getContinueOnNoEffect()) + ->setContinueOnMissingFields($this->getContinueOnMissingFields()); + + if ($this->actingAsPHID !== null) { + $editor->setActingAsPHID($this->actingAsPHID); + } + + return $editor; + } + }