1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-25 16:22:43 +01:00

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:
epriestley 2013-12-26 10:40:52 -08:00
parent ac19c55822
commit aad6b57c36
12 changed files with 259 additions and 37 deletions

1
bin/harbormaster Symbolic link
View file

@ -0,0 +1 @@
../scripts/setup/manage_harbormaster.php

View 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);

View file

@ -707,6 +707,7 @@ phutil_register_library_map(array(
'HarbormasterBuildViewController' => 'applications/harbormaster/controller/HarbormasterBuildViewController.php', 'HarbormasterBuildViewController' => 'applications/harbormaster/controller/HarbormasterBuildViewController.php',
'HarbormasterBuildWorker' => 'applications/harbormaster/worker/HarbormasterBuildWorker.php', 'HarbormasterBuildWorker' => 'applications/harbormaster/worker/HarbormasterBuildWorker.php',
'HarbormasterBuildable' => 'applications/harbormaster/storage/HarbormasterBuildable.php', 'HarbormasterBuildable' => 'applications/harbormaster/storage/HarbormasterBuildable.php',
'HarbormasterBuildableInterface' => 'applications/harbormaster/interface/HarbormasterBuildableInterface.php',
'HarbormasterBuildableListController' => 'applications/harbormaster/controller/HarbormasterBuildableListController.php', 'HarbormasterBuildableListController' => 'applications/harbormaster/controller/HarbormasterBuildableListController.php',
'HarbormasterBuildableQuery' => 'applications/harbormaster/query/HarbormasterBuildableQuery.php', 'HarbormasterBuildableQuery' => 'applications/harbormaster/query/HarbormasterBuildableQuery.php',
'HarbormasterBuildableSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildableSearchEngine.php', 'HarbormasterBuildableSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildableSearchEngine.php',
@ -715,6 +716,8 @@ phutil_register_library_map(array(
'HarbormasterController' => 'applications/harbormaster/controller/HarbormasterController.php', 'HarbormasterController' => 'applications/harbormaster/controller/HarbormasterController.php',
'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php', 'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php',
'HarbormasterHTTPRequestBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.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', 'HarbormasterObject' => 'applications/harbormaster/storage/HarbormasterObject.php',
'HarbormasterPHIDTypeBuild' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuild.php', 'HarbormasterPHIDTypeBuild' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuild.php',
'HarbormasterPHIDTypeBuildItem' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuildItem.php', 'HarbormasterPHIDTypeBuildItem' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuildItem.php',
@ -2747,6 +2750,7 @@ phutil_register_library_map(array(
array( array(
0 => 'DifferentialDAO', 0 => 'DifferentialDAO',
1 => 'PhabricatorPolicyInterface', 1 => 'PhabricatorPolicyInterface',
2 => 'HarbormasterBuildableInterface',
), ),
'DifferentialDiffContentMail' => 'DifferentialMail', 'DifferentialDiffContentMail' => 'DifferentialMail',
'DifferentialDiffCreateController' => 'DifferentialController', 'DifferentialDiffCreateController' => 'DifferentialController',
@ -2814,6 +2818,7 @@ phutil_register_library_map(array(
2 => 'PhabricatorPolicyInterface', 2 => 'PhabricatorPolicyInterface',
3 => 'PhabricatorFlaggableInterface', 3 => 'PhabricatorFlaggableInterface',
4 => 'PhrequentTrackableInterface', 4 => 'PhrequentTrackableInterface',
5 => 'HarbormasterBuildableInterface',
), ),
'DifferentialRevisionCommentListView' => 'AphrontView', 'DifferentialRevisionCommentListView' => 'AphrontView',
'DifferentialRevisionCommentView' => 'AphrontView', 'DifferentialRevisionCommentView' => 'AphrontView',
@ -3131,6 +3136,7 @@ phutil_register_library_map(array(
array( array(
0 => 'HarbormasterDAO', 0 => 'HarbormasterDAO',
1 => 'PhabricatorPolicyInterface', 1 => 'PhabricatorPolicyInterface',
2 => 'HarbormasterBuildableInterface',
), ),
'HarbormasterBuildableListController' => 'HarbormasterBuildableListController' =>
array( array(
@ -3144,6 +3150,8 @@ phutil_register_library_map(array(
'HarbormasterController' => 'PhabricatorController', 'HarbormasterController' => 'PhabricatorController',
'HarbormasterDAO' => 'PhabricatorLiskDAO', 'HarbormasterDAO' => 'PhabricatorLiskDAO',
'HarbormasterHTTPRequestBuildStepImplementation' => 'VariableBuildStepImplementation', 'HarbormasterHTTPRequestBuildStepImplementation' => 'VariableBuildStepImplementation',
'HarbormasterManagementBuildWorkflow' => 'HarbormasterManagementWorkflow',
'HarbormasterManagementWorkflow' => 'PhutilArgumentWorkflow',
'HarbormasterObject' => 'HarbormasterDAO', 'HarbormasterObject' => 'HarbormasterDAO',
'HarbormasterPHIDTypeBuild' => 'PhabricatorPHIDType', 'HarbormasterPHIDTypeBuild' => 'PhabricatorPHIDType',
'HarbormasterPHIDTypeBuildItem' => 'PhabricatorPHIDType', 'HarbormasterPHIDTypeBuildItem' => 'PhabricatorPHIDType',
@ -4342,6 +4350,7 @@ phutil_register_library_map(array(
1 => 'PhabricatorPolicyInterface', 1 => 'PhabricatorPolicyInterface',
2 => 'PhabricatorFlaggableInterface', 2 => 'PhabricatorFlaggableInterface',
3 => 'PhabricatorTokenReceiverInterface', 3 => 'PhabricatorTokenReceiverInterface',
4 => 'HarbormasterBuildableInterface',
), ),
'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker',
'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO',

View file

@ -2,7 +2,9 @@
final class DifferentialDiff final class DifferentialDiff
extends DifferentialDAO extends DifferentialDAO
implements PhabricatorPolicyInterface { implements
PhabricatorPolicyInterface,
HarbormasterBuildableInterface {
protected $revisionID; protected $revisionID;
protected $authorPHID; protected $authorPHID;
@ -339,4 +341,24 @@ final class DifferentialDiff
return null; 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;
}
} }

View file

@ -5,7 +5,8 @@ final class DifferentialRevision extends DifferentialDAO
PhabricatorTokenReceiverInterface, PhabricatorTokenReceiverInterface,
PhabricatorPolicyInterface, PhabricatorPolicyInterface,
PhabricatorFlaggableInterface, PhabricatorFlaggableInterface,
PhrequentTrackableInterface { PhrequentTrackableInterface,
HarbormasterBuildableInterface {
protected $title = ''; protected $title = '';
protected $originalTitle; protected $originalTitle;
@ -412,4 +413,16 @@ final class DifferentialRevision extends DifferentialDAO
return DifferentialRevisionStatus::isClosedStatus($this->getStatus()); return DifferentialRevisionStatus::isClosedStatus($this->getStatus());
} }
/* -( HarbormasterBuildableInterface )------------------------------------- */
public function getHarbormasterBuildablePHID() {
return $this->loadActiveDiff()->getPHID();
}
public function getHarbormasterContainerPHID() {
return $this->getPHID();
}
} }

View file

@ -41,16 +41,10 @@ final class HarbormasterPlanRunController
->withNames(array($v_name)) ->withNames(array($v_name))
->executeOne(); ->executeOne();
if ($object instanceof DifferentialRevision) { if ($object instanceof HarbormasterBuildableInterface) {
$revision = $object;
$object = $object->loadActiveDiff();
$buildable $buildable
->setBuildablePHID($object->getPHID()) ->setBuildablePHID($object->getHarbormasterBuildablePHID())
->setContainerPHID($revision->getPHID()); ->setContainerPHID($object->getHarbormasterContainerPHID());
} else if ($object instanceof PhabricatorRepositoryCommit) {
$buildable
->setBuildablePHID($object->getPHID())
->setContainerPHID($object->getRepository()->getPHID());
} else { } else {
$e_name = pht('Invalid'); $e_name = pht('Invalid');
$errors[] = pht('Enter the name of a revision or commit.'); $errors[] = pht('Enter the name of a revision or commit.');
@ -62,6 +56,7 @@ final class HarbormasterPlanRunController
if (!$errors) { if (!$errors) {
$buildable->save(); $buildable->save();
$buildable->applyPlan($plan);
$buildable_uri = '/B'.$buildable->getID(); $buildable_uri = '/B'.$buildable->getID();
return id(new AphrontRedirectResponse())->setURI($buildable_uri); return id(new AphrontRedirectResponse())->setURI($buildable_uri);
@ -80,8 +75,12 @@ final class HarbormasterPlanRunController
->setUser($viewer) ->setUser($viewer)
->appendRemarkupInstructions( ->appendRemarkupInstructions(
pht( pht(
"Enter the name of a commit or revision to run this plan on.\n\n". "Enter the name of a commit or revision to run this plan on (for ".
"For example: `rX123456` or `D123`")) "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( ->appendChild(
id(new AphrontFormTextControl()) id(new AphrontFormTextControl())
->setLabel('Buildable Name') ->setLabel('Buildable Name')
@ -90,7 +89,7 @@ final class HarbormasterPlanRunController
->setValue($v_name)); ->setValue($v_name));
$dialog = id(new AphrontDialogView()) $dialog = id(new AphrontDialogView())
->setWidth(AphrontDialogView::WIDTH_FORM) ->setWidth(AphrontDialogView::WIDTH_FULL)
->setUser($viewer) ->setUser($viewer)
->setTitle($title) ->setTitle($title)
->appendChild($form) ->appendChild($form)

View file

@ -24,12 +24,19 @@ final class HarbormasterUIEventListener
return; return;
} }
$target = null; if ($object instanceof HarbormasterBuildable) {
if ($object instanceof PhabricatorRepositoryCommit) { // Although HarbormasterBuildable implements the correct interface, it
$target = $object; // does not make sense to show a build's build status. In the best case
} elseif ($object instanceof DifferentialRevision) { // it is meaningless, and in the worst case it's confusing.
$target = $object->loadActiveDiff(); return;
} else { }
if (!($object instanceof HarbormasterBuildableInterface)) {
return;
}
$buildable_phid = $object->getBuildablePHID();
if (!$buildable_phid) {
return; return;
} }
@ -39,7 +46,8 @@ final class HarbormasterUIEventListener
$buildables = id(new HarbormasterBuildableQuery()) $buildables = id(new HarbormasterBuildableQuery())
->setViewer($user) ->setViewer($user)
->withBuildablePHIDs(array($target->getPHID())) ->withManualBuildables(false)
->withBuildablePHIDs(array($buildable_phid))
->execute(); ->execute();
if (!$buildables) { if (!$buildables) {
return; return;
@ -62,8 +70,7 @@ final class HarbormasterUIEventListener
foreach ($builds as $build) { foreach ($builds as $build) {
$item = new PHUIStatusItemView(); $item = new PHUIStatusItemView();
$item->setTarget( $item->setTarget($build_handles[$build->getPHID()]->renderLink());
$build_handles[$build->getPHID()]->renderLink());
switch ($build->getBuildStatus()) { switch ($build->getBuildStatus()) {
case HarbormasterBuild::STATUS_INACTIVE: case HarbormasterBuild::STATUS_INACTIVE:

View file

@ -0,0 +1,8 @@
<?php
interface HarbormasterBuildableInterface {
public function getHarbormasterBuildablePHID();
public function getHarbormasterContainerPHID();
}

View file

@ -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;
}
}

View file

@ -0,0 +1,10 @@
<?php
abstract class HarbormasterManagementWorkflow
extends PhutilArgumentWorkflow {
public function isExecutable() {
return true;
}
}

View file

@ -1,7 +1,9 @@
<?php <?php
final class HarbormasterBuildable extends HarbormasterDAO final class HarbormasterBuildable extends HarbormasterDAO
implements PhabricatorPolicyInterface { implements
PhabricatorPolicyInterface,
HarbormasterBuildableInterface {
protected $buildablePHID; protected $buildablePHID;
protected $containerPHID; protected $containerPHID;
@ -86,21 +88,27 @@ final class HarbormasterBuildable extends HarbormasterDAO
continue; continue;
} }
$build = HarbormasterBuild::initializeNewBuild( $buildable->applyPlan($plan);
PhabricatorUser::getOmnipotentUser());
$build->setBuildablePHID($buildable->getPHID());
$build->setBuildPlanPHID($plan->getPHID());
$build->setBuildStatus(HarbormasterBuild::STATUS_PENDING);
$build->save();
PhabricatorWorker::scheduleTask(
'HarbormasterBuildWorker',
array(
'buildID' => $build->getID()
));
} }
} }
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() { public function getConfiguration() {
return array( return array(
self::CONFIG_AUX_PHID => true, self::CONFIG_AUX_PHID => true,
@ -184,4 +192,21 @@ final class HarbormasterBuildable extends HarbormasterDAO
'buildable.'); '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();
}
} }

View file

@ -5,7 +5,8 @@ final class PhabricatorRepositoryCommit
implements implements
PhabricatorPolicyInterface, PhabricatorPolicyInterface,
PhabricatorFlaggableInterface, PhabricatorFlaggableInterface,
PhabricatorTokenReceiverInterface { PhabricatorTokenReceiverInterface,
HarbormasterBuildableInterface {
protected $repositoryID; protected $repositoryID;
protected $phid; protected $phid;
@ -231,4 +232,17 @@ final class PhabricatorRepositoryCommit
return id(new PhabricatorRepositoryCommit()) return id(new PhabricatorRepositoryCommit())
->loadFromArray($dict); ->loadFromArray($dict);
} }
/* -( HarbormasterBuildableInterface )------------------------------------- */
public function getHarbormasterBuildablePHID() {
return $this->getPHID();
}
public function getHarbormasterContainerPHID() {
return $this->getRepository()->getPHID();
}
} }