1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-09-20 09:18:48 +02:00

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
This commit is contained in:
epriestley 2013-10-25 17:46:08 -07:00
parent c585f97e90
commit 5f6ea9f662
13 changed files with 261 additions and 17 deletions

View file

@ -449,6 +449,9 @@ phutil_register_library_map(array(
'DiffusionBrowseResultSet' => 'applications/diffusion/data/DiffusionBrowseResultSet.php',
'DiffusionBrowseSearchController' => 'applications/diffusion/controller/DiffusionBrowseSearchController.php',
'DiffusionBrowseTableView' => 'applications/diffusion/view/DiffusionBrowseTableView.php',
'DiffusionCapabilityCreateRepositories' => 'applications/diffusion/capability/DiffusionCapabilityCreateRepositories.php',
'DiffusionCapabilityDefaultEdit' => 'applications/diffusion/capability/DiffusionCapabilityDefaultEdit.php',
'DiffusionCapabilityDefaultView' => 'applications/diffusion/capability/DiffusionCapabilityDefaultView.php',
'DiffusionChangeController' => 'applications/diffusion/controller/DiffusionChangeController.php',
'DiffusionCommentListView' => 'applications/diffusion/view/DiffusionCommentListView.php',
'DiffusionCommentView' => 'applications/diffusion/view/DiffusionCommentView.php',
@ -2634,6 +2637,9 @@ phutil_register_library_map(array(
'DiffusionBrowseMainController' => 'DiffusionBrowseController',
'DiffusionBrowseSearchController' => 'DiffusionBrowseController',
'DiffusionBrowseTableView' => 'DiffusionView',
'DiffusionCapabilityCreateRepositories' => 'PhabricatorPolicyCapability',
'DiffusionCapabilityDefaultEdit' => 'PhabricatorPolicyCapability',
'DiffusionCapabilityDefaultView' => 'PhabricatorPolicyCapability',
'DiffusionChangeController' => 'DiffusionController',
'DiffusionCommentListView' => 'AphrontView',
'DiffusionCommentView' => 'AphrontView',

View file

@ -103,4 +103,17 @@ final class PhabricatorApplicationDiffusion extends PhabricatorApplication {
return 0.120;
}
protected function getCustomCapabilities() {
return array(
DiffusionCapabilityDefaultView::CAPABILITY => array(
),
DiffusionCapabilityDefaultEdit::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
DiffusionCapabilityCreateRepositories::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
);
}
}

View file

@ -0,0 +1,20 @@
<?php
final class DiffusionCapabilityCreateRepositories
extends PhabricatorPolicyCapability {
const CAPABILITY = 'diffusion.create';
public function getCapabilityKey() {
return self::CAPABILITY;
}
public function getCapabilityName() {
return pht('Can Create Repositories');
}
public function describeCapabilityRejection() {
return pht('You do not have permission to create new repositories.');
}
}

View file

@ -0,0 +1,16 @@
<?php
final class DiffusionCapabilityDefaultEdit
extends PhabricatorPolicyCapability {
const CAPABILITY = 'diffusion.default.edit';
public function getCapabilityKey() {
return self::CAPABILITY;
}
public function getCapabilityName() {
return pht('Default Edit Policy');
}
}

View file

@ -0,0 +1,20 @@
<?php
final class DiffusionCapabilityDefaultView
extends PhabricatorPolicyCapability {
const CAPABILITY = 'diffusion.default.view';
public function getCapabilityKey() {
return self::CAPABILITY;
}
public function getCapabilityName() {
return pht('Default View Policy');
}
public function shouldAllowPublicPolicySetting() {
return true;
}
}

View file

@ -32,6 +32,9 @@ final class DiffusionRepositoryCreateController
$cancel_uri = $this->getRepositoryControllerURI($repository, 'edit/');
} else {
$this->requireApplicationCapability(
DiffusionCapabilityCreateRepositories::CAPABILITY);
$cancel_uri = $this->getApplicationURI();
}
@ -60,15 +63,19 @@ final class DiffusionRepositoryCreateController
if ($request->isFormPost()) {
$form->readFromRequest($request);
if ($form->isComplete()) {
$is_create = ($this->edit === null);
if ($this->edit != 'remote') {
// TODO: This exception is heartwarming but should probably take more
// substantive actions.
throw new Exception("GOOD JOB AT FORM");
if ($is_create) {
$repository = PhabricatorRepository::initializeNewRepository(
$viewer);
}
$template = id(new PhabricatorRepositoryTransaction());
$type_name = PhabricatorRepositoryTransaction::TYPE_NAME;
$type_vcs = PhabricatorRepositoryTransaction::TYPE_VCS;
$type_activate = PhabricatorRepositoryTransaction::TYPE_ACTIVATE;
$type_local_path = PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH;
$type_remote_uri = PhabricatorRepositoryTransaction::TYPE_REMOTE_URI;
$type_ssh_login = PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN;
$type_ssh_key = PhabricatorRepositoryTransaction::TYPE_SSH_KEY;
@ -78,6 +85,44 @@ final class DiffusionRepositoryCreateController
$xactions = array();
// If we're creating a new repository, set all this core stuff.
if ($is_create) {
$callsign = $form->getPage('name')
->getControl('callsign')->getValue();
// We must set this to a unique value to save the repository
// initially, and it's immutable, so we don't bother using
// transactions to apply this change.
$repository->setCallsign($callsign);
$xactions[] = id(clone $template)
->setTransactionType($type_name)
->setNewValue(
$form->getPage('name')->getControl('name')->getValue());
$xactions[] = id(clone $template)
->setTransactionType($type_vcs)
->setNewValue(
$form->getPage('vcs')->getControl('vcs')->getValue());
$activate = $form->getPage('done')
->getControl('activate')->getValue();
$xactions[] = id(clone $template)
->setTransactionType($type_activate)
->setNewValue(
($activate == 'start'));
$default_local_path = PhabricatorEnv::getEnvConfig(
'repository.default-local-path');
$default_local_path = rtrim($default_local_path, '/');
$default_local_path = $default_local_path.'/'.$callsign.'/';
$xactions[] = id(clone $template)
->setTransactionType($type_local_path)
->setNewValue($default_local_path);
}
$xactions[] = id(clone $template)
->setTransactionType($type_remote_uri)
->setNewValue(
@ -619,7 +664,7 @@ final class DiffusionRepositoryCreateController
pht('Configure More Options First'),
pht(
'Configure more options before beginning the repository '.
'import. This will let you fine-tune settings.. You can '.
'import. This will let you fine-tune settings. You can '.
'start the import whenever you are ready.')));
}

View file

@ -336,12 +336,12 @@ final class DiffusionRepositoryEditMainController
$view->addProperty(pht('Default Branch'), $default_branch);
$track_only = nonempty(
$repository->getHumanReadableDetail('branch-filter'),
$repository->getHumanReadableDetail('branch-filter', array()),
phutil_tag('em', array(), pht('Track All Branches')));
$view->addProperty(pht('Track Only'), $track_only);
$autoclose_only = nonempty(
$repository->getHumanReadableDetail('close-commits-filter'),
$repository->getHumanReadableDetail('close-commits-filter', array()),
phutil_tag('em', array(), pht('Autoclose On All Branches')));
$view->addProperty(pht('Autoclose Only'), $autoclose_only);

View file

@ -90,7 +90,6 @@ final class DiffusionRepositoryListController extends DiffusionController
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
id(new PhabricatorRepositorySearchEngine())
->setViewer($viewer)
->addNavigationItems($nav->getMenu());
@ -100,6 +99,22 @@ final class DiffusionRepositoryListController extends DiffusionController
return $nav;
}
public function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
$can_create = $this->hasApplicationCapability(
DiffusionCapabilityCreateRepositories::CAPABILITY);
$crumbs->addAction(
id(new PHUIListItemView())
->setName(pht('Import Repository'))
->setHref($this->getApplicationURI('/create/'))
->setDisabled(!$can_create)
->setIcon('create'));
return $crumbs;
}
private function buildShortcuts() {
$shortcuts = id(new PhabricatorRepositoryShortcut())->loadAll();
if ($shortcuts) {

View file

@ -16,14 +16,14 @@ final class PhabricatorRepositoryConfigOptions
public function getOptions() {
return array(
$this->newOption('repository.default-local-path', 'string', null)
$this->newOption('repository.default-local-path', 'string', '/var/repo/')
->setSummary(
pht("Default location to store local copies of repositories."))
->setDescription(
pht(
"The default location in which to store local copies of ".
"repositories. Anything stored in this directory will be assumed ".
"to be under the control of phabricator, which means that ".
"to be under the control of Phabricator, which means that ".
"Phabricator will try to do some maintenance on working copies ".
"if there are problems (such as a change to the remote origin ".
"url). This maintenance may include completely removing (and ".

View file

@ -62,15 +62,24 @@ final class ConduitAPI_repository_create_Method
}
protected function execute(ConduitAPIRequest $request) {
if (!$request->getUser()->getIsAdmin()) {
throw new ConduitException('ERR-PERMISSIONS');
}
$application = id(new PhabricatorApplicationQuery())
->setViewer($request->getUser())
->withClasses(array('PhabricatorApplicationDiffusion'))
->executeOne();
PhabricatorPolicyFilter::requireCapability(
$request->getUser(),
$application,
DiffusionCapabilityCreateRepositories::CAPABILITY);
// TODO: This has some duplication with (and lacks some of the validation
// of) the web workflow; refactor things so they can share more code as this
// stabilizes.
// stabilizes. Specifically, this should move to transactions since they
// work properly now.
$repository = PhabricatorRepository::initializeNewRepository(
$request->getUser());
$repository = new PhabricatorRepository();
$repository->setName($request->getValue('name'));
$callsign = $request->getValue('callsign');

View file

@ -6,6 +6,7 @@ final class PhabricatorRepositoryEditor
public function getTransactionTypes() {
$types = parent::getTransactionTypes();
$types[] = PhabricatorRepositoryTransaction::TYPE_VCS;
$types[] = PhabricatorRepositoryTransaction::TYPE_ACTIVATE;
$types[] = PhabricatorRepositoryTransaction::TYPE_NAME;
$types[] = PhabricatorRepositoryTransaction::TYPE_DESCRIPTION;
@ -36,6 +37,8 @@ final class PhabricatorRepositoryEditor
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorRepositoryTransaction::TYPE_VCS:
return $object->getVersionControlSystem();
case PhabricatorRepositoryTransaction::TYPE_ACTIVATE:
return $object->isTracked();
case PhabricatorRepositoryTransaction::TYPE_NAME:
@ -96,6 +99,7 @@ final class PhabricatorRepositoryEditor
case PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN:
case PhabricatorRepositoryTransaction::TYPE_HTTP_PASS:
case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH:
case PhabricatorRepositoryTransaction::TYPE_VCS:
return $xaction->getNewValue();
case PhabricatorRepositoryTransaction::TYPE_NOTIFY:
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
@ -108,6 +112,9 @@ final class PhabricatorRepositoryEditor
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorRepositoryTransaction::TYPE_VCS:
$object->setVersionControlSystem($xaction->getNewValue());
break;
case PhabricatorRepositoryTransaction::TYPE_ACTIVATE:
$object->setDetail('tracking-enabled', $xaction->getNewValue());
break;
@ -219,4 +226,36 @@ final class PhabricatorRepositoryEditor
return parent::transactionHasEffect($object, $xaction);
}
protected function requireCapabilities(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorRepositoryTransaction::TYPE_ACTIVATE:
case PhabricatorRepositoryTransaction::TYPE_NAME:
case PhabricatorRepositoryTransaction::TYPE_DESCRIPTION:
case PhabricatorRepositoryTransaction::TYPE_ENCODING:
case PhabricatorRepositoryTransaction::TYPE_DEFAULT_BRANCH:
case PhabricatorRepositoryTransaction::TYPE_TRACK_ONLY:
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE_ONLY:
case PhabricatorRepositoryTransaction::TYPE_UUID:
case PhabricatorRepositoryTransaction::TYPE_SVN_SUBPATH:
case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI:
case PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN:
case PhabricatorRepositoryTransaction::TYPE_SSH_KEY:
case PhabricatorRepositoryTransaction::TYPE_SSH_KEYFILE:
case PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN:
case PhabricatorRepositoryTransaction::TYPE_HTTP_PASS:
case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH:
case PhabricatorRepositoryTransaction::TYPE_VCS:
case PhabricatorRepositoryTransaction::TYPE_NOTIFY:
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
PhabricatorPolicyFilter::requireCapability(
$this->requireActor(),
$object,
PhabricatorPolicyCapability::CAN_EDIT);
break;
}
}
}

View file

@ -29,8 +29,8 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
protected $name;
protected $callsign;
protected $uuid;
protected $viewPolicy = PhabricatorPolicies::POLICY_USER;
protected $editPolicy = PhabricatorPolicies::POLICY_ADMIN;
protected $viewPolicy;
protected $editPolicy;
protected $versionControlSystem;
protected $details = array();
@ -40,6 +40,20 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
private $commitCount = self::ATTACHABLE;
private $mostRecentCommit = self::ATTACHABLE;
public static function initializeNewRepository(PhabricatorUser $actor) {
$app = id(new PhabricatorApplicationQuery())
->setViewer($actor)
->withClasses(array('PhabricatorApplicationDiffusion'))
->executeOne();
$view_policy = $app->getPolicy(DiffusionCapabilityDefaultView::CAPABILITY);
$edit_policy = $app->getPolicy(DiffusionCapabilityDefaultEdit::CAPABILITY);
return id(new PhabricatorRepository())
->setViewPolicy($view_policy)
->setEditPolicy($edit_policy);
}
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,

View file

@ -3,6 +3,7 @@
final class PhabricatorRepositoryTransaction
extends PhabricatorApplicationTransaction {
const TYPE_VCS = 'repo:vcs';
const TYPE_ACTIVATE = 'repo:activate';
const TYPE_NAME = 'repo:name';
const TYPE_DESCRIPTION = 'repo:description';
@ -34,6 +35,48 @@ final class PhabricatorRepositoryTransaction
return null;
}
public function shouldHide() {
$old = $this->getOldValue();
$new = $this->getNewValue();
switch ($this->getTransactionType()) {
case self::TYPE_REMOTE_URI:
case self::TYPE_SSH_LOGIN:
case self::TYPE_SSH_KEY:
case self::TYPE_SSH_KEYFILE:
case self::TYPE_HTTP_LOGIN:
case self::TYPE_HTTP_PASS:
// Hide null vs empty string changes.
return (!strlen($old) && !strlen($new));
case self::TYPE_LOCAL_PATH:
case self::TYPE_NAME:
// Hide these on create, they aren't interesting and we have an
// explicit "create" transaction.
if (!strlen($old)) {
return true;
}
break;
}
return parent::shouldHide();
}
public function getIcon() {
switch ($this->getTransactionType()) {
case self::TYPE_VCS:
return 'create';
}
return parent::getIcon();
}
public function getColor() {
switch ($this->getTransactionType()) {
case self::TYPE_VCS:
return 'green';
}
return parent::getIcon();
}
public function getTitle() {
$author_phid = $this->getAuthorPHID();
@ -41,6 +84,10 @@ final class PhabricatorRepositoryTransaction
$new = $this->getNewValue();
switch ($this->getTransactionType()) {
case self::TYPE_VCS:
return pht(
'%s created this repository.',
$this->renderHandleLink($author_phid));
case self::TYPE_ACTIVATE:
if ($new) {
return pht(