3 final class ReleephProductEditController
extends ReleephProductController
{
5 public function handleRequest(AphrontRequest
$request) {
6 $viewer = $request->getViewer();
7 $id = $request->getURIData('projectID');
9 $product = id(new ReleephProductQuery())
12 ->requireCapabilities(
14 PhabricatorPolicyCapability
::CAN_VIEW
,
15 PhabricatorPolicyCapability
::CAN_EDIT
,
19 return new Aphront404Response();
21 $this->setProduct($product);
24 $e_trunk_branch = true;
25 $e_branch_template = false;
28 $product_name = $request->getStr('name', $product->getName());
30 $trunk_branch = $request->getStr('trunkBranch', $product->getTrunkBranch());
31 $branch_template = $request->getStr('branchTemplate');
32 if ($branch_template === null) {
33 $branch_template = $product->getDetail('branchTemplate');
35 $pick_failure_instructions = $request->getStr('pickFailureInstructions',
36 $product->getDetail('pick_failure_instructions'));
37 $test_paths = $request->getStr('testPaths');
38 if ($test_paths !== null) {
39 $test_paths = array_filter(explode("\n", $test_paths));
41 $test_paths = $product->getDetail('testPaths', array());
44 $repository_phid = $product->getRepositoryPHID();
46 if ($request->isFormPost()) {
47 $pusher_phids = $request->getArr('pushers');
50 $e_name = pht('Required');
52 pht('Your Releeph product should have a simple descriptive name.');
56 $e_trunk_branch = pht('Required');
58 pht('You must specify which branch you will be picking from.');
61 $other_releeph_products = id(new ReleephProject())
62 ->loadAllWhere('id != %d', $product->getID());
63 $other_releeph_product_names = mpull($other_releeph_products,
66 if (in_array($product_name, $other_releeph_product_names)) {
67 $errors[] = pht('Releeph product name %s is already taken',
71 foreach ($test_paths as $test_path) {
72 $result = @preg_match
($test_path, '');
73 $is_a_valid_regexp = $result !== false;
74 if (!$is_a_valid_regexp) {
75 $errors[] = pht('Please provide a valid regular expression: '.
76 '%s is not valid', $test_path);
81 ->setName($product_name)
82 ->setTrunkBranch($trunk_branch)
83 ->setDetail('pushers', $pusher_phids)
84 ->setDetail('pick_failure_instructions', $pick_failure_instructions)
85 ->setDetail('branchTemplate', $branch_template)
86 ->setDetail('testPaths', $test_paths);
88 $fake_commit_handle = ReleephBranchTemplate
::getFakeCommitHandleFor(
92 if ($branch_template) {
93 list($branch_name, $template_errors) = id(new ReleephBranchTemplate())
94 ->setCommitHandle($fake_commit_handle)
95 ->setReleephProjectName($product_name)
96 ->interpolate($branch_template);
98 if ($template_errors) {
99 $e_branch_template = pht('Whoopsies!');
100 foreach ($template_errors as $template_error) {
101 $errors[] = pht('Template error: %s', $template_error);
109 return id(new AphrontRedirectResponse())->setURI($product->getURI());
113 $pusher_phids = $request->getArr(
115 $product->getDetail('pushers', array()));
117 $form = id(new AphrontFormView())
118 ->setUser($request->getUser())
120 id(new AphrontFormTextControl())
121 ->setLabel(pht('Name'))
123 ->setValue($product_name)
125 ->setCaption(pht('A name like "Thrift" but not "Thrift releases".')))
127 id(new AphrontFormStaticControl())
128 ->setLabel(pht('Repository'))
130 $product->getRepository()->getName()))
132 id(new AphrontFormStaticControl())
133 ->setLabel(pht('Repository'))
135 $product->getRepository()->getName()))
137 id(new AphrontFormStaticControl())
138 ->setLabel(pht('Releeph Project PHID'))
140 $product->getPHID()))
142 id(new AphrontFormTextControl())
143 ->setLabel(pht('Trunk'))
144 ->setValue($trunk_branch)
145 ->setName('trunkBranch')
146 ->setError($e_trunk_branch))
148 id(new AphrontFormTextAreaControl())
149 ->setLabel(pht('Pick Instructions'))
150 ->setValue($pick_failure_instructions)
151 ->setName('pickFailureInstructions')
153 pht('Instructions for pick failures, which will be used '.
154 'in emails generated by failed picks')))
156 id(new AphrontFormTextAreaControl())
157 ->setLabel(pht('Tests paths'))
158 ->setValue(implode("\n", $test_paths))
159 ->setName('testPaths')
161 pht('List of strings that all test files contain in their path '.
162 'in this project. One string per line. '.
163 'Examples: \'__tests__\', \'/javatests/\'...')));
165 $branch_template_input = id(new AphrontFormTextControl())
166 ->setName('branchTemplate')
167 ->setValue($branch_template)
168 ->setLabel(pht('Branch Template'))
169 ->setError($e_branch_template)
171 pht("Leave this blank to use your installation's default."));
173 $branch_template_preview = id(new ReleephBranchPreviewView())
174 ->setLabel(pht('Preview'))
175 ->addControl('template', $branch_template_input)
176 ->addStatic('repositoryPHID', $repository_phid)
177 ->addStatic('isSymbolic', false)
178 ->addStatic('projectName', $product->getName());
182 id(new AphrontFormTokenizerControl())
183 ->setLabel(pht('Pushers'))
185 ->setDatasource(new PhabricatorPeopleDatasource())
186 ->setValue($pusher_phids))
187 ->appendChild($branch_template_input)
188 ->appendChild($branch_template_preview)
189 ->appendRemarkupInstructions($this->getBranchHelpText());
193 id(new AphrontFormSubmitControl())
194 ->addCancelButton('/releeph/product/')
195 ->setValue(pht('Save')));
197 $box = id(new PHUIObjectBoxView())
198 ->setHeaderText(pht('Product'))
199 ->setFormErrors($errors)
200 ->setBackground(PHUIObjectBoxView
::BLUE_PROPERTY
)
201 ->appendChild($form);
203 $title = pht('Edit Product');
205 $crumbs = $this->buildApplicationCrumbs();
206 $crumbs->addTextCrumb(pht('Edit Product'));
207 $crumbs->setBorder(true);
209 $header = id(new PHUIHeaderView())
211 ->setHeaderIcon('fa-pencil');
213 $view = id(new PHUITwoColumnView())
217 return $this->newPage()
220 ->appendChild($view);
224 private function getBranchHelpText() {
227 ==== Interpolations ====
231 | `%P` | The name of your product, with spaces changed to "-".
232 | `%p` | Like %P, but all lowercase.
233 | `%Y` | The four digit year associated with the branch date.
234 | `%m` | The two digit month.
235 | `%d` | The two digit day.
236 | `%v` | The handle of the commit where the branch was cut ("rXYZa4b3c2d1").
237 | `%V` | The abbreviated commit id where the branch was cut ("a4b3c2d1").
238 | `%..` | Any other sequence interpreted by `strftime()`.
239 | `%%` | A literal percent sign.
242 ==== Tips for Branch Templates ====
244 Use a directory to separate your release branches from other branches:
248 => releases/2012-30-16-rHERGE32cd512a52b7
250 Include a second hierarchy if you share your repository with other products:
253 releases/%P/%p-release-%Y%m%d-%V
254 => releases/Tintin/tintin-release-20121116-32cd512a52b7
256 Keep your branch names simple, avoiding strange punctuation, most of which is
257 forbidden or escaped anyway:
259 lang=none, counterexample
260 releases//..clown-releases..//`date --iso=seconds`-$(sudo halt)
262 Include the date early in your template, in an order which sorts properly:
266 => releases/20121116-rHERGE32cd512a52b7 (good!)
269 => releases/32cd512a52b7-11.16.2012 (awful!)