mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 06:42:42 +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:
parent
ac19c55822
commit
aad6b57c36
12 changed files with 259 additions and 37 deletions
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,21 +88,27 @@ 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();
|
||||
|
||||
PhabricatorWorker::scheduleTask(
|
||||
'HarbormasterBuildWorker',
|
||||
array(
|
||||
'buildID' => $build->getID()
|
||||
));
|
||||
$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() {
|
||||
return array(
|
||||
self::CONFIG_AUX_PHID => true,
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue