@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+54 -26
+5
resources/sql/autopatches/20140821.harbormasterbuildgen.1.sql
··· 1 + ALTER TABLE {$NAMESPACE}_harbormaster.harbormaster_build 2 + ADD COLUMN `buildGeneration` INT UNSIGNED NOT NULL DEFAULT 0; 3 + 4 + ALTER TABLE {$NAMESPACE}_harbormaster.harbormaster_buildtarget 5 + ADD COLUMN `buildGeneration` INT UNSIGNED NOT NULL DEFAULT 0;
+11 -2
src/applications/harbormaster/controller/HarbormasterBuildViewController.php
··· 14 14 $viewer = $request->getUser(); 15 15 16 16 $id = $this->id; 17 + $generation = $request->getInt('g'); 17 18 18 19 $build = id(new HarbormasterBuildQuery()) 19 20 ->setViewer($viewer) ··· 52 53 '/'.$build->getBuildable()->getMonogram()); 53 54 $crumbs->addTextCrumb($title); 54 55 56 + if ($generation === null || $generation > $build->getBuildGeneration() || 57 + $generation < 0) { 58 + $generation = $build->getBuildGeneration(); 59 + } 60 + 55 61 $build_targets = id(new HarbormasterBuildTargetQuery()) 56 62 ->setViewer($viewer) 57 63 ->needBuildSteps(true) 58 64 ->withBuildPHIDs(array($build->getPHID())) 65 + ->withBuildGenerations(array($generation)) 59 66 ->execute(); 60 - 61 67 62 68 if ($build_targets) { 63 69 $messages = id(new HarbormasterBuildMessageQuery()) ··· 435 441 $handles[$build->getBuildPlanPHID()]->renderLink()); 436 442 437 443 $properties->addProperty( 444 + pht('Restarts'), 445 + $build->getBuildGeneration()); 446 + 447 + $properties->addProperty( 438 448 pht('Status'), 439 449 $this->getStatus($build)); 440 - 441 450 } 442 451 443 452 private function getStatus(HarbormasterBuild $build) {
+14 -23
src/applications/harbormaster/engine/HarbormasterBuildEngine.php
··· 100 100 private function updateBuild(HarbormasterBuild $build) { 101 101 if (($build->getBuildStatus() == HarbormasterBuild::STATUS_PENDING) || 102 102 ($build->isRestarting())) { 103 - $this->destroyBuildTargets($build); 103 + $this->restartBuild($build); 104 104 $build->setBuildStatus(HarbormasterBuild::STATUS_BUILDING); 105 105 $build->save(); 106 106 } ··· 122 122 } 123 123 } 124 124 125 - private function destroyBuildTargets(HarbormasterBuild $build) { 126 - $this->releaseAllArtifacts($build); 127 - 128 - $targets = id(new HarbormasterBuildTargetQuery()) 129 - ->setViewer($this->getViewer()) 130 - ->withBuildPHIDs(array($build->getPHID())) 131 - ->execute(); 132 - 133 - if (!$targets) { 134 - return; 135 - } 125 + private function restartBuild(HarbormasterBuild $build) { 136 126 137 - $target_phids = mpull($targets, 'getPHID'); 127 + // We're restarting the build, so release all previous artifacts. 128 + $this->releaseAllArtifacts($build); 138 129 139 - $artifacts = id(new HarbormasterBuildArtifactQuery()) 140 - ->setViewer($this->getViewer()) 141 - ->withBuildTargetPHIDs($target_phids) 142 - ->execute(); 130 + // Increment the build generation counter on the build. 131 + $build->setBuildGeneration($build->getBuildGeneration() + 1); 143 132 144 - foreach ($artifacts as $artifact) { 145 - $artifact->delete(); 146 - } 133 + // TODO: Currently running targets should periodically check their build 134 + // generation (which won't have changed) against the build's generation. 135 + // If it is different, they should automatically stop what they're doing 136 + // and abort. 147 137 148 - foreach ($targets as $target) { 149 - $target->delete(); 150 - } 138 + // Previously we used to delete targets, logs and artifacts here. Instead 139 + // leave them around so users can view previous generations of this build. 151 140 } 152 141 153 142 private function updateBuildSteps(HarbormasterBuild $build) { 154 143 $targets = id(new HarbormasterBuildTargetQuery()) 155 144 ->setViewer($this->getViewer()) 156 145 ->withBuildPHIDs(array($build->getPHID())) 146 + ->withBuildGenerations(array($build->getBuildGeneration())) 157 147 ->execute(); 158 148 159 149 $this->updateWaitingTargets($targets); ··· 454 444 $targets = id(new HarbormasterBuildTargetQuery()) 455 445 ->setViewer(PhabricatorUser::getOmnipotentUser()) 456 446 ->withBuildPHIDs(array($build->getPHID())) 447 + ->withBuildGenerations(array($build->getBuildGeneration())) 457 448 ->execute(); 458 449 459 450 if (count($targets) === 0) {
+7
src/applications/harbormaster/query/HarbormasterBuildQuery.php
··· 122 122 $targets = mgroup($targets, 'getBuildPHID'); 123 123 foreach ($page as $build) { 124 124 $build_targets = idx($targets, $build->getPHID(), array()); 125 + 126 + foreach ($build_targets as $phid => $target) { 127 + if ($target->getBuildGeneration() !== $build->getBuildGeneration()) { 128 + unset($build_targets[$phid]); 129 + } 130 + } 131 + 125 132 $build->attachBuildTargets($build_targets); 126 133 } 127 134 }
+13
src/applications/harbormaster/query/HarbormasterBuildTargetQuery.php
··· 6 6 private $ids; 7 7 private $phids; 8 8 private $buildPHIDs; 9 + private $buildGenerations; 9 10 private $needBuildSteps; 10 11 11 12 public function withIDs(array $ids) { ··· 20 21 21 22 public function withBuildPHIDs(array $build_phids) { 22 23 $this->buildPHIDs = $build_phids; 24 + return $this; 25 + } 26 + 27 + public function withBuildGenerations(array $build_generations) { 28 + $this->buildGenerations = $build_generations; 23 29 return $this; 24 30 } 25 31 ··· 65 71 $conn_r, 66 72 'buildPHID in (%Ls)', 67 73 $this->buildPHIDs); 74 + } 75 + 76 + if ($this->buildGenerations) { 77 + $where[] = qsprintf( 78 + $conn_r, 79 + 'buildGeneration in (%Ld)', 80 + $this->buildGenerations); 68 81 } 69 82 70 83 $where[] = $this->buildPagingClause($conn_r);
+1
src/applications/harbormaster/storage/build/HarbormasterBuild.php
··· 6 6 protected $buildablePHID; 7 7 protected $buildPlanPHID; 8 8 protected $buildStatus; 9 + protected $buildGeneration; 9 10 10 11 private $buildable = self::ATTACHABLE; 11 12 private $buildPlan = self::ATTACHABLE;
+3 -1
src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php
··· 12 12 protected $targetStatus; 13 13 protected $dateStarted; 14 14 protected $dateCompleted; 15 + protected $buildGeneration; 15 16 16 17 const STATUS_PENDING = 'target/pending'; 17 18 const STATUS_BUILDING = 'target/building'; ··· 82 83 ->setClassName($build_step->getClassName()) 83 84 ->setDetails($build_step->getDetails()) 84 85 ->setTargetStatus(self::STATUS_PENDING) 85 - ->setVariables($variables); 86 + ->setVariables($variables) 87 + ->setBuildGeneration($build->getBuildGeneration()); 86 88 } 87 89 88 90 public function getConfiguration() {