public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $e_name = true; $e_callsign = true; $repository = new PhabricatorRepository(); $type_map = PhabricatorRepositoryType::getAllRepositoryTypes(); $errors = array(); if ($request->isFormPost()) { $repository->setName($request->getStr('name')); $repository->setCallsign($request->getStr('callsign')); $repository->setVersionControlSystem($request->getStr('type')); if (!strlen($repository->getName())) { $e_name = 'Required'; $errors[] = 'Repository name is required.'; } else { $e_name = null; } if (!strlen($repository->getCallsign())) { $e_callsign = 'Required'; $errors[] = 'Callsign is required.'; } else { if (!preg_match('/^[A-Z]+$/', $repository->getCallsign())) { $e_callsign = 'Invalid'; $errors[] = 'Callsign must be ALL UPPERCASE LETTERS.'; } else { $e_callsign = null; } } if (empty($type_map[$repository->getVersionControlSystem()])) { $errors[] = 'Invalid version control system.'; } if (!$errors) { try { $repository->save(); return id(new AphrontRedirectResponse())->setURI('/repository/edit/' . $repository->getID() . '/'); } catch (AphrontQueryDuplicateKeyException $ex) { $e_callsign = 'Duplicate'; $errors[] = 'Callsign must be unique. Another repository already ' . 'uses that callsign.'; } } } $error_view = null; if ($errors) { $error_view = new AphrontErrorView(); $error_view->setErrors($errors); $error_view->setTitle('Form Errors'); } $form = new AphrontFormView(); $form->setUser($user)->setAction('/repository/create/')->appendChild(id(new AphrontFormTextControl())->setLabel('Name')->setName('name')->setValue($repository->getName())->setError($e_name)->setCaption('Human-readable repository name.'))->appendChild('<p class="aphront-form-instructions">Select a "Callsign" — a ' . 'short, uppercase string to identify revisions in this repository. If ' . 'you choose "EX", revisions in this repository will be identified ' . 'with the prefix "rEX".</p>')->appendChild(id(new AphrontFormTextControl())->setLabel('Callsign')->setName('callsign')->setValue($repository->getCallsign())->setError($e_callsign)->setCaption('Short, UPPERCASE identifier. Once set, it can not be changed.'))->appendChild(id(new AphrontFormSelectControl())->setLabel('Type')->setName('type')->setOptions($type_map)->setValue($repository->getVersionControlSystem()))->appendChild(id(new AphrontFormSubmitControl())->setValue('Create Repository')->addCancelButton('/repository/')); $panel = new AphrontPanelView(); $panel->setHeader('Create Repository'); $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_FORM); return $this->buildStandardPageResponse(array($error_view, $panel), array('title' => 'Create Repository')); }
public function buildSearchForm(AphrontFormView $form, PhabricatorSavedQuery $saved_query) { $callsigns = $saved_query->getParameter('callsigns', array()); $types = $saved_query->getParameter('types', array()); $types = array_fuse($types); $name = $saved_query->getParameter('name'); $any_project_phids = $saved_query->getParameter('anyProjectPHIDs', array()); if ($any_project_phids) { $any_project_handles = id(new PhabricatorHandleQuery())->setViewer($this->requireViewer())->withPHIDs($any_project_phids)->execute(); } else { $any_project_handles = array(); } $form->appendChild(id(new AphrontFormTextControl())->setName('callsigns')->setLabel(pht('Callsigns'))->setValue(implode(', ', $callsigns)))->appendChild(id(new AphrontFormTextControl())->setName('name')->setLabel(pht('Name Contains'))->setValue($name))->appendChild(id(new AphrontFormTokenizerControl())->setDatasource(new PhabricatorProjectDatasource())->setName('anyProjects')->setLabel(pht('In Any Project'))->setValue($any_project_handles))->appendChild(id(new AphrontFormSelectControl())->setName('status')->setLabel(pht('Status'))->setValue($saved_query->getParameter('status'))->setOptions($this->getStatusOptions()))->appendChild(id(new AphrontFormSelectControl())->setName('hosted')->setLabel(pht('Hosted'))->setValue($saved_query->getParameter('hosted'))->setOptions($this->getHostedOptions())); $type_control = id(new AphrontFormCheckboxControl())->setLabel(pht('Types')); $all_types = PhabricatorRepositoryType::getAllRepositoryTypes(); foreach ($all_types as $key => $name) { $type_control->addCheckbox('types[]', $key, $name, isset($types[$key])); } $form->appendChild($type_control)->appendChild(id(new AphrontFormSelectControl())->setName('order')->setLabel(pht('Order'))->setValue($saved_query->getParameter('order'))->setOptions($this->getOrderOptions())); }
protected function buildCustomSearchFields() { return array(id(new PhabricatorSearchStringListField())->setLabel(pht('Callsigns'))->setKey('callsigns'), id(new PhabricatorSearchTextField())->setLabel(pht('Name Contains'))->setKey('name'), id(new PhabricatorSearchSelectField())->setLabel(pht('Status'))->setKey('status')->setOptions($this->getStatusOptions()), id(new PhabricatorSearchSelectField())->setLabel(pht('Hosted'))->setKey('hosted')->setOptions($this->getHostedOptions()), id(new PhabricatorSearchCheckboxesField())->setLabel(pht('Types'))->setKey('types')->setOptions(PhabricatorRepositoryType::getAllRepositoryTypes())); }
protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions) { $errors = parent::validateTransaction($object, $type, $xactions); switch ($type) { case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE_ONLY: case PhabricatorRepositoryTransaction::TYPE_TRACK_ONLY: foreach ($xactions as $xaction) { foreach ($xaction->getNewValue() as $pattern) { // Check for invalid regular expressions. $regexp = PhabricatorRepository::extractBranchRegexp($pattern); if ($regexp !== null) { $ok = @preg_match($regexp, ''); if ($ok === false) { $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Expression "%s" is not a valid regular expression. Note ' . 'that you must include delimiters.', $regexp), $xaction); $errors[] = $error; continue; } } // Check for formatting mistakes like `regex(...)` instead of // `regexp(...)`. $matches = null; if (preg_match('/^([^(]+)\\(.*\\)\\z/', $pattern, $matches)) { switch ($matches[1]) { case 'regexp': break; default: $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Matching function "%s(...)" is not recognized. Valid ' . 'functions are: regexp(...).', $matches[1]), $xaction); $errors[] = $error; break; } } } } break; case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS: foreach ($xactions as $xaction) { $old = nonempty($xaction->getOldValue(), array()); $new = nonempty($xaction->getNewValue(), array()); $add = array_diff($new, $old); $invalid = PhabricatorObjectQuery::loadInvalidPHIDsForViewer($this->getActor(), $add); if ($invalid) { $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Some of the selected automation blueprints are invalid ' . 'or restricted: %s.', implode(', ', $invalid)), $xaction); } } break; case PhabricatorRepositoryTransaction::TYPE_VCS: $vcs_map = PhabricatorRepositoryType::getAllRepositoryTypes(); $current_vcs = $object->getVersionControlSystem(); if (!$this->getIsNewObject()) { foreach ($xactions as $xaction) { if ($xaction->getNewValue() == $current_vcs) { continue; } $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Immutable'), pht('You can not change the version control system an existing ' . 'repository uses. It can only be set when a repository is ' . 'first created.'), $xaction); } } else { $value = $object->getVersionControlSystem(); foreach ($xactions as $xaction) { $value = $xaction->getNewValue(); if (empty($vcs_map[$value])) { $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Specified version control system must be a VCS ' . 'recognized by Phabricator: %s.', implode(', ', array_keys($vcs_map))), $xaction); } } if (!strlen($value)) { $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('When creating a repository, you must specify a valid ' . 'underlying version control system: %s.', implode(', ', array_keys($vcs_map))), nonempty(last($xactions), null)); $error->setIsMissingFieldError(true); $errors[] = $error; } } break; case PhabricatorRepositoryTransaction::TYPE_NAME: $missing = $this->validateIsEmptyTextField($object->getName(), $xactions); if ($missing) { $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Repository name is required.'), nonempty(last($xactions), null)); $error->setIsMissingFieldError(true); $errors[] = $error; } break; case PhabricatorRepositoryTransaction::TYPE_ACTIVATE: $status_map = PhabricatorRepository::getStatusMap(); foreach ($xactions as $xaction) { $status = $xaction->getNewValue(); if (empty($status_map[$status])) { $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Repository status "%s" is not valid.', $status), $xaction); } } break; case PhabricatorRepositoryTransaction::TYPE_ENCODING: foreach ($xactions as $xaction) { // Make sure the encoding is valid by converting to UTF-8. This tests // that the user has mbstring installed, and also that they didn't // type a garbage encoding name. Note that we're converting from // UTF-8 to the target encoding, because mbstring is fine with // converting from a nonsense encoding. $encoding = $xaction->getNewValue(); if (!strlen($encoding)) { continue; } try { phutil_utf8_convert('.', $encoding, 'UTF-8'); } catch (Exception $ex) { $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Repository encoding "%s" is not valid: %s', $encoding, $ex->getMessage()), $xaction); } } break; case PhabricatorRepositoryTransaction::TYPE_SLUG: foreach ($xactions as $xaction) { $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); if (!strlen($new)) { continue; } if ($new === $old) { continue; } try { PhabricatorRepository::assertValidRepositorySlug($new); } catch (Exception $ex) { $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), $ex->getMessage(), $xaction); continue; } $other = id(new PhabricatorRepositoryQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withSlugs(array($new))->executeOne(); if ($other && $other->getID() !== $object->getID()) { $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Duplicate'), pht('The selected repository short name is already in use by ' . 'another repository. Choose a unique short name.'), $xaction); continue; } } break; case PhabricatorRepositoryTransaction::TYPE_CALLSIGN: foreach ($xactions as $xaction) { $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); if (!strlen($new)) { continue; } if ($new === $old) { continue; } try { PhabricatorRepository::assertValidCallsign($new); } catch (Exception $ex) { $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), $ex->getMessage(), $xaction); continue; } $other = id(new PhabricatorRepositoryQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withCallsigns(array($new))->executeOne(); if ($other && $other->getID() !== $object->getID()) { $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Duplicate'), pht('The selected callsign ("%s") is already in use by another ' . 'repository. Choose a unique callsign.', $new), $xaction); continue; } } break; case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES: foreach ($xactions as $xaction) { $old = $object->getSymbolSources(); $new = $xaction->getNewValue(); // If the viewer is adding new repositories, make sure they are // valid and visible. $add = array_diff($new, $old); if (!$add) { continue; } $repositories = id(new PhabricatorRepositoryQuery())->setViewer($this->getActor())->withPHIDs($add)->execute(); $repositories = mpull($repositories, null, 'getPHID'); foreach ($add as $phid) { if (isset($repositories[$phid])) { continue; } $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Repository ("%s") does not exist, or you do not have ' . 'permission to see it.', $phid), $xaction); break; } } break; } return $errors; }
protected function buildCustomEditFields($object) { $viewer = $this->getViewer(); $policies = id(new PhabricatorPolicyQuery())->setViewer($viewer)->setObject($object)->execute(); $track_value = $object->getDetail('branch-filter', array()); $track_value = array_keys($track_value); $autoclose_value = $object->getDetail('close-commits-filter', array()); $autoclose_value = array_keys($autoclose_value); $automation_instructions = pht("Configure **Repository Automation** to allow Phabricator to " . "write to this repository." . "\n\n" . "IMPORTANT: This feature is new, experimental, and not supported. " . "Use it at your own risk."); $staging_instructions = pht("To make it easier to run integration tests and builds on code " . "under review, you can configure a **Staging Area**. When `arc` " . "creates a diff, it will push a copy of the changes to the " . "configured staging area with a corresponding tag." . "\n\n" . "IMPORTANT: This feature is new, experimental, and not supported. " . "Use it at your own risk."); $subpath_instructions = pht('If you want to import only part of a repository, like `trunk/`, ' . 'you can set a path in **Import Only**. Phabricator will ignore ' . 'commits which do not affect this path.'); return array(id(new PhabricatorSelectEditField())->setKey('vcs')->setLabel(pht('Version Control System'))->setTransactionType(PhabricatorRepositoryTransaction::TYPE_VCS)->setIsConduitOnly(true)->setIsCopyable(true)->setOptions(PhabricatorRepositoryType::getAllRepositoryTypes())->setDescription(pht('Underlying repository version control system.'))->setConduitDescription(pht('Choose which version control system to use when creating a ' . 'repository.'))->setConduitTypeDescription(pht('Version control system selection.'))->setValue($object->getVersionControlSystem()), id(new PhabricatorTextEditField())->setKey('name')->setLabel(pht('Name'))->setIsRequired(true)->setTransactionType(PhabricatorRepositoryTransaction::TYPE_NAME)->setDescription(pht('The repository name.'))->setConduitDescription(pht('Rename the repository.'))->setConduitTypeDescription(pht('New repository name.'))->setValue($object->getName()), id(new PhabricatorTextEditField())->setKey('callsign')->setLabel(pht('Callsign'))->setTransactionType(PhabricatorRepositoryTransaction::TYPE_CALLSIGN)->setDescription(pht('The repository callsign.'))->setConduitDescription(pht('Change the repository callsign.'))->setConduitTypeDescription(pht('New repository callsign.'))->setValue($object->getCallsign()), id(new PhabricatorTextEditField())->setKey('shortName')->setLabel(pht('Short Name'))->setTransactionType(PhabricatorRepositoryTransaction::TYPE_SLUG)->setDescription(pht('Short, unique repository name.'))->setConduitDescription(pht('Change the repository short name.'))->setConduitTypeDescription(pht('New short name for the repository.'))->setValue($object->getRepositorySlug()), id(new PhabricatorRemarkupEditField())->setKey('description')->setLabel(pht('Description'))->setTransactionType(PhabricatorRepositoryTransaction::TYPE_DESCRIPTION)->setDescription(pht('Repository description.'))->setConduitDescription(pht('Change the repository description.'))->setConduitTypeDescription(pht('New repository description.'))->setValue($object->getDetail('description')), id(new PhabricatorTextEditField())->setKey('encoding')->setLabel(pht('Text Encoding'))->setIsCopyable(true)->setTransactionType(PhabricatorRepositoryTransaction::TYPE_ENCODING)->setDescription(pht('Default text encoding.'))->setConduitDescription(pht('Change the default text encoding.'))->setConduitTypeDescription(pht('New text encoding.'))->setValue($object->getDetail('encoding')), id(new PhabricatorBoolEditField())->setKey('allowDangerousChanges')->setLabel(pht('Allow Dangerous Changes'))->setIsCopyable(true)->setIsConduitOnly(true)->setOptions(pht('Prevent Dangerous Changes'), pht('Allow Dangerous Changes'))->setTransactionType(PhabricatorRepositoryTransaction::TYPE_DANGEROUS)->setDescription(pht('Permit dangerous changes to be made.'))->setConduitDescription(pht('Allow or prevent dangerous changes.'))->setConduitTypeDescription(pht('New protection setting.'))->setValue($object->shouldAllowDangerousChanges()), id(new PhabricatorSelectEditField())->setKey('status')->setLabel(pht('Status'))->setTransactionType(PhabricatorRepositoryTransaction::TYPE_ACTIVATE)->setIsConduitOnly(true)->setOptions(PhabricatorRepository::getStatusNameMap())->setDescription(pht('Active or inactive status.'))->setConduitDescription(pht('Active or deactivate the repository.'))->setConduitTypeDescription(pht('New repository status.'))->setValue($object->getStatus()), id(new PhabricatorTextEditField())->setKey('defaultBranch')->setLabel(pht('Default Branch'))->setTransactionType(PhabricatorRepositoryTransaction::TYPE_DEFAULT_BRANCH)->setIsCopyable(true)->setDescription(pht('Default branch name.'))->setConduitDescription(pht('Set the default branch name.'))->setConduitTypeDescription(pht('New default branch name.'))->setValue($object->getDetail('default-branch')), id(new PhabricatorTextAreaEditField())->setIsStringList(true)->setKey('trackOnly')->setLabel(pht('Track Only'))->setTransactionType(PhabricatorRepositoryTransaction::TYPE_TRACK_ONLY)->setIsCopyable(true)->setDescription(pht('Track only these branches.'))->setConduitDescription(pht('Set the tracked branches.'))->setConduitTypeDescription(pht('New tracked branchs.'))->setValue($track_value), id(new PhabricatorTextAreaEditField())->setIsStringList(true)->setKey('autocloseOnly')->setLabel(pht('Autoclose Only'))->setTransactionType(PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE_ONLY)->setIsCopyable(true)->setDescription(pht('Autoclose commits on only these branches.'))->setConduitDescription(pht('Set the autoclose branches.'))->setConduitTypeDescription(pht('New default tracked branchs.'))->setValue($autoclose_value), id(new PhabricatorTextEditField())->setKey('importOnly')->setLabel(pht('Import Only'))->setTransactionType(PhabricatorRepositoryTransaction::TYPE_SVN_SUBPATH)->setIsCopyable(true)->setDescription(pht('Subpath to selectively import.'))->setConduitDescription(pht('Set the subpath to import.'))->setConduitTypeDescription(pht('New subpath to import.'))->setValue($object->getDetail('svn-subpath'))->setControlInstructions($subpath_instructions), id(new PhabricatorTextEditField())->setKey('stagingAreaURI')->setLabel(pht('Staging Area URI'))->setTransactionType(PhabricatorRepositoryTransaction::TYPE_STAGING_URI)->setIsCopyable(true)->setDescription(pht('Staging area URI.'))->setConduitDescription(pht('Set the staging area URI.'))->setConduitTypeDescription(pht('New staging area URI.'))->setValue($object->getStagingURI())->setControlInstructions($staging_instructions), id(new PhabricatorDatasourceEditField())->setKey('automationBlueprintPHIDs')->setLabel(pht('Use Blueprints'))->setTransactionType(PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS)->setIsCopyable(true)->setDatasource(new DrydockBlueprintDatasource())->setDescription(pht('Automation blueprints.'))->setConduitDescription(pht('Change automation blueprints.'))->setConduitTypeDescription(pht('New blueprint PHIDs.'))->setValue($object->getAutomationBlueprintPHIDs())->setControlInstructions($automation_instructions), id(new PhabricatorStringListEditField())->setKey('symbolLanguages')->setLabel(pht('Languages'))->setTransactionType(PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE)->setIsCopyable(true)->setDescription(pht('Languages which define symbols in this repository.'))->setConduitDescription(pht('Change symbol languages for this repository.'))->setConduitTypeDescription(pht('New symbol langauges.'))->setValue($object->getSymbolLanguages()), id(new PhabricatorDatasourceEditField())->setKey('symbolRepositoryPHIDs')->setLabel(pht('Uses Symbols From'))->setTransactionType(PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES)->setIsCopyable(true)->setDatasource(new DiffusionRepositoryDatasource())->setDescription(pht('Repositories to link symbols from.'))->setConduitDescription(pht('Change symbol source repositories.'))->setConduitTypeDescription(pht('New symbol repositories.'))->setValue($object->getSymbolSources()), id(new PhabricatorBoolEditField())->setKey('publish')->setLabel(pht('Publish/Notify'))->setTransactionType(PhabricatorRepositoryTransaction::TYPE_NOTIFY)->setIsCopyable(true)->setOptions(pht('Disable Notifications, Feed, and Herald'), pht('Enable Notifications, Feed, and Herald'))->setDescription(pht('Configure how changes are published.'))->setConduitDescription(pht('Change publishing options.'))->setConduitTypeDescription(pht('New notification setting.'))->setValue(!$object->getDetail('herald-disabled')), id(new PhabricatorBoolEditField())->setKey('autoclose')->setLabel(pht('Autoclose'))->setTransactionType(PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE)->setIsCopyable(true)->setOptions(pht('Disable Autoclose'), pht('Enable Autoclose'))->setDescription(pht('Stop or resume autoclosing in this repository.'))->setConduitDescription(pht('Change autoclose setting.'))->setConduitTypeDescription(pht('New autoclose setting.'))->setValue(!$object->getDetail('disable-autoclose')), id(new PhabricatorPolicyEditField())->setKey('policy.push')->setLabel(pht('Push Policy'))->setAliases(array('push'))->setIsCopyable(true)->setCapability(DiffusionPushCapability::CAPABILITY)->setPolicies($policies)->setTransactionType(PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY)->setDescription(pht('Controls who can push changes to the repository.'))->setConduitDescription(pht('Change the push policy of the repository.'))->setConduitTypeDescription(pht('New policy PHID or constant.'))->setValue($object->getPolicy(DiffusionPushCapability::CAPABILITY))); }