mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 00:42:41 +01:00
Add an "Restartable: If Failed" behavior to Harbormaster build plans
Summary: Ref T13249. Ref T13258. In some cases, builds are not idempotent and should not be restarted casually. If the scary part is at the very end (deploy / provision / whatever), it could be okay to restart them if they previously failed. Also, make the "reasons why you can't restart" and "explanations of why you can't restart" logic a little more cohesive. Test Plan: - Tried to restart builds in various states (failed/not failed, restartable always/if failed/never, already restarted), got appropriate errors or restarts. - (I'm not sure the "Autoplan" error is normally reachable, since you can't edit autoplans to configure things to let you try to restart them.) Reviewers: amckinley Reviewed By: amckinley Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam Maniphest Tasks: T13258, T13249 Differential Revision: https://secure.phabricator.com/D20252
This commit is contained in:
parent
1d4f6bd444
commit
c1bff3b801
7 changed files with 104 additions and 26 deletions
|
@ -1443,6 +1443,7 @@ phutil_register_library_map(array(
|
|||
'HarbormasterQueryBuildsConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryBuildsConduitAPIMethod.php',
|
||||
'HarbormasterQueryBuildsSearchEngineAttachment' => 'applications/harbormaster/engineextension/HarbormasterQueryBuildsSearchEngineAttachment.php',
|
||||
'HarbormasterRemarkupRule' => 'applications/harbormaster/remarkup/HarbormasterRemarkupRule.php',
|
||||
'HarbormasterRestartException' => 'applications/harbormaster/exception/HarbormasterRestartException.php',
|
||||
'HarbormasterRunBuildPlansHeraldAction' => 'applications/harbormaster/herald/HarbormasterRunBuildPlansHeraldAction.php',
|
||||
'HarbormasterSchemaSpec' => 'applications/harbormaster/storage/HarbormasterSchemaSpec.php',
|
||||
'HarbormasterScratchTable' => 'applications/harbormaster/storage/HarbormasterScratchTable.php',
|
||||
|
@ -7093,6 +7094,7 @@ phutil_register_library_map(array(
|
|||
'HarbormasterQueryBuildsConduitAPIMethod' => 'HarbormasterConduitAPIMethod',
|
||||
'HarbormasterQueryBuildsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||
'HarbormasterRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
||||
'HarbormasterRestartException' => 'Exception',
|
||||
'HarbormasterRunBuildPlansHeraldAction' => 'HeraldAction',
|
||||
'HarbormasterSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||
'HarbormasterScratchTable' => 'HarbormasterDAO',
|
||||
|
|
|
@ -52,6 +52,10 @@ final class HarbormasterBuildStatus extends Phobject {
|
|||
return ($this->key === self::STATUS_PASSED);
|
||||
}
|
||||
|
||||
public function isFailed() {
|
||||
return ($this->key === self::STATUS_FAILED);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a human readable name for a build status constant.
|
||||
|
|
|
@ -64,19 +64,13 @@ final class HarbormasterBuildActionController
|
|||
'restart. Side effects of the build will occur again. Really '.
|
||||
'restart build?');
|
||||
$submit = pht('Restart Build');
|
||||
} else if (!$build->getBuildPlan()->canRestartBuildPlan()) {
|
||||
$title = pht('Not Restartable');
|
||||
$body = pht(
|
||||
'The build plan for this build is not restartable, so you '.
|
||||
'can not restart the build.');
|
||||
} else {
|
||||
$title = pht('Unable to Restart Build');
|
||||
if ($build->isRestarting()) {
|
||||
$body = pht(
|
||||
'This build is already restarting. You can not reissue a '.
|
||||
'restart command to a restarting build.');
|
||||
} else {
|
||||
$body = pht('You can not restart this build.');
|
||||
try {
|
||||
$build->assertCanRestartBuild();
|
||||
throw new Exception(pht('Expected to be unable to restart build.'));
|
||||
} catch (HarbormasterRestartException $ex) {
|
||||
$title = $ex->getTitle();
|
||||
$body = $ex->getBody();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
final class HarbormasterRestartException extends Exception {
|
||||
|
||||
private $title;
|
||||
private $body = array();
|
||||
|
||||
public function __construct($title, $body = null) {
|
||||
$this->setTitle($title);
|
||||
$this->appendParagraph($body);
|
||||
|
||||
parent::__construct($title);
|
||||
}
|
||||
|
||||
public function setTitle($title) {
|
||||
$this->title = $title;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function appendParagraph($description) {
|
||||
$this->body[] = $description;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBody() {
|
||||
return $this->body;
|
||||
}
|
||||
|
||||
}
|
|
@ -15,6 +15,7 @@ final class HarbormasterBuildPlanBehavior
|
|||
|
||||
const BEHAVIOR_RESTARTABLE = 'restartable';
|
||||
const RESTARTABLE_ALWAYS = 'always';
|
||||
const RESTARTABLE_IF_FAILED = 'failed';
|
||||
const RESTARTABLE_NEVER = 'never';
|
||||
|
||||
const BEHAVIOR_DRAFTS = 'hold-drafts';
|
||||
|
@ -251,6 +252,12 @@ final class HarbormasterBuildPlanBehavior
|
|||
->setIsDefault(true)
|
||||
->setDescription(
|
||||
pht('The build may be restarted.')),
|
||||
id(new HarbormasterBuildPlanBehaviorOption())
|
||||
->setKey(self::RESTARTABLE_IF_FAILED)
|
||||
->setIcon('fa-times-circle-o yellow')
|
||||
->setName(pht('If Failed'))
|
||||
->setDescription(
|
||||
pht('The build may be restarted if it has failed.')),
|
||||
id(new HarbormasterBuildPlanBehaviorOption())
|
||||
->setKey(self::RESTARTABLE_NEVER)
|
||||
->setIcon('fa-times red')
|
||||
|
|
|
@ -183,6 +183,10 @@ final class HarbormasterBuild extends HarbormasterDAO
|
|||
return $this->getBuildStatusObject()->isPassed();
|
||||
}
|
||||
|
||||
public function isFailed() {
|
||||
return $this->getBuildStatusObject()->isFailed();
|
||||
}
|
||||
|
||||
public function getURI() {
|
||||
$id = $this->getID();
|
||||
return "/harbormaster/build/{$id}/";
|
||||
|
@ -211,16 +215,60 @@ final class HarbormasterBuild extends HarbormasterDAO
|
|||
}
|
||||
|
||||
public function canRestartBuild() {
|
||||
try {
|
||||
$this->assertCanRestartBuild();
|
||||
return true;
|
||||
} catch (HarbormasterRestartException $ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function assertCanRestartBuild() {
|
||||
if ($this->isAutobuild()) {
|
||||
return false;
|
||||
throw new HarbormasterRestartException(
|
||||
pht('Can Not Restart Autobuild'),
|
||||
pht(
|
||||
'This build can not be restarted because it is an automatic '.
|
||||
'build.'));
|
||||
}
|
||||
|
||||
$restartable = HarbormasterBuildPlanBehavior::BEHAVIOR_RESTARTABLE;
|
||||
$plan = $this->getBuildPlan();
|
||||
if (!$plan->canRestartBuildPlan()) {
|
||||
return false;
|
||||
|
||||
$option = HarbormasterBuildPlanBehavior::getBehavior($restartable)
|
||||
->getPlanOption($plan);
|
||||
$option_key = $option->getKey();
|
||||
|
||||
$never_restartable = HarbormasterBuildPlanBehavior::RESTARTABLE_NEVER;
|
||||
$is_never = ($option_key === $never_restartable);
|
||||
if ($is_never) {
|
||||
throw new HarbormasterRestartException(
|
||||
pht('Build Plan Prevents Restart'),
|
||||
pht(
|
||||
'This build can not be restarted because the build plan is '.
|
||||
'configured to prevent the build from restarting.'));
|
||||
}
|
||||
|
||||
return !$this->isRestarting();
|
||||
$failed_restartable = HarbormasterBuildPlanBehavior::RESTARTABLE_IF_FAILED;
|
||||
$is_failed = ($option_key === $failed_restartable);
|
||||
if ($is_failed) {
|
||||
if (!$this->isFailed()) {
|
||||
throw new HarbormasterRestartException(
|
||||
pht('Only Restartable if Failed'),
|
||||
pht(
|
||||
'This build can not be restarted because the build plan is '.
|
||||
'configured to prevent the build from restarting unless it '.
|
||||
'has failed, and it has not failed.'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isRestarting()) {
|
||||
throw new HarbormasterRestartException(
|
||||
pht('Already Restarting'),
|
||||
pht(
|
||||
'This build is already restarting. You can not reissue a restart '.
|
||||
'command to a restarting build.'));
|
||||
}
|
||||
}
|
||||
|
||||
public function canPauseBuild() {
|
||||
|
|
|
@ -175,16 +175,6 @@ final class HarbormasterBuildPlan extends HarbormasterDAO
|
|||
$capability);
|
||||
}
|
||||
|
||||
public function canRestartBuildPlan() {
|
||||
$restartable = HarbormasterBuildPlanBehavior::BEHAVIOR_RESTARTABLE;
|
||||
$is_restartable = HarbormasterBuildPlanBehavior::RESTARTABLE_ALWAYS;
|
||||
|
||||
$option = HarbormasterBuildPlanBehavior::getBehavior($restartable)
|
||||
->getPlanOption($this);
|
||||
|
||||
return ($option->getKey() === $is_restartable);
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorSubscribableInterface )----------------------------------- */
|
||||
|
||||
|
|
Loading…
Reference in a new issue