Add bin/harbormaster to make builds easier to debug
				
					
				
			Summary: Ref T1049. Adds `bin/harbormaster` and `bin/harbormaster build` for applying plans from the console. Since this gets `--trace`, it's much easier to debug what's going on. This doesn't work properly with some of the Drydock steps yet, I need to look at those. I think `setRunAllTasksInProcess` probably obsoletes some of the mechanisms. It might also not work with "Wait for Builds" but I didn't check. Test Plan: Used `bin/harbormaster` to run a bunch of builds. Ran builds from web UI. Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T1049 Differential Revision: https://secure.phabricator.com/D7825
This commit is contained in:
		
							
								
								
									
										1
									
								
								bin/harbormaster
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								bin/harbormaster
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | ||||
| ../scripts/setup/manage_harbormaster.php | ||||
							
								
								
									
										22
									
								
								scripts/setup/manage_harbormaster.php
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										22
									
								
								scripts/setup/manage_harbormaster.php
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| #!/usr/bin/env php | ||||
| <?php | ||||
|  | ||||
| $root = dirname(dirname(dirname(__FILE__))); | ||||
| require_once $root.'/scripts/__init_script__.php'; | ||||
|  | ||||
| $args = new PhutilArgumentParser($argv); | ||||
| $args->setTagline('manage Harbormaster'); | ||||
| $args->setSynopsis(<<<EOSYNOPSIS | ||||
| **harbormaster** __command__ [__options__] | ||||
|   Manage and debug Harbormaster. | ||||
|  | ||||
| EOSYNOPSIS | ||||
|   ); | ||||
| $args->parseStandardArguments(); | ||||
|  | ||||
| $workflows = id(new PhutilSymbolLoader()) | ||||
|   ->setAncestorClass('HarbormasterManagementWorkflow') | ||||
|   ->loadObjects(); | ||||
| $workflows[] = new PhutilHelpArgumentWorkflow(); | ||||
|  | ||||
| $args->parseWorkflows($workflows); | ||||
| @@ -707,6 +707,7 @@ phutil_register_library_map(array( | ||||
|     'HarbormasterBuildViewController' => 'applications/harbormaster/controller/HarbormasterBuildViewController.php', | ||||
|     'HarbormasterBuildWorker' => 'applications/harbormaster/worker/HarbormasterBuildWorker.php', | ||||
|     'HarbormasterBuildable' => 'applications/harbormaster/storage/HarbormasterBuildable.php', | ||||
|     'HarbormasterBuildableInterface' => 'applications/harbormaster/interface/HarbormasterBuildableInterface.php', | ||||
|     'HarbormasterBuildableListController' => 'applications/harbormaster/controller/HarbormasterBuildableListController.php', | ||||
|     'HarbormasterBuildableQuery' => 'applications/harbormaster/query/HarbormasterBuildableQuery.php', | ||||
|     'HarbormasterBuildableSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildableSearchEngine.php', | ||||
| @@ -715,6 +716,8 @@ phutil_register_library_map(array( | ||||
|     'HarbormasterController' => 'applications/harbormaster/controller/HarbormasterController.php', | ||||
|     'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php', | ||||
|     'HarbormasterHTTPRequestBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php', | ||||
|     'HarbormasterManagementBuildWorkflow' => 'applications/harbormaster/management/HarbormasterManagementBuildWorkflow.php', | ||||
|     'HarbormasterManagementWorkflow' => 'applications/harbormaster/management/HarbormasterManagementWorkflow.php', | ||||
|     'HarbormasterObject' => 'applications/harbormaster/storage/HarbormasterObject.php', | ||||
|     'HarbormasterPHIDTypeBuild' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuild.php', | ||||
|     'HarbormasterPHIDTypeBuildItem' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuildItem.php', | ||||
| @@ -2747,6 +2750,7 @@ phutil_register_library_map(array( | ||||
|     array( | ||||
|       0 => 'DifferentialDAO', | ||||
|       1 => 'PhabricatorPolicyInterface', | ||||
|       2 => 'HarbormasterBuildableInterface', | ||||
|     ), | ||||
|     'DifferentialDiffContentMail' => 'DifferentialMail', | ||||
|     'DifferentialDiffCreateController' => 'DifferentialController', | ||||
| @@ -2814,6 +2818,7 @@ phutil_register_library_map(array( | ||||
|       2 => 'PhabricatorPolicyInterface', | ||||
|       3 => 'PhabricatorFlaggableInterface', | ||||
|       4 => 'PhrequentTrackableInterface', | ||||
|       5 => 'HarbormasterBuildableInterface', | ||||
|     ), | ||||
|     'DifferentialRevisionCommentListView' => 'AphrontView', | ||||
|     'DifferentialRevisionCommentView' => 'AphrontView', | ||||
| @@ -3131,6 +3136,7 @@ phutil_register_library_map(array( | ||||
|     array( | ||||
|       0 => 'HarbormasterDAO', | ||||
|       1 => 'PhabricatorPolicyInterface', | ||||
|       2 => 'HarbormasterBuildableInterface', | ||||
|     ), | ||||
|     'HarbormasterBuildableListController' => | ||||
|     array( | ||||
| @@ -3144,6 +3150,8 @@ phutil_register_library_map(array( | ||||
|     'HarbormasterController' => 'PhabricatorController', | ||||
|     'HarbormasterDAO' => 'PhabricatorLiskDAO', | ||||
|     'HarbormasterHTTPRequestBuildStepImplementation' => 'VariableBuildStepImplementation', | ||||
|     'HarbormasterManagementBuildWorkflow' => 'HarbormasterManagementWorkflow', | ||||
|     'HarbormasterManagementWorkflow' => 'PhutilArgumentWorkflow', | ||||
|     'HarbormasterObject' => 'HarbormasterDAO', | ||||
|     'HarbormasterPHIDTypeBuild' => 'PhabricatorPHIDType', | ||||
|     'HarbormasterPHIDTypeBuildItem' => 'PhabricatorPHIDType', | ||||
| @@ -4342,6 +4350,7 @@ phutil_register_library_map(array( | ||||
|       1 => 'PhabricatorPolicyInterface', | ||||
|       2 => 'PhabricatorFlaggableInterface', | ||||
|       3 => 'PhabricatorTokenReceiverInterface', | ||||
|       4 => 'HarbormasterBuildableInterface', | ||||
|     ), | ||||
|     'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker', | ||||
|     'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO', | ||||
|   | ||||
| @@ -2,7 +2,9 @@ | ||||
|  | ||||
| final class DifferentialDiff | ||||
|   extends DifferentialDAO | ||||
|   implements PhabricatorPolicyInterface { | ||||
|   implements | ||||
|     PhabricatorPolicyInterface, | ||||
|     HarbormasterBuildableInterface { | ||||
|  | ||||
|   protected $revisionID; | ||||
|   protected $authorPHID; | ||||
| @@ -339,4 +341,24 @@ final class DifferentialDiff | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* -(  HarbormasterBuildableInterface  )------------------------------------- */ | ||||
|  | ||||
|  | ||||
|   public function getHarbormasterBuildablePHID() { | ||||
|     return $this->getPHID(); | ||||
|   } | ||||
|  | ||||
|   public function getHarbormasterContainerPHID() { | ||||
|     if ($this->getRevisionID()) { | ||||
|       $revision = id(new DifferentialRevision())->load($this->getRevisionID()); | ||||
|       if ($revision) { | ||||
|         return $revision->getPHID(); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -5,7 +5,8 @@ final class DifferentialRevision extends DifferentialDAO | ||||
|     PhabricatorTokenReceiverInterface, | ||||
|     PhabricatorPolicyInterface, | ||||
|     PhabricatorFlaggableInterface, | ||||
|     PhrequentTrackableInterface { | ||||
|     PhrequentTrackableInterface, | ||||
|     HarbormasterBuildableInterface { | ||||
|  | ||||
|   protected $title = ''; | ||||
|   protected $originalTitle; | ||||
| @@ -412,4 +413,16 @@ final class DifferentialRevision extends DifferentialDAO | ||||
|     return DifferentialRevisionStatus::isClosedStatus($this->getStatus()); | ||||
|   } | ||||
|  | ||||
|  | ||||
| /* -(  HarbormasterBuildableInterface  )------------------------------------- */ | ||||
|  | ||||
|  | ||||
|   public function getHarbormasterBuildablePHID() { | ||||
|     return $this->loadActiveDiff()->getPHID(); | ||||
|   } | ||||
|  | ||||
|   public function getHarbormasterContainerPHID() { | ||||
|     return $this->getPHID(); | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -41,16 +41,10 @@ final class HarbormasterPlanRunController | ||||
|           ->withNames(array($v_name)) | ||||
|           ->executeOne(); | ||||
|  | ||||
|         if ($object instanceof DifferentialRevision) { | ||||
|           $revision = $object; | ||||
|           $object = $object->loadActiveDiff(); | ||||
|         if ($object instanceof HarbormasterBuildableInterface) { | ||||
|           $buildable | ||||
|             ->setBuildablePHID($object->getPHID()) | ||||
|             ->setContainerPHID($revision->getPHID()); | ||||
|         } else if ($object instanceof PhabricatorRepositoryCommit) { | ||||
|           $buildable | ||||
|             ->setBuildablePHID($object->getPHID()) | ||||
|             ->setContainerPHID($object->getRepository()->getPHID()); | ||||
|             ->setBuildablePHID($object->getHarbormasterBuildablePHID()) | ||||
|             ->setContainerPHID($object->getHarbormasterContainerPHID()); | ||||
|         } else { | ||||
|           $e_name = pht('Invalid'); | ||||
|           $errors[] = pht('Enter the name of a revision or commit.'); | ||||
| @@ -62,6 +56,7 @@ final class HarbormasterPlanRunController | ||||
|  | ||||
|       if (!$errors) { | ||||
|         $buildable->save(); | ||||
|         $buildable->applyPlan($plan); | ||||
|  | ||||
|         $buildable_uri = '/B'.$buildable->getID(); | ||||
|         return id(new AphrontRedirectResponse())->setURI($buildable_uri); | ||||
| @@ -80,8 +75,12 @@ final class HarbormasterPlanRunController | ||||
|       ->setUser($viewer) | ||||
|       ->appendRemarkupInstructions( | ||||
|         pht( | ||||
|           "Enter the name of a commit or revision to run this plan on.\n\n". | ||||
|           "For example: `rX123456` or `D123`")) | ||||
|           "Enter the name of a commit or revision to run this plan on (for ". | ||||
|           "example, `rX123456` or `D123`).\n\n". | ||||
|           "For more detailed output, you can also run manual builds from ". | ||||
|           "the command line:\n\n". | ||||
|           "  phabricator/ $ ./bin/harbormaster build <object> --plan %s", | ||||
|           $plan->getID())) | ||||
|       ->appendChild( | ||||
|         id(new AphrontFormTextControl()) | ||||
|           ->setLabel('Buildable Name') | ||||
| @@ -90,7 +89,7 @@ final class HarbormasterPlanRunController | ||||
|           ->setValue($v_name)); | ||||
|  | ||||
|     $dialog = id(new AphrontDialogView()) | ||||
|       ->setWidth(AphrontDialogView::WIDTH_FORM) | ||||
|       ->setWidth(AphrontDialogView::WIDTH_FULL) | ||||
|       ->setUser($viewer) | ||||
|       ->setTitle($title) | ||||
|       ->appendChild($form) | ||||
|   | ||||
| @@ -24,12 +24,19 @@ final class HarbormasterUIEventListener | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     $target = null; | ||||
|     if ($object instanceof PhabricatorRepositoryCommit) { | ||||
|       $target = $object; | ||||
|     } elseif ($object instanceof DifferentialRevision) { | ||||
|       $target = $object->loadActiveDiff(); | ||||
|     } else { | ||||
|     if ($object instanceof HarbormasterBuildable) { | ||||
|       // Although HarbormasterBuildable implements the correct interface, it | ||||
|       // does not make sense to show a build's build status. In the best case | ||||
|       // it is meaningless, and in the worst case it's confusing. | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     if (!($object instanceof HarbormasterBuildableInterface)) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     $buildable_phid = $object->getBuildablePHID(); | ||||
|     if (!$buildable_phid) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
| @@ -39,7 +46,8 @@ final class HarbormasterUIEventListener | ||||
|  | ||||
|     $buildables = id(new HarbormasterBuildableQuery()) | ||||
|       ->setViewer($user) | ||||
|       ->withBuildablePHIDs(array($target->getPHID())) | ||||
|       ->withManualBuildables(false) | ||||
|       ->withBuildablePHIDs(array($buildable_phid)) | ||||
|       ->execute(); | ||||
|     if (!$buildables) { | ||||
|       return; | ||||
| @@ -62,8 +70,7 @@ final class HarbormasterUIEventListener | ||||
|  | ||||
|     foreach ($builds as $build) { | ||||
|       $item = new PHUIStatusItemView(); | ||||
|       $item->setTarget( | ||||
|         $build_handles[$build->getPHID()]->renderLink()); | ||||
|       $item->setTarget($build_handles[$build->getPHID()]->renderLink()); | ||||
|  | ||||
|       switch ($build->getBuildStatus()) { | ||||
|         case HarbormasterBuild::STATUS_INACTIVE: | ||||
|   | ||||
| @@ -0,0 +1,8 @@ | ||||
| <?php | ||||
|  | ||||
| interface HarbormasterBuildableInterface { | ||||
|  | ||||
|   public function getHarbormasterBuildablePHID(); | ||||
|   public function getHarbormasterContainerPHID(); | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,92 @@ | ||||
| <?php | ||||
|  | ||||
| final class HarbormasterManagementBuildWorkflow | ||||
|   extends HarbormasterManagementWorkflow { | ||||
|  | ||||
|   public function didConstruct() { | ||||
|     $this | ||||
|       ->setName('build') | ||||
|       ->setExamples('**build** [__options__] __buildable__ --plan __id__') | ||||
|       ->setSynopsis(pht('Run plan __id__ on __buildable__.')) | ||||
|       ->setArguments( | ||||
|         array( | ||||
|           array( | ||||
|             'name' => 'plan', | ||||
|             'param' => 'id', | ||||
|             'help' => pht('ID of build plan to run.'), | ||||
|           ), | ||||
|           array( | ||||
|             'name'        => 'buildable', | ||||
|             'wildcard'    => true, | ||||
|           ), | ||||
|         )); | ||||
|   } | ||||
|  | ||||
|   public function execute(PhutilArgumentParser $args) { | ||||
|     $viewer = PhabricatorUser::getOmnipotentUser(); | ||||
|  | ||||
|     $names = $args->getArg('buildable'); | ||||
|     if (count($names) != 1) { | ||||
|       throw new PhutilArgumentUsageException( | ||||
|         pht('Specify exactly one buildable, by object name.')); | ||||
|     } | ||||
|  | ||||
|     $name = head($names); | ||||
|  | ||||
|     $buildable = id(new PhabricatorObjectQuery()) | ||||
|       ->setViewer($viewer) | ||||
|       ->withNames($names) | ||||
|       ->executeOne(); | ||||
|     if (!$buildable) { | ||||
|       throw new PhutilArgumentUsageException( | ||||
|         pht('No such buildable "%s"!', $name)); | ||||
|     } | ||||
|  | ||||
|     if (!($buildable instanceof HarbormasterBuildableInterface)) { | ||||
|       throw new PhutilArgumentUsageException( | ||||
|         pht('Object "%s" is not a buildable!', $name)); | ||||
|     } | ||||
|  | ||||
|     $plan_id = $args->getArg('plan'); | ||||
|     if (!$plan_id) { | ||||
|       throw new PhutilArgumentUsageException( | ||||
|         pht('Use --plan to specify a build plan to run.')); | ||||
|     } | ||||
|  | ||||
|     $plan = id(new HarbormasterBuildPlanQuery()) | ||||
|       ->setViewer($viewer) | ||||
|       ->withIDs(array($plan_id)) | ||||
|       ->executeOne(); | ||||
|     if (!$plan) { | ||||
|       throw new PhutilArgumentUsageException( | ||||
|         pht('Build plan "%s" does not exist.', $plan_id)); | ||||
|     } | ||||
|  | ||||
|     $console = PhutilConsole::getConsole(); | ||||
|  | ||||
|     $buildable = HarbormasterBuildable::initializeNewBuildable($viewer) | ||||
|       ->setIsManualBuildable(true) | ||||
|       ->setBuildablePHID($buildable->getHarbormasterBuildablePHID()) | ||||
|       ->setContainerPHID($buildable->getHarbormasterContainerPHID()) | ||||
|       ->save(); | ||||
|  | ||||
|     $console->writeOut( | ||||
|       "%s\n", | ||||
|       pht( | ||||
|         'Applying plan %s to new buildable %s...', | ||||
|         $plan->getID(), | ||||
|         'B'.$buildable->getID())); | ||||
|  | ||||
|     $console->writeOut( | ||||
|       "\n    %s\n\n", | ||||
|       PhabricatorEnv::getProductionURI('/B'.$buildable->getID())); | ||||
|  | ||||
|     PhabricatorWorker::setRunAllTasksInProcess(true); | ||||
|     $buildable->applyPlan($plan); | ||||
|  | ||||
|     $console->writeOut("%s\n", pht('Done.')); | ||||
|  | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,10 @@ | ||||
| <?php | ||||
|  | ||||
| abstract class HarbormasterManagementWorkflow | ||||
|   extends PhutilArgumentWorkflow { | ||||
|  | ||||
|   public function isExecutable() { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -1,7 +1,9 @@ | ||||
| <?php | ||||
|  | ||||
| final class HarbormasterBuildable extends HarbormasterDAO | ||||
|   implements PhabricatorPolicyInterface { | ||||
|   implements | ||||
|     PhabricatorPolicyInterface, | ||||
|     HarbormasterBuildableInterface { | ||||
|  | ||||
|   protected $buildablePHID; | ||||
|   protected $containerPHID; | ||||
| @@ -86,19 +88,25 @@ final class HarbormasterBuildable extends HarbormasterDAO | ||||
|         continue; | ||||
|       } | ||||
|  | ||||
|       $build = HarbormasterBuild::initializeNewBuild( | ||||
|         PhabricatorUser::getOmnipotentUser()); | ||||
|       $build->setBuildablePHID($buildable->getPHID()); | ||||
|       $build->setBuildPlanPHID($plan->getPHID()); | ||||
|       $build->setBuildStatus(HarbormasterBuild::STATUS_PENDING); | ||||
|       $build->save(); | ||||
|       $buildable->applyPlan($plan); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   public function applyPlan(HarbormasterBuildPlan $plan) { | ||||
|     $viewer = PhabricatorUser::getOmnipotentUser(); | ||||
|     $build = HarbormasterBuild::initializeNewBuild($viewer) | ||||
|       ->setBuildablePHID($this->getPHID()) | ||||
|       ->setBuildPlanPHID($plan->getPHID()) | ||||
|       ->setBuildStatus(HarbormasterBuild::STATUS_PENDING) | ||||
|       ->save(); | ||||
|  | ||||
|     PhabricatorWorker::scheduleTask( | ||||
|       'HarbormasterBuildWorker', | ||||
|       array( | ||||
|         'buildID' => $build->getID() | ||||
|       )); | ||||
|     } | ||||
|  | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   public function getConfiguration() { | ||||
| @@ -184,4 +192,21 @@ final class HarbormasterBuildable extends HarbormasterDAO | ||||
|       'buildable.'); | ||||
|   } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* -(  HarbormasterBuildableInterface  )------------------------------------- */ | ||||
|  | ||||
|  | ||||
|   public function getHarbormasterBuildablePHID() { | ||||
|     // NOTE: This is essentially just for convenience, as it allows you create | ||||
|     // a copy of a buildable by specifying `B123` without bothering to go | ||||
|     // look up the underlying object. | ||||
|     return $this->getBuildablePHID(); | ||||
|   } | ||||
|  | ||||
|   public function getHarbormasterContainerPHID() { | ||||
|     return $this->getContainerPHID(); | ||||
|   } | ||||
|  | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -5,7 +5,8 @@ final class PhabricatorRepositoryCommit | ||||
|   implements | ||||
|     PhabricatorPolicyInterface, | ||||
|     PhabricatorFlaggableInterface, | ||||
|     PhabricatorTokenReceiverInterface { | ||||
|     PhabricatorTokenReceiverInterface, | ||||
|     HarbormasterBuildableInterface { | ||||
|  | ||||
|   protected $repositoryID; | ||||
|   protected $phid; | ||||
| @@ -231,4 +232,17 @@ final class PhabricatorRepositoryCommit | ||||
|     return id(new PhabricatorRepositoryCommit()) | ||||
|       ->loadFromArray($dict); | ||||
|   } | ||||
|  | ||||
|  | ||||
| /* -(  HarbormasterBuildableInterface  )------------------------------------- */ | ||||
|  | ||||
|  | ||||
|   public function getHarbormasterBuildablePHID() { | ||||
|     return $this->getPHID(); | ||||
|   } | ||||
|  | ||||
|   public function getHarbormasterContainerPHID() { | ||||
|     return $this->getRepository()->getPHID(); | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 epriestley
					epriestley