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