@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
at recaptime-dev/main 270 lines 8.3 kB view raw
1<?php 2 3final class HarbormasterStepEditController 4 extends HarbormasterPlanController { 5 6 public function handleRequest(AphrontRequest $request) { 7 $viewer = $this->getViewer(); 8 $id = $request->getURIData('id'); 9 10 if ($id) { 11 $step = id(new HarbormasterBuildStepQuery()) 12 ->setViewer($viewer) 13 ->withIDs(array($id)) 14 ->requireCapabilities( 15 array( 16 PhabricatorPolicyCapability::CAN_VIEW, 17 PhabricatorPolicyCapability::CAN_EDIT, 18 )) 19 ->executeOne(); 20 if (!$step) { 21 return new Aphront404Response(); 22 } 23 $plan = $step->getBuildPlan(); 24 25 $is_new = false; 26 } else { 27 $plan_id = $request->getURIData('plan'); 28 $class = $request->getURIData('class'); 29 30 $plan = id(new HarbormasterBuildPlanQuery()) 31 ->setViewer($viewer) 32 ->withIDs(array($plan_id)) 33 ->requireCapabilities( 34 array( 35 PhabricatorPolicyCapability::CAN_VIEW, 36 PhabricatorPolicyCapability::CAN_EDIT, 37 )) 38 ->executeOne(); 39 if (!$plan) { 40 return new Aphront404Response(); 41 } 42 43 $impl = HarbormasterBuildStepImplementation::getImplementation($class); 44 if (!$impl) { 45 return new Aphront404Response(); 46 } 47 48 if ($impl->shouldRequireAutotargeting()) { 49 // No manual creation of autotarget steps. 50 return new Aphront404Response(); 51 } 52 53 $step = HarbormasterBuildStep::initializeNewStep($viewer) 54 ->setBuildPlanPHID($plan->getPHID()) 55 ->setClassName($class); 56 57 $is_new = true; 58 } 59 60 $plan_uri = $this->getApplicationURI('plan/'.$plan->getID().'/'); 61 62 if ($is_new) { 63 $cancel_uri = $plan_uri; 64 } else { 65 $cancel_uri = $this->getApplicationURI('step/view/'.$step->getID().'/'); 66 } 67 68 $implementation = $step->getStepImplementation(); 69 70 $field_list = PhabricatorCustomField::getObjectFields( 71 $step, 72 PhabricatorCustomField::ROLE_EDIT); 73 $field_list 74 ->setViewer($viewer) 75 ->readFieldsFromStorage($step); 76 77 $e_name = true; 78 $v_name = $step->getName(); 79 $e_description = null; 80 $v_description = $step->getDescription(); 81 $e_depends_on = null; 82 $v_depends_on = $step->getDetail('dependsOn', array()); 83 84 $errors = array(); 85 $validation_exception = null; 86 if ($request->isFormPost()) { 87 $e_name = null; 88 $v_name = $request->getStr('name'); 89 $v_description = $request->getStr('description'); 90 $v_depends_on = $request->getArr('dependsOn'); 91 92 $xactions = $field_list->buildFieldTransactionsFromRequest( 93 new HarbormasterBuildStepTransaction(), 94 $request); 95 96 $editor = id(new HarbormasterBuildStepEditor()) 97 ->setActor($viewer) 98 ->setContinueOnNoEffect(true) 99 ->setContentSourceFromRequest($request); 100 101 $name_xaction = id(new HarbormasterBuildStepTransaction()) 102 ->setTransactionType(HarbormasterBuildStepTransaction::TYPE_NAME) 103 ->setNewValue($v_name); 104 array_unshift($xactions, $name_xaction); 105 106 $depends_on_xaction = id(new HarbormasterBuildStepTransaction()) 107 ->setTransactionType( 108 HarbormasterBuildStepTransaction::TYPE_DEPENDS_ON) 109 ->setNewValue($v_depends_on); 110 array_unshift($xactions, $depends_on_xaction); 111 112 $description_xaction = id(new HarbormasterBuildStepTransaction()) 113 ->setTransactionType( 114 HarbormasterBuildStepTransaction::TYPE_DESCRIPTION) 115 ->setNewValue($v_description); 116 array_unshift($xactions, $description_xaction); 117 118 if ($is_new) { 119 // When creating a new step, make sure we have a create transaction 120 // so we'll apply the transactions even if the step has no 121 // configurable options. 122 $create_xaction = id(new HarbormasterBuildStepTransaction()) 123 ->setTransactionType(HarbormasterBuildStepTransaction::TYPE_CREATE); 124 array_unshift($xactions, $create_xaction); 125 } 126 127 try { 128 $editor->applyTransactions($step, $xactions); 129 130 $step_uri = $this->getApplicationURI('step/view/'.$step->getID().'/'); 131 132 return id(new AphrontRedirectResponse())->setURI($step_uri); 133 } catch (PhabricatorApplicationTransactionValidationException $ex) { 134 $validation_exception = $ex; 135 } 136 } 137 138 $form = id(new AphrontFormView()) 139 ->setUser($viewer); 140 141 $instructions = $implementation->getEditInstructions(); 142 if (phutil_nonempty_string($instructions)) { 143 $form->appendRemarkupInstructions($instructions); 144 } 145 146 $form->appendChild( 147 id(new AphrontFormTextControl()) 148 ->setName('name') 149 ->setLabel(pht('Name')) 150 ->setError($e_name) 151 ->setValue($v_name)); 152 153 $form->appendChild(id(new AphrontFormDividerControl())); 154 155 $field_list->appendFieldsToForm($form); 156 157 $form->appendChild(id(new AphrontFormDividerControl())); 158 159 $form 160 ->appendControl( 161 id(new AphrontFormTokenizerControl()) 162 ->setDatasource(id(new HarbormasterBuildDependencyDatasource()) 163 ->setParameters(array( 164 'planPHID' => $plan->getPHID(), 165 'stepPHID' => $is_new ? null : $step->getPHID(), 166 ))) 167 ->setName('dependsOn') 168 ->setLabel(pht('Depends On')) 169 ->setError($e_depends_on) 170 ->setValue($v_depends_on)); 171 172 $form 173 ->appendChild( 174 id(new PhabricatorRemarkupControl()) 175 ->setUser($viewer) 176 ->setName('description') 177 ->setLabel(pht('Description')) 178 ->setError($e_description) 179 ->setValue($v_description)); 180 181 $crumbs = $this->buildApplicationCrumbs(); 182 $id = $plan->getID(); 183 $crumbs->addTextCrumb(pht('Plan %d', $id), $plan_uri); 184 185 if ($is_new) { 186 $submit = pht('Create Build Step'); 187 $header = id(new PHUIHeaderView()) 188 ->setHeader(pht('New Step: %s', $implementation->getName())) 189 ->setHeaderIcon('fa-plus-square'); 190 $crumbs->addTextCrumb(pht('Add Step')); 191 } else { 192 $submit = pht('Save Build Step'); 193 $header = id(new PHUIHeaderView()) 194 ->setHeader(pht('Edit Step: %s', $implementation->getName())) 195 ->setHeaderIcon('fa-pencil'); 196 $crumbs->addTextCrumb(pht('Step %d', $step->getID()), $cancel_uri); 197 $crumbs->addTextCrumb(pht('Edit Step')); 198 } 199 $crumbs->setBorder(true); 200 201 $form->appendChild( 202 id(new AphrontFormSubmitControl()) 203 ->setValue($submit) 204 ->addCancelButton($cancel_uri)); 205 206 $box = id(new PHUIObjectBoxView()) 207 ->setHeaderText(pht('Step')) 208 ->setValidationException($validation_exception) 209 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 210 ->setForm($form); 211 212 $variables = $this->renderBuildVariablesTable(); 213 214 if ($is_new) { 215 $xaction_view = null; 216 $timeline = null; 217 } else { 218 $timeline = $this->buildTransactionTimeline( 219 $step, 220 new HarbormasterBuildStepTransactionQuery()); 221 $timeline->setShouldTerminate(true); 222 } 223 224 $view = id(new PHUITwoColumnView()) 225 ->setHeader($header) 226 ->setFooter(array( 227 $box, 228 $variables, 229 $timeline, 230 )); 231 232 return $this->newPage() 233 ->setTitle($implementation->getName()) 234 ->setCrumbs($crumbs) 235 ->appendChild($view); 236 237 } 238 239 private function renderBuildVariablesTable() { 240 $viewer = $this->getRequest()->getUser(); 241 242 $variables = HarbormasterBuild::getAvailableBuildVariables(); 243 ksort($variables); 244 245 $rows = array(); 246 $rows[] = pht( 247 'The following variables can be used in most fields. '. 248 'To reference a variable, use `%s` in a field.', 249 '${name}'); 250 $rows[] = sprintf( 251 '| %s | %s |', 252 pht('Variable'), 253 pht('Description')); 254 $rows[] = '|---|---|'; 255 foreach ($variables as $name => $description) { 256 $rows[] = '| `'.$name.'` | '.$description.' |'; 257 } 258 $rows = implode("\n", $rows); 259 260 $form = id(new AphrontFormView()) 261 ->setUser($viewer) 262 ->appendRemarkupInstructions($rows); 263 264 return id(new PHUIObjectBoxView()) 265 ->setHeaderText(pht('Build Variables')) 266 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 267 ->appendChild($form); 268 } 269 270}