mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 00:42:41 +01:00
Add "Clone As" to repositories and generate full clone commands in UI
Summary: Ref T4175. - Add a configurable name for the clone-as directory, so you can have "Bits & Pieces" clone as "bits~n~pieces/" or simliar. - By default, use "reasonable" heruistics to choose such a name. - Generate a copy/pasteable clone commmand with this directory name. Test Plan: Looked at some repositories. Reviewers: btrahan, chad Reviewed By: chad CC: aran Maniphest Tasks: T4175 Differential Revision: https://secure.phabricator.com/D8097
This commit is contained in:
parent
96dd530c44
commit
ffeee37810
7 changed files with 124 additions and 10 deletions
|
@ -176,38 +176,50 @@ final class DiffusionRepositoryController extends DiffusionController {
|
|||
if ($repository->isHosted()) {
|
||||
$ssh_uri = $repository->getSSHCloneURIObject();
|
||||
if ($ssh_uri) {
|
||||
$clone_uri = $this->renderCloneURI(
|
||||
$clone_uri = $this->renderCloneCommand(
|
||||
$repository,
|
||||
$ssh_uri,
|
||||
$repository->getServeOverSSH(),
|
||||
'/settings/panel/ssh/');
|
||||
|
||||
$view->addProperty(pht('Clone URI (SSH)'), $clone_uri);
|
||||
$view->addProperty(
|
||||
$repository->isSVN()
|
||||
? pht('Checkout (SSH)')
|
||||
: pht('Clone (SSH)'),
|
||||
$clone_uri);
|
||||
}
|
||||
|
||||
$http_uri = $repository->getHTTPCloneURIObject();
|
||||
if ($http_uri) {
|
||||
$clone_uri = $this->renderCloneURI(
|
||||
$clone_uri = $this->renderCloneCommand(
|
||||
$repository,
|
||||
$http_uri,
|
||||
$repository->getServeOverHTTP(),
|
||||
PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth')
|
||||
? '/settings/panel/vcspassword/'
|
||||
: null);
|
||||
|
||||
$view->addProperty(pht('Clone URI (HTTP)'), $clone_uri);
|
||||
$view->addProperty(
|
||||
$repository->isSVN()
|
||||
? pht('Checkout (HTTP)')
|
||||
: pht('Clone (HTTP)'),
|
||||
$clone_uri);
|
||||
}
|
||||
} else {
|
||||
switch ($repository->getVersionControlSystem()) {
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
||||
$view->addProperty(
|
||||
pht('Clone URI'),
|
||||
$this->renderCloneURI(
|
||||
pht('Clone'),
|
||||
$this->renderCloneCommand(
|
||||
$repository,
|
||||
$repository->getPublicCloneURI()));
|
||||
break;
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||
$view->addProperty(
|
||||
pht('Repository Root'),
|
||||
$this->renderCloneURI(
|
||||
pht('Checkout'),
|
||||
$this->renderCloneCommand(
|
||||
$repository,
|
||||
$repository->getPublicCloneURI()));
|
||||
break;
|
||||
}
|
||||
|
@ -526,7 +538,8 @@ final class DiffusionRepositoryController extends DiffusionController {
|
|||
return $browse_panel;
|
||||
}
|
||||
|
||||
private function renderCloneURI(
|
||||
private function renderCloneCommand(
|
||||
PhabricatorRepository $repository,
|
||||
$uri,
|
||||
$serve_mode = null,
|
||||
$manage_uri = null) {
|
||||
|
@ -535,11 +548,32 @@ final class DiffusionRepositoryController extends DiffusionController {
|
|||
|
||||
Javelin::initBehavior('select-on-click');
|
||||
|
||||
switch ($repository->getVersionControlSystem()) {
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||
$command = csprintf(
|
||||
'git clone %s %s',
|
||||
$uri,
|
||||
$repository->getCloneName());
|
||||
break;
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
||||
$command = csprintf(
|
||||
'hg clone %s %s',
|
||||
$uri,
|
||||
$repository->getCloneName());
|
||||
break;
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||
$command = csprintf(
|
||||
'svn checkout %s %s',
|
||||
$uri,
|
||||
$repository->getCloneName());
|
||||
break;
|
||||
}
|
||||
|
||||
$input = javelin_tag(
|
||||
'input',
|
||||
array(
|
||||
'type' => 'text',
|
||||
'value' => (string)$uri,
|
||||
'value' => (string)$command,
|
||||
'class' => 'diffusion-clone-uri',
|
||||
'sigil' => 'select-on-click',
|
||||
'readonly' => 'true',
|
||||
|
|
|
@ -28,6 +28,7 @@ final class DiffusionRepositoryEditBasicController
|
|||
|
||||
$v_name = $repository->getName();
|
||||
$v_desc = $repository->getDetail('description');
|
||||
$v_clone_name = $repository->getDetail('clone-name');
|
||||
$e_name = true;
|
||||
$errors = array();
|
||||
|
||||
|
@ -35,6 +36,7 @@ final class DiffusionRepositoryEditBasicController
|
|||
$v_name = $request->getStr('name');
|
||||
$v_desc = $request->getStr('description');
|
||||
$v_projects = $request->getArr('projectPHIDs');
|
||||
$v_clone_name = $request->getStr('cloneName');
|
||||
|
||||
if (!strlen($v_name)) {
|
||||
$e_name = pht('Required');
|
||||
|
@ -50,6 +52,7 @@ final class DiffusionRepositoryEditBasicController
|
|||
$type_name = PhabricatorRepositoryTransaction::TYPE_NAME;
|
||||
$type_desc = PhabricatorRepositoryTransaction::TYPE_DESCRIPTION;
|
||||
$type_edge = PhabricatorTransactions::TYPE_EDGE;
|
||||
$type_clone_name = PhabricatorRepositoryTransaction::TYPE_CLONE_NAME;
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_name)
|
||||
|
@ -59,6 +62,10 @@ final class DiffusionRepositoryEditBasicController
|
|||
->setTransactionType($type_desc)
|
||||
->setNewValue($v_desc);
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_clone_name)
|
||||
->setNewValue($v_clone_name);
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType($type_edge)
|
||||
->setMetadataValue(
|
||||
|
@ -93,6 +100,15 @@ final class DiffusionRepositoryEditBasicController
|
|||
->setLabel(pht('Name'))
|
||||
->setValue($v_name)
|
||||
->setError($e_name))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('cloneName')
|
||||
->setLabel(pht('Clone/Checkout As'))
|
||||
->setValue($v_clone_name)
|
||||
->setCaption(
|
||||
pht(
|
||||
'Optional directory name to use when cloning or checking out '.
|
||||
'this repository.')))
|
||||
->appendChild(
|
||||
id(new PhabricatorRemarkupControl())
|
||||
->setName('description')
|
||||
|
|
|
@ -253,6 +253,15 @@ final class DiffusionRepositoryEditMainController
|
|||
$view->addProperty(pht('Type'), $type);
|
||||
$view->addProperty(pht('Callsign'), $repository->getCallsign());
|
||||
|
||||
|
||||
$clone_name = $repository->getDetail('clone-name');
|
||||
|
||||
$view->addProperty(
|
||||
pht('Clone/Checkout As'),
|
||||
$clone_name
|
||||
? $clone_name.'/'
|
||||
: phutil_tag('em', array(), $repository->getCloneName().'/'));
|
||||
|
||||
$project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||
$repository->getPHID(),
|
||||
PhabricatorEdgeConfig::TYPE_OBJECT_HAS_PROJECT);
|
||||
|
|
|
@ -31,6 +31,7 @@ final class PhabricatorRepositoryEditor
|
|||
$types[] = PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_CREDENTIAL;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_DANGEROUS;
|
||||
$types[] = PhabricatorRepositoryTransaction::TYPE_CLONE_NAME;
|
||||
|
||||
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
||||
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||
|
@ -84,6 +85,8 @@ final class PhabricatorRepositoryEditor
|
|||
return $object->getCredentialPHID();
|
||||
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
||||
return $object->shouldAllowDangerousChanges();
|
||||
case PhabricatorRepositoryTransaction::TYPE_CLONE_NAME:
|
||||
return $object->getDetail('clone-name');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,6 +118,7 @@ final class PhabricatorRepositoryEditor
|
|||
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
|
||||
case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
|
||||
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
||||
case PhabricatorRepositoryTransaction::TYPE_CLONE_NAME:
|
||||
return $xaction->getNewValue();
|
||||
case PhabricatorRepositoryTransaction::TYPE_NOTIFY:
|
||||
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
|
||||
|
@ -183,6 +187,9 @@ final class PhabricatorRepositoryEditor
|
|||
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
||||
$object->setDetail('allow-dangerous-changes', $xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorRepositoryTransaction::TYPE_CLONE_NAME:
|
||||
$object->setDetail('clone-name', $xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorRepositoryTransaction::TYPE_ENCODING:
|
||||
// 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
|
||||
|
@ -294,6 +301,7 @@ final class PhabricatorRepositoryEditor
|
|||
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
|
||||
case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
|
||||
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
||||
case PhabricatorRepositoryTransaction::TYPE_CLONE_NAME:
|
||||
PhabricatorPolicyFilter::requireCapability(
|
||||
$this->requireActor(),
|
||||
$object,
|
||||
|
|
|
@ -212,6 +212,34 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the name of the directory this repository should clone or checkout
|
||||
* into. For example, if the repository name is "Example Repository", a
|
||||
* reasonable name might be "example-repository". This is used to help users
|
||||
* get reasonable results when cloning repositories, since they generally do
|
||||
* not want to clone into directories called "X/" or "Example Repository/".
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCloneName() {
|
||||
$name = $this->getDetail('clone-name');
|
||||
|
||||
// Make some reasonable effort to produce reasonable default directory
|
||||
// names from repository names.
|
||||
if (!strlen($name)) {
|
||||
$name = $this->getName();
|
||||
$name = phutil_utf8_strtolower($name);
|
||||
$name = preg_replace('@[/ -:]+@', '-', $name);
|
||||
$name = trim($name, '-');
|
||||
if (!strlen($name)) {
|
||||
$name = $this->getCallsign();
|
||||
}
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
|
||||
/* -( Remote Command Execution )------------------------------------------- */
|
||||
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ final class PhabricatorRepositoryTransaction
|
|||
const TYPE_PUSH_POLICY = 'repo:push-policy';
|
||||
const TYPE_CREDENTIAL = 'repo:credential';
|
||||
const TYPE_DANGEROUS = 'repo:dangerous';
|
||||
const TYPE_CLONE_NAME = 'repo:clone-name';
|
||||
|
||||
// TODO: Clean up these legacy transaction types.
|
||||
const TYPE_SSH_LOGIN = 'repo:ssh-login';
|
||||
|
@ -349,6 +350,23 @@ final class PhabricatorRepositoryTransaction
|
|||
'%s enabled protection against dangerous changes.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
}
|
||||
case self::TYPE_CLONE_NAME:
|
||||
if (strlen($old) && !strlen($new)) {
|
||||
return pht(
|
||||
'%s removed the clone name of this repository.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
} else if (strlen($new) && !strlen($old)) {
|
||||
return pht(
|
||||
'%s set the clone name of this repository to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$new);
|
||||
} else {
|
||||
return pht(
|
||||
'%s changed the clone name of this repository from "%s" to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$old,
|
||||
$new);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::getTitle();
|
||||
|
|
|
@ -228,6 +228,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
private function applyInternalEffects(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
||||
$object->setViewPolicy($xaction->getNewValue());
|
||||
|
|
Loading…
Reference in a new issue