1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-10 08:52:39 +01:00

Don't create invalid build steps while adding them

Summary:
Ref T1049. Currently, the "add" dialog lets you select a build step type, but then immediately creates one. If you "cancel" from the edit screen, you end up with an empty (and almost certainly invalid) build step.

Instead, don't create the step until it's valid.

Test Plan: Add Step -> Pick Type -> Add Step -> Cancel no longer creates empty step.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T1049

Differential Revision: https://secure.phabricator.com/D8605
This commit is contained in:
epriestley 2014-03-25 16:12:05 -07:00
parent d6b937ca27
commit 6e3c17e6f9
4 changed files with 97 additions and 54 deletions

View file

@ -50,6 +50,8 @@ final class PhabricatorApplicationHarbormaster extends PhabricatorApplication {
=> 'HarbormasterBuildableListController', => 'HarbormasterBuildableListController',
'step/' => array( 'step/' => array(
'add/(?:(?P<id>\d+)/)?' => 'HarbormasterStepAddController', 'add/(?:(?P<id>\d+)/)?' => 'HarbormasterStepAddController',
'new/(?P<plan>\d+)/(?P<class>[^/]+)/'
=> 'HarbormasterStepEditController',
'edit/(?:(?P<id>\d+)/)?' => 'HarbormasterStepEditController', 'edit/(?:(?P<id>\d+)/)?' => 'HarbormasterStepEditController',
'delete/(?:(?P<id>\d+)/)?' => 'HarbormasterStepDeleteController', 'delete/(?:(?P<id>\d+)/)?' => 'HarbormasterStepDeleteController',
), ),

View file

@ -16,47 +16,32 @@ final class HarbormasterStepAddController
$this->requireApplicationCapability( $this->requireApplicationCapability(
HarbormasterCapabilityManagePlans::CAPABILITY); HarbormasterCapabilityManagePlans::CAPABILITY);
$id = $this->id;
$plan = id(new HarbormasterBuildPlanQuery()) $plan = id(new HarbormasterBuildPlanQuery())
->setViewer($viewer) ->setViewer($viewer)
->withIDs(array($id)) ->withIDs(array($this->id))
->executeOne(); ->executeOne();
if (!$plan) { if (!$plan) {
return new Aphront404Response(); return new Aphront404Response();
} }
$cancel_uri = $this->getApplicationURI('plan/'.$plan->getID().'/'); $plan_id = $plan->getID();
$cancel_uri = $this->getApplicationURI("plan/{$plan_id}/");
if ($request->isDialogFormPost()) { $errors = array();
$class = $request->getStr('step-type'); if ($request->isFormPost()) {
$class = $request->getStr('class');
if (!HarbormasterBuildStepImplementation::getImplementation($class)) { if (!HarbormasterBuildStepImplementation::getImplementation($class)) {
return $this->createDialog($cancel_uri); $errors[] = pht(
'Choose the type of build step you want to add.');
} }
if (!$errors) {
$steps = $plan->loadOrderedBuildSteps(); $new_uri = $this->getApplicationURI("step/new/{$plan_id}/{$class}/");
return id(new AphrontRedirectResponse())->setURI($new_uri);
$step = new HarbormasterBuildStep();
$step->setBuildPlanPHID($plan->getPHID());
$step->setClassName($class);
$step->setDetails(array());
$step->setSequence(count($steps) + 1);
$step->save();
$edit_uri = $this->getApplicationURI("step/edit/".$step->getID()."/");
return id(new AphrontRedirectResponse())->setURI($edit_uri);
} }
return $this->createDialog($cancel_uri);
} }
private function createDialog($cancel_uri) {
$request = $this->getRequest();
$viewer = $request->getUser();
$control = id(new AphrontFormRadioButtonControl()) $control = id(new AphrontFormRadioButtonControl())
->setName('step-type'); ->setName('class');
$all = HarbormasterBuildStepImplementation::getImplementations(); $all = HarbormasterBuildStepImplementation::getImplementations();
foreach ($all as $class => $implementation) { foreach ($all as $class => $implementation) {
@ -66,10 +51,16 @@ final class HarbormasterStepAddController
$implementation->getGenericDescription()); $implementation->getGenericDescription());
} }
if ($errors) {
$errors = id(new AphrontErrorView())
->setErrors($errors);
}
return $this->newDialog() return $this->newDialog()
->setTitle(pht('Add New Step')) ->setTitle(pht('Add New Step'))
->addSubmitButton(pht('Add Build Step')) ->addSubmitButton(pht('Add Build Step'))
->addCancelButton($cancel_uri) ->addCancelButton($cancel_uri)
->appendChild($errors)
->appendParagraph(pht('Choose a type of build step to add:')) ->appendParagraph(pht('Choose a type of build step to add:'))
->appendChild($control); ->appendChild($control);
} }

View file

@ -4,9 +4,13 @@ final class HarbormasterStepEditController
extends HarbormasterController { extends HarbormasterController {
private $id; private $id;
private $planID;
private $className;
public function willProcessRequest(array $data) { public function willProcessRequest(array $data) {
$this->id = idx($data, 'id'); $this->id = idx($data, 'id');
$this->planID = idx($data, 'plan');
$this->className = idx($data, 'class');
} }
public function processRequest() { public function processRequest() {
@ -16,6 +20,7 @@ final class HarbormasterStepEditController
$this->requireApplicationCapability( $this->requireApplicationCapability(
HarbormasterCapabilityManagePlans::CAPABILITY); HarbormasterCapabilityManagePlans::CAPABILITY);
if ($this->id) {
$step = id(new HarbormasterBuildStepQuery()) $step = id(new HarbormasterBuildStepQuery())
->setViewer($viewer) ->setViewer($viewer)
->withIDs(array($this->id)) ->withIDs(array($this->id))
@ -23,9 +28,33 @@ final class HarbormasterStepEditController
if (!$step) { if (!$step) {
return new Aphront404Response(); return new Aphront404Response();
} }
$plan = $step->getBuildPlan(); $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(); $implementation = $step->getStepImplementation();
$field_list = PhabricatorCustomField::getObjectFields( $field_list = PhabricatorCustomField::getObjectFields(
@ -47,10 +76,16 @@ final class HarbormasterStepEditController
->setContinueOnNoEffect(true) ->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request); ->setContentSourceFromRequest($request);
if ($is_new) {
// This is okay, but a little iffy. We should move it inside the editor
// if we create plans elsewhere.
$steps = $plan->loadOrderedBuildSteps();
$step->setSequence(count($steps) + 1);
}
try { try {
$editor->applyTransactions($step, $xactions); $editor->applyTransactions($step, $xactions);
return id(new AphrontRedirectResponse()) return id(new AphrontRedirectResponse())->setURI($plan_uri);
->setURI($this->getApplicationURI('plan/'.$plan->getID().'/'));
} catch (PhabricatorApplicationTransactionValidationException $ex) { } catch (PhabricatorApplicationTransactionValidationException $ex) {
$validation_exception = $ex; $validation_exception = $ex;
} }
@ -61,26 +96,36 @@ final class HarbormasterStepEditController
$field_list->appendFieldsToForm($form); $field_list->appendFieldsToForm($form);
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( $form->appendChild(
id(new AphrontFormSubmitControl()) id(new AphrontFormSubmitControl())
->setValue(pht('Save Build Step')) ->setValue($submit)
->addCancelButton( ->addCancelButton($plan_uri));
$this->getApplicationURI('plan/'.$plan->getID().'/')));
$box = id(new PHUIObjectBoxView()) $box = id(new PHUIObjectBoxView())
->setHeaderText('Edit Step: '.$implementation->getName()) ->setHeaderText($header)
->setValidationException($validation_exception) ->setValidationException($validation_exception)
->setForm($form); ->setForm($form);
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();
$id = $plan->getID(); $id = $plan->getID();
$crumbs->addTextCrumb( $crumbs->addTextCrumb(pht('Plan %d', $id), $plan_uri);
pht("Plan %d", $id), $crumbs->addTextCrumb($crumb);
$this->getApplicationURI("plan/{$id}/"));
$crumbs->addTextCrumb(pht('Edit Step'));
$variables = $this->renderBuildVariablesTable(); $variables = $this->renderBuildVariablesTable();
if ($is_new) {
$xaction_view = null;
} else {
$xactions = id(new HarbormasterBuildStepTransactionQuery()) $xactions = id(new HarbormasterBuildStepTransactionQuery())
->setViewer($viewer) ->setViewer($viewer)
->withObjectPHIDs(array($step->getPHID())) ->withObjectPHIDs(array($step->getPHID()))
@ -91,6 +136,7 @@ final class HarbormasterStepEditController
->setObjectPHID($step->getPHID()) ->setObjectPHID($step->getPHID())
->setTransactions($xactions) ->setTransactions($xactions)
->setShouldTerminate(true); ->setShouldTerminate(true);
}
return $this->buildApplicationPage( return $this->buildApplicationPage(
array( array(

View file

@ -14,6 +14,10 @@ final class HarbormasterBuildStep extends HarbormasterDAO
private $customFields = self::ATTACHABLE; private $customFields = self::ATTACHABLE;
private $implementation; private $implementation;
public static function initializeNewStep(PhabricatorUser $actor) {
return id(new HarbormasterBuildStep());
}
public function getConfiguration() { public function getConfiguration() {
return array( return array(
self::CONFIG_AUX_PHID => true, self::CONFIG_AUX_PHID => true,