Index: resources/sql/patches/20131224.harbormanual.sql =================================================================== --- /dev/null +++ resources/sql/patches/20131224.harbormanual.sql @@ -0,0 +1,6 @@ +ALTER TABLE {$NAMESPACE}_harbormaster.harbormaster_buildable + ADD isManualBuildable BOOL NOT NULL; + +ALTER TABLE {$NAMESPACE}_harbormaster.harbormaster_buildable + ADD KEY `key_manual` (isManualBuildable); + Index: src/__phutil_library_map__.php =================================================================== --- src/__phutil_library_map__.php +++ src/__phutil_library_map__.php @@ -707,8 +707,6 @@ 'HarbormasterBuildViewController' => 'applications/harbormaster/controller/HarbormasterBuildViewController.php', 'HarbormasterBuildWorker' => 'applications/harbormaster/worker/HarbormasterBuildWorker.php', 'HarbormasterBuildable' => 'applications/harbormaster/storage/HarbormasterBuildable.php', - 'HarbormasterBuildableApplyController' => 'applications/harbormaster/controller/HarbormasterBuildableApplyController.php', - 'HarbormasterBuildableEditController' => 'applications/harbormaster/controller/HarbormasterBuildableEditController.php', 'HarbormasterBuildableListController' => 'applications/harbormaster/controller/HarbormasterBuildableListController.php', 'HarbormasterBuildableQuery' => 'applications/harbormaster/query/HarbormasterBuildableQuery.php', 'HarbormasterBuildableSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildableSearchEngine.php', @@ -730,6 +728,7 @@ 'HarbormasterPlanEditController' => 'applications/harbormaster/controller/HarbormasterPlanEditController.php', 'HarbormasterPlanListController' => 'applications/harbormaster/controller/HarbormasterPlanListController.php', 'HarbormasterPlanOrderController' => 'applications/harbormaster/controller/HarbormasterPlanOrderController.php', + 'HarbormasterPlanRunController' => 'applications/harbormaster/controller/HarbormasterPlanRunController.php', 'HarbormasterPlanViewController' => 'applications/harbormaster/controller/HarbormasterPlanViewController.php', 'HarbormasterRemarkupRule' => 'applications/harbormaster/remarkup/HarbormasterRemarkupRule.php', 'HarbormasterScratchTable' => 'applications/harbormaster/storage/HarbormasterScratchTable.php', @@ -3133,8 +3132,6 @@ 0 => 'HarbormasterDAO', 1 => 'PhabricatorPolicyInterface', ), - 'HarbormasterBuildableApplyController' => 'HarbormasterController', - 'HarbormasterBuildableEditController' => 'HarbormasterController', 'HarbormasterBuildableListController' => array( 0 => 'HarbormasterController', @@ -3164,6 +3161,7 @@ 1 => 'PhabricatorApplicationSearchResultsControllerInterface', ), 'HarbormasterPlanOrderController' => 'HarbormasterController', + 'HarbormasterPlanRunController' => 'HarbormasterController', 'HarbormasterPlanViewController' => 'HarbormasterPlanController', 'HarbormasterRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'HarbormasterScratchTable' => 'HarbormasterDAO', Index: src/applications/harbormaster/application/PhabricatorApplicationHarbormaster.php =================================================================== --- src/applications/harbormaster/application/PhabricatorApplicationHarbormaster.php +++ src/applications/harbormaster/application/PhabricatorApplicationHarbormaster.php @@ -48,10 +48,6 @@ '/harbormaster/' => array( '(?:query/(?P[^/]+)/)?' => 'HarbormasterBuildableListController', - 'buildable/' => array( - 'edit/(?:(?P\d+)/)?' => 'HarbormasterBuildableEditController', - 'apply/(?:(?P\d+)/)?' => 'HarbormasterBuildableApplyController', - ), 'step/' => array( 'add/(?:(?P\d+)/)?' => 'HarbormasterStepAddController', 'edit/(?:(?P\d+)/)?' => 'HarbormasterStepEditController', @@ -67,6 +63,7 @@ 'edit/(?:(?P\d+)/)?' => 'HarbormasterPlanEditController', 'order/(?:(?P\d+)/)?' => 'HarbormasterPlanOrderController', 'disable/(?P\d+)/' => 'HarbormasterPlanDisableController', + 'run/(?P\d+)/' => 'HarbormasterPlanRunController', '(?P\d+)/' => 'HarbormasterPlanViewController', ), ), Index: src/applications/harbormaster/controller/HarbormasterBuildableApplyController.php =================================================================== --- src/applications/harbormaster/controller/HarbormasterBuildableApplyController.php +++ /dev/null @@ -1,74 +0,0 @@ -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!"); - } - - $buildable_uri = '/B'.$buildable->getID(); - - if ($request->isDialogFormPost()) { - $plan = id(new HarbormasterBuildPlanQuery()) - ->setViewer($viewer) - ->withIDs(array($request->getInt('build-plan'))) - ->executeOne(); - - HarbormasterBuildable::applyBuildPlans( - $buildable->getBuildablePHID(), - $buildable->getContainerPHID(), - array($plan->getPHID())); - - return id(new AphrontRedirectResponse())->setURI($buildable_uri); - } - - $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(pht('Apply')) - ->addCancelButton($buildable_uri); - $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)); - return id(new AphrontDialogResponse())->setDialog($dialog); - } - -} Index: src/applications/harbormaster/controller/HarbormasterBuildableEditController.php =================================================================== --- src/applications/harbormaster/controller/HarbormasterBuildableEditController.php +++ /dev/null @@ -1,140 +0,0 @@ -id = idx($data, 'id'); - } - - public function processRequest() { - $request = $this->getRequest(); - $viewer = $request->getUser(); - - $this->requireApplicationCapability( - HarbormasterCapabilityManagePlans::CAPABILITY); - - if ($this->id) { - $buildable = id(new HarbormasterBuildableQuery()) - ->setViewer($viewer) - ->withIDs(array($this->id)) - ->executeOne(); - if (!$buildable) { - return new Aphront404Response(); - } - } else { - $buildable = HarbormasterBuildable::initializeNewBuildable($viewer); - } - - $e_name = true; - $v_name = null; - - $errors = array(); - if ($request->isFormPost()) { - $v_name = $request->getStr('buildablePHID'); - - if ($v_name) { - $object = id(new PhabricatorObjectQuery()) - ->setViewer($viewer) - ->withNames(array($v_name)) - ->executeOne(); - - if ($object instanceof DifferentialRevision) { - $revision = $object; - $object = $object->loadActiveDiff(); - $buildable - ->setBuildablePHID($object->getPHID()) - ->setContainerPHID($revision->getPHID()); - } else if ($object instanceof PhabricatorRepositoryCommit) { - $buildable - ->setBuildablePHID($object->getPHID()) - ->setContainerPHID($object->getRepository()->getPHID()); - } else { - $e_name = pht('Invalid'); - $errors[] = pht('Enter the name of a revision or commit.'); - } - } else { - $e_name = pht('Required'); - $errors[] = pht('You must choose a revision or commit to build.'); - } - - if (!$errors) { - $buildable->save(); - - $buildable_uri = '/B'.$buildable->getID(); - return id(new AphrontRedirectResponse())->setURI($buildable_uri); - } - } - - if ($errors) { - $errors = id(new AphrontErrorView())->setErrors($errors); - } - - $is_new = (!$buildable->getID()); - if ($is_new) { - $title = pht('New Buildable'); - $cancel_uri = $this->getApplicationURI(); - $save_button = pht('Create Buildable'); - } else { - $id = $buildable->getID(); - - $title = pht('Edit Buildable'); - $cancel_uri = "/B{$id}"; - $save_button = pht('Save Buildable'); - } - - $form = id(new AphrontFormView()) - ->setUser($viewer); - - if ($is_new) { - $form - ->appendRemarkupInstructions( - pht( - 'Enter the name of a commit or revision, like `rX123456789` '. - 'or `D123`.')) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel('Buildable Name') - ->setName('buildablePHID') - ->setError($e_name) - ->setValue($v_name)); - } else { - $form->appendChild( - id(new AphrontFormMarkupControl()) - ->setLabel(pht('Buildable')) - ->setValue($buildable->getBuildableHandle()->renderLink())); - } - - $form->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue($save_button) - ->addCancelButton($cancel_uri)); - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText($title) - ->setFormError($errors) - ->setForm($form); - - $crumbs = $this->buildApplicationCrumbs(); - if ($is_new) { - $crumbs->addTextCrumb(pht('New Buildable')); - } else { - $id = $buildable->getID(); - $crumbs->addTextCrumb("B{$id}", "/B{$id}"); - $crumbs->addTextCrumb(pht('Edit')); - } - - return $this->buildApplicationPage( - array( - $crumbs, - $box, - ), - array( - 'title' => $title, - 'device' => true, - )); - } - -} Index: src/applications/harbormaster/controller/HarbormasterBuildableListController.php =================================================================== --- src/applications/harbormaster/controller/HarbormasterBuildableListController.php +++ src/applications/harbormaster/controller/HarbormasterBuildableListController.php @@ -44,8 +44,14 @@ $item->setHref("/B{$id}"); } + if ($buildable->getIsManualBuildable()) { + $item->addIcon('wrench-grey', pht('Manual')); + } + $list->addItem($item); + + // TODO: This is proof-of-concept for getting meaningful status // information into this list, and should get an improvement pass // once we're a little farther along. @@ -86,8 +92,7 @@ $nav->addFilter('new/', pht('New Build Plan')); } - $nav->addLabel('Utilities'); - $nav->addFilter('buildable/edit/', pht('New Manual Build')); + $nav->addLabel(pht('Build Plans')); $nav->addFilter('plan/', pht('Manage Build Plans')); $nav->selectFilter(null); Index: src/applications/harbormaster/controller/HarbormasterBuildableViewController.php =================================================================== --- src/applications/harbormaster/controller/HarbormasterBuildableViewController.php +++ src/applications/harbormaster/controller/HarbormasterBuildableViewController.php @@ -118,15 +118,6 @@ ->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; } @@ -153,6 +144,12 @@ $buildable->getContainerHandle()->renderLink()); } + $properties->addProperty( + pht('Origin'), + $buildable->getIsManualBuildable() + ? pht('Manual Buildable') + : pht('Automatic Buildable')); + } } Index: src/applications/harbormaster/controller/HarbormasterPlanRunController.php =================================================================== --- /dev/null +++ src/applications/harbormaster/controller/HarbormasterPlanRunController.php @@ -0,0 +1,103 @@ +id = $data['id']; + } + + public function processRequest() { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $this->requireApplicationCapability( + HarbormasterCapabilityManagePlans::CAPABILITY); + + $plan_id = $this->id; + $plan = id(new HarbormasterBuildPlanQuery()) + ->setViewer($viewer) + ->withIDs(array($plan_id)) + ->executeOne(); + if (!$plan) { + return new Aphront404Response(); + } + + $e_name = true; + $v_name = null; + + $errors = array(); + if ($request->isFormPost()) { + $buildable = HarbormasterBuildable::initializeNewBuildable($viewer) + ->setIsManualBuildable(true); + + $v_name = $request->getStr('buildablePHID'); + + if ($v_name) { + $object = id(new PhabricatorObjectQuery()) + ->setViewer($viewer) + ->withNames(array($v_name)) + ->executeOne(); + + if ($object instanceof DifferentialRevision) { + $revision = $object; + $object = $object->loadActiveDiff(); + $buildable + ->setBuildablePHID($object->getPHID()) + ->setContainerPHID($revision->getPHID()); + } else if ($object instanceof PhabricatorRepositoryCommit) { + $buildable + ->setBuildablePHID($object->getPHID()) + ->setContainerPHID($object->getRepository()->getPHID()); + } else { + $e_name = pht('Invalid'); + $errors[] = pht('Enter the name of a revision or commit.'); + } + } else { + $e_name = pht('Required'); + $errors[] = pht('You must choose a revision or commit to build.'); + } + + if (!$errors) { + $buildable->save(); + + $buildable_uri = '/B'.$buildable->getID(); + return id(new AphrontRedirectResponse())->setURI($buildable_uri); + } + } + + if ($errors) { + $errors = id(new AphrontErrorView())->setErrors($errors); + } + + $title = pht('Run Build Plan Manually'); + $cancel_uri = $this->getApplicationURI("plan/{$plan_id}/"); + $save_button = pht('Run Plan Manually'); + + $form = id(new PHUIFormLayoutView()) + ->setUser($viewer) + ->appendRemarkupInstructions( + pht( + "Enter the name of a commit or revision to run this plan on.\n\n". + "For example: `rX123456` or `D123`")) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Buildable Name') + ->setName('buildablePHID') + ->setError($e_name) + ->setValue($v_name)); + + $dialog = id(new AphrontDialogView()) + ->setWidth(AphrontDialogView::WIDTH_FORM) + ->setUser($viewer) + ->setTitle($title) + ->appendChild($form) + ->addCancelButton($cancel_uri) + ->addSubmitButton($save_button); + + return id(new AphrontDialogResponse())->setDialog($dialog); + } + +} Index: src/applications/harbormaster/controller/HarbormasterPlanViewController.php =================================================================== --- src/applications/harbormaster/controller/HarbormasterPlanViewController.php +++ src/applications/harbormaster/controller/HarbormasterPlanViewController.php @@ -200,10 +200,18 @@ id(new PhabricatorActionView()) ->setName(pht('Add Build Step')) ->setHref($this->getApplicationURI("step/add/{$id}/")) - ->setWorkflow($can_edit) + ->setWorkflow(true) ->setDisabled(!$can_edit) ->setIcon('new')); + $list->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Run Plan Manually')) + ->setHref($this->getApplicationURI("plan/run/{$id}/")) + ->setWorkflow(true) + ->setDisabled(!$can_edit) + ->setIcon('start-sandcastle')); + return $list; } Index: src/applications/harbormaster/query/HarbormasterBuildableQuery.php =================================================================== --- src/applications/harbormaster/query/HarbormasterBuildableQuery.php +++ src/applications/harbormaster/query/HarbormasterBuildableQuery.php @@ -7,6 +7,7 @@ private $phids; private $buildablePHIDs; private $containerPHIDs; + private $manualBuildables; private $needContainerObjects; private $needContainerHandles; @@ -33,6 +34,11 @@ return $this; } + public function withManualBuildables($manual) { + $this->manualBuildables = $manual; + return $this; + } + public function needContainerObjects($need) { $this->needContainerObjects = $need; return $this; @@ -197,6 +203,13 @@ $this->containerPHIDs); } + if ($this->manualBuildables !== null) { + $where[] = qsprintf( + $conn_r, + 'isManualBuildable = %d', + (int)$this->manualBuildables); + } + $where[] = $this->buildPagingClause($conn_r); return $this->formatWhereClause($where); Index: src/applications/harbormaster/query/HarbormasterBuildableSearchEngine.php =================================================================== --- src/applications/harbormaster/query/HarbormasterBuildableSearchEngine.php +++ src/applications/harbormaster/query/HarbormasterBuildableSearchEngine.php @@ -42,6 +42,9 @@ $buildable_phids = array_merge($commits, $diffs); $saved->setParameter('buildablePHIDs', $buildable_phids); + $saved->setParameter( + 'manual', + $this->readBoolFromRequest($request, 'manual')); return $saved; } @@ -63,6 +66,11 @@ $query->withBuildablePHIDs($buildable_phids); } + $manual = $saved->getParameter('manual'); + if ($manual !== null) { + $query->withManualBuildables($manual); + } + return $query; } @@ -126,7 +134,18 @@ id(new AphrontFormTextControl()) ->setLabel(pht('Commits')) ->setName('commits') - ->setValue(implode(', ', $commit_names))); + ->setValue(implode(', ', $commit_names))) + ->appendChild( + id(new AphrontFormSelectControl()) + ->setLabel(pht('Origin')) + ->setName('manual') + ->setValue($this->getBoolFromQuery($saved_query, 'manual')) + ->setOptions( + array( + '' => pht('(All Origins)'), + 'true' => pht('Manual Buildables'), + 'false' => pht('Automatic Buildables'), + ))); } protected function getURI($path) { Index: src/applications/harbormaster/step/WaitForPreviousBuildStepImplementation.php =================================================================== --- src/applications/harbormaster/step/WaitForPreviousBuildStepImplementation.php +++ src/applications/harbormaster/step/WaitForPreviousBuildStepImplementation.php @@ -102,6 +102,7 @@ $buildables = id(new HarbormasterBuildableQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withBuildablePHIDs($build_objects) + ->withManualBuildables(false) ->execute(); $buildable_phids = mpull($buildables, 'getPHID'); Index: src/applications/harbormaster/storage/HarbormasterBuildable.php =================================================================== --- src/applications/harbormaster/storage/HarbormasterBuildable.php +++ src/applications/harbormaster/storage/HarbormasterBuildable.php @@ -7,6 +7,7 @@ protected $containerPHID; protected $buildStatus; protected $buildableStatus; + protected $isManualBuildable; private $buildableObject = self::ATTACHABLE; private $containerObject = self::ATTACHABLE; @@ -18,6 +19,7 @@ public static function initializeNewBuildable(PhabricatorUser $actor) { return id(new HarbormasterBuildable()) + ->setIsManualBuildable(0) ->setBuildStatus(self::STATUS_WHATEVER) ->setBuildableStatus(self::STATUS_WHATEVER); } @@ -34,6 +36,7 @@ $buildable = id(new HarbormasterBuildableQuery()) ->setViewer($actor) ->withBuildablePHIDs(array($buildable_object_phid)) + ->withManualBuildables(false) ->setLimit(1) ->executeOne(); if ($buildable) { Index: src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php =================================================================== --- src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php +++ src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php @@ -1848,6 +1848,10 @@ 'type' => 'sql', 'name' => $this->getPatchPath('20131219.pxdrop.sql'), ), + '20131224.harbormanual.sql' => array( + 'type' => 'sql', + 'name' => $this->getPatchPath('20131224.harbormanual.sql'), + ), ); } }