1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-24 14:30:56 +01:00

[harbormaster/abort-builds] Support aborting builds in Harbormaster

Summary: Ref T1049.  This adds support for aborting builds in Harbormaster.

Test Plan: Tested it in production.

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: yelirekim, traviscline, joshuaspence, Korvin, epriestley

Projects: #harbormaster

Maniphest Tasks: T1049

Differential Revision: https://secure.phabricator.com/D11870
This commit is contained in:
June Rhodes 2015-09-21 12:07:24 -07:00 committed by epriestley
parent 26552a588b
commit d5dc4588fc
12 changed files with 183 additions and 68 deletions

View file

@ -65,12 +65,13 @@ final class PhabricatorHarbormasterApplication extends PhabricatorApplication {
'delete/(?:(?P<id>\d+)/)?' => 'HarbormasterStepDeleteController',
),
'buildable/' => array(
'(?P<id>\d+)/(?P<action>stop|resume|restart)/'
'(?P<id>\d+)/(?P<action>pause|resume|restart|abort)/'
=> 'HarbormasterBuildableActionController',
),
'build/' => array(
'(?P<id>\d+)/' => 'HarbormasterBuildViewController',
'(?P<action>stop|resume|restart)/(?P<id>\d+)/(?:(?P<via>[^/]+)/)?'
'(?P<action>pause|resume|restart|abort)/'.
'(?P<id>\d+)/(?:(?P<via>[^/]+)/)?'
=> 'HarbormasterBuildActionController',
),
'plan/' => array(

View file

@ -35,12 +35,15 @@ final class HarbormasterBuildActionController
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 @@ final class HarbormasterBuildActionController
}
}
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 @@ final class HarbormasterBuildActionController
$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 @@ final class HarbormasterBuildActionController
$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.');
}
}

View file

@ -29,10 +29,12 @@ final class HarbormasterBuildViewController
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 @@ final class HarbormasterBuildViewController
->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 @@ final class HarbormasterBuildViewController
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 @@ final class HarbormasterBuildViewController
$item = new PHUIStatusItemView();
if ($build->isStopping()) {
if ($build->isPausing()) {
$status_name = pht('Pausing');
$icon = PHUIStatusItemView::ICON_RIGHT;
$color = 'dark';

View file

@ -39,8 +39,8 @@ final class HarbormasterBuildableActionController
$issuable[] = $build;
}
break;
case HarbormasterBuildCommand::COMMAND_STOP:
if ($build->canStopBuild()) {
case HarbormasterBuildCommand::COMMAND_PAUSE:
if ($build->canPauseBuild()) {
$issuable[] = $build;
}
break;
@ -49,6 +49,11 @@ final class HarbormasterBuildableActionController
$issuable[] = $build;
}
break;
case HarbormasterBuildCommand::COMMAND_ABORT:
if ($build->canAbortBuild()) {
$issuable[] = $build;
}
break;
default:
return new Aphront400Response();
}
@ -94,20 +99,32 @@ final class HarbormasterBuildableActionController
'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 Stop Build');
$body = pht('No builds can be stopped.');
$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 Abort Builds');
$body = pht('No builds can be aborted.');
}
break;
case HarbormasterBuildCommand::COMMAND_RESUME:
@ -116,7 +133,7 @@ final class HarbormasterBuildableActionController
$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;

View file

@ -84,7 +84,8 @@ final class HarbormasterBuildableViewController
$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 @@ final class HarbormasterBuildableViewController
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 @@ final class HarbormasterBuildableViewController
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 @@ final class HarbormasterBuildableViewController
->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 @@ final class HarbormasterBuildableViewController
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 @@ final class HarbormasterBuildableViewController
$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 @@ final class HarbormasterBuildableViewController
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();

View file

@ -71,12 +71,15 @@ final class HarbormasterBuildTransactionEditor
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));
}

View file

@ -98,6 +98,12 @@ final class HarbormasterBuildEngine extends Phobject {
}
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 @@ final class HarbormasterBuildEngine extends Phobject {
$build->save();
}
if ($build->isStopping() && !$build->isComplete()) {
$build->setBuildStatus(HarbormasterBuild::STATUS_STOPPED);
if ($build->isPausing() && !$build->isComplete()) {
$build->setBuildStatus(HarbormasterBuild::STATUS_PAUSED);
$build->save();
}

View file

@ -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;

View file

@ -31,13 +31,17 @@ final class HarbormasterBuildTransaction
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 @@ final class HarbormasterBuildTransaction
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 @@ final class HarbormasterBuildTransaction
return 'green';
case self::TYPE_COMMAND:
switch ($new) {
case HarbormasterBuildCommand::COMMAND_STOP:
case HarbormasterBuildCommand::COMMAND_PAUSE:
case HarbormasterBuildCommand::COMMAND_ABORT:
return 'red';
}
}

View file

@ -35,9 +35,9 @@ final class HarbormasterBuildableTransaction
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 @@ final class HarbormasterBuildableTransaction
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 @@ final class HarbormasterBuildableTransaction
return 'green';
case self::TYPE_COMMAND:
switch ($new) {
case HarbormasterBuildCommand::COMMAND_STOP:
case HarbormasterBuildCommand::COMMAND_PAUSE:
return 'red';
}
}

View file

@ -41,15 +41,20 @@ final class HarbormasterBuild extends HarbormasterDAO
*/
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 @@ final class HarbormasterBuild extends HarbormasterDAO
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 @@ final class HarbormasterBuild extends HarbormasterDAO
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 @@ final class HarbormasterBuild extends HarbormasterDAO
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 @@ final class HarbormasterBuild extends HarbormasterDAO
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 @@ final class HarbormasterBuild extends HarbormasterDAO
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 @@ final class HarbormasterBuild extends HarbormasterDAO
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 @@ final class HarbormasterBuild extends HarbormasterDAO
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 @@ final class HarbormasterBuild extends HarbormasterDAO
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();

View file

@ -268,6 +268,7 @@ final class HarbormasterBuildTarget extends HarbormasterDAO
public function isFailed() {
switch ($this->getTargetStatus()) {
case self::STATUS_FAILED:
case self::STATUS_ABORTED:
return true;
}