Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F18729823
D9807.id23652.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
8 KB
Referenced Files
None
Subscribers
None
D9807.id23652.diff
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -787,6 +787,7 @@
'HarbormasterPlanViewController' => 'applications/harbormaster/controller/HarbormasterPlanViewController.php',
'HarbormasterPublishFragmentBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterPublishFragmentBuildStepImplementation.php',
'HarbormasterRemarkupRule' => 'applications/harbormaster/remarkup/HarbormasterRemarkupRule.php',
+ 'HarbormasterRunBuildPlanBuildImplementation' => 'applications/harbormaster/step/HarbormasterRunBuildPlanBuildImplementation.php',
'HarbormasterScratchTable' => 'applications/harbormaster/storage/HarbormasterScratchTable.php',
'HarbormasterSleepBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterSleepBuildStepImplementation.php',
'HarbormasterStepAddController' => 'applications/harbormaster/controller/HarbormasterStepAddController.php',
@@ -3541,6 +3542,7 @@
'HarbormasterPlanViewController' => 'HarbormasterPlanController',
'HarbormasterPublishFragmentBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
'HarbormasterRemarkupRule' => 'PhabricatorRemarkupRuleObject',
+ 'HarbormasterRunBuildPlanBuildImplementation' => 'HarbormasterBuildStepImplementation',
'HarbormasterScratchTable' => 'HarbormasterDAO',
'HarbormasterSleepBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
'HarbormasterStepAddController' => 'HarbormasterController',
diff --git a/src/applications/harbormaster/controller/HarbormasterPlanViewController.php b/src/applications/harbormaster/controller/HarbormasterPlanViewController.php
--- a/src/applications/harbormaster/controller/HarbormasterPlanViewController.php
+++ b/src/applications/harbormaster/controller/HarbormasterPlanViewController.php
@@ -37,7 +37,7 @@
$title = pht('Plan %d', $id);
$header = id(new PHUIHeaderView())
- ->setHeader($title)
+ ->setHeader($plan->getName())
->setUser($viewer)
->setPolicyObject($plan);
diff --git a/src/applications/harbormaster/step/HarbormasterRunBuildPlanBuildImplementation.php b/src/applications/harbormaster/step/HarbormasterRunBuildPlanBuildImplementation.php
new file mode 100644
--- /dev/null
+++ b/src/applications/harbormaster/step/HarbormasterRunBuildPlanBuildImplementation.php
@@ -0,0 +1,202 @@
+<?php
+
+final class HarbormasterRunBuildPlanBuildImplementation
+ extends HarbormasterBuildStepImplementation {
+
+ public function getName() {
+ return pht('Start or Wait for Build Plan');
+ }
+
+ public function getGenericDescription() {
+ return pht(
+ 'Start or wait for another build plan to finish on the same buildable.');
+ }
+
+ public function getDescription() {
+ $target_plan_id = $this->getSetting('id');
+ $never_start = $this->getSetting('waitonly');
+
+ $prefix = pht('Start and / or wait');
+ if ($never_start) {
+ $prefix = pht('Wait');
+ }
+
+ $target_plan = id(new HarbormasterBuildPlanQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withIDs(array($target_plan_id))
+ ->executeOne();
+
+ if ($target_plan === null) {
+ return pht(
+ '%s for a non-existent build plan '.
+ 'to finish on this buildable.',
+ $prefix);
+ }
+
+ $name = $this->formatValueForDescription($target_plan->getName());
+
+ return pht(
+ '%s for build plan %s to finish on this buildable.',
+ $prefix,
+ $name);
+ }
+
+ public function execute(
+ HarbormasterBuild $build,
+ HarbormasterBuildTarget $build_target) {
+
+ $target_plan_id = $this->getSetting('id');
+ $never_start = $this->getSetting('waitonly');
+
+ // Get the target build plan type.
+ $target_plan = id(new HarbormasterBuildPlanQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withIDs(array($target_plan_id))
+ ->executeOne();
+ if (!$target_plan) {
+ throw new Exception('Unable to find build plan with ID '.$target_plan_id);
+ }
+
+ // If the target plan is the same as the current plan, we
+ // automatically pass.
+ if ($target_plan->getPHID() === $build->getBuildPlanPHID()) {
+ return;
+ }
+
+ // Find all other builds running on this buildable.
+ $buildable = $build->getBuildable();
+ $other_builds = id(new HarbormasterBuildQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withBuildablePHIDs(array($buildable->getPHID()))
+ ->execute();
+
+ // Find the build for that build plan (if it exists).
+ $target_build = null;
+ foreach ($other_builds as $other_build) {
+ if ($other_build->getBuildPlanPHID() === $target_plan->getPHID()) {
+ $target_build = $other_build;
+ break;
+ }
+ }
+
+ if (!$never_start) {
+ if ($target_build === null) {
+ // There is no current build with this build plan on the buildable,
+ // so now we're going to start one.
+ $target_build = $build->getBuildable()->applyPlan($target_plan);
+ } else {
+ // If the build plan has failed on a previous run, restart it.
+ switch ($target_build->getBuildStatus()) {
+ case HarbormasterBuild::STATUS_FAILED:
+ case HarbormasterBuild::STATUS_ERROR: {
+ $harbormaster_phid = id(new PhabricatorApplicationHarbormaster())
+ ->getPHID();
+
+ $daemon_source = PhabricatorContentSource::newForSource(
+ PhabricatorContentSource::SOURCE_DAEMON,
+ array());
+
+ $editor = id(new HarbormasterBuildTransactionEditor())
+ ->setActor(PhabricatorUser::getOmnipotentUser())
+ ->setActingAsPHID($harbormaster_phid)
+ ->setContentSource($daemon_source)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true);
+
+ $xaction = id(new HarbormasterBuildTransaction())
+ ->setTransactionType(HarbormasterBuildTransaction::TYPE_COMMAND)
+ ->setNewValue(HarbormasterBuildCommand::COMMAND_RESTART);
+
+ $editor->applyTransactions($target_build, array($xaction));
+
+ break;
+ }
+ }
+ }
+ }
+
+ if ($target_build !== null) {
+ $target_build_phid = $target_build->getPHID();
+ } else {
+ $target_build_phid = null;
+ }
+
+ do {
+
+ // If the target build PHID is currently null, then we
+ // are in a wait-only scenario (there's no other way for this
+ // to be null). In this case, we just keep polling for the
+ // appearance of a build with the appropriate build plan.
+ if ($target_build_phid === null) {
+ // Find all other builds running on this buildable.
+ $buildable = $build->getBuildable();
+ $other_builds = id(new HarbormasterBuildQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withBuildablePHIDs(array($buildable->getPHID()))
+ ->execute();
+
+ // Find the build for that build plan (if it exists).
+ $target_build = null;
+ foreach ($other_builds as $other_build) {
+ if ($other_build->getBuildPlanPHID() === $target_plan->getPHID()) {
+ $target_build = $other_build;
+ break;
+ }
+ }
+
+ if ($target_build === null) {
+ sleep(15);
+ continue;
+ } else {
+ $target_build_phid = $target_build->getPHID();
+ }
+ }
+
+ // Re-query to get the latest state.
+ $target_build = id(new HarbormasterBuildQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withPHIDs(array($target_build_phid))
+ ->executeOne();
+
+ if (!$target_build) {
+ throw new Exception('Build has disappeared!');
+ }
+
+ // If the build has not yet passed, yield for the moment.
+ if ($target_build->isBuilding() || $target_build->isRestarting() ||
+ $target_build->getBuildStatus() === HarbormasterBuild::STATUS_STOPPED) {
+ sleep(15);
+ continue;
+ }
+
+ // Otherwise check the result and if it's an error or failure result,
+ // then throw an exception.
+ switch ($target_build->getBuildStatus()) {
+ case HarbormasterBuild::STATUS_FAILED:
+ case HarbormasterBuild::STATUS_ERROR:
+ throw new Exception('Build plan failed, not continuing!');
+ }
+
+ // Pass if we get to here.
+ break;
+ } while (true);
+ }
+
+ public function getFieldSpecifications() {
+ return array(
+ 'id' => array(
+ 'name' => pht('Target Build Plan ID'),
+ 'type' => 'text',
+ 'required' => true,
+ ),
+ 'waitonly' => array(
+ 'name' => pht('Do Not Start'),
+ 'type' => 'bool',
+ 'caption' => pht(
+ 'Only wait for the build plan, never start it from this step.'),
+ ),
+ );
+ }
+
+
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Oct 1 2025, 11:55 AM (22 w, 21 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
8872004
Default Alt Text
D9807.id23652.diff (8 KB)
Attached To
Mode
D9807: [harbormaster/run-build-plan] Implement build step for running another build plan
Attached
Detach File
Event Timeline
Log In to Comment