diff --git a/src/applications/differential/controller/DifferentialRevisionOperationController.php b/src/applications/differential/controller/DifferentialRevisionOperationController.php --- a/src/applications/differential/controller/DifferentialRevisionOperationController.php +++ b/src/applications/differential/controller/DifferentialRevisionOperationController.php @@ -58,6 +58,48 @@ $repository->getMonogram())); } + $op = new DrydockLandRepositoryOperation(); + + // Check for other operations. Eventually this should probably be more + // general (e.g., it's OK to land to multiple different branches + // simultaneously) but just put this in as a sanity check for now. + $other_operations = id(new DrydockRepositoryOperationQuery()) + ->setViewer($viewer) + ->withObjectPHIDs(array($revision->getPHID())) + ->withOperationTypes( + array( + $op->getOperationConstant(), + )) + ->withOperationStates( + array( + DrydockRepositoryOperation::STATE_WAIT, + DrydockRepositoryOperation::STATE_WORK, + DrydockRepositoryOperation::STATE_DONE, + )) + ->execute(); + + if ($other_operations) { + $any_done = false; + foreach ($other_operations as $operation) { + if ($operation->isDone()) { + $any_done = true; + break; + } + } + + if ($any_done) { + return $this->rejectOperation( + $revision, + pht('Already Complete'), + pht('This revision has already landed.')); + } else { + return $this->rejectOperation( + $revision, + pht('Already In Flight'), + pht('This revision is already landing.')); + } + } + if ($request->isFormPost()) { // NOTE: The operation is locked to the current active diff, so if the // revision is updated before the operation applies nothing sneaky @@ -65,8 +107,6 @@ $diff = $revision->getActiveDiff(); - $op = new DrydockLandRepositoryOperation(); - $operation = DrydockRepositoryOperation::initializeNewOperation($op) ->setAuthorPHID($viewer->getPHID()) ->setObjectPHID($revision->getPHID()) diff --git a/src/applications/differential/controller/DifferentialRevisionViewController.php b/src/applications/differential/controller/DifferentialRevisionViewController.php --- a/src/applications/differential/controller/DifferentialRevisionViewController.php +++ b/src/applications/differential/controller/DifferentialRevisionViewController.php @@ -1047,6 +1047,10 @@ $operations = id(new DrydockRepositoryOperationQuery()) ->setViewer($viewer) ->withObjectPHIDs(array($revision->getPHID())) + ->withOperationTypes( + array( + DrydockLandRepositoryOperation::OPCONST, + )) ->withOperationStates( array( DrydockRepositoryOperation::STATE_WAIT, @@ -1058,7 +1062,16 @@ return null; } - $operation = head(msort($operations, 'getID')); + $state_fail = DrydockRepositoryOperation::STATE_FAIL; + + // We're going to show the oldest operation which hasn't failed, or the + // most recent failure if they're all failures. + $operations = msort($operations, 'getID'); + foreach ($operations as $operation) { + if ($operation->getOperationState() != $state_fail) { + break; + } + } $box_view = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Active Operations')); diff --git a/src/applications/drydock/query/DrydockRepositoryOperationQuery.php b/src/applications/drydock/query/DrydockRepositoryOperationQuery.php --- a/src/applications/drydock/query/DrydockRepositoryOperationQuery.php +++ b/src/applications/drydock/query/DrydockRepositoryOperationQuery.php @@ -7,6 +7,7 @@ private $objectPHIDs; private $repositoryPHIDs; private $operationStates; + private $operationTypes; public function withIDs(array $ids) { $this->ids = $ids; @@ -33,6 +34,11 @@ return $this; } + public function withOperationTypes(array $types) { + $this->operationTypes = $types; + return $this; + } + public function newResultObject() { return new DrydockRepositoryOperation(); } @@ -139,6 +145,13 @@ $this->operationStates); } + if ($this->operationTypes !== null) { + $where[] = qsprintf( + $conn, + 'operationType IN (%Ls)', + $this->operationTypes); + } + return $where; } diff --git a/src/applications/drydock/storage/DrydockRepositoryOperation.php b/src/applications/drydock/storage/DrydockRepositoryOperation.php --- a/src/applications/drydock/storage/DrydockRepositoryOperation.php +++ b/src/applications/drydock/storage/DrydockRepositoryOperation.php @@ -158,6 +158,10 @@ return false; } + public function isDone() { + return ($this->getOperationState() === self::STATE_DONE); + } + public function getWorkingCopyMerges() { return $this->getImplementation()->getWorkingCopyMerges( $this);