diff --git a/src/applications/harbormaster/application/PhabricatorHarbormasterApplication.php b/src/applications/harbormaster/application/PhabricatorHarbormasterApplication.php --- a/src/applications/harbormaster/application/PhabricatorHarbormasterApplication.php +++ b/src/applications/harbormaster/application/PhabricatorHarbormasterApplication.php @@ -65,12 +65,13 @@ 'delete/(?:(?P\d+)/)?' => 'HarbormasterStepDeleteController', ), 'buildable/' => array( - '(?P\d+)/(?Pstop|resume|restart)/' + '(?P\d+)/(?Ppause|resume|restart|abort)/' => 'HarbormasterBuildableActionController', ), 'build/' => array( '(?P\d+)/' => 'HarbormasterBuildViewController', - '(?Pstop|resume|restart)/(?P\d+)/(?:(?P[^/]+)/)?' + '(?Ppause|resume|restart|abort)/'. + '(?P\d+)/(?:(?P[^/]+)/)?' => 'HarbormasterBuildActionController', ), 'plan/' => array( diff --git a/src/applications/harbormaster/controller/HarbormasterBuildActionController.php b/src/applications/harbormaster/controller/HarbormasterBuildActionController.php --- a/src/applications/harbormaster/controller/HarbormasterBuildActionController.php +++ b/src/applications/harbormaster/controller/HarbormasterBuildActionController.php @@ -35,12 +35,15 @@ case HarbormasterBuildCommand::COMMAND_RESTART: $can_issue = $build->canRestartBuild(); break; - case HarbormasterBuildCommand::COMMAND_STOP: - $can_issue = $build->canStopBuild(); + case HarbormasterBuildCommand::COMMAND_PAUSE: + $can_issue = $build->canPauseBuild(); break; case HarbormasterBuildCommand::COMMAND_RESUME: $can_issue = $build->canResumeBuild(); break; + case HarbormasterBuildCommand::COMMAND_ABORT: + $can_issue = $build->canAbortBuild(); + break; default: return new Aphront400Response(); } @@ -90,7 +93,19 @@ } } break; - case HarbormasterBuildCommand::COMMAND_STOP: + case HarbormasterBuildCommand::COMMAND_ABORT: + if ($can_issue) { + $title = pht('Really abort build?'); + $body = pht( + 'Progress on this build will be discarded. Really '. + 'abort build?'); + $submit = pht('Abort Build'); + } else { + $title = pht('Unable to Abort Build'); + $body = pht('You can not abort this build.'); + } + break; + case HarbormasterBuildCommand::COMMAND_PAUSE: if ($can_issue) { $title = pht('Really pause build?'); $body = pht( @@ -103,11 +118,11 @@ $body = pht( 'This build is already complete. You can not pause a completed '. 'build.'); - } else if ($build->isStopped()) { + } else if ($build->isPaused()) { $body = pht( 'This build is already paused. You can not pause a build which '. 'has already been paused.'); - } else if ($build->isStopping()) { + } else if ($build->isPausing()) { $body = pht( 'This build is already pausing. You can not reissue a pause '. 'command to a pausing build.'); @@ -129,9 +144,9 @@ $body = pht( 'This build is already resuming. You can not reissue a resume '. 'command to a resuming build.'); - } else if (!$build->isStopped()) { + } else if (!$build->isPaused()) { $body = pht( - 'This build is not stopped. You can only resume a stopped '. + 'This build is not paused. You can only resume a paused '. 'build.'); } } diff --git a/src/applications/harbormaster/controller/HarbormasterBuildViewController.php b/src/applications/harbormaster/controller/HarbormasterBuildViewController.php --- a/src/applications/harbormaster/controller/HarbormasterBuildViewController.php +++ b/src/applications/harbormaster/controller/HarbormasterBuildViewController.php @@ -29,10 +29,12 @@ if ($build->isRestarting()) { $header->setStatus('fa-exclamation-triangle', 'red', pht('Restarting')); - } else if ($build->isStopping()) { + } else if ($build->isPausing()) { $header->setStatus('fa-exclamation-triangle', 'red', pht('Pausing')); } else if ($build->isResuming()) { $header->setStatus('fa-exclamation-triangle', 'red', pht('Resuming')); + } else if ($build->isAborting()) { + $header->setStatus('fa-exclamation-triangle', 'red', pht('Aborting')); } $box = id(new PHUIObjectBoxView()) @@ -447,8 +449,9 @@ ->setObjectURI("/build/{$id}"); $can_restart = $build->canRestartBuild(); - $can_stop = $build->canStopBuild(); + $can_pause = $build->canPauseBuild(); $can_resume = $build->canResumeBuild(); + $can_abort = $build->canAbortBuild(); $list->addAction( id(new PhabricatorActionView()) @@ -471,11 +474,19 @@ id(new PhabricatorActionView()) ->setName(pht('Pause Build')) ->setIcon('fa-pause') - ->setHref($this->getApplicationURI('/build/stop/'.$id.'/')) - ->setDisabled(!$can_stop) + ->setHref($this->getApplicationURI('/build/pause/'.$id.'/')) + ->setDisabled(!$can_pause) ->setWorkflow(true)); } + $list->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Abort Build')) + ->setIcon('fa-exclamation-triangle') + ->setHref($this->getApplicationURI('/build/abort/'.$id.'/')) + ->setDisabled(!$can_abort) + ->setWorkflow(true)); + return $list; } @@ -522,7 +533,7 @@ $item = new PHUIStatusItemView(); - if ($build->isStopping()) { + if ($build->isPausing()) { $status_name = pht('Pausing'); $icon = PHUIStatusItemView::ICON_RIGHT; $color = 'dark'; diff --git a/src/applications/harbormaster/controller/HarbormasterBuildableActionController.php b/src/applications/harbormaster/controller/HarbormasterBuildableActionController.php --- a/src/applications/harbormaster/controller/HarbormasterBuildableActionController.php +++ b/src/applications/harbormaster/controller/HarbormasterBuildableActionController.php @@ -39,8 +39,8 @@ $issuable[] = $build; } break; - case HarbormasterBuildCommand::COMMAND_STOP: - if ($build->canStopBuild()) { + case HarbormasterBuildCommand::COMMAND_PAUSE: + if ($build->canPauseBuild()) { $issuable[] = $build; } break; @@ -49,6 +49,11 @@ $issuable[] = $build; } break; + case HarbormasterBuildCommand::COMMAND_ABORT: + if ($build->canAbortBuild()) { + $issuable[] = $build; + } + break; default: return new Aphront400Response(); } @@ -94,20 +99,32 @@ 'restart all builds?'); $submit = pht('Restart All Builds'); } else { - $title = pht('Unable to Restart Build'); + $title = pht('Unable to Restart Builds'); $body = pht('No builds can be restarted.'); } break; - case HarbormasterBuildCommand::COMMAND_STOP: + case HarbormasterBuildCommand::COMMAND_PAUSE: if ($issuable) { - $title = pht('Really stop all builds?'); + $title = pht('Really pause all builds?'); $body = pht( - 'If you stop all build, work will halt once the current steps '. + 'If you pause all builds, work will halt once the current steps '. 'complete. You can resume the builds later.'); - $submit = pht('Stop All Builds'); + $submit = pht('Pause All Builds'); + } else { + $title = pht('Unable to Pause Builds'); + $body = pht('No builds can be paused.'); + } + break; + case HarbormasterBuildCommand::COMMAND_ABORT: + if ($issuable) { + $title = pht('Really abort all builds?'); + $body = pht( + 'If you abort all builds, work will halt immediately. Work '. + 'will be discarded, and builds must be completely restarted.'); + $submit = pht('Abort All Builds'); } else { - $title = pht('Unable to Stop Build'); - $body = pht('No builds can be stopped.'); + $title = pht('Unable to Abort Builds'); + $body = pht('No builds can be aborted.'); } break; case HarbormasterBuildCommand::COMMAND_RESUME: @@ -116,7 +133,7 @@ $body = pht('Work will continue on all builds. Really resume?'); $submit = pht('Resume All Builds'); } else { - $title = pht('Unable to Resume Build'); + $title = pht('Unable to Resume Builds'); $body = pht('No builds can be resumed.'); } break; diff --git a/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php b/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php --- a/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php +++ b/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php @@ -84,7 +84,8 @@ $can_restart = false; $can_resume = false; - $can_stop = false; + $can_pause = false; + $can_abort = false; foreach ($buildable->getBuilds() as $build) { if ($build->canRestartBuild()) { @@ -93,14 +94,18 @@ if ($build->canResumeBuild()) { $can_resume = true; } - if ($build->canStopBuild()) { - $can_stop = true; + if ($build->canPauseBuild()) { + $can_pause = true; + } + if ($build->canAbortBuild()) { + $can_abort = true; } } $restart_uri = "buildable/{$id}/restart/"; - $stop_uri = "buildable/{$id}/stop/"; + $pause_uri = "buildable/{$id}/pause/"; $resume_uri = "buildable/{$id}/resume/"; + $abort_uri = "buildable/{$id}/abort/"; $list->addAction( id(new PhabricatorActionView()) @@ -114,9 +119,9 @@ id(new PhabricatorActionView()) ->setIcon('fa-pause') ->setName(pht('Pause All Builds')) - ->setHref($this->getApplicationURI($stop_uri)) + ->setHref($this->getApplicationURI($pause_uri)) ->setWorkflow(true) - ->setDisabled(!$can_stop || !$can_edit)); + ->setDisabled(!$can_pause || !$can_edit)); $list->addAction( id(new PhabricatorActionView()) @@ -126,6 +131,14 @@ ->setWorkflow(true) ->setDisabled(!$can_resume || !$can_edit)); + $list->addAction( + id(new PhabricatorActionView()) + ->setIcon('fa-exclamation-triangle') + ->setName(pht('Abort All Builds')) + ->setHref($this->getApplicationURI($abort_uri)) + ->setWorkflow(true) + ->setDisabled(!$can_abort || !$can_edit)); + return $list; } @@ -181,7 +194,7 @@ if ($build->isRestarting()) { $item->addIcon('fa-repeat', pht('Restarting')); - } else if ($build->isStopping()) { + } else if ($build->isPausing()) { $item->addIcon('fa-pause', pht('Pausing')); } else if ($build->isResuming()) { $item->addIcon('fa-play', pht('Resuming')); @@ -191,7 +204,8 @@ $restart_uri = "build/restart/{$build_id}/buildable/"; $resume_uri = "build/resume/{$build_id}/buildable/"; - $stop_uri = "build/stop/{$build_id}/buildable/"; + $pause_uri = "build/pause/{$build_id}/buildable/"; + $abort_uri = "build/abort/{$build_id}/buildable/"; $item->addAction( id(new PHUIListItemView()) @@ -213,9 +227,9 @@ id(new PHUIListItemView()) ->setIcon('fa-pause') ->setName(pht('Pause')) - ->setHref($this->getApplicationURI($stop_uri)) + ->setHref($this->getApplicationURI($pause_uri)) ->setWorkflow(true) - ->setDisabled(!$build->canStopBuild())); + ->setDisabled(!$build->canPauseBuild())); } $targets = $build->getBuildTargets(); diff --git a/src/applications/harbormaster/editor/HarbormasterBuildTransactionEditor.php b/src/applications/harbormaster/editor/HarbormasterBuildTransactionEditor.php --- a/src/applications/harbormaster/editor/HarbormasterBuildTransactionEditor.php +++ b/src/applications/harbormaster/editor/HarbormasterBuildTransactionEditor.php @@ -71,12 +71,15 @@ case HarbormasterBuildCommand::COMMAND_RESTART: $issuable = $build->canRestartBuild(); break; - case HarbormasterBuildCommand::COMMAND_STOP: - $issuable = $build->canStopBuild(); + case HarbormasterBuildCommand::COMMAND_PAUSE: + $issuable = $build->canPauseBuild(); break; case HarbormasterBuildCommand::COMMAND_RESUME: $issuable = $build->canResumeBuild(); break; + case HarbormasterBuildCommand::COMMAND_ABORT: + $issuable = $build->canAbortBuild(); + break; default: throw new Exception(pht('Unknown command %s', $command)); } diff --git a/src/applications/harbormaster/engine/HarbormasterBuildEngine.php b/src/applications/harbormaster/engine/HarbormasterBuildEngine.php --- a/src/applications/harbormaster/engine/HarbormasterBuildEngine.php +++ b/src/applications/harbormaster/engine/HarbormasterBuildEngine.php @@ -98,6 +98,12 @@ } private function updateBuild(HarbormasterBuild $build) { + if ($build->isAborting()) { + $this->releaseAllArtifacts($build); + $build->setBuildStatus(HarbormasterBuild::STATUS_ABORTED); + $build->save(); + } + if (($build->getBuildStatus() == HarbormasterBuild::STATUS_PENDING) || ($build->isRestarting())) { $this->restartBuild($build); @@ -110,8 +116,8 @@ $build->save(); } - if ($build->isStopping() && !$build->isComplete()) { - $build->setBuildStatus(HarbormasterBuild::STATUS_STOPPED); + if ($build->isPausing() && !$build->isComplete()) { + $build->setBuildStatus(HarbormasterBuild::STATUS_PAUSED); $build->save(); } diff --git a/src/applications/harbormaster/storage/HarbormasterBuildCommand.php b/src/applications/harbormaster/storage/HarbormasterBuildCommand.php --- a/src/applications/harbormaster/storage/HarbormasterBuildCommand.php +++ b/src/applications/harbormaster/storage/HarbormasterBuildCommand.php @@ -2,9 +2,10 @@ final class HarbormasterBuildCommand extends HarbormasterDAO { - const COMMAND_STOP = 'stop'; + const COMMAND_PAUSE = 'pause'; const COMMAND_RESUME = 'resume'; const COMMAND_RESTART = 'restart'; + const COMMAND_ABORT = 'abort'; protected $authorPHID; protected $targetPHID; diff --git a/src/applications/harbormaster/storage/HarbormasterBuildTransaction.php b/src/applications/harbormaster/storage/HarbormasterBuildTransaction.php --- a/src/applications/harbormaster/storage/HarbormasterBuildTransaction.php +++ b/src/applications/harbormaster/storage/HarbormasterBuildTransaction.php @@ -31,13 +31,17 @@ return pht( '%s restarted this build.', $this->renderHandleLink($author_phid)); + case HarbormasterBuildCommand::COMMAND_ABORT: + return pht( + '%s aborted this build.', + $this->renderHandleLink($author_phid)); case HarbormasterBuildCommand::COMMAND_RESUME: return pht( '%s resumed this build.', $this->renderHandleLink($author_phid)); - case HarbormasterBuildCommand::COMMAND_STOP: + case HarbormasterBuildCommand::COMMAND_PAUSE: return pht( - '%s stopped this build.', + '%s paused this build.', $this->renderHandleLink($author_phid)); } } @@ -59,8 +63,10 @@ return 'fa-backward'; case HarbormasterBuildCommand::COMMAND_RESUME: return 'fa-play'; - case HarbormasterBuildCommand::COMMAND_STOP: - return 'fa-stop'; + case HarbormasterBuildCommand::COMMAND_PAUSE: + return 'fa-pause'; + case HarbormasterBuildCommand::COMMAND_ABORT: + return 'fa-exclamation-triangle'; } } @@ -78,7 +84,8 @@ return 'green'; case self::TYPE_COMMAND: switch ($new) { - case HarbormasterBuildCommand::COMMAND_STOP: + case HarbormasterBuildCommand::COMMAND_PAUSE: + case HarbormasterBuildCommand::COMMAND_ABORT: return 'red'; } } diff --git a/src/applications/harbormaster/storage/HarbormasterBuildableTransaction.php b/src/applications/harbormaster/storage/HarbormasterBuildableTransaction.php --- a/src/applications/harbormaster/storage/HarbormasterBuildableTransaction.php +++ b/src/applications/harbormaster/storage/HarbormasterBuildableTransaction.php @@ -35,9 +35,9 @@ return pht( '%s resumed this buildable.', $this->renderHandleLink($author_phid)); - case HarbormasterBuildCommand::COMMAND_STOP: + case HarbormasterBuildCommand::COMMAND_PAUSE: return pht( - '%s stopped this buildable.', + '%s paused this buildable.', $this->renderHandleLink($author_phid)); } } @@ -59,8 +59,8 @@ return 'fa-backward'; case HarbormasterBuildCommand::COMMAND_RESUME: return 'fa-play'; - case HarbormasterBuildCommand::COMMAND_STOP: - return 'fa-stop'; + case HarbormasterBuildCommand::COMMAND_PAUSE: + return 'fa-pause'; } } @@ -78,7 +78,7 @@ return 'green'; case self::TYPE_COMMAND: switch ($new) { - case HarbormasterBuildCommand::COMMAND_STOP: + case HarbormasterBuildCommand::COMMAND_PAUSE: return 'red'; } } diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuild.php b/src/applications/harbormaster/storage/build/HarbormasterBuild.php --- a/src/applications/harbormaster/storage/build/HarbormasterBuild.php +++ b/src/applications/harbormaster/storage/build/HarbormasterBuild.php @@ -42,14 +42,19 @@ const STATUS_FAILED = 'failed'; /** + * The build has aborted. + */ + const STATUS_ABORTED = 'aborted'; + + /** * The build encountered an unexpected error. */ const STATUS_ERROR = 'error'; /** - * The build has been stopped. + * The build has been paused. */ - const STATUS_STOPPED = 'stopped'; + const STATUS_PAUSED = 'paused'; /** * The build has been deadlocked. @@ -75,9 +80,11 @@ return pht('Passed'); case self::STATUS_FAILED: return pht('Failed'); + case self::STATUS_ABORTED: + return pht('Aborted'); case self::STATUS_ERROR: return pht('Unexpected Error'); - case self::STATUS_STOPPED: + case self::STATUS_PAUSED: return pht('Paused'); case self::STATUS_DEADLOCKED: return pht('Deadlocked'); @@ -97,9 +104,11 @@ return PHUIStatusItemView::ICON_ACCEPT; case self::STATUS_FAILED: return PHUIStatusItemView::ICON_REJECT; + case self::STATUS_ABORTED: + return PHUIStatusItemView::ICON_MINUS; case self::STATUS_ERROR: return PHUIStatusItemView::ICON_MINUS; - case self::STATUS_STOPPED: + case self::STATUS_PAUSED: return PHUIStatusItemView::ICON_MINUS; case self::STATUS_DEADLOCKED: return PHUIStatusItemView::ICON_WARNING; @@ -118,10 +127,11 @@ case self::STATUS_PASSED: return 'green'; case self::STATUS_FAILED: + case self::STATUS_ABORTED: case self::STATUS_ERROR: case self::STATUS_DEADLOCKED: return 'red'; - case self::STATUS_STOPPED: + case self::STATUS_PAUSED: return 'dark'; default: return 'bluegrey'; @@ -284,16 +294,17 @@ switch ($this->getBuildStatus()) { case self::STATUS_PASSED: case self::STATUS_FAILED: + case self::STATUS_ABORTED: case self::STATUS_ERROR: - case self::STATUS_STOPPED: + case self::STATUS_PAUSED: return true; } return false; } - public function isStopped() { - return ($this->getBuildStatus() == self::STATUS_STOPPED); + public function isPaused() { + return ($this->getBuildStatus() == self::STATUS_PAUSED); } @@ -317,14 +328,22 @@ return !$this->isRestarting(); } - public function canStopBuild() { + public function canPauseBuild() { if ($this->isAutobuild()) { return false; } return !$this->isComplete() && - !$this->isStopped() && - !$this->isStopping(); + !$this->isPaused() && + !$this->isPausing(); + } + + public function canAbortBuild() { + if ($this->isAutobuild()) { + return false; + } + + return !$this->isComplete(); } public function canResumeBuild() { @@ -332,26 +351,29 @@ return false; } - return $this->isStopped() && + return $this->isPaused() && !$this->isResuming(); } - public function isStopping() { - $is_stopping = false; + public function isPausing() { + $is_pausing = false; foreach ($this->getUnprocessedCommands() as $command_object) { $command = $command_object->getCommand(); switch ($command) { - case HarbormasterBuildCommand::COMMAND_STOP: - $is_stopping = true; + case HarbormasterBuildCommand::COMMAND_PAUSE: + $is_pausing = true; break; case HarbormasterBuildCommand::COMMAND_RESUME: case HarbormasterBuildCommand::COMMAND_RESTART: - $is_stopping = false; + $is_pausing = false; + break; + case HarbormasterBuildCommand::COMMAND_ABORT: + $is_pausing = true; break; } } - return $is_stopping; + return $is_pausing; } public function isResuming() { @@ -363,7 +385,10 @@ case HarbormasterBuildCommand::COMMAND_RESUME: $is_resuming = true; break; - case HarbormasterBuildCommand::COMMAND_STOP: + case HarbormasterBuildCommand::COMMAND_PAUSE: + $is_resuming = false; + break; + case HarbormasterBuildCommand::COMMAND_ABORT: $is_resuming = false; break; } @@ -386,6 +411,20 @@ return $is_restarting; } + public function isAborting() { + $is_aborting = false; + foreach ($this->getUnprocessedCommands() as $command_object) { + $command = $command_object->getCommand(); + switch ($command) { + case HarbormasterBuildCommand::COMMAND_ABORT: + $is_aborting = true; + break; + } + } + + return $is_aborting; + } + public function deleteUnprocessedCommands() { foreach ($this->getUnprocessedCommands() as $key => $command_object) { $command_object->delete(); diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php b/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php --- a/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php +++ b/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php @@ -268,6 +268,7 @@ public function isFailed() { switch ($this->getTargetStatus()) { case self::STATUS_FAILED: + case self::STATUS_ABORTED: return true; }