Changeset View
Changeset View
Standalone View
Standalone View
src/applications/harbormaster/storage/build/HarbormasterBuild.php
Show First 20 Lines • Show All 201 Lines • ▼ Show 20 Lines | final class HarbormasterBuild extends HarbormasterDAO | ||||
public function isPassed() { | public function isPassed() { | ||||
return $this->getBuildStatusObject()->isPassed(); | return $this->getBuildStatusObject()->isPassed(); | ||||
} | } | ||||
public function isFailed() { | public function isFailed() { | ||||
return $this->getBuildStatusObject()->isFailed(); | return $this->getBuildStatusObject()->isFailed(); | ||||
} | } | ||||
public function isPending() { | |||||
return $this->getBuildstatusObject()->isPending(); | |||||
} | |||||
public function getURI() { | public function getURI() { | ||||
$id = $this->getID(); | $id = $this->getID(); | ||||
return "/harbormaster/build/{$id}/"; | return "/harbormaster/build/{$id}/"; | ||||
} | } | ||||
public function getBuildPendingStatusObject() { | public function getBuildPendingStatusObject() { | ||||
list($pending_status) = $this->getUnprocessedMessageState(); | |||||
if ($pending_status !== null) { | |||||
return HarbormasterBuildStatus::newBuildStatusObject($pending_status); | |||||
} | |||||
return $this->getBuildStatusObject(); | |||||
} | |||||
protected function getBuildStatusObject() { | |||||
$status_key = $this->getBuildStatus(); | |||||
return HarbormasterBuildStatus::newBuildStatusObject($status_key); | |||||
} | |||||
public function getObjectName() { | |||||
return pht('Build %d', $this->getID()); | |||||
} | |||||
/* -( Build Messages )----------------------------------------------------- */ | |||||
private function getUnprocessedMessages() { | |||||
return $this->assertAttached($this->unprocessedMessages); | |||||
} | |||||
public function getUnprocessedMessagesForApply() { | |||||
$unprocessed_state = $this->getUnprocessedMessageState(); | |||||
list($pending_status, $apply_messages) = $unprocessed_state; | |||||
return $apply_messages; | |||||
} | |||||
private function getUnprocessedMessageState() { | |||||
// NOTE: If a build has multiple unprocessed messages, we'll ignore | // NOTE: If a build has multiple unprocessed messages, we'll ignore | ||||
// messages that are obsoleted by a later or stronger message. | // messages that are obsoleted by a later or stronger message. | ||||
// | // | ||||
// For example, if a build has both "pause" and "abort" messages in queue, | // For example, if a build has both "pause" and "abort" messages in queue, | ||||
// we just ignore the "pause" message and perform an "abort", since pausing | // we just ignore the "pause" message and perform an "abort", since pausing | ||||
// first wouldn't affect the final state, so we can just skip it. | // first wouldn't affect the final state, so we can just skip it. | ||||
// | // | ||||
// Likewise, if a build has both "restart" and "abort" messages, the most | // Likewise, if a build has both "restart" and "abort" messages, the most | ||||
// recent message is controlling: we'll take whichever action a command | // recent message is controlling: we'll take whichever action a command | ||||
// was most recently issued for. | // was most recently issued for. | ||||
$is_restarting = false; | $is_restarting = false; | ||||
$is_aborting = false; | $is_aborting = false; | ||||
$is_pausing = false; | $is_pausing = false; | ||||
$is_resuming = false; | $is_resuming = false; | ||||
$apply_messages = array(); | |||||
foreach ($this->getUnprocessedMessages() as $message_object) { | foreach ($this->getUnprocessedMessages() as $message_object) { | ||||
$message_type = $message_object->getType(); | $message_type = $message_object->getType(); | ||||
switch ($message_type) { | switch ($message_type) { | ||||
case HarbormasterBuildCommand::COMMAND_RESTART: | case HarbormasterBuildCommand::COMMAND_RESTART: | ||||
$is_restarting = true; | $is_restarting = true; | ||||
$is_aborting = false; | $is_aborting = false; | ||||
$apply_messages = array($message_object); | |||||
break; | break; | ||||
case HarbormasterBuildCommand::COMMAND_ABORT: | case HarbormasterBuildCommand::COMMAND_ABORT: | ||||
$is_aborting = true; | $is_aborting = true; | ||||
$is_restarting = false; | $is_restarting = false; | ||||
$apply_messages = array($message_object); | |||||
break; | break; | ||||
case HarbormasterBuildCommand::COMMAND_PAUSE: | case HarbormasterBuildCommand::COMMAND_PAUSE: | ||||
$is_pausing = true; | $is_pausing = true; | ||||
$is_resuming = false; | $is_resuming = false; | ||||
$apply_messages = array($message_object); | |||||
break; | break; | ||||
case HarbormasterBuildCommand::COMMAND_RESUME: | case HarbormasterBuildCommand::COMMAND_RESUME: | ||||
$is_resuming = true; | $is_resuming = true; | ||||
$is_pausing = false; | $is_pausing = false; | ||||
$apply_messages = array($message_object); | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
$pending_status = null; | $pending_status = null; | ||||
if ($is_restarting) { | if ($is_restarting) { | ||||
$pending_status = HarbormasterBuildStatus::PENDING_RESTARTING; | $pending_status = HarbormasterBuildStatus::PENDING_RESTARTING; | ||||
} else if ($is_aborting) { | } else if ($is_aborting) { | ||||
$pending_status = HarbormasterBuildStatus::PENDING_ABORTING; | $pending_status = HarbormasterBuildStatus::PENDING_ABORTING; | ||||
} else if ($is_pausing) { | } else if ($is_pausing) { | ||||
$pending_status = HarbormasterBuildStatus::PENDING_PAUSING; | $pending_status = HarbormasterBuildStatus::PENDING_PAUSING; | ||||
} else if ($is_resuming) { | } else if ($is_resuming) { | ||||
$pending_status = HarbormasterBuildStatus::PENDING_RESUMING; | $pending_status = HarbormasterBuildStatus::PENDING_RESUMING; | ||||
} | } | ||||
if ($pending_status !== null) { | return array($pending_status, $apply_messages); | ||||
return HarbormasterBuildStatus::newBuildStatusObject($pending_status); | |||||
} | |||||
return $this->getBuildStatusObject(); | |||||
} | |||||
protected function getBuildStatusObject() { | |||||
$status_key = $this->getBuildStatus(); | |||||
return HarbormasterBuildStatus::newBuildStatusObject($status_key); | |||||
} | |||||
public function getObjectName() { | |||||
return pht('Build %d', $this->getID()); | |||||
} | |||||
/* -( Build Messages )----------------------------------------------------- */ | |||||
private function getUnprocessedMessages() { | |||||
return $this->assertAttached($this->unprocessedMessages); | |||||
} | } | ||||
public function attachUnprocessedMessages(array $messages) { | public function attachUnprocessedMessages(array $messages) { | ||||
assert_instances_of($messages, 'HarbormasterBuildMessage'); | assert_instances_of($messages, 'HarbormasterBuildMessage'); | ||||
$this->unprocessedMessages = $messages; | $this->unprocessedMessages = $messages; | ||||
return $this; | return $this; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | if ($need_edit) { | ||||
PhabricatorPolicyFilter::requireCapability( | PhabricatorPolicyFilter::requireCapability( | ||||
$viewer, | $viewer, | ||||
$plan, | $plan, | ||||
PhabricatorPolicyCapability::CAN_EDIT); | PhabricatorPolicyCapability::CAN_EDIT); | ||||
} | } | ||||
} | } | ||||
public function sendMessage(PhabricatorUser $viewer, $message_type) { | public function sendMessage(PhabricatorUser $viewer, $message_type) { | ||||
// TODO: This should not be an editor transaction, but there are plans to | HarbormasterBuildMessage::initializeNewMessage($viewer) | ||||
// merge BuildCommand into BuildMessage which should moot this. As this | ->setReceiverPHID($this->getPHID()) | ||||
// exists today, it can race against BuildEngine. | ->setType($message_type) | ||||
->save(); | |||||
// This is a bogus content source, but this whole flow should be obsolete | |||||
// soon. | PhabricatorWorker::scheduleTask( | ||||
$content_source = PhabricatorContentSource::newForSource( | 'HarbormasterBuildWorker', | ||||
PhabricatorConsoleContentSource::SOURCECONST); | array( | ||||
'buildID' => $this->getID(), | |||||
$editor = id(new HarbormasterBuildTransactionEditor()) | ), | ||||
->setActor($viewer) | array( | ||||
->setContentSource($content_source) | 'objectPHID' => $this->getPHID(), | ||||
->setContinueOnNoEffect(true) | 'containerPHID' => $this->getBuildablePHID(), | ||||
->setContinueOnMissingFields(true); | )); | ||||
} | |||||
$viewer_phid = $viewer->getPHID(); | |||||
if (!$viewer_phid) { | public function releaseAllArtifacts(PhabricatorUser $viewer) { | ||||
$acting_phid = id(new PhabricatorHarbormasterApplication())->getPHID(); | $targets = id(new HarbormasterBuildTargetQuery()) | ||||
$editor->setActingAsPHID($acting_phid); | ->setViewer($viewer) | ||||
} | ->withBuildPHIDs(array($this->getPHID())) | ||||
->withBuildGenerations(array($this->getBuildGeneration())) | |||||
$xaction = id(new HarbormasterBuildTransaction()) | ->execute(); | ||||
->setTransactionType(HarbormasterBuildTransaction::TYPE_COMMAND) | |||||
->setNewValue($message_type); | if (!$targets) { | ||||
return; | |||||
} | |||||
$target_phids = mpull($targets, 'getPHID'); | |||||
$artifacts = id(new HarbormasterBuildArtifactQuery()) | |||||
->setViewer($viewer) | |||||
->withBuildTargetPHIDs($target_phids) | |||||
->withIsReleased(false) | |||||
->execute(); | |||||
foreach ($artifacts as $artifact) { | |||||
$artifact->releaseArtifact(); | |||||
} | |||||
} | |||||
public function restartBuild(PhabricatorUser $viewer) { | |||||
// TODO: This should become transactional. | |||||
// We're restarting the build, so release all previous artifacts. | |||||
$this->releaseAllArtifacts($viewer); | |||||
// Increment the build generation counter on the build. | |||||
$this->setBuildGeneration($this->getBuildGeneration() + 1); | |||||
// Currently running targets should periodically check their build | |||||
// generation (which won't have changed) against the build's generation. | |||||
// If it is different, they will automatically stop what they're doing | |||||
// and abort. | |||||
$editor->applyTransactions($this, array($xaction)); | // Previously we used to delete targets, logs and artifacts here. Instead, | ||||
// leave them around so users can view previous generations of this build. | |||||
} | } | ||||
/* -( PhabricatorApplicationTransactionInterface )------------------------- */ | /* -( PhabricatorApplicationTransactionInterface )------------------------- */ | ||||
public function getApplicationTransactionEditor() { | public function getApplicationTransactionEditor() { | ||||
return new HarbormasterBuildTransactionEditor(); | return new HarbormasterBuildTransactionEditor(); | ||||
▲ Show 20 Lines • Show All 113 Lines • Show Last 20 Lines |