Page MenuHomePhabricator

D7498.id16904.diff

D7498.id16904.diff

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
@@ -657,6 +657,7 @@
'HarbormasterBuildTarget' => 'applications/harbormaster/storage/build/HarbormasterBuildTarget.php',
'HarbormasterBuildTargetQuery' => 'applications/harbormaster/query/HarbormasterBuildTargetQuery.php',
'HarbormasterBuildable' => 'applications/harbormaster/storage/HarbormasterBuildable.php',
+ 'HarbormasterBuildableApplyController' => 'applications/harbormaster/controller/HarbormasterBuildableApplyController.php',
'HarbormasterBuildableArtifactQuery' => 'applications/harbormaster/query/HarbormasterBuildableArtifactQuery.php',
'HarbormasterBuildableEditController' => 'applications/harbormaster/controller/HarbormasterBuildableEditController.php',
'HarbormasterBuildableListController' => 'applications/harbormaster/controller/HarbormasterBuildableListController.php',
@@ -1330,6 +1331,7 @@
'PhabricatorGlobalUploadTargetView' => 'applications/files/view/PhabricatorGlobalUploadTargetView.php',
'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/PhabricatorHandleObjectSelectorDataView.php',
'PhabricatorHandleQuery' => 'applications/phid/query/PhabricatorHandleQuery.php',
+ 'PhabricatorHarbormasterBuildDaemon' => 'applications/harbormaster/daemon/PhabricatorHarbormasterBuildDaemon.php',
'PhabricatorHash' => 'infrastructure/util/PhabricatorHash.php',
'PhabricatorHashTestCase' => 'infrastructure/util/__tests__/PhabricatorHashTestCase.php',
'PhabricatorHelpController' => 'applications/help/controller/PhabricatorHelpController.php',
@@ -2873,6 +2875,7 @@
0 => 'HarbormasterDAO',
1 => 'PhabricatorPolicyInterface',
),
+ 'HarbormasterBuildableApplyController' => 'HarbormasterController',
'HarbormasterBuildableArtifactQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'HarbormasterBuildableEditController' => 'HarbormasterController',
'HarbormasterBuildableListController' =>
@@ -3638,6 +3641,7 @@
'PhabricatorGlobalLock' => 'PhutilLock',
'PhabricatorGlobalUploadTargetView' => 'AphrontView',
'PhabricatorHandleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'PhabricatorHarbormasterBuildDaemon' => 'PhabricatorDaemon',
'PhabricatorHashTestCase' => 'PhabricatorTestCase',
'PhabricatorHelpController' => 'PhabricatorController',
'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController',
diff --git a/src/applications/harbormaster/application/PhabricatorApplicationHarbormaster.php b/src/applications/harbormaster/application/PhabricatorApplicationHarbormaster.php
--- a/src/applications/harbormaster/application/PhabricatorApplicationHarbormaster.php
+++ b/src/applications/harbormaster/application/PhabricatorApplicationHarbormaster.php
@@ -44,6 +44,7 @@
=> 'HarbormasterBuildableListController',
'buildable/' => array(
'edit/(?:(?P<id>\d+)/)?' => 'HarbormasterBuildableEditController',
+ 'apply/(?:(?P<id>\d+)/)?' => 'HarbormasterBuildableApplyController',
),
'plan/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
diff --git a/src/applications/harbormaster/controller/HarbormasterBuildableApplyController.php b/src/applications/harbormaster/controller/HarbormasterBuildableApplyController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/harbormaster/controller/HarbormasterBuildableApplyController.php
@@ -0,0 +1,74 @@
+<?php
+
+final class HarbormasterBuildableApplyController
+ extends HarbormasterController {
+
+ private $id;
+
+ public function willProcessRequest(array $data) {
+ $this->id = $data['id'];
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ $id = $this->id;
+
+ $buildable = id(new HarbormasterBuildableQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->executeOne();
+ if ($buildable === null) {
+ throw new Exception("Buildable not found!");
+ }
+
+ if ($request->isDialogFormPost()) {
+ $plan = id(new HarbormasterBuildPlanQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($request->getInt('build-plan')))
+ ->executeOne();
+
+ $build = HarbormasterBuild::initializeNewBuild($viewer);
+ $build->setBuildablePHID($buildable->getPHID());
+ $build->setBuildPlanPHID($plan->getPHID());
+ $build->setBuildStatus(HarbormasterBuild::STATUS_PENDING);
+ $build->save();
+
+ return id(new AphrontRedirectResponse());
+ }
+
+ $plans = id(new HarbormasterBuildPlanQuery())
+ ->setViewer($viewer)
+ ->execute();
+
+ $options = array();
+ foreach ($plans as $plan) {
+ $options[$plan->getID()] = $plan->getName();
+ }
+
+ // FIXME: I'd really like to use the dialog that "Edit Differential
+ // Revisions" uses, but that code is quite hard-coded for the particular
+ // uses, so for now we just give a single dropdown.
+
+ $dialog = new AphrontDialogView();
+ $dialog->setTitle(pht('Apply which plan?'))
+ ->setUser($viewer)
+ ->addSubmitButton('Apply')
+ ->addCancelButton('Cancel');
+ $dialog->appendChild(
+ phutil_tag(
+ 'p',
+ array(),
+ pht(
+ 'Select what build plan you want to apply to this buildable: ')));
+ $dialog->appendChild(
+ id(new AphrontFormSelectControl())
+ ->setUser($viewer)
+ ->setName('build-plan')
+ ->setOptions($options));
+ $dialog->addHiddenInput('confirmed', "true");
+ return id(new AphrontDialogResponse())->setDialog($dialog);
+ }
+
+}
diff --git a/src/applications/harbormaster/controller/HarbormasterBuildableListController.php b/src/applications/harbormaster/controller/HarbormasterBuildableListController.php
--- a/src/applications/harbormaster/controller/HarbormasterBuildableListController.php
+++ b/src/applications/harbormaster/controller/HarbormasterBuildableListController.php
@@ -36,7 +36,7 @@
$id = $buildable->getID();
$item = id(new PHUIObjectItemView())
- ->setHeader(pht('Build %d', $buildable->getID()));
+ ->setHeader(pht('Buildable %d', $buildable->getID()));
if ($id) {
$item->setHref("/B{$id}");
diff --git a/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php b/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php
--- a/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php
+++ b/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php
@@ -37,6 +37,32 @@
$item = id(new PHUIObjectItemView())
->setObjectName(pht('Build %d', $build->getID()))
->setHeader($build->getName());
+ switch ($build->getBuildStatus()) {
+ case HarbormasterBuild::STATUS_INACTIVE:
+ $item->setBarColor('grey');
+ $item->addAttribute(pht('Inactive'));
+ break;
+ case HarbormasterBuild::STATUS_PENDING:
+ $item->setBarColor('blue');
+ $item->addAttribute(pht('Pending'));
+ break;
+ case HarbormasterBuild::STATUS_WAITING:
+ $item->setBarColor('blue');
+ $item->addAttribute(pht('Waiting on Resource'));
+ break;
+ case HarbormasterBuild::STATUS_BUILDING:
+ $item->setBarColor('yellow');
+ $item->addAttribute(pht('Building'));
+ break;
+ case HarbormasterBuild::STATUS_PASSED:
+ $item->setBarColor('green');
+ $item->addAttribute(pht('Passed'));
+ break;
+ case HarbormasterBuild::STATUS_FAILED:
+ $item->setBarColor('red');
+ $item->addAttribute(pht('Failed'));
+ break;
+ }
$build_list->addItem($item);
}
@@ -80,6 +106,15 @@
->setObject($buildable)
->setObjectURI("/B{$id}");
+ $apply_uri = $this->getApplicationURI('/buildable/apply/'.$id.'/');
+
+ $list->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Apply Build Plan'))
+ ->setIcon('edit')
+ ->setHref($apply_uri)
+ ->setWorkflow(true));
+
return $list;
}
diff --git a/src/applications/harbormaster/daemon/PhabricatorHarbormasterBuildDaemon.php b/src/applications/harbormaster/daemon/PhabricatorHarbormasterBuildDaemon.php
new file mode 100644
--- /dev/null
+++ b/src/applications/harbormaster/daemon/PhabricatorHarbormasterBuildDaemon.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Run builds
+ */
+final class PhabricatorHarbormasterBuildDaemon
+ extends PhabricatorDaemon {
+
+ public function run() {
+ while (true) {
+
+ // Take exactly one build off the queue.
+ $build = id(new HarbormasterBuildQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withBuildStatuses(array(HarbormasterBuild::STATUS_PENDING))
+ ->needBuildPlans(true)
+ ->executeOne();
+ if ($build === null) {
+ $this->sleep(15);
+ continue;
+ }
+
+ try {
+ // FIXME: Make this actually atomic in case someone is running two
+ // or more build daemons.
+ $build->setBuildStatus(HarbormasterBuild::STATUS_BUILDING);
+ $build->save();
+
+ $buildable = $build->getBuildable();
+ $plan = $build->getBuildPlan();
+
+ // TODO: Do the actual build here.
+ $this->sleep(15);
+
+ // If we get to here, then the build has passed.
+ $build->setBuildStatus(HarbormasterBuild::STATUS_PASSED);
+ $build->save();
+ } catch (Exception $e) {
+ // If any exception is raised, the build is marked as a failure and
+ // the exception is re-thrown (this ensures we don't leave builds
+ // in an inconsistent state).
+ $build->setBuildStatus(HarbormasterBuild::STATUS_FAILED);
+ $build->save();
+ throw $e;
+ }
+
+ $this->sleep(15);
+ }
+ }
+
+}
diff --git a/src/applications/harbormaster/query/HarbormasterBuildQuery.php b/src/applications/harbormaster/query/HarbormasterBuildQuery.php
--- a/src/applications/harbormaster/query/HarbormasterBuildQuery.php
+++ b/src/applications/harbormaster/query/HarbormasterBuildQuery.php
@@ -5,6 +5,7 @@
private $ids;
private $phids;
+ private $buildStatuses;
private $buildablePHIDs;
private $buildPlanPHIDs;
@@ -20,6 +21,11 @@
return $this;
}
+ public function withBuildStatuses(array $build_statuses) {
+ $this->buildStatuses = $build_statuses;
+ return $this;
+ }
+
public function withBuildablePHIDs(array $buildable_phids) {
$this->buildablePHIDs = $buildable_phids;
return $this;
@@ -115,6 +121,13 @@
$this->phids);
}
+ if ($this->buildStatuses) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'buildStatus in (%Ls)',
+ $this->buildStatuses);
+ }
+
if ($this->buildablePHIDs) {
$where[] = qsprintf(
$conn_r,
diff --git a/src/applications/harbormaster/storage/HarbormasterBuildable.php b/src/applications/harbormaster/storage/HarbormasterBuildable.php
--- a/src/applications/harbormaster/storage/HarbormasterBuildable.php
+++ b/src/applications/harbormaster/storage/HarbormasterBuildable.php
@@ -12,10 +12,12 @@
private $containerObject = self::ATTACHABLE;
private $buildableHandle = self::ATTACHABLE;
+ const STATUS_WHATEVER = 'whatever';
+
public static function initializeNewBuildable(PhabricatorUser $actor) {
return id(new HarbormasterBuildable())
- ->setBuildStatus('new') // TODO: Define these.
- ->setBuildableStatus('active'); // TODO: Define these, too.
+ ->setBuildStatus(self::STATUS_WHATEVER)
+ ->setBuildableStatus(self::STATUS_WHATEVER);
}
public function getConfiguration() {
diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuild.php b/src/applications/harbormaster/storage/build/HarbormasterBuild.php
--- a/src/applications/harbormaster/storage/build/HarbormasterBuild.php
+++ b/src/applications/harbormaster/storage/build/HarbormasterBuild.php
@@ -10,9 +10,39 @@
private $buildable = self::ATTACHABLE;
private $buildPlan = self::ATTACHABLE;
+ /**
+ * Not currently being built.
+ */
+ const STATUS_INACTIVE = 'inactive';
+
+ /**
+ * Pending pick up by the Harbormaster daemon.
+ */
+ const STATUS_PENDING = 'pending';
+
+ /**
+ * Waiting for a resource to be allocated (not yet relevant).
+ */
+ const STATUS_WAITING = 'waiting';
+
+ /**
+ * Current building the buildable.
+ */
+ const STATUS_BUILDING = 'building';
+
+ /**
+ * The build has passed.
+ */
+ const STATUS_PASSED = 'passed';
+
+ /**
+ * The build has failed.
+ */
+ const STATUS_FAILED = 'failed';
+
public static function initializeNewBuild(PhabricatorUser $actor) {
return id(new HarbormasterBuild())
- ->setBuildStatus('building'); // TODO: Sort this.
+ ->setBuildStatus(self::STATUS_INACTIVE);
}
public function getConfiguration() {

File Metadata

Mime Type
text/x-diff
Storage Engine
amazon-s3
Storage Format
Raw Data
Storage Handle
phabricator/hb/sf/jk3yxrv2kpy5l7p6
Default Alt Text
D7498.id16904.diff (12 KB)

Event Timeline