/** * Get a map of the @{class:HarbormasterBuildStep} objects for a list of * autotarget keys. * * This method creates the steps if they do not yet exist. * * @param list<string> Autotarget keys, like `"core.arc.lint"`. * @return map<string, object> Map of keys to step objects. */ private function generateBuildStepMap(array $autotargets) { $viewer = $this->getViewer(); $autosteps = $this->getAutosteps($autotargets); $autosteps = mgroup($autosteps, 'getBuildStepAutotargetPlanKey'); $plans = id(new HarbormasterBuildPlanQuery())->setViewer($viewer)->withPlanAutoKeys(array_keys($autosteps))->needBuildSteps(true)->execute(); $plans = mpull($plans, null, 'getPlanAutoKey'); // NOTE: When creating the plan and steps, we save the autokeys as the // names. These won't actually be shown in the UI, but make the data more // consistent for secondary consumers like typeaheads. $step_map = array(); foreach ($autosteps as $plan_key => $steps) { $plan = idx($plans, $plan_key); if (!$plan) { $plan = HarbormasterBuildPlan::initializeNewBuildPlan($viewer)->setName($plan_key)->setPlanAutoKey($plan_key); } $current = $plan->getBuildSteps(); $current = mpull($current, null, 'getStepAutoKey'); $new_steps = array(); foreach ($steps as $step_key => $step) { if (isset($current[$step_key])) { $step_map[$step_key] = $current[$step_key]; continue; } $new_step = HarbormasterBuildStep::initializeNewStep($viewer)->setName($step_key)->setClassName(get_class($step))->setStepAutoKey($step_key); $new_steps[$step_key] = $new_step; } if ($new_steps) { $plan->openTransaction(); if (!$plan->getPHID()) { $plan->save(); } foreach ($new_steps as $step_key => $step) { $step->setBuildPlanPHID($plan->getPHID()); $step->save(); $step->attachBuildPlan($plan); $step_map[$step_key] = $step; } $plan->saveTransaction(); } } return $step_map; }
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())); }
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); }