mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-29 10:12:41 +01:00
Implement build generations in Harbormaster
Summary: Ref T5932. Ref T5936. This implements build generations in Harbormaster, which provides the infrastructure required to both show users the previous states of restarted builds and to allow users to forcefully abort builds (and their targets). You can view previous generations of a build by adding `?g=<n>` to the URI, but this isn't exposed in the UI anywhere yet. Test Plan: Ran a build plan with a Sleep step in it. Reconfigured it for various sleep times and viewed previous generations of the build after restarting it. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Maniphest Tasks: T5932, T5936 Differential Revision: https://secure.phabricator.com/D10321
This commit is contained in:
parent
a2a0f002f0
commit
efadfbbc97
7 changed files with 54 additions and 26 deletions
|
@ -0,0 +1,5 @@
|
|||
ALTER TABLE {$NAMESPACE}_harbormaster.harbormaster_build
|
||||
ADD COLUMN `buildGeneration` INT UNSIGNED NOT NULL DEFAULT 0;
|
||||
|
||||
ALTER TABLE {$NAMESPACE}_harbormaster.harbormaster_buildtarget
|
||||
ADD COLUMN `buildGeneration` INT UNSIGNED NOT NULL DEFAULT 0;
|
|
@ -14,6 +14,7 @@ final class HarbormasterBuildViewController
|
|||
$viewer = $request->getUser();
|
||||
|
||||
$id = $this->id;
|
||||
$generation = $request->getInt('g');
|
||||
|
||||
$build = id(new HarbormasterBuildQuery())
|
||||
->setViewer($viewer)
|
||||
|
@ -52,13 +53,18 @@ final class HarbormasterBuildViewController
|
|||
'/'.$build->getBuildable()->getMonogram());
|
||||
$crumbs->addTextCrumb($title);
|
||||
|
||||
if ($generation === null || $generation > $build->getBuildGeneration() ||
|
||||
$generation < 0) {
|
||||
$generation = $build->getBuildGeneration();
|
||||
}
|
||||
|
||||
$build_targets = id(new HarbormasterBuildTargetQuery())
|
||||
->setViewer($viewer)
|
||||
->needBuildSteps(true)
|
||||
->withBuildPHIDs(array($build->getPHID()))
|
||||
->withBuildGenerations(array($generation))
|
||||
->execute();
|
||||
|
||||
|
||||
if ($build_targets) {
|
||||
$messages = id(new HarbormasterBuildMessageQuery())
|
||||
->setViewer($viewer)
|
||||
|
@ -434,10 +440,13 @@ final class HarbormasterBuildViewController
|
|||
pht('Build Plan'),
|
||||
$handles[$build->getBuildPlanPHID()]->renderLink());
|
||||
|
||||
$properties->addProperty(
|
||||
pht('Restarts'),
|
||||
$build->getBuildGeneration());
|
||||
|
||||
$properties->addProperty(
|
||||
pht('Status'),
|
||||
$this->getStatus($build));
|
||||
|
||||
}
|
||||
|
||||
private function getStatus(HarbormasterBuild $build) {
|
||||
|
|
|
@ -100,7 +100,7 @@ final class HarbormasterBuildEngine extends Phobject {
|
|||
private function updateBuild(HarbormasterBuild $build) {
|
||||
if (($build->getBuildStatus() == HarbormasterBuild::STATUS_PENDING) ||
|
||||
($build->isRestarting())) {
|
||||
$this->destroyBuildTargets($build);
|
||||
$this->restartBuild($build);
|
||||
$build->setBuildStatus(HarbormasterBuild::STATUS_BUILDING);
|
||||
$build->save();
|
||||
}
|
||||
|
@ -122,38 +122,28 @@ final class HarbormasterBuildEngine extends Phobject {
|
|||
}
|
||||
}
|
||||
|
||||
private function destroyBuildTargets(HarbormasterBuild $build) {
|
||||
private function restartBuild(HarbormasterBuild $build) {
|
||||
|
||||
// We're restarting the build, so release all previous artifacts.
|
||||
$this->releaseAllArtifacts($build);
|
||||
|
||||
$targets = id(new HarbormasterBuildTargetQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withBuildPHIDs(array($build->getPHID()))
|
||||
->execute();
|
||||
// Increment the build generation counter on the build.
|
||||
$build->setBuildGeneration($build->getBuildGeneration() + 1);
|
||||
|
||||
if (!$targets) {
|
||||
return;
|
||||
}
|
||||
// TODO: Currently running targets should periodically check their build
|
||||
// generation (which won't have changed) against the build's generation.
|
||||
// If it is different, they should automatically stop what they're doing
|
||||
// and abort.
|
||||
|
||||
$target_phids = mpull($targets, 'getPHID');
|
||||
|
||||
$artifacts = id(new HarbormasterBuildArtifactQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withBuildTargetPHIDs($target_phids)
|
||||
->execute();
|
||||
|
||||
foreach ($artifacts as $artifact) {
|
||||
$artifact->delete();
|
||||
}
|
||||
|
||||
foreach ($targets as $target) {
|
||||
$target->delete();
|
||||
}
|
||||
// Previously we used to delete targets, logs and artifacts here. Instead
|
||||
// leave them around so users can view previous generations of this build.
|
||||
}
|
||||
|
||||
private function updateBuildSteps(HarbormasterBuild $build) {
|
||||
$targets = id(new HarbormasterBuildTargetQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withBuildPHIDs(array($build->getPHID()))
|
||||
->withBuildGenerations(array($build->getBuildGeneration()))
|
||||
->execute();
|
||||
|
||||
$this->updateWaitingTargets($targets);
|
||||
|
@ -454,6 +444,7 @@ final class HarbormasterBuildEngine extends Phobject {
|
|||
$targets = id(new HarbormasterBuildTargetQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withBuildPHIDs(array($build->getPHID()))
|
||||
->withBuildGenerations(array($build->getBuildGeneration()))
|
||||
->execute();
|
||||
|
||||
if (count($targets) === 0) {
|
||||
|
|
|
@ -122,6 +122,13 @@ final class HarbormasterBuildQuery
|
|||
$targets = mgroup($targets, 'getBuildPHID');
|
||||
foreach ($page as $build) {
|
||||
$build_targets = idx($targets, $build->getPHID(), array());
|
||||
|
||||
foreach ($build_targets as $phid => $target) {
|
||||
if ($target->getBuildGeneration() !== $build->getBuildGeneration()) {
|
||||
unset($build_targets[$phid]);
|
||||
}
|
||||
}
|
||||
|
||||
$build->attachBuildTargets($build_targets);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ final class HarbormasterBuildTargetQuery
|
|||
private $ids;
|
||||
private $phids;
|
||||
private $buildPHIDs;
|
||||
private $buildGenerations;
|
||||
private $needBuildSteps;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
|
@ -23,6 +24,11 @@ final class HarbormasterBuildTargetQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withBuildGenerations(array $build_generations) {
|
||||
$this->buildGenerations = $build_generations;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function needBuildSteps($need_build_steps) {
|
||||
$this->needBuildSteps = $need_build_steps;
|
||||
return $this;
|
||||
|
@ -67,6 +73,13 @@ final class HarbormasterBuildTargetQuery
|
|||
$this->buildPHIDs);
|
||||
}
|
||||
|
||||
if ($this->buildGenerations) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'buildGeneration in (%Ld)',
|
||||
$this->buildGenerations);
|
||||
}
|
||||
|
||||
$where[] = $this->buildPagingClause($conn_r);
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
|
|
|
@ -6,6 +6,7 @@ final class HarbormasterBuild extends HarbormasterDAO
|
|||
protected $buildablePHID;
|
||||
protected $buildPlanPHID;
|
||||
protected $buildStatus;
|
||||
protected $buildGeneration;
|
||||
|
||||
private $buildable = self::ATTACHABLE;
|
||||
private $buildPlan = self::ATTACHABLE;
|
||||
|
|
|
@ -12,6 +12,7 @@ final class HarbormasterBuildTarget extends HarbormasterDAO
|
|||
protected $targetStatus;
|
||||
protected $dateStarted;
|
||||
protected $dateCompleted;
|
||||
protected $buildGeneration;
|
||||
|
||||
const STATUS_PENDING = 'target/pending';
|
||||
const STATUS_BUILDING = 'target/building';
|
||||
|
@ -82,7 +83,8 @@ final class HarbormasterBuildTarget extends HarbormasterDAO
|
|||
->setClassName($build_step->getClassName())
|
||||
->setDetails($build_step->getDetails())
|
||||
->setTargetStatus(self::STATUS_PENDING)
|
||||
->setVariables($variables);
|
||||
->setVariables($variables)
|
||||
->setBuildGeneration($build->getBuildGeneration());
|
||||
}
|
||||
|
||||
public function getConfiguration() {
|
||||
|
|
Loading…
Reference in a new issue