@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
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}