1
0
Fork 0
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:
epriestley 2014-01-30 11:42:10 -08:00
parent 96dd530c44
commit ffeee37810
7 changed files with 124 additions and 10 deletions

View file

@ -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',

View file

@ -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')

View file

@ -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);

View file

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

View file

@ -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 )------------------------------------------- */

View file

@ -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();

View file

@ -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());