@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 "Wait for Previous Builds" build step

Summary: This adds a build step which will block a build from continuing if there are previous builds of the build plan still running.

Test Plan: Configured a build plan with a wait of 60 seconds and a "wait for previous builds", then started a build. While that was still building, reconfigured the plan to have a wait time of 3 seconds, started it, and saw it move into the "Waiting" status. When the 60 second build finished, both builds passed.

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley

CC: Korvin, epriestley, aran

Maniphest Tasks: T1049

Differential Revision: https://secure.phabricator.com/D7745

+144 -5
+2
src/__phutil_library_map__.php
··· 2366 2366 'SlowvoteRemarkupRule' => 'applications/slowvote/remarkup/SlowvoteRemarkupRule.php', 2367 2367 'UploadArtifactBuildStepImplementation' => 'applications/harbormaster/step/UploadArtifactBuildStepImplementation.php', 2368 2368 'VariableBuildStepImplementation' => 'applications/harbormaster/step/VariableBuildStepImplementation.php', 2369 + 'WaitForPreviousBuildStepImplementation' => 'applications/harbormaster/step/WaitForPreviousBuildStepImplementation.php', 2369 2370 ), 2370 2371 'function' => 2371 2372 array( ··· 5056 5057 'SlowvoteRemarkupRule' => 'PhabricatorRemarkupRuleObject', 5057 5058 'UploadArtifactBuildStepImplementation' => 'VariableBuildStepImplementation', 5058 5059 'VariableBuildStepImplementation' => 'BuildStepImplementation', 5060 + 'WaitForPreviousBuildStepImplementation' => 'BuildStepImplementation', 5059 5061 ), 5060 5062 ));
+5 -2
src/applications/harbormaster/controller/HarbormasterBuildViewController.php
··· 49 49 $targets = array(); 50 50 foreach ($build_targets as $build_target) { 51 51 $header = id(new PHUIHeaderView()) 52 - ->setHeader(pht('Build Target %d', $build_target->getID())) 52 + ->setHeader(pht( 53 + 'Build Target %d (%s)', 54 + $build_target->getID(), 55 + $build_target->getImplementation()->getName())) 53 56 ->setUser($viewer); 54 57 $properties = new PHUIPropertyListView(); 55 58 ··· 280 283 case HarbormasterBuild::STATUS_PENDING: 281 284 return pht('Pending'); 282 285 case HarbormasterBuild::STATUS_WAITING: 283 - return pht('Waiting on Resource'); 286 + return pht('Waiting'); 284 287 case HarbormasterBuild::STATUS_BUILDING: 285 288 return pht('Building'); 286 289 case HarbormasterBuild::STATUS_PASSED:
+2 -2
src/applications/harbormaster/controller/HarbormasterBuildableViewController.php
··· 52 52 $item->addAttribute(pht('Pending')); 53 53 break; 54 54 case HarbormasterBuild::STATUS_WAITING: 55 - $item->setBarColor('blue'); 56 - $item->addAttribute(pht('Waiting on Resource')); 55 + $item->setBarColor('violet'); 56 + $item->addAttribute(pht('Waiting')); 57 57 break; 58 58 case HarbormasterBuild::STATUS_BUILDING: 59 59 $item->setBarColor('yellow');
+1 -1
src/applications/harbormaster/step/BuildStepImplementation.php
··· 53 53 /** 54 54 * Validate the current settings of this build step. 55 55 */ 56 - public function validate() { 56 + public function validateSettings() { 57 57 return true; 58 58 } 59 59
+127
src/applications/harbormaster/step/WaitForPreviousBuildStepImplementation.php
··· 1 + <?php 2 + 3 + final class WaitForPreviousBuildStepImplementation 4 + extends BuildStepImplementation { 5 + 6 + public function getName() { 7 + return pht('Wait for Previous Commits to Build'); 8 + } 9 + 10 + public function getGenericDescription() { 11 + return pht( 12 + 'Wait for previous commits to finish building the current plan '. 13 + 'before continuing.'); 14 + } 15 + 16 + public function getDescription() { 17 + return pht( 18 + 'Wait for previous commits to finish building the current plan '. 19 + 'before continuing.'); 20 + } 21 + 22 + public function execute( 23 + HarbormasterBuild $build, 24 + HarbormasterBuildTarget $build_target) { 25 + 26 + // We can only wait when building against commits. 27 + $buildable = $build->getBuildable(); 28 + $object = $buildable->getBuildableObject(); 29 + if (!($object instanceof PhabricatorRepositoryCommit)) { 30 + return; 31 + } 32 + 33 + // We are blocked until all previous builds finish. 34 + $build->setBuildStatus(HarbormasterBuild::STATUS_WAITING); 35 + $build->save(); 36 + 37 + // Block until all previous builds of the same build plan have 38 + // finished. 39 + $plan = $build->getBuildPlan(); 40 + 41 + $log = null; 42 + $log_start = null; 43 + $blockers = $this->getBlockers($object, $plan, $build); 44 + while (count($blockers) > 0) { 45 + if ($build->checkForCancellation()) { 46 + if ($log !== null) { 47 + $log->finalize($log_start); 48 + } 49 + return; 50 + } 51 + 52 + if ($log === null) { 53 + $log = $build->createLog($build_target, "waiting", "blockers"); 54 + $log_start = $log->start(); 55 + } 56 + 57 + $log->append("Blocked by: ".implode(",", $blockers)."\n"); 58 + 59 + sleep(1); 60 + $blockers = $this->getBlockers($object, $plan, $build); 61 + } 62 + if ($log !== null) { 63 + $log->finalize($log_start); 64 + } 65 + 66 + // Move back into building status. 67 + $build->setBuildStatus(HarbormasterBuild::STATUS_BUILDING); 68 + $build->save(); 69 + } 70 + 71 + private function getBlockers( 72 + PhabricatorRepositoryCommit $commit, 73 + HarbormasterBuildPlan $plan, 74 + HarbormasterBuild $source) { 75 + 76 + $call = new ConduitCall( 77 + 'diffusion.commitparentsquery', 78 + array( 79 + 'commit' => $commit->getCommitIdentifier(), 80 + 'callsign' => $commit->getRepository()->getCallsign() 81 + )); 82 + $call->setUser(PhabricatorUser::getOmnipotentUser()); 83 + $parents = $call->execute(); 84 + 85 + $hashes = array(); 86 + foreach ($parents as $parent => $obj) { 87 + $hashes[] = $parent; 88 + } 89 + 90 + $parents = id(new DiffusionCommitQuery()) 91 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 92 + ->withRepository($commit->getRepository()) 93 + ->withIdentifiers($hashes) 94 + ->execute(); 95 + 96 + $blockers = array(); 97 + 98 + $build_objects = array(); 99 + foreach ($parents as $parent) { 100 + if (!$parent->isImported()) { 101 + $blockers[] = pht('Commit %s', $parent->getCommitIdentifier()); 102 + } else { 103 + $build_objects[] = $parent->getPHID(); 104 + } 105 + } 106 + 107 + $buildables = id(new HarbormasterBuildableQuery()) 108 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 109 + ->withBuildablePHIDs($build_objects) 110 + ->execute(); 111 + $buildable_phids = mpull($buildables, 'getPHID'); 112 + 113 + $builds = id(new HarbormasterBuildQuery()) 114 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 115 + ->withBuildablePHIDs($buildable_phids) 116 + ->withBuildPlanPHIDs(array($plan->getPHID())) 117 + ->execute(); 118 + 119 + foreach ($builds as $build) { 120 + if ($build->isBuilding()) { 121 + $blockers[] = pht('Build %d', $build->getID()); 122 + } 123 + } 124 + 125 + return $blockers; 126 + } 127 + }
+7
src/applications/harbormaster/storage/build/HarbormasterBuild.php
··· 94 94 return $this->assertAttached($this->buildPlan); 95 95 } 96 96 97 + public function isBuilding() { 98 + return $this->getBuildStatus() === self::STATUS_PENDING || 99 + $this->getBuildStatus() === self::STATUS_WAITING || 100 + $this->getBuildStatus() === self::STATUS_BUILDING || 101 + $this->getCancelRequested(); 102 + } 103 + 97 104 public function createLog( 98 105 HarbormasterBuildTarget $build_target, 99 106 $log_source,