mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-03 19:31:02 +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()) {
|
if ($repository->isHosted()) {
|
||||||
$ssh_uri = $repository->getSSHCloneURIObject();
|
$ssh_uri = $repository->getSSHCloneURIObject();
|
||||||
if ($ssh_uri) {
|
if ($ssh_uri) {
|
||||||
$clone_uri = $this->renderCloneURI(
|
$clone_uri = $this->renderCloneCommand(
|
||||||
|
$repository,
|
||||||
$ssh_uri,
|
$ssh_uri,
|
||||||
$repository->getServeOverSSH(),
|
$repository->getServeOverSSH(),
|
||||||
'/settings/panel/ssh/');
|
'/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();
|
$http_uri = $repository->getHTTPCloneURIObject();
|
||||||
if ($http_uri) {
|
if ($http_uri) {
|
||||||
$clone_uri = $this->renderCloneURI(
|
$clone_uri = $this->renderCloneCommand(
|
||||||
|
$repository,
|
||||||
$http_uri,
|
$http_uri,
|
||||||
$repository->getServeOverHTTP(),
|
$repository->getServeOverHTTP(),
|
||||||
PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth')
|
PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth')
|
||||||
? '/settings/panel/vcspassword/'
|
? '/settings/panel/vcspassword/'
|
||||||
: null);
|
: null);
|
||||||
|
|
||||||
$view->addProperty(pht('Clone URI (HTTP)'), $clone_uri);
|
$view->addProperty(
|
||||||
|
$repository->isSVN()
|
||||||
|
? pht('Checkout (HTTP)')
|
||||||
|
: pht('Clone (HTTP)'),
|
||||||
|
$clone_uri);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch ($repository->getVersionControlSystem()) {
|
switch ($repository->getVersionControlSystem()) {
|
||||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
||||||
$view->addProperty(
|
$view->addProperty(
|
||||||
pht('Clone URI'),
|
pht('Clone'),
|
||||||
$this->renderCloneURI(
|
$this->renderCloneCommand(
|
||||||
|
$repository,
|
||||||
$repository->getPublicCloneURI()));
|
$repository->getPublicCloneURI()));
|
||||||
break;
|
break;
|
||||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||||
$view->addProperty(
|
$view->addProperty(
|
||||||
pht('Repository Root'),
|
pht('Checkout'),
|
||||||
$this->renderCloneURI(
|
$this->renderCloneCommand(
|
||||||
|
$repository,
|
||||||
$repository->getPublicCloneURI()));
|
$repository->getPublicCloneURI()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -526,7 +538,8 @@ final class DiffusionRepositoryController extends DiffusionController {
|
||||||
return $browse_panel;
|
return $browse_panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function renderCloneURI(
|
private function renderCloneCommand(
|
||||||
|
PhabricatorRepository $repository,
|
||||||
$uri,
|
$uri,
|
||||||
$serve_mode = null,
|
$serve_mode = null,
|
||||||
$manage_uri = null) {
|
$manage_uri = null) {
|
||||||
|
@ -535,11 +548,32 @@ final class DiffusionRepositoryController extends DiffusionController {
|
||||||
|
|
||||||
Javelin::initBehavior('select-on-click');
|
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 = javelin_tag(
|
||||||
'input',
|
'input',
|
||||||
array(
|
array(
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'value' => (string)$uri,
|
'value' => (string)$command,
|
||||||
'class' => 'diffusion-clone-uri',
|
'class' => 'diffusion-clone-uri',
|
||||||
'sigil' => 'select-on-click',
|
'sigil' => 'select-on-click',
|
||||||
'readonly' => 'true',
|
'readonly' => 'true',
|
||||||
|
|
|
@ -28,6 +28,7 @@ final class DiffusionRepositoryEditBasicController
|
||||||
|
|
||||||
$v_name = $repository->getName();
|
$v_name = $repository->getName();
|
||||||
$v_desc = $repository->getDetail('description');
|
$v_desc = $repository->getDetail('description');
|
||||||
|
$v_clone_name = $repository->getDetail('clone-name');
|
||||||
$e_name = true;
|
$e_name = true;
|
||||||
$errors = array();
|
$errors = array();
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@ final class DiffusionRepositoryEditBasicController
|
||||||
$v_name = $request->getStr('name');
|
$v_name = $request->getStr('name');
|
||||||
$v_desc = $request->getStr('description');
|
$v_desc = $request->getStr('description');
|
||||||
$v_projects = $request->getArr('projectPHIDs');
|
$v_projects = $request->getArr('projectPHIDs');
|
||||||
|
$v_clone_name = $request->getStr('cloneName');
|
||||||
|
|
||||||
if (!strlen($v_name)) {
|
if (!strlen($v_name)) {
|
||||||
$e_name = pht('Required');
|
$e_name = pht('Required');
|
||||||
|
@ -50,6 +52,7 @@ final class DiffusionRepositoryEditBasicController
|
||||||
$type_name = PhabricatorRepositoryTransaction::TYPE_NAME;
|
$type_name = PhabricatorRepositoryTransaction::TYPE_NAME;
|
||||||
$type_desc = PhabricatorRepositoryTransaction::TYPE_DESCRIPTION;
|
$type_desc = PhabricatorRepositoryTransaction::TYPE_DESCRIPTION;
|
||||||
$type_edge = PhabricatorTransactions::TYPE_EDGE;
|
$type_edge = PhabricatorTransactions::TYPE_EDGE;
|
||||||
|
$type_clone_name = PhabricatorRepositoryTransaction::TYPE_CLONE_NAME;
|
||||||
|
|
||||||
$xactions[] = id(clone $template)
|
$xactions[] = id(clone $template)
|
||||||
->setTransactionType($type_name)
|
->setTransactionType($type_name)
|
||||||
|
@ -59,6 +62,10 @@ final class DiffusionRepositoryEditBasicController
|
||||||
->setTransactionType($type_desc)
|
->setTransactionType($type_desc)
|
||||||
->setNewValue($v_desc);
|
->setNewValue($v_desc);
|
||||||
|
|
||||||
|
$xactions[] = id(clone $template)
|
||||||
|
->setTransactionType($type_clone_name)
|
||||||
|
->setNewValue($v_clone_name);
|
||||||
|
|
||||||
$xactions[] = id(clone $template)
|
$xactions[] = id(clone $template)
|
||||||
->setTransactionType($type_edge)
|
->setTransactionType($type_edge)
|
||||||
->setMetadataValue(
|
->setMetadataValue(
|
||||||
|
@ -93,6 +100,15 @@ final class DiffusionRepositoryEditBasicController
|
||||||
->setLabel(pht('Name'))
|
->setLabel(pht('Name'))
|
||||||
->setValue($v_name)
|
->setValue($v_name)
|
||||||
->setError($e_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(
|
->appendChild(
|
||||||
id(new PhabricatorRemarkupControl())
|
id(new PhabricatorRemarkupControl())
|
||||||
->setName('description')
|
->setName('description')
|
||||||
|
|
|
@ -253,6 +253,15 @@ final class DiffusionRepositoryEditMainController
|
||||||
$view->addProperty(pht('Type'), $type);
|
$view->addProperty(pht('Type'), $type);
|
||||||
$view->addProperty(pht('Callsign'), $repository->getCallsign());
|
$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(
|
$project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||||
$repository->getPHID(),
|
$repository->getPHID(),
|
||||||
PhabricatorEdgeConfig::TYPE_OBJECT_HAS_PROJECT);
|
PhabricatorEdgeConfig::TYPE_OBJECT_HAS_PROJECT);
|
||||||
|
|
|
@ -31,6 +31,7 @@ final class PhabricatorRepositoryEditor
|
||||||
$types[] = PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY;
|
$types[] = PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY;
|
||||||
$types[] = PhabricatorRepositoryTransaction::TYPE_CREDENTIAL;
|
$types[] = PhabricatorRepositoryTransaction::TYPE_CREDENTIAL;
|
||||||
$types[] = PhabricatorRepositoryTransaction::TYPE_DANGEROUS;
|
$types[] = PhabricatorRepositoryTransaction::TYPE_DANGEROUS;
|
||||||
|
$types[] = PhabricatorRepositoryTransaction::TYPE_CLONE_NAME;
|
||||||
|
|
||||||
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
||||||
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||||
|
@ -84,6 +85,8 @@ final class PhabricatorRepositoryEditor
|
||||||
return $object->getCredentialPHID();
|
return $object->getCredentialPHID();
|
||||||
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
||||||
return $object->shouldAllowDangerousChanges();
|
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_PUSH_POLICY:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
|
case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
||||||
|
case PhabricatorRepositoryTransaction::TYPE_CLONE_NAME:
|
||||||
return $xaction->getNewValue();
|
return $xaction->getNewValue();
|
||||||
case PhabricatorRepositoryTransaction::TYPE_NOTIFY:
|
case PhabricatorRepositoryTransaction::TYPE_NOTIFY:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
|
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
|
||||||
|
@ -183,6 +187,9 @@ final class PhabricatorRepositoryEditor
|
||||||
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
||||||
$object->setDetail('allow-dangerous-changes', $xaction->getNewValue());
|
$object->setDetail('allow-dangerous-changes', $xaction->getNewValue());
|
||||||
return;
|
return;
|
||||||
|
case PhabricatorRepositoryTransaction::TYPE_CLONE_NAME:
|
||||||
|
$object->setDetail('clone-name', $xaction->getNewValue());
|
||||||
|
return;
|
||||||
case PhabricatorRepositoryTransaction::TYPE_ENCODING:
|
case PhabricatorRepositoryTransaction::TYPE_ENCODING:
|
||||||
// Make sure the encoding is valid by converting to UTF-8. This tests
|
// 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
|
// 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_PUSH_POLICY:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
|
case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
|
||||||
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
case PhabricatorRepositoryTransaction::TYPE_DANGEROUS:
|
||||||
|
case PhabricatorRepositoryTransaction::TYPE_CLONE_NAME:
|
||||||
PhabricatorPolicyFilter::requireCapability(
|
PhabricatorPolicyFilter::requireCapability(
|
||||||
$this->requireActor(),
|
$this->requireActor(),
|
||||||
$object,
|
$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 )------------------------------------------- */
|
/* -( Remote Command Execution )------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ final class PhabricatorRepositoryTransaction
|
||||||
const TYPE_PUSH_POLICY = 'repo:push-policy';
|
const TYPE_PUSH_POLICY = 'repo:push-policy';
|
||||||
const TYPE_CREDENTIAL = 'repo:credential';
|
const TYPE_CREDENTIAL = 'repo:credential';
|
||||||
const TYPE_DANGEROUS = 'repo:dangerous';
|
const TYPE_DANGEROUS = 'repo:dangerous';
|
||||||
|
const TYPE_CLONE_NAME = 'repo:clone-name';
|
||||||
|
|
||||||
// TODO: Clean up these legacy transaction types.
|
// TODO: Clean up these legacy transaction types.
|
||||||
const TYPE_SSH_LOGIN = 'repo:ssh-login';
|
const TYPE_SSH_LOGIN = 'repo:ssh-login';
|
||||||
|
@ -349,6 +350,23 @@ final class PhabricatorRepositoryTransaction
|
||||||
'%s enabled protection against dangerous changes.',
|
'%s enabled protection against dangerous changes.',
|
||||||
$this->renderHandleLink($author_phid));
|
$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();
|
return parent::getTitle();
|
||||||
|
|
|
@ -228,6 +228,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
private function applyInternalEffects(
|
private function applyInternalEffects(
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
PhabricatorApplicationTransaction $xaction) {
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
switch ($xaction->getTransactionType()) {
|
switch ($xaction->getTransactionType()) {
|
||||||
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
||||||
$object->setViewPolicy($xaction->getNewValue());
|
$object->setViewPolicy($xaction->getNewValue());
|
||||||
|
|
Loading…
Reference in a new issue