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

Configure Feed

Select the types of activity you want to include in your feed.

Activate the new Repository creation workflow

Summary:
Ref T2231. This:

- Activates the new multi-step workflow, and exposes it in the UI.
- Adds "can create", "default view" and "default edit" capabilities.
- Provides a default value for `repository.default-local-path` and forces repositories into it by default. It's still editable, but Phabricator gets it correct (for some definition of correct) by default now.

Test Plan: Created some new repositories with the new workflow.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T1286, T2231

Differential Revision: https://secure.phabricator.com/D7413

+261 -17
+6
src/__phutil_library_map__.php
··· 449 449 'DiffusionBrowseResultSet' => 'applications/diffusion/data/DiffusionBrowseResultSet.php', 450 450 'DiffusionBrowseSearchController' => 'applications/diffusion/controller/DiffusionBrowseSearchController.php', 451 451 'DiffusionBrowseTableView' => 'applications/diffusion/view/DiffusionBrowseTableView.php', 452 + 'DiffusionCapabilityCreateRepositories' => 'applications/diffusion/capability/DiffusionCapabilityCreateRepositories.php', 453 + 'DiffusionCapabilityDefaultEdit' => 'applications/diffusion/capability/DiffusionCapabilityDefaultEdit.php', 454 + 'DiffusionCapabilityDefaultView' => 'applications/diffusion/capability/DiffusionCapabilityDefaultView.php', 452 455 'DiffusionChangeController' => 'applications/diffusion/controller/DiffusionChangeController.php', 453 456 'DiffusionCommentListView' => 'applications/diffusion/view/DiffusionCommentListView.php', 454 457 'DiffusionCommentView' => 'applications/diffusion/view/DiffusionCommentView.php', ··· 2634 2637 'DiffusionBrowseMainController' => 'DiffusionBrowseController', 2635 2638 'DiffusionBrowseSearchController' => 'DiffusionBrowseController', 2636 2639 'DiffusionBrowseTableView' => 'DiffusionView', 2640 + 'DiffusionCapabilityCreateRepositories' => 'PhabricatorPolicyCapability', 2641 + 'DiffusionCapabilityDefaultEdit' => 'PhabricatorPolicyCapability', 2642 + 'DiffusionCapabilityDefaultView' => 'PhabricatorPolicyCapability', 2637 2643 'DiffusionChangeController' => 'DiffusionController', 2638 2644 'DiffusionCommentListView' => 'AphrontView', 2639 2645 'DiffusionCommentView' => 'AphrontView',
+13
src/applications/diffusion/application/PhabricatorApplicationDiffusion.php
··· 103 103 return 0.120; 104 104 } 105 105 106 + protected function getCustomCapabilities() { 107 + return array( 108 + DiffusionCapabilityDefaultView::CAPABILITY => array( 109 + ), 110 + DiffusionCapabilityDefaultEdit::CAPABILITY => array( 111 + 'default' => PhabricatorPolicies::POLICY_ADMIN, 112 + ), 113 + DiffusionCapabilityCreateRepositories::CAPABILITY => array( 114 + 'default' => PhabricatorPolicies::POLICY_ADMIN, 115 + ), 116 + ); 117 + } 118 + 106 119 }
+20
src/applications/diffusion/capability/DiffusionCapabilityCreateRepositories.php
··· 1 + <?php 2 + 3 + final class DiffusionCapabilityCreateRepositories 4 + extends PhabricatorPolicyCapability { 5 + 6 + const CAPABILITY = 'diffusion.create'; 7 + 8 + public function getCapabilityKey() { 9 + return self::CAPABILITY; 10 + } 11 + 12 + public function getCapabilityName() { 13 + return pht('Can Create Repositories'); 14 + } 15 + 16 + public function describeCapabilityRejection() { 17 + return pht('You do not have permission to create new repositories.'); 18 + } 19 + 20 + }
+16
src/applications/diffusion/capability/DiffusionCapabilityDefaultEdit.php
··· 1 + <?php 2 + 3 + final class DiffusionCapabilityDefaultEdit 4 + extends PhabricatorPolicyCapability { 5 + 6 + const CAPABILITY = 'diffusion.default.edit'; 7 + 8 + public function getCapabilityKey() { 9 + return self::CAPABILITY; 10 + } 11 + 12 + public function getCapabilityName() { 13 + return pht('Default Edit Policy'); 14 + } 15 + 16 + }
+20
src/applications/diffusion/capability/DiffusionCapabilityDefaultView.php
··· 1 + <?php 2 + 3 + final class DiffusionCapabilityDefaultView 4 + extends PhabricatorPolicyCapability { 5 + 6 + const CAPABILITY = 'diffusion.default.view'; 7 + 8 + public function getCapabilityKey() { 9 + return self::CAPABILITY; 10 + } 11 + 12 + public function getCapabilityName() { 13 + return pht('Default View Policy'); 14 + } 15 + 16 + public function shouldAllowPublicPolicySetting() { 17 + return true; 18 + } 19 + 20 + }
+50 -5
src/applications/diffusion/controller/DiffusionRepositoryCreateController.php
··· 32 32 33 33 $cancel_uri = $this->getRepositoryControllerURI($repository, 'edit/'); 34 34 } else { 35 + $this->requireApplicationCapability( 36 + DiffusionCapabilityCreateRepositories::CAPABILITY); 37 + 35 38 $cancel_uri = $this->getApplicationURI(); 36 39 } 37 40 ··· 60 63 if ($request->isFormPost()) { 61 64 $form->readFromRequest($request); 62 65 if ($form->isComplete()) { 66 + $is_create = ($this->edit === null); 63 67 64 - if ($this->edit != 'remote') { 65 - // TODO: This exception is heartwarming but should probably take more 66 - // substantive actions. 67 - throw new Exception("GOOD JOB AT FORM"); 68 + if ($is_create) { 69 + $repository = PhabricatorRepository::initializeNewRepository( 70 + $viewer); 68 71 } 69 72 70 73 $template = id(new PhabricatorRepositoryTransaction()); 71 74 75 + $type_name = PhabricatorRepositoryTransaction::TYPE_NAME; 76 + $type_vcs = PhabricatorRepositoryTransaction::TYPE_VCS; 77 + $type_activate = PhabricatorRepositoryTransaction::TYPE_ACTIVATE; 78 + $type_local_path = PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH; 72 79 $type_remote_uri = PhabricatorRepositoryTransaction::TYPE_REMOTE_URI; 73 80 $type_ssh_login = PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN; 74 81 $type_ssh_key = PhabricatorRepositoryTransaction::TYPE_SSH_KEY; ··· 77 84 $type_http_pass = PhabricatorRepositoryTransaction::TYPE_HTTP_PASS; 78 85 79 86 $xactions = array(); 87 + 88 + // If we're creating a new repository, set all this core stuff. 89 + if ($is_create) { 90 + $callsign = $form->getPage('name') 91 + ->getControl('callsign')->getValue(); 92 + 93 + // We must set this to a unique value to save the repository 94 + // initially, and it's immutable, so we don't bother using 95 + // transactions to apply this change. 96 + $repository->setCallsign($callsign); 97 + 98 + $xactions[] = id(clone $template) 99 + ->setTransactionType($type_name) 100 + ->setNewValue( 101 + $form->getPage('name')->getControl('name')->getValue()); 102 + 103 + $xactions[] = id(clone $template) 104 + ->setTransactionType($type_vcs) 105 + ->setNewValue( 106 + $form->getPage('vcs')->getControl('vcs')->getValue()); 107 + 108 + $activate = $form->getPage('done') 109 + ->getControl('activate')->getValue(); 110 + $xactions[] = id(clone $template) 111 + ->setTransactionType($type_activate) 112 + ->setNewValue( 113 + ($activate == 'start')); 114 + 115 + $default_local_path = PhabricatorEnv::getEnvConfig( 116 + 'repository.default-local-path'); 117 + 118 + $default_local_path = rtrim($default_local_path, '/'); 119 + $default_local_path = $default_local_path.'/'.$callsign.'/'; 120 + 121 + $xactions[] = id(clone $template) 122 + ->setTransactionType($type_local_path) 123 + ->setNewValue($default_local_path); 124 + } 80 125 81 126 $xactions[] = id(clone $template) 82 127 ->setTransactionType($type_remote_uri) ··· 619 664 pht('Configure More Options First'), 620 665 pht( 621 666 'Configure more options before beginning the repository '. 622 - 'import. This will let you fine-tune settings.. You can '. 667 + 'import. This will let you fine-tune settings. You can '. 623 668 'start the import whenever you are ready.'))); 624 669 } 625 670
+2 -2
src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php
··· 336 336 $view->addProperty(pht('Default Branch'), $default_branch); 337 337 338 338 $track_only = nonempty( 339 - $repository->getHumanReadableDetail('branch-filter'), 339 + $repository->getHumanReadableDetail('branch-filter', array()), 340 340 phutil_tag('em', array(), pht('Track All Branches'))); 341 341 $view->addProperty(pht('Track Only'), $track_only); 342 342 343 343 $autoclose_only = nonempty( 344 - $repository->getHumanReadableDetail('close-commits-filter'), 344 + $repository->getHumanReadableDetail('close-commits-filter', array()), 345 345 phutil_tag('em', array(), pht('Autoclose On All Branches'))); 346 346 $view->addProperty(pht('Autoclose Only'), $autoclose_only); 347 347
+16 -1
src/applications/diffusion/controller/DiffusionRepositoryListController.php
··· 90 90 $nav = new AphrontSideNavFilterView(); 91 91 $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); 92 92 93 - 94 93 id(new PhabricatorRepositorySearchEngine()) 95 94 ->setViewer($viewer) 96 95 ->addNavigationItems($nav->getMenu()); ··· 98 97 $nav->selectFilter(null); 99 98 100 99 return $nav; 100 + } 101 + 102 + public function buildApplicationCrumbs() { 103 + $crumbs = parent::buildApplicationCrumbs(); 104 + 105 + $can_create = $this->hasApplicationCapability( 106 + DiffusionCapabilityCreateRepositories::CAPABILITY); 107 + 108 + $crumbs->addAction( 109 + id(new PHUIListItemView()) 110 + ->setName(pht('Import Repository')) 111 + ->setHref($this->getApplicationURI('/create/')) 112 + ->setDisabled(!$can_create) 113 + ->setIcon('create')); 114 + 115 + return $crumbs; 101 116 } 102 117 103 118 private function buildShortcuts() {
+2 -2
src/applications/repository/PhabricatorRepositoryConfigOptions.php
··· 16 16 17 17 public function getOptions() { 18 18 return array( 19 - $this->newOption('repository.default-local-path', 'string', null) 19 + $this->newOption('repository.default-local-path', 'string', '/var/repo/') 20 20 ->setSummary( 21 21 pht("Default location to store local copies of repositories.")) 22 22 ->setDescription( 23 23 pht( 24 24 "The default location in which to store local copies of ". 25 25 "repositories. Anything stored in this directory will be assumed ". 26 - "to be under the control of phabricator, which means that ". 26 + "to be under the control of Phabricator, which means that ". 27 27 "Phabricator will try to do some maintenance on working copies ". 28 28 "if there are problems (such as a change to the remote origin ". 29 29 "url). This maintenance may include completely removing (and ".
+14 -5
src/applications/repository/conduit/ConduitAPI_repository_create_Method.php
··· 62 62 } 63 63 64 64 protected function execute(ConduitAPIRequest $request) { 65 - if (!$request->getUser()->getIsAdmin()) { 66 - throw new ConduitException('ERR-PERMISSIONS'); 67 - } 65 + $application = id(new PhabricatorApplicationQuery()) 66 + ->setViewer($request->getUser()) 67 + ->withClasses(array('PhabricatorApplicationDiffusion')) 68 + ->executeOne(); 69 + 70 + PhabricatorPolicyFilter::requireCapability( 71 + $request->getUser(), 72 + $application, 73 + DiffusionCapabilityCreateRepositories::CAPABILITY); 68 74 69 75 // TODO: This has some duplication with (and lacks some of the validation 70 76 // of) the web workflow; refactor things so they can share more code as this 71 - // stabilizes. 77 + // stabilizes. Specifically, this should move to transactions since they 78 + // work properly now. 79 + 80 + $repository = PhabricatorRepository::initializeNewRepository( 81 + $request->getUser()); 72 82 73 - $repository = new PhabricatorRepository(); 74 83 $repository->setName($request->getValue('name')); 75 84 76 85 $callsign = $request->getValue('callsign');
+39
src/applications/repository/editor/PhabricatorRepositoryEditor.php
··· 6 6 public function getTransactionTypes() { 7 7 $types = parent::getTransactionTypes(); 8 8 9 + $types[] = PhabricatorRepositoryTransaction::TYPE_VCS; 9 10 $types[] = PhabricatorRepositoryTransaction::TYPE_ACTIVATE; 10 11 $types[] = PhabricatorRepositoryTransaction::TYPE_NAME; 11 12 $types[] = PhabricatorRepositoryTransaction::TYPE_DESCRIPTION; ··· 36 37 PhabricatorApplicationTransaction $xaction) { 37 38 38 39 switch ($xaction->getTransactionType()) { 40 + case PhabricatorRepositoryTransaction::TYPE_VCS: 41 + return $object->getVersionControlSystem(); 39 42 case PhabricatorRepositoryTransaction::TYPE_ACTIVATE: 40 43 return $object->isTracked(); 41 44 case PhabricatorRepositoryTransaction::TYPE_NAME: ··· 96 99 case PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN: 97 100 case PhabricatorRepositoryTransaction::TYPE_HTTP_PASS: 98 101 case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH: 102 + case PhabricatorRepositoryTransaction::TYPE_VCS: 99 103 return $xaction->getNewValue(); 100 104 case PhabricatorRepositoryTransaction::TYPE_NOTIFY: 101 105 case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE: ··· 108 112 PhabricatorApplicationTransaction $xaction) { 109 113 110 114 switch ($xaction->getTransactionType()) { 115 + case PhabricatorRepositoryTransaction::TYPE_VCS: 116 + $object->setVersionControlSystem($xaction->getNewValue()); 117 + break; 111 118 case PhabricatorRepositoryTransaction::TYPE_ACTIVATE: 112 119 $object->setDetail('tracking-enabled', $xaction->getNewValue()); 113 120 break; ··· 217 224 } 218 225 219 226 return parent::transactionHasEffect($object, $xaction); 227 + } 228 + 229 + protected function requireCapabilities( 230 + PhabricatorLiskDAO $object, 231 + PhabricatorApplicationTransaction $xaction) { 232 + 233 + switch ($xaction->getTransactionType()) { 234 + case PhabricatorRepositoryTransaction::TYPE_ACTIVATE: 235 + case PhabricatorRepositoryTransaction::TYPE_NAME: 236 + case PhabricatorRepositoryTransaction::TYPE_DESCRIPTION: 237 + case PhabricatorRepositoryTransaction::TYPE_ENCODING: 238 + case PhabricatorRepositoryTransaction::TYPE_DEFAULT_BRANCH: 239 + case PhabricatorRepositoryTransaction::TYPE_TRACK_ONLY: 240 + case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE_ONLY: 241 + case PhabricatorRepositoryTransaction::TYPE_UUID: 242 + case PhabricatorRepositoryTransaction::TYPE_SVN_SUBPATH: 243 + case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI: 244 + case PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN: 245 + case PhabricatorRepositoryTransaction::TYPE_SSH_KEY: 246 + case PhabricatorRepositoryTransaction::TYPE_SSH_KEYFILE: 247 + case PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN: 248 + case PhabricatorRepositoryTransaction::TYPE_HTTP_PASS: 249 + case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH: 250 + case PhabricatorRepositoryTransaction::TYPE_VCS: 251 + case PhabricatorRepositoryTransaction::TYPE_NOTIFY: 252 + case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE: 253 + PhabricatorPolicyFilter::requireCapability( 254 + $this->requireActor(), 255 + $object, 256 + PhabricatorPolicyCapability::CAN_EDIT); 257 + break; 258 + } 220 259 } 221 260 222 261 }
+16 -2
src/applications/repository/storage/PhabricatorRepository.php
··· 29 29 protected $name; 30 30 protected $callsign; 31 31 protected $uuid; 32 - protected $viewPolicy = PhabricatorPolicies::POLICY_USER; 33 - protected $editPolicy = PhabricatorPolicies::POLICY_ADMIN; 32 + protected $viewPolicy; 33 + protected $editPolicy; 34 34 35 35 protected $versionControlSystem; 36 36 protected $details = array(); ··· 39 39 40 40 private $commitCount = self::ATTACHABLE; 41 41 private $mostRecentCommit = self::ATTACHABLE; 42 + 43 + public static function initializeNewRepository(PhabricatorUser $actor) { 44 + $app = id(new PhabricatorApplicationQuery()) 45 + ->setViewer($actor) 46 + ->withClasses(array('PhabricatorApplicationDiffusion')) 47 + ->executeOne(); 48 + 49 + $view_policy = $app->getPolicy(DiffusionCapabilityDefaultView::CAPABILITY); 50 + $edit_policy = $app->getPolicy(DiffusionCapabilityDefaultEdit::CAPABILITY); 51 + 52 + return id(new PhabricatorRepository()) 53 + ->setViewPolicy($view_policy) 54 + ->setEditPolicy($edit_policy); 55 + } 42 56 43 57 public function getConfiguration() { 44 58 return array(
+47
src/applications/repository/storage/PhabricatorRepositoryTransaction.php
··· 3 3 final class PhabricatorRepositoryTransaction 4 4 extends PhabricatorApplicationTransaction { 5 5 6 + const TYPE_VCS = 'repo:vcs'; 6 7 const TYPE_ACTIVATE = 'repo:activate'; 7 8 const TYPE_NAME = 'repo:name'; 8 9 const TYPE_DESCRIPTION = 'repo:description'; ··· 34 35 return null; 35 36 } 36 37 38 + public function shouldHide() { 39 + $old = $this->getOldValue(); 40 + $new = $this->getNewValue(); 41 + 42 + switch ($this->getTransactionType()) { 43 + case self::TYPE_REMOTE_URI: 44 + case self::TYPE_SSH_LOGIN: 45 + case self::TYPE_SSH_KEY: 46 + case self::TYPE_SSH_KEYFILE: 47 + case self::TYPE_HTTP_LOGIN: 48 + case self::TYPE_HTTP_PASS: 49 + // Hide null vs empty string changes. 50 + return (!strlen($old) && !strlen($new)); 51 + case self::TYPE_LOCAL_PATH: 52 + case self::TYPE_NAME: 53 + // Hide these on create, they aren't interesting and we have an 54 + // explicit "create" transaction. 55 + if (!strlen($old)) { 56 + return true; 57 + } 58 + break; 59 + } 60 + 61 + return parent::shouldHide(); 62 + } 63 + 64 + public function getIcon() { 65 + switch ($this->getTransactionType()) { 66 + case self::TYPE_VCS: 67 + return 'create'; 68 + } 69 + return parent::getIcon(); 70 + } 71 + 72 + public function getColor() { 73 + switch ($this->getTransactionType()) { 74 + case self::TYPE_VCS: 75 + return 'green'; 76 + } 77 + return parent::getIcon(); 78 + } 79 + 37 80 public function getTitle() { 38 81 $author_phid = $this->getAuthorPHID(); 39 82 ··· 41 84 $new = $this->getNewValue(); 42 85 43 86 switch ($this->getTransactionType()) { 87 + case self::TYPE_VCS: 88 + return pht( 89 + '%s created this repository.', 90 + $this->renderHandleLink($author_phid)); 44 91 case self::TYPE_ACTIVATE: 45 92 if ($new) { 46 93 return pht(