public function processRequest()
 {
     $request = $this->getRequest();
     $viewer = $request->getUser();
     $this->requireApplicationCapability(HarbormasterManagePlansCapability::CAPABILITY);
     $plan = id(new HarbormasterBuildPlanQuery())->setViewer($viewer)->withIDs(array($this->id))->executeOne();
     if (!$plan) {
         return new Aphront404Response();
     }
     $plan_id = $plan->getID();
     $cancel_uri = $this->getApplicationURI("plan/{$plan_id}/");
     $errors = array();
     if ($request->isFormPost()) {
         $class = $request->getStr('class');
         if (!HarbormasterBuildStepImplementation::getImplementation($class)) {
             $errors[] = pht('Choose the type of build step you want to add.');
         }
         if (!$errors) {
             $new_uri = $this->getApplicationURI("step/new/{$plan_id}/{$class}/");
             return id(new AphrontRedirectResponse())->setURI($new_uri);
         }
     }
     $control = id(new AphrontFormRadioButtonControl())->setName('class');
     $all = HarbormasterBuildStepImplementation::getImplementations();
     foreach ($all as $class => $implementation) {
         $control->addButton($class, $implementation->getName(), $implementation->getGenericDescription());
     }
     if ($errors) {
         $errors = id(new AphrontErrorView())->setErrors($errors);
     }
     return $this->newDialog()->setTitle(pht('Add New Step'))->addSubmitButton(pht('Add Build Step'))->addCancelButton($cancel_uri)->appendChild($errors)->appendParagraph(pht('Choose a type of build step to add:'))->appendChild($control);
 }
Exemplo n.º 2
0
 public function getStepImplementation()
 {
     if ($this->implementation === null) {
         $obj = HarbormasterBuildStepImplementation::requireImplementation($this->className);
         $obj->loadSettings($this);
         $this->implementation = $obj;
     }
     return $this->implementation;
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $this->getViewer();
     $plan = id(new HarbormasterBuildPlanQuery())->setViewer($viewer)->withIDs(array($request->getURIData('id')))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
     if (!$plan) {
         return new Aphront404Response();
     }
     $plan_id = $plan->getID();
     $cancel_uri = $this->getApplicationURI("plan/{$plan_id}/");
     $plan_title = pht('Plan %d', $plan_id);
     $all = HarbormasterBuildStepImplementation::getImplementations();
     $all = msort($all, 'getName');
     $all_groups = HarbormasterBuildStepGroup::getAllGroups();
     foreach ($all as $impl) {
         $group_key = $impl->getBuildStepGroupKey();
         if (empty($all_groups[$group_key])) {
             throw new Exception(pht('Build step "%s" has step group key "%s", but no step group ' . 'with that key exists.', get_class($impl), $group_key));
         }
     }
     $groups = mgroup($all, 'getBuildStepGroupKey');
     $boxes = array();
     $enabled_groups = HarbormasterBuildStepGroup::getAllEnabledGroups();
     foreach ($enabled_groups as $group) {
         $list = id(new PHUIObjectItemListView())->setNoDataString(pht('This group has no available build steps.'));
         $steps = idx($groups, $group->getGroupKey(), array());
         foreach ($steps as $key => $impl) {
             if ($impl->shouldRequireAutotargeting()) {
                 unset($steps[$key]);
                 continue;
             }
         }
         if (!$steps && !$group->shouldShowIfEmpty()) {
             continue;
         }
         foreach ($steps as $key => $impl) {
             $class = get_class($impl);
             $new_uri = $this->getApplicationURI("step/new/{$plan_id}/{$class}/");
             $item = id(new PHUIObjectItemView())->setHeader($impl->getName())->setHref($new_uri)->addAttribute($impl->getGenericDescription());
             $list->addItem($item);
         }
         $box = id(new PHUIObjectBoxView())->setHeaderText($group->getGroupName())->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->appendChild($list);
         $boxes[] = $box;
     }
     $crumbs = $this->buildApplicationCrumbs()->addTextCrumb($plan_title, $cancel_uri)->addTextCrumb(pht('Add Build Step'))->setBorder(true);
     $title = array($plan_title, pht('Add Build Step'));
     $header = id(new PHUIHeaderView())->setHeader(pht('Add Build Step'))->setHeaderIcon('fa-plus-square');
     $view = id(new PHUITwoColumnView())->setHeader($header)->setFooter(array($boxes));
     return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->appendChild($view);
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $this->getViewer();
     $this->requireApplicationCapability(HarbormasterManagePlansCapability::CAPABILITY);
     $plan = id(new HarbormasterBuildPlanQuery())->setViewer($viewer)->withIDs(array($request->getURIData('id')))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
     if (!$plan) {
         return new Aphront404Response();
     }
     $plan_id = $plan->getID();
     $cancel_uri = $this->getApplicationURI("plan/{$plan_id}/");
     $all = HarbormasterBuildStepImplementation::getImplementations();
     foreach ($all as $key => $impl) {
         if ($impl->shouldRequireAutotargeting()) {
             unset($all[$key]);
         }
     }
     $errors = array();
     if ($request->isFormPost()) {
         $class = $request->getStr('class');
         if (empty($all[$class])) {
             $errors[] = pht('Choose the type of build step you want to add.');
         }
         if (!$errors) {
             $new_uri = $this->getApplicationURI("step/new/{$plan_id}/{$class}/");
             return id(new AphrontRedirectResponse())->setURI($new_uri);
         }
     }
     $control = id(new AphrontFormRadioButtonControl())->setName('class');
     foreach ($all as $class => $implementation) {
         $control->addButton($class, $implementation->getName(), $implementation->getGenericDescription());
     }
     if ($errors) {
         $errors = id(new PHUIInfoView())->setErrors($errors);
     }
     return $this->newDialog()->setTitle(pht('Add New Step'))->addSubmitButton(pht('Add Build Step'))->addCancelButton($cancel_uri)->appendChild($errors)->appendParagraph(pht('Choose a type of build step to add:'))->appendChild($control);
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $viewer = $request->getUser();
     $this->requireApplicationCapability(HarbormasterManagePlansCapability::CAPABILITY);
     if ($this->id) {
         $step = id(new HarbormasterBuildStepQuery())->setViewer($viewer)->withIDs(array($this->id))->executeOne();
         if (!$step) {
             return new Aphront404Response();
         }
         $plan = $step->getBuildPlan();
         $is_new = false;
     } else {
         $plan = id(new HarbormasterBuildPlanQuery())->setViewer($viewer)->withIDs(array($this->planID))->executeOne();
         if (!$plan) {
             return new Aphront404Response();
         }
         $impl = HarbormasterBuildStepImplementation::getImplementation($this->className);
         if (!$impl) {
             return new Aphront404Response();
         }
         $step = HarbormasterBuildStep::initializeNewStep($viewer)->setBuildPlanPHID($plan->getPHID())->setClassName($this->className);
         $is_new = true;
     }
     $plan_uri = $this->getApplicationURI('plan/' . $plan->getID() . '/');
     $implementation = $step->getStepImplementation();
     $field_list = PhabricatorCustomField::getObjectFields($step, PhabricatorCustomField::ROLE_EDIT);
     $field_list->setViewer($viewer)->readFieldsFromStorage($step);
     $e_name = true;
     $v_name = $step->getName();
     $e_description = true;
     $v_description = $step->getDescription();
     $e_depends_on = true;
     $raw_depends_on = $step->getDetail('dependsOn', array());
     $v_depends_on = id(new PhabricatorHandleQuery())->setViewer($viewer)->withPHIDs($raw_depends_on)->execute();
     $errors = array();
     $validation_exception = null;
     if ($request->isFormPost()) {
         $e_name = null;
         $v_name = $request->getStr('name');
         $e_description = null;
         $v_description = $request->getStr('description');
         $e_depends_on = null;
         $v_depends_on = $request->getArr('dependsOn');
         $xactions = $field_list->buildFieldTransactionsFromRequest(new HarbormasterBuildStepTransaction(), $request);
         $editor = id(new HarbormasterBuildStepEditor())->setActor($viewer)->setContinueOnNoEffect(true)->setContentSourceFromRequest($request);
         $name_xaction = id(new HarbormasterBuildStepTransaction())->setTransactionType(HarbormasterBuildStepTransaction::TYPE_NAME)->setNewValue($v_name);
         array_unshift($xactions, $name_xaction);
         $depends_on_xaction = id(new HarbormasterBuildStepTransaction())->setTransactionType(HarbormasterBuildStepTransaction::TYPE_DEPENDS_ON)->setNewValue($v_depends_on);
         array_unshift($xactions, $depends_on_xaction);
         $description_xaction = id(new HarbormasterBuildStepTransaction())->setTransactionType(HarbormasterBuildStepTransaction::TYPE_DESCRIPTION)->setNewValue($v_description);
         array_unshift($xactions, $description_xaction);
         if ($is_new) {
             // When creating a new step, make sure we have a create transaction
             // so we'll apply the transactions even if the step has no
             // configurable options.
             $create_xaction = id(new HarbormasterBuildStepTransaction())->setTransactionType(HarbormasterBuildStepTransaction::TYPE_CREATE);
             array_unshift($xactions, $create_xaction);
         }
         try {
             $editor->applyTransactions($step, $xactions);
             return id(new AphrontRedirectResponse())->setURI($plan_uri);
         } catch (PhabricatorApplicationTransactionValidationException $ex) {
             $validation_exception = $ex;
         }
     }
     $form = id(new AphrontFormView())->setUser($viewer)->appendChild(id(new AphrontFormTextControl())->setName('name')->setLabel(pht('Name'))->setError($e_name)->setValue($v_name));
     $form->appendChild(id(new AphrontFormTokenizerControl())->setDatasource(id(new HarbormasterBuildDependencyDatasource())->setParameters(array('planPHID' => $plan->getPHID(), 'stepPHID' => $is_new ? null : $step->getPHID())))->setName('dependsOn')->setLabel(pht('Depends On'))->setError($e_depends_on)->setValue($v_depends_on));
     $field_list->appendFieldsToForm($form);
     $form->appendChild(id(new PhabricatorRemarkupControl())->setName('description')->setLabel(pht('Description'))->setError($e_description)->setValue($v_description));
     if ($is_new) {
         $submit = pht('Create Build Step');
         $header = pht('New Step: %s', $implementation->getName());
         $crumb = pht('Add Step');
     } else {
         $submit = pht('Save Build Step');
         $header = pht('Edit Step: %s', $implementation->getName());
         $crumb = pht('Edit Step');
     }
     $form->appendChild(id(new AphrontFormSubmitControl())->setValue($submit)->addCancelButton($plan_uri));
     $box = id(new PHUIObjectBoxView())->setHeaderText($header)->setValidationException($validation_exception)->setForm($form);
     $crumbs = $this->buildApplicationCrumbs();
     $id = $plan->getID();
     $crumbs->addTextCrumb(pht('Plan %d', $id), $plan_uri);
     $crumbs->addTextCrumb($crumb);
     $variables = $this->renderBuildVariablesTable();
     if ($is_new) {
         $xaction_view = null;
     } else {
         $xactions = id(new HarbormasterBuildStepTransactionQuery())->setViewer($viewer)->withObjectPHIDs(array($step->getPHID()))->execute();
         $xaction_view = id(new PhabricatorApplicationTransactionView())->setUser($viewer)->setObjectPHID($step->getPHID())->setTransactions($xactions)->setShouldTerminate(true);
     }
     return $this->buildApplicationPage(array($crumbs, $box, $variables, $xaction_view), array('title' => $implementation->getName()));
 }
 private function buildStepList(HarbormasterBuildPlan $plan)
 {
     $viewer = $this->getViewer();
     $run_order = HarbormasterBuildGraph::determineDependencyExecution($plan);
     $steps = id(new HarbormasterBuildStepQuery())->setViewer($viewer)->withBuildPlanPHIDs(array($plan->getPHID()))->execute();
     $steps = mpull($steps, null, 'getPHID');
     $has_manage = $this->hasApplicationCapability(HarbormasterManagePlansCapability::CAPABILITY);
     $has_edit = PhabricatorPolicyFilter::hasCapability($viewer, $plan, PhabricatorPolicyCapability::CAN_EDIT);
     $can_edit = $has_manage && $has_edit;
     $step_list = id(new PHUIObjectItemListView())->setUser($viewer)->setNoDataString(pht('This build plan does not have any build steps yet.'));
     $i = 1;
     $last_depth = 0;
     $has_any_conflicts = false;
     $is_deadlocking = false;
     foreach ($run_order as $run_ref) {
         $step = $steps[$run_ref['node']->getPHID()];
         $depth = $run_ref['depth'] + 1;
         if ($last_depth !== $depth) {
             $last_depth = $depth;
             $i = 1;
         } else {
             $i++;
         }
         $implementation = null;
         try {
             $implementation = $step->getStepImplementation();
         } catch (Exception $ex) {
             // We can't initialize the implementation. This might be because
             // it's been renamed or no longer exists.
             $item = id(new PHUIObjectItemView())->setObjectName(pht('Step %d.%d', $depth, $i))->setHeader(pht('Unknown Implementation'))->setStatusIcon('fa-warning red')->addAttribute(pht('This step has an invalid implementation (%s).', $step->getClassName()))->addAction(id(new PHUIListItemView())->setIcon('fa-times')->addSigil('harbormaster-build-step-delete')->setWorkflow(true)->setRenderNameAsTooltip(true)->setName(pht('Delete'))->setHref($this->getApplicationURI('step/delete/' . $step->getID() . '/')));
             $step_list->addItem($item);
             continue;
         }
         $item = id(new PHUIObjectItemView())->setObjectName(pht('Step %d.%d', $depth, $i))->setHeader($step->getName());
         $item->addAttribute($implementation->getDescription());
         $step_id = $step->getID();
         $edit_uri = $this->getApplicationURI("step/edit/{$step_id}/");
         $delete_uri = $this->getApplicationURI("step/delete/{$step_id}/");
         if ($can_edit) {
             $item->setHref($edit_uri);
         }
         $item->setHref($edit_uri)->addAction(id(new PHUIListItemView())->setIcon('fa-times')->addSigil('harbormaster-build-step-delete')->setWorkflow(true)->setDisabled(!$can_edit)->setHref($this->getApplicationURI('step/delete/' . $step->getID() . '/')));
         $depends = $step->getStepImplementation()->getDependencies($step);
         $inputs = $step->getStepImplementation()->getArtifactInputs();
         $outputs = $step->getStepImplementation()->getArtifactOutputs();
         $has_conflicts = false;
         if ($depends || $inputs || $outputs) {
             $available_artifacts = HarbormasterBuildStepImplementation::getAvailableArtifacts($plan, $step, null);
             $available_artifacts = ipull($available_artifacts, 'type');
             list($depends_ui, $has_conflicts) = $this->buildDependsOnList($depends, pht('Depends On'), $steps);
             list($inputs_ui, $has_conflicts) = $this->buildArtifactList($inputs, 'in', pht('Input Artifacts'), $available_artifacts);
             list($outputs_ui) = $this->buildArtifactList($outputs, 'out', pht('Output Artifacts'), array());
             $item->appendChild(phutil_tag('div', array('class' => 'harbormaster-artifact-io'), array($depends_ui, $inputs_ui, $outputs_ui)));
         }
         if ($has_conflicts) {
             $has_any_conflicts = true;
             $item->setStatusIcon('fa-warning red');
         }
         if ($run_ref['cycle']) {
             $is_deadlocking = true;
         }
         if ($is_deadlocking) {
             $item->setStatusIcon('fa-warning red');
         }
         $step_list->addItem($item);
     }
     $step_list->setFlush(true);
     $plan_id = $plan->getID();
     $header = id(new PHUIHeaderView())->setHeader(pht('Build Steps'))->addActionLink(id(new PHUIButtonView())->setText(pht('Add Build Step'))->setHref($this->getApplicationURI("step/add/{$plan_id}/"))->setTag('a')->setIcon(id(new PHUIIconView())->setIconFont('fa-plus'))->setDisabled(!$can_edit)->setWorkflow(!$can_edit));
     $step_box = id(new PHUIObjectBoxView())->setHeader($header)->appendChild($step_list);
     return array($step_box, $has_any_conflicts, $is_deadlocking);
 }
 /**
  * Get all of the @{class:HarbormasterBuildStepImplementation} objects for
  * a list of autotarget keys.
  *
  * @param list<string> Autotarget keys, like `"core.arc.lint"`.
  * @return map<string, object> Map of keys to implementations.
  */
 private function getAutosteps(array $autotargets)
 {
     $all_steps = HarbormasterBuildStepImplementation::getImplementations();
     $all_steps = mpull($all_steps, null, 'getBuildStepAutotargetStepKey');
     // Make sure all the targets really exist.
     foreach ($autotargets as $autotarget) {
         if (empty($all_steps[$autotarget])) {
             throw new Exception(pht('No build step provides autotarget "%s"!', $autotarget));
         }
     }
     return array_select_keys($all_steps, $autotargets);
 }
 public function testGetImplementations()
 {
     HarbormasterBuildStepImplementation::getImplementations();
     $this->assertTrue(true);
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $this->getViewer();
     $id = $request->getURIData('id');
     if ($id) {
         $step = id(new HarbormasterBuildStepQuery())->setViewer($viewer)->withIDs(array($id))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
         if (!$step) {
             return new Aphront404Response();
         }
         $plan = $step->getBuildPlan();
         $is_new = false;
     } else {
         $plan_id = $request->getURIData('plan');
         $class = $request->getURIData('class');
         $plan = id(new HarbormasterBuildPlanQuery())->setViewer($viewer)->withIDs(array($plan_id))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
         if (!$plan) {
             return new Aphront404Response();
         }
         $impl = HarbormasterBuildStepImplementation::getImplementation($class);
         if (!$impl) {
             return new Aphront404Response();
         }
         if ($impl->shouldRequireAutotargeting()) {
             // No manual creation of autotarget steps.
             return new Aphront404Response();
         }
         $step = HarbormasterBuildStep::initializeNewStep($viewer)->setBuildPlanPHID($plan->getPHID())->setClassName($class);
         $is_new = true;
     }
     $plan_uri = $this->getApplicationURI('plan/' . $plan->getID() . '/');
     if ($is_new) {
         $cancel_uri = $plan_uri;
     } else {
         $cancel_uri = $this->getApplicationURI('step/view/' . $step->getID() . '/');
     }
     $implementation = $step->getStepImplementation();
     $field_list = PhabricatorCustomField::getObjectFields($step, PhabricatorCustomField::ROLE_EDIT);
     $field_list->setViewer($viewer)->readFieldsFromStorage($step);
     $e_name = true;
     $v_name = $step->getName();
     $e_description = null;
     $v_description = $step->getDescription();
     $e_depends_on = null;
     $v_depends_on = $step->getDetail('dependsOn', array());
     $errors = array();
     $validation_exception = null;
     if ($request->isFormPost()) {
         $e_name = null;
         $v_name = $request->getStr('name');
         $v_description = $request->getStr('description');
         $v_depends_on = $request->getArr('dependsOn');
         $xactions = $field_list->buildFieldTransactionsFromRequest(new HarbormasterBuildStepTransaction(), $request);
         $editor = id(new HarbormasterBuildStepEditor())->setActor($viewer)->setContinueOnNoEffect(true)->setContentSourceFromRequest($request);
         $name_xaction = id(new HarbormasterBuildStepTransaction())->setTransactionType(HarbormasterBuildStepTransaction::TYPE_NAME)->setNewValue($v_name);
         array_unshift($xactions, $name_xaction);
         $depends_on_xaction = id(new HarbormasterBuildStepTransaction())->setTransactionType(HarbormasterBuildStepTransaction::TYPE_DEPENDS_ON)->setNewValue($v_depends_on);
         array_unshift($xactions, $depends_on_xaction);
         $description_xaction = id(new HarbormasterBuildStepTransaction())->setTransactionType(HarbormasterBuildStepTransaction::TYPE_DESCRIPTION)->setNewValue($v_description);
         array_unshift($xactions, $description_xaction);
         if ($is_new) {
             // When creating a new step, make sure we have a create transaction
             // so we'll apply the transactions even if the step has no
             // configurable options.
             $create_xaction = id(new HarbormasterBuildStepTransaction())->setTransactionType(HarbormasterBuildStepTransaction::TYPE_CREATE);
             array_unshift($xactions, $create_xaction);
         }
         try {
             $editor->applyTransactions($step, $xactions);
             $step_uri = $this->getApplicationURI('step/view/' . $step->getID() . '/');
             return id(new AphrontRedirectResponse())->setURI($step_uri);
         } catch (PhabricatorApplicationTransactionValidationException $ex) {
             $validation_exception = $ex;
         }
     }
     $form = id(new AphrontFormView())->setUser($viewer);
     $instructions = $implementation->getEditInstructions();
     if (strlen($instructions)) {
         $form->appendRemarkupInstructions($instructions);
     }
     $form->appendChild(id(new AphrontFormTextControl())->setName('name')->setLabel(pht('Name'))->setError($e_name)->setValue($v_name));
     $form->appendChild(id(new AphrontFormDividerControl()));
     $field_list->appendFieldsToForm($form);
     $form->appendChild(id(new AphrontFormDividerControl()));
     $form->appendControl(id(new AphrontFormTokenizerControl())->setDatasource(id(new HarbormasterBuildDependencyDatasource())->setParameters(array('planPHID' => $plan->getPHID(), 'stepPHID' => $is_new ? null : $step->getPHID())))->setName('dependsOn')->setLabel(pht('Depends On'))->setError($e_depends_on)->setValue($v_depends_on));
     $form->appendChild(id(new PhabricatorRemarkupControl())->setUser($viewer)->setName('description')->setLabel(pht('Description'))->setError($e_description)->setValue($v_description));
     $crumbs = $this->buildApplicationCrumbs();
     $id = $plan->getID();
     $crumbs->addTextCrumb(pht('Plan %d', $id), $plan_uri);
     if ($is_new) {
         $submit = pht('Create Build Step');
         $header = id(new PHUIHeaderView())->setHeader(pht('New Step: %s', $implementation->getName()))->setHeaderIcon('fa-plus-square');
         $crumbs->addTextCrumb(pht('Add Step'));
     } else {
         $submit = pht('Save Build Step');
         $header = id(new PHUIHeaderView())->setHeader(pht('Edit Step: %s', $implementation->getName()))->setHeaderIcon('fa-pencil');
         $crumbs->addTextCrumb(pht('Step %d', $step->getID()), $cancel_uri);
         $crumbs->addTextCrumb(pht('Edit Step'));
     }
     $crumbs->setBorder(true);
     $form->appendChild(id(new AphrontFormSubmitControl())->setValue($submit)->addCancelButton($cancel_uri));
     $box = id(new PHUIObjectBoxView())->setHeaderText(pht('Step'))->setValidationException($validation_exception)->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->setForm($form);
     $variables = $this->renderBuildVariablesTable();
     if ($is_new) {
         $xaction_view = null;
         $timeline = null;
     } else {
         $timeline = $this->buildTransactionTimeline($step, new HarbormasterBuildStepTransactionQuery());
         $timeline->setShouldTerminate(true);
     }
     $view = id(new PHUITwoColumnView())->setHeader($header)->setFooter(array($box, $variables, $timeline));
     return $this->newPage()->setTitle($implementation->getName())->setCrumbs($crumbs)->appendChild($view);
 }