Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditActivateController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditActivateController.php
index 3ebed70348..52ab0d01ca 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditActivateController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditActivateController.php
@@ -1,58 +1,61 @@
<?php
final class DiffusionRepositoryEditActivateController
extends DiffusionRepositoryManageController {
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContextForEdit();
if ($response) {
return $response;
}
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$panel_uri = id(new DiffusionRepositoryBasicsManagementPanel())
->setRepository($repository)
->getPanelURI();
if ($request->isFormPost()) {
if (!$repository->isTracked()) {
$new_status = PhabricatorRepository::STATUS_ACTIVE;
} else {
$new_status = PhabricatorRepository::STATUS_INACTIVE;
}
$xaction = id(new PhabricatorRepositoryTransaction())
->setTransactionType(PhabricatorRepositoryTransaction::TYPE_ACTIVATE)
->setNewValue($new_status);
$editor = id(new PhabricatorRepositoryEditor())
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true)
->setContentSourceFromRequest($request)
->setActor($viewer)
->applyTransactions($repository, array($xaction));
return id(new AphrontReloadResponse())->setURI($panel_uri);
}
if ($repository->isTracked()) {
$title = pht('Deactivate Repository');
- $body = pht('Deactivate this repository?');
+ $body = pht(
+ 'If you deactivate this repository, it will no longer be updated. '.
+ 'Observation and mirroring will cease, and pushing and pulling will '.
+ 'be disabled. You can reactivate the repository later.');
$submit = pht('Deactivate Repository');
} else {
$title = pht('Activate Repository');
$body = pht('Activate this repository?');
$submit = pht('Activate Repository');
}
return $this->newDialog()
->setTitle($title)
->appendChild($body)
->addSubmitButton($submit)
->addCancelButton($panel_uri);
}
}
diff --git a/src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php b/src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php
index 3d510f4648..699bd83aa3 100644
--- a/src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php
+++ b/src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php
@@ -1,411 +1,429 @@
<?php
final class DiffusionRepositoryEditEngine
extends PhabricatorEditEngine {
const ENGINECONST = 'diffusion.repository';
private $versionControlSystem;
public function setVersionControlSystem($version_control_system) {
$this->versionControlSystem = $version_control_system;
return $this;
}
public function getVersionControlSystem() {
return $this->versionControlSystem;
}
public function isEngineConfigurable() {
return false;
}
public function getEngineName() {
return pht('Repositories');
}
public function getSummaryHeader() {
return pht('Edit Repositories');
}
public function getSummaryText() {
return pht('Creates and edits repositories.');
}
public function getEngineApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
protected function newEditableObject() {
$viewer = $this->getViewer();
$repository = PhabricatorRepository::initializeNewRepository($viewer);
$vcs = $this->getVersionControlSystem();
if ($vcs) {
$repository->setVersionControlSystem($vcs);
}
// Pick a random open service to allocate this repository on, if any exist.
// If there are no services, we aren't in cluster mode and will allocate
// locally. If there are services but none permit allocations, we fail.
// Eventually we can make this more flexible, but this rule is a reasonable
// starting point as we begin to deploy cluster services.
$services = id(new AlmanacServiceQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withServiceTypes(
array(
AlmanacClusterRepositoryServiceType::SERVICETYPE,
))
->needProperties(true)
->execute();
if ($services) {
// Filter out services which do not permit new allocations.
foreach ($services as $key => $possible_service) {
if ($possible_service->getAlmanacPropertyValue('closed')) {
unset($services[$key]);
}
}
if (!$services) {
throw new Exception(
pht(
'This install is configured in cluster mode, but all available '.
'repository cluster services are closed to new allocations. '.
'At least one service must be open to allow new allocations to '.
'take place.'));
}
shuffle($services);
$service = head($services);
$repository->setAlmanacServicePHID($service->getPHID());
}
return $repository;
}
protected function newObjectQuery() {
return new PhabricatorRepositoryQuery();
}
protected function getObjectCreateTitleText($object) {
return pht('Create Repository');
}
protected function getObjectCreateButtonText($object) {
return pht('Create Repository');
}
protected function getObjectEditTitleText($object) {
return pht('Edit Repository: %s', $object->getName());
}
protected function getObjectEditShortText($object) {
return $object->getDisplayName();
}
protected function getObjectCreateShortText() {
return pht('Create Repository');
}
protected function getObjectName() {
return pht('Repository');
}
protected function getObjectViewURI($object) {
return $object->getPathURI('manage/');
}
protected function getCreateNewObjectPolicy() {
return $this->getApplication()->getPolicy(
DiffusionCreateRepositoriesCapability::CAPABILITY);
}
protected function newPages($object) {
$panels = DiffusionRepositoryManagementPanel::getAllPanels();
$pages = array();
$uris = array();
foreach ($panels as $panel_key => $panel) {
$panel->setRepository($object);
$uris[$panel_key] = $panel->getPanelURI();
$page = $panel->newEditEnginePage();
if (!$page) {
continue;
}
$pages[] = $page;
}
$basics_key = DiffusionRepositoryBasicsManagementPanel::PANELKEY;
$basics_uri = $uris[$basics_key];
$more_pages = array(
id(new PhabricatorEditPage())
->setKey('encoding')
->setLabel(pht('Text Encoding'))
->setViewURI($basics_uri)
->setFieldKeys(
array(
'encoding',
)),
id(new PhabricatorEditPage())
->setKey('extensions')
->setLabel(pht('Extensions'))
->setIsDefault(true),
);
foreach ($more_pages as $page) {
$pages[] = $page;
}
return $pages;
}
protected function willConfigureFields($object, array $fields) {
// Change the default field order so related fields are adjacent.
$after = array(
'policy.edit' => array('policy.push'),
);
$result = array();
foreach ($fields as $key => $value) {
$result[$key] = $value;
if (!isset($after[$key])) {
continue;
}
foreach ($after[$key] as $next_key) {
if (!isset($fields[$next_key])) {
continue;
}
unset($result[$next_key]);
$result[$next_key] = $fields[$next_key];
unset($fields[$next_key]);
}
}
return $result;
}
protected function buildCustomEditFields($object) {
$viewer = $this->getViewer();
$policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer)
->setObject($object)
->execute();
$track_value = $object->getDetail('branch-filter', array());
$track_value = array_keys($track_value);
$autoclose_value = $object->getDetail('close-commits-filter', array());
$autoclose_value = array_keys($autoclose_value);
+ $automation_instructions = pht(
+ "Configure **Repository Automation** to allow Phabricator to ".
+ "write to this repository.".
+ "\n\n".
+ "IMPORTANT: This feature is new, experimental, and not supported. ".
+ "Use it at your own risk.");
+
+ $staging_instructions = pht(
+ "To make it easier to run integration tests and builds on code ".
+ "under review, you can configure a **Staging Area**. When `arc` ".
+ "creates a diff, it will push a copy of the changes to the ".
+ "configured staging area with a corresponding tag.".
+ "\n\n".
+ "IMPORTANT: This feature is new, experimental, and not supported. ".
+ "Use it at your own risk.");
+
return array(
id(new PhabricatorSelectEditField())
->setKey('vcs')
->setLabel(pht('Version Control System'))
->setTransactionType(PhabricatorRepositoryTransaction::TYPE_VCS)
->setIsConduitOnly(true)
->setIsCopyable(true)
->setOptions(PhabricatorRepositoryType::getAllRepositoryTypes())
->setDescription(pht('Underlying repository version control system.'))
->setConduitDescription(
pht(
'Choose which version control system to use when creating a '.
'repository.'))
->setConduitTypeDescription(pht('Version control system selection.'))
->setValue($object->getVersionControlSystem()),
id(new PhabricatorTextEditField())
->setKey('name')
->setLabel(pht('Name'))
->setIsRequired(true)
->setTransactionType(PhabricatorRepositoryTransaction::TYPE_NAME)
->setDescription(pht('The repository name.'))
->setConduitDescription(pht('Rename the repository.'))
->setConduitTypeDescription(pht('New repository name.'))
->setValue($object->getName()),
id(new PhabricatorTextEditField())
->setKey('callsign')
->setLabel(pht('Callsign'))
->setTransactionType(PhabricatorRepositoryTransaction::TYPE_CALLSIGN)
->setDescription(pht('The repository callsign.'))
->setConduitDescription(pht('Change the repository callsign.'))
->setConduitTypeDescription(pht('New repository callsign.'))
->setValue($object->getCallsign()),
id(new PhabricatorTextEditField())
->setKey('shortName')
->setLabel(pht('Short Name'))
->setTransactionType(PhabricatorRepositoryTransaction::TYPE_SLUG)
->setDescription(pht('Short, unique repository name.'))
->setConduitDescription(pht('Change the repository short name.'))
->setConduitTypeDescription(pht('New short name for the repository.'))
->setValue($object->getRepositorySlug()),
id(new PhabricatorRemarkupEditField())
->setKey('description')
->setLabel(pht('Description'))
->setTransactionType(PhabricatorRepositoryTransaction::TYPE_DESCRIPTION)
->setDescription(pht('Repository description.'))
->setConduitDescription(pht('Change the repository description.'))
->setConduitTypeDescription(pht('New repository description.'))
->setValue($object->getDetail('description')),
id(new PhabricatorTextEditField())
->setKey('encoding')
->setLabel(pht('Text Encoding'))
->setIsCopyable(true)
->setTransactionType(PhabricatorRepositoryTransaction::TYPE_ENCODING)
->setDescription(pht('Default text encoding.'))
->setConduitDescription(pht('Change the default text encoding.'))
->setConduitTypeDescription(pht('New text encoding.'))
->setValue($object->getDetail('encoding')),
id(new PhabricatorBoolEditField())
->setKey('allowDangerousChanges')
->setLabel(pht('Allow Dangerous Changes'))
->setIsCopyable(true)
->setIsConduitOnly(true)
->setOptions(
pht('Prevent Dangerous Changes'),
pht('Allow Dangerous Changes'))
->setTransactionType(PhabricatorRepositoryTransaction::TYPE_DANGEROUS)
->setDescription(pht('Permit dangerous changes to be made.'))
->setConduitDescription(pht('Allow or prevent dangerous changes.'))
->setConduitTypeDescription(pht('New protection setting.'))
->setValue($object->shouldAllowDangerousChanges()),
id(new PhabricatorSelectEditField())
->setKey('status')
->setLabel(pht('Status'))
->setTransactionType(PhabricatorRepositoryTransaction::TYPE_ACTIVATE)
->setIsConduitOnly(true)
->setOptions(PhabricatorRepository::getStatusNameMap())
->setDescription(pht('Active or inactive status.'))
->setConduitDescription(pht('Active or deactivate the repository.'))
->setConduitTypeDescription(pht('New repository status.'))
->setValue($object->getStatus()),
id(new PhabricatorTextEditField())
->setKey('defaultBranch')
->setLabel(pht('Default Branch'))
->setTransactionType(
PhabricatorRepositoryTransaction::TYPE_DEFAULT_BRANCH)
->setIsCopyable(true)
->setDescription(pht('Default branch name.'))
->setConduitDescription(pht('Set the default branch name.'))
->setConduitTypeDescription(pht('New default branch name.'))
->setValue($object->getDetail('default-branch')),
id(new PhabricatorTextAreaEditField())
->setIsStringList(true)
->setKey('trackOnly')
->setLabel(pht('Track Only'))
->setTransactionType(
PhabricatorRepositoryTransaction::TYPE_TRACK_ONLY)
->setIsCopyable(true)
->setDescription(pht('Track only these branches.'))
->setConduitDescription(pht('Set the tracked branches.'))
->setConduitTypeDescription(pht('New tracked branchs.'))
->setValue($track_value),
id(new PhabricatorTextAreaEditField())
->setIsStringList(true)
->setKey('autocloseOnly')
->setLabel(pht('Autoclose Only'))
->setTransactionType(
PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE_ONLY)
->setIsCopyable(true)
->setDescription(pht('Autoclose commits on only these branches.'))
->setConduitDescription(pht('Set the autoclose branches.'))
->setConduitTypeDescription(pht('New default tracked branchs.'))
->setValue($autoclose_value),
id(new PhabricatorTextEditField())
->setKey('stagingAreaURI')
->setLabel(pht('Staging Area URI'))
->setTransactionType(
PhabricatorRepositoryTransaction::TYPE_STAGING_URI)
->setIsCopyable(true)
->setDescription(pht('Staging area URI.'))
->setConduitDescription(pht('Set the staging area URI.'))
->setConduitTypeDescription(pht('New staging area URI.'))
- ->setValue($object->getStagingURI()),
+ ->setValue($object->getStagingURI())
+ ->setControlInstructions($staging_instructions),
id(new PhabricatorDatasourceEditField())
->setKey('automationBlueprintPHIDs')
->setLabel(pht('Use Blueprints'))
->setTransactionType(
PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS)
->setIsCopyable(true)
->setDatasource(new DrydockBlueprintDatasource())
->setDescription(pht('Automation blueprints.'))
->setConduitDescription(pht('Change automation blueprints.'))
->setConduitTypeDescription(pht('New blueprint PHIDs.'))
- ->setValue($object->getAutomationBlueprintPHIDs()),
+ ->setValue($object->getAutomationBlueprintPHIDs())
+ ->setControlInstructions($automation_instructions),
id(new PhabricatorStringListEditField())
->setKey('symbolLanguages')
->setLabel(pht('Languages'))
->setTransactionType(
PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE)
->setIsCopyable(true)
->setDescription(
pht('Languages which define symbols in this repository.'))
->setConduitDescription(
pht('Change symbol languages for this repository.'))
->setConduitTypeDescription(
pht('New symbol langauges.'))
->setValue($object->getSymbolLanguages()),
id(new PhabricatorDatasourceEditField())
->setKey('symbolRepositoryPHIDs')
->setLabel(pht('Uses Symbols From'))
->setTransactionType(
PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES)
->setIsCopyable(true)
->setDatasource(new DiffusionRepositoryDatasource())
->setDescription(pht('Repositories to link symbols from.'))
->setConduitDescription(pht('Change symbol source repositories.'))
->setConduitTypeDescription(pht('New symbol repositories.'))
->setValue($object->getSymbolSources()),
id(new PhabricatorBoolEditField())
->setKey('publish')
->setLabel(pht('Publish/Notify'))
->setTransactionType(
PhabricatorRepositoryTransaction::TYPE_NOTIFY)
->setIsCopyable(true)
->setOptions(
pht('Disable Notifications, Feed, and Herald'),
pht('Enable Notifications, Feed, and Herald'))
->setDescription(pht('Configure how changes are published.'))
->setConduitDescription(pht('Change publishing options.'))
->setConduitTypeDescription(pht('New notification setting.'))
->setValue(!$object->getDetail('herald-disabled')),
id(new PhabricatorBoolEditField())
->setKey('autoclose')
->setLabel(pht('Autoclose'))
->setTransactionType(
PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE)
->setIsCopyable(true)
->setOptions(
pht('Disable Autoclose'),
pht('Enable Autoclose'))
->setDescription(pht('Stop or resume autoclosing in this repository.'))
->setConduitDescription(pht('Change autoclose setting.'))
->setConduitTypeDescription(pht('New autoclose setting.'))
->setValue(!$object->getDetail('disable-autoclose')),
id(new PhabricatorPolicyEditField())
->setKey('policy.push')
->setLabel(pht('Push Policy'))
->setAliases(array('push'))
->setIsCopyable(true)
->setCapability(DiffusionPushCapability::CAPABILITY)
->setPolicies($policies)
->setTransactionType(PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY)
->setDescription(
pht('Controls who can push changes to the repository.'))
->setConduitDescription(
pht('Change the push policy of the repository.'))
->setConduitTypeDescription(pht('New policy PHID or constant.'))
->setValue($object->getPolicy(DiffusionPushCapability::CAPABILITY)),
);
}
}
diff --git a/src/applications/diffusion/editor/DiffusionURIEditEngine.php b/src/applications/diffusion/editor/DiffusionURIEditEngine.php
index 639dd74400..fdc91cff5f 100644
--- a/src/applications/diffusion/editor/DiffusionURIEditEngine.php
+++ b/src/applications/diffusion/editor/DiffusionURIEditEngine.php
@@ -1,182 +1,219 @@
<?php
final class DiffusionURIEditEngine
extends PhabricatorEditEngine {
const ENGINECONST = 'diffusion.uri';
private $repository;
public function setRepository(PhabricatorRepository $repository) {
$this->repository = $repository;
return $this;
}
public function getRepository() {
return $this->repository;
}
public function isEngineConfigurable() {
return false;
}
public function getEngineName() {
return pht('Repository URIs');
}
public function getSummaryHeader() {
return pht('Edit Repository URI');
}
public function getSummaryText() {
return pht('Creates and edits repository URIs.');
}
public function getEngineApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
protected function newEditableObject() {
$uri = PhabricatorRepositoryURI::initializeNewURI();
$repository = $this->getRepository();
if ($repository) {
$uri->setRepositoryPHID($repository->getPHID());
$uri->attachRepository($repository);
}
return $uri;
}
protected function newObjectQuery() {
return new PhabricatorRepositoryURIQuery();
}
protected function getObjectCreateTitleText($object) {
return pht('Create Repository URI');
}
protected function getObjectCreateButtonText($object) {
return pht('Create Repository URI');
}
protected function getObjectEditTitleText($object) {
return pht('Edit Repository URI %d', $object->getID());
}
protected function getObjectEditShortText($object) {
return pht('URI %d', $object->getID());
}
protected function getObjectCreateShortText() {
return pht('Create Repository URI');
}
protected function getObjectName() {
return pht('Repository URI');
}
protected function getObjectViewURI($object) {
return $object->getViewURI();
}
protected function buildCustomEditFields($object) {
$viewer = $this->getViewer();
$uri_instructions = null;
if ($object->isBuiltin()) {
$is_builtin = true;
$uri_value = (string)$object->getDisplayURI();
switch ($object->getBuiltinProtocol()) {
case PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH:
$uri_instructions = pht(
" - Configure [[ %s | %s ]] to change the SSH username.\n".
" - Configure [[ %s | %s ]] to change the SSH host.\n".
" - Configure [[ %s | %s ]] to change the SSH port.",
'/config/edit/diffusion.ssh-user/',
'diffusion.ssh-user',
'/config/edit/diffusion.ssh-host/',
'diffusion.ssh-host',
'/config/edit/diffusion.ssh-port/',
'diffusion.ssh-port');
break;
}
} else {
$is_builtin = false;
$uri_value = $object->getURI();
+
+ if ($object->getRepositoryPHID()) {
+ $repository = $object->getRepository();
+ if ($repository->isGit()) {
+ $uri_instructions = pht(
+ "Provide the URI of a Git repository. It should usually look ".
+ "like one of these examples:\n".
+ "\n".
+ "| Example Git URIs\n".
+ "| -----------------------\n".
+ "| `git@github.com:example/example.git`\n".
+ "| `ssh://user@host.com/git/example.git`\n".
+ "| `https://example.com/repository.git`");
+ } else if ($repository->isHg()) {
+ $uri_instructions = pht(
+ "Provide the URI of a Mercurial repository. It should usually ".
+ "look like one of these examples:\n".
+ "\n".
+ "| Example Mercurial URIs\n".
+ "|-----------------------\n".
+ "| `ssh://hg@bitbucket.org/example/repository`\n".
+ "| `https://bitbucket.org/example/repository`");
+ } else if ($repository->isSVN()) {
+ $uri_instructions = pht(
+ "Provide the **Repository Root** of a Subversion repository. ".
+ "You can identify this by running `svn info` in a working ".
+ "copy. It should usually look like one of these examples:\n".
+ "\n".
+ "| Example Subversion URIs\n".
+ "|-----------------------\n".
+ "| `http://svn.example.org/svnroot/`\n".
+ "| `svn+ssh://svn.example.com/svnroot/`\n".
+ "| `svn://svn.example.net/svnroot/`\n\n".
+ "You **MUST** specify the root of the repository, not a ".
+ "subdirectory.");
+ }
+ }
}
return array(
id(new PhabricatorHandlesEditField())
->setKey('repository')
->setAliases(array('repositoryPHID'))
->setLabel(pht('Repository'))
->setIsRequired(true)
->setIsConduitOnly(true)
->setTransactionType(
PhabricatorRepositoryURITransaction::TYPE_REPOSITORY)
->setDescription(pht('The repository this URI is associated with.'))
->setConduitDescription(
pht(
'Create a URI in a given repository. This transaction type '.
'must be present when creating a new URI and must not be '.
'present when editing an existing URI.'))
->setConduitTypeDescription(
pht('Repository PHID to create a new URI for.'))
->setSingleValue($object->getRepositoryPHID()),
id(new PhabricatorTextEditField())
->setKey('uri')
->setLabel(pht('URI'))
->setTransactionType(PhabricatorRepositoryURITransaction::TYPE_URI)
->setDescription(pht('The repository URI.'))
->setConduitDescription(pht('Change the repository URI.'))
->setConduitTypeDescription(pht('New repository URI.'))
->setIsRequired(!$is_builtin)
->setIsLocked($is_builtin)
->setValue($uri_value)
->setControlInstructions($uri_instructions),
id(new PhabricatorSelectEditField())
->setKey('io')
->setLabel(pht('I/O Type'))
->setTransactionType(PhabricatorRepositoryURITransaction::TYPE_IO)
->setDescription(pht('URI I/O behavior.'))
->setConduitDescription(pht('Adjust I/O behavior.'))
->setConduitTypeDescription(pht('New I/O behavior.'))
->setValue($object->getIOType())
->setOptions($object->getAvailableIOTypeOptions()),
id(new PhabricatorSelectEditField())
->setKey('display')
->setLabel(pht('Display Type'))
->setTransactionType(PhabricatorRepositoryURITransaction::TYPE_DISPLAY)
->setDescription(pht('URI display behavior.'))
->setConduitDescription(pht('Change display behavior.'))
->setConduitTypeDescription(pht('New display behavior.'))
->setValue($object->getDisplayType())
->setOptions($object->getAvailableDisplayTypeOptions()),
id(new PhabricatorHandlesEditField())
->setKey('credential')
->setAliases(array('credentialPHID'))
->setLabel(pht('Credential'))
->setIsConduitOnly(true)
->setTransactionType(
PhabricatorRepositoryURITransaction::TYPE_CREDENTIAL)
->setDescription(
pht('The credential to use when interacting with this URI.'))
->setConduitDescription(pht('Change the credential for this URI.'))
->setConduitTypeDescription(pht('New credential PHID, or null.'))
->setSingleValue($object->getCredentialPHID()),
id(new PhabricatorBoolEditField())
->setKey('disable')
->setLabel(pht('Disabled'))
->setIsConduitOnly(true)
->setTransactionType(PhabricatorRepositoryURITransaction::TYPE_DISABLE)
->setDescription(pht('Active status of the URI.'))
->setConduitDescription(pht('Disable or activate the URI.'))
->setConduitTypeDescription(pht('True to disable the URI.'))
->setOptions(pht('Enable'), pht('Disable'))
->setValue($object->getIsDisabled()),
);
}
}
diff --git a/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php
index a601bd1d64..573162b927 100644
--- a/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php
+++ b/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php
@@ -1,504 +1,513 @@
<?php
final class DiffusionRepositoryStatusManagementPanel
extends DiffusionRepositoryManagementPanel {
const PANELKEY = 'status';
public function getManagementPanelLabel() {
return pht('Status');
}
public function getManagementPanelOrder() {
return 200;
}
public function getManagementPanelIcon() {
$repository = $this->getRepository();
// TODO: We could try to show a warning icon in more cases, but just
// raise in the most serious cases for now.
$messages = $this->loadStatusMessages($repository);
$raw_error = $this->buildRepositoryRawError($repository, $messages);
if ($raw_error) {
return 'fa-exclamation-triangle red';
}
return 'fa-check grey';
}
protected function buildManagementPanelActions() {
$repository = $this->getRepository();
$viewer = $this->getViewer();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$repository,
PhabricatorPolicyCapability::CAN_EDIT);
$update_uri = $repository->getPathURI('edit/update/');
return array(
id(new PhabricatorActionView())
->setIcon('fa-refresh')
->setName(pht('Update Now'))
->setWorkflow(true)
->setDisabled(!$can_edit)
->setHref($update_uri),
);
}
public function buildManagementPanelContent() {
$repository = $this->getRepository();
$viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
->setViewer($viewer)
->setActionList($this->newActions());
$view->addProperty(
pht('Update Frequency'),
$this->buildRepositoryUpdateInterval($repository));
$messages = $this->loadStatusMessages($repository);
$status = $this->buildRepositoryStatus($repository, $messages);
$raw_error = $this->buildRepositoryRawError($repository, $messages);
$view->addProperty(pht('Status'), $status);
if ($raw_error) {
$view->addSectionHeader(pht('Raw Error'));
$view->addTextContent($raw_error);
}
return $this->newBox(pht('Status'), $view);
}
private function buildRepositoryUpdateInterval(
PhabricatorRepository $repository) {
$smart_wait = $repository->loadUpdateInterval();
$doc_href = PhabricatorEnv::getDoclink(
'Diffusion User Guide: Repository Updates');
return array(
phutil_format_relative_time_detailed($smart_wait),
" \xC2\xB7 ",
phutil_tag(
'a',
array(
'href' => $doc_href,
'target' => '_blank',
),
pht('Learn More')),
);
}
private function buildRepositoryStatus(
PhabricatorRepository $repository,
array $messages) {
$viewer = $this->getViewer();
$is_cluster = $repository->getAlmanacServicePHID();
$view = new PHUIStatusListView();
if ($repository->isTracked()) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(pht('Repository Active')));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'bluegrey')
->setTarget(pht('Repository Inactive'))
->setNote(
pht('Activate this repository to begin or resume import.')));
return $view;
}
$binaries = array();
$svnlook_check = false;
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$binaries[] = 'git';
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$binaries[] = 'svn';
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$binaries[] = 'hg';
break;
}
if ($repository->isHosted()) {
$proto_https = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTPS;
$proto_http = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTP;
$can_http = $repository->canServeProtocol($proto_http, false) ||
$repository->canServeProtocol($proto_https, false);
if ($can_http) {
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$binaries[] = 'git-http-backend';
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$binaries[] = 'svnserve';
$binaries[] = 'svnadmin';
$binaries[] = 'svnlook';
$svnlook_check = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$binaries[] = 'hg';
break;
}
}
$proto_ssh = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH;
$can_ssh = $repository->canServeProtocol($proto_ssh, false);
if ($can_ssh) {
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$binaries[] = 'git-receive-pack';
$binaries[] = 'git-upload-pack';
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$binaries[] = 'svnserve';
$binaries[] = 'svnadmin';
$binaries[] = 'svnlook';
$svnlook_check = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$binaries[] = 'hg';
break;
}
}
}
$binaries = array_unique($binaries);
if (!$is_cluster) {
// We're only checking for binaries if we aren't running with a cluster
// configuration. In theory, we could check for binaries on the
// repository host machine, but we'd need to make this more complicated
// to do that.
foreach ($binaries as $binary) {
$where = Filesystem::resolveBinary($binary);
if (!$where) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(
pht('Missing Binary %s', phutil_tag('tt', array(), $binary)))
->setNote(pht(
"Unable to find this binary in the webserver's PATH. You may ".
"need to configure %s.",
$this->getEnvConfigLink())));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(
pht('Found Binary %s', phutil_tag('tt', array(), $binary)))
->setNote(phutil_tag('tt', array(), $where)));
}
}
// This gets checked generically above. However, for svn commit hooks, we
// need this to be in environment.append-paths because subversion strips
// PATH.
if ($svnlook_check) {
$where = Filesystem::resolveBinary('svnlook');
if ($where) {
$path = substr($where, 0, strlen($where) - strlen('svnlook'));
$dirs = PhabricatorEnv::getEnvConfig('environment.append-paths');
$in_path = false;
foreach ($dirs as $dir) {
if (Filesystem::isDescendant($path, $dir)) {
$in_path = true;
break;
}
}
if (!$in_path) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(
pht('Missing Binary %s', phutil_tag('tt', array(), $binary)))
->setNote(pht(
'Unable to find this binary in `%s`. '.
'You need to configure %s and include %s.',
'environment.append-paths',
$this->getEnvConfigLink(),
$path)));
}
}
}
}
$doc_href = PhabricatorEnv::getDocLink('Managing Daemons with phd');
$daemon_instructions = pht(
'Use %s to start daemons. See %s.',
phutil_tag('tt', array(), 'bin/phd start'),
phutil_tag(
'a',
array(
'href' => $doc_href,
),
pht('Managing Daemons with phd')));
$pull_daemon = id(new PhabricatorDaemonLogQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)
->withDaemonClasses(array('PhabricatorRepositoryPullLocalDaemon'))
->setLimit(1)
->execute();
if ($pull_daemon) {
// TODO: In a cluster environment, we need a daemon on this repository's
// host, specifically, and we aren't checking for that right now. This
// is a reasonable proxy for things being more-or-less correctly set up,
// though.
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(pht('Pull Daemon Running')));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(pht('Pull Daemon Not Running'))
->setNote($daemon_instructions));
}
$task_daemon = id(new PhabricatorDaemonLogQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)
->withDaemonClasses(array('PhabricatorTaskmasterDaemon'))
->setLimit(1)
->execute();
if ($task_daemon) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(pht('Task Daemon Running')));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(pht('Task Daemon Not Running'))
->setNote($daemon_instructions));
}
if ($is_cluster) {
// Just omit this status check for now in cluster environments. We
// could make a service call and pull it from the repository host
// eventually.
} else if ($repository->usesLocalWorkingCopy()) {
$local_parent = dirname($repository->getLocalPath());
if (Filesystem::pathExists($local_parent)) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(pht('Storage Directory OK'))
->setNote(phutil_tag('tt', array(), $local_parent)));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(pht('No Storage Directory'))
->setNote(
pht(
'Storage directory %s does not exist, or is not readable by '.
'the webserver. Create this directory or make it readable.',
phutil_tag('tt', array(), $local_parent))));
return $view;
}
$local_path = $repository->getLocalPath();
$message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_INIT);
if ($message) {
switch ($message->getStatusCode()) {
case PhabricatorRepositoryStatusMessage::CODE_ERROR:
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(pht('Initialization Error'))
->setNote($message->getParameter('message')));
return $view;
case PhabricatorRepositoryStatusMessage::CODE_OKAY:
if (Filesystem::pathExists($local_path)) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(pht('Working Copy OK'))
->setNote(phutil_tag('tt', array(), $local_path)));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(pht('Working Copy Error'))
->setNote(
pht(
'Working copy %s has been deleted, or is not '.
'readable by the webserver. Make this directory '.
'readable. If it has been deleted, the daemons should '.
'restore it automatically.',
phutil_tag('tt', array(), $local_path))));
return $view;
}
break;
case PhabricatorRepositoryStatusMessage::CODE_WORKING:
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green')
->setTarget(pht('Initializing Working Copy'))
->setNote(pht('Daemons are initializing the working copy.')));
return $view;
default:
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(pht('Unknown Init Status'))
->setNote($message->getStatusCode()));
return $view;
}
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange')
->setTarget(pht('No Working Copy Yet'))
->setNote(
pht('Waiting for daemons to build a working copy.')));
return $view;
}
}
$message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH);
if ($message) {
switch ($message->getStatusCode()) {
case PhabricatorRepositoryStatusMessage::CODE_ERROR:
$message = $message->getParameter('message');
$suggestion = null;
if (preg_match('/Permission denied \(publickey\)./', $message)) {
$suggestion = pht(
'Public Key Error: This error usually indicates that the '.
'keypair you have configured does not have permission to '.
'access the repository.');
}
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
->setTarget(pht('Update Error'))
->setNote($suggestion));
return $view;
case PhabricatorRepositoryStatusMessage::CODE_OKAY:
$ago = (PhabricatorTime::getNow() - $message->getEpoch());
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(pht('Updates OK'))
->setNote(
pht(
'Last updated %s (%s ago).',
phabricator_datetime($message->getEpoch(), $viewer),
phutil_format_relative_time_detailed($ago))));
break;
}
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange')
->setTarget(pht('Waiting For Update'))
->setNote(
pht('Waiting for daemons to read updates.')));
}
if ($repository->isImporting()) {
$ratio = $repository->loadImportProgress();
$percentage = sprintf('%.2f%%', 100 * $ratio);
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green')
->setTarget(pht('Importing'))
->setNote(
pht('%s Complete', $percentage)));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(pht('Fully Imported')));
}
if (idx($messages, PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE)) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_UP, 'indigo')
->setTarget(pht('Prioritized'))
->setNote(pht('This repository will be updated soon!')));
}
return $view;
}
private function buildRepositoryRawError(
PhabricatorRepository $repository,
array $messages) {
$viewer = $this->getViewer();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$repository,
PhabricatorPolicyCapability::CAN_EDIT);
$raw_error = null;
$message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH);
if ($message) {
switch ($message->getStatusCode()) {
case PhabricatorRepositoryStatusMessage::CODE_ERROR:
$raw_error = $message->getParameter('message');
break;
}
}
if ($raw_error !== null) {
if (!$can_edit) {
$raw_message = pht(
'You must be able to edit a repository to see raw error messages '.
'because they sometimes disclose sensitive information.');
$raw_message = phutil_tag('em', array(), $raw_message);
} else {
$raw_message = phutil_escape_html_newlines($raw_error);
}
} else {
$raw_message = null;
}
return $raw_message;
}
private function loadStatusMessages(PhabricatorRepository $repository) {
$messages = id(new PhabricatorRepositoryStatusMessage())
->loadAllWhere('repositoryID = %d', $repository->getID());
$messages = mpull($messages, null, 'getStatusType');
return $messages;
}
+ private function getEnvConfigLink() {
+ $config_href = '/config/edit/environment.append-paths/';
+ return phutil_tag(
+ 'a',
+ array(
+ 'href' => $config_href,
+ ),
+ 'environment.append-paths');
+ }
}
diff --git a/src/docs/user/userguide/diffusion_managing.diviner b/src/docs/user/userguide/diffusion_managing.diviner
index c3492c507a..efdb783c04 100644
--- a/src/docs/user/userguide/diffusion_managing.diviner
+++ b/src/docs/user/userguide/diffusion_managing.diviner
@@ -1,310 +1,353 @@
@title Diffusion User Guide: Managing Repositories
@group userguide
Guide to configuring and managing repositories in Diffusion.
Overview
========
After you create a new repository in Diffusion or select **Manage Repository**
from the main screen if an existing repository, you'll be taken to the
repository management interface for that repository.
On this interface, you'll find many options which allow you to configure the
behavior of a repository. This document walks through the options.
Basics
======
The **Basics** section of the management interface allows you to configure
the repository name, description, and identifiers. You can also activate or
deactivate the repository here, and configure a few other miscellaneous
settings.
Basics: Name
============
The repository name is a human-readable primary name for the repository. It
does not need to be unique
Because the name is not unique and does not have any meaningful restrictions,
it's fairly ambiguous and isn't very useful as an identifier. The other basic
information (primarily callsigns and short names) gives you control over
repository identifiers.
Basics: Callsigns
=================
Each repository can optionally be identified by a "callsign", which is a short
uppercase string like "P" (for Phabricator) or "ARC" (for Arcanist).
The primary goal of callsigns is to namespace commits to SVN repositories: if
you use multiple SVN repositories, each repository has a revision 1, revision 2,
etc., so referring to them by number alone is ambiguous.
However, even for Git and Mercurial they impart additional information to human
readers and allow parsers to detect that something is a commit name with high
probability (and allow distinguishing between multiple copies of a repository).
Configuring a callsign can make interacting with a commonly-used repository
easier, but you may not want to bother assigning one to every repository if you
have some similar, templated, or rarely-used repositories.
If you choose to assign a callsign to a repository, it must be unique within an
install but do not need to be globally unique, so you are free to use the
single-letter callsigns for brevity. For example, Facebook uses "E" for the
Engineering repository, "O" for the Ops repository, "Y" for a Yum package
repository, and so on, while Phabricator uses "P", "ARC", "PHU" for libphutil,
and "J" for Javelin. Keeping callsigns brief will make them easier to use, and
the use of one-character callsigns is encouraged if they are reasonably
evocative.
If you configure a callsign like `XYZ`, Phabricator will activate callsign URIs
and activate the callsign identifier (like `rXYZ`) for the repository. These
more human-readable identifiers can make things a little easier to interact
with.
Basics: Short Name
==================
Each repository can optionally have a unique short name. Short names must be
unique and have some minor restrictions to make sure they are unambiguous and
appropriate for use as directory names and in URIs.
Basics: Description
===================
You may optionally provide a brief (or, at your discretion, excruciatingly
long) human-readable description of the repository. This description will be
shown on the main repository page.
You can also create a `README` file at the repository root (or in any
subdirectory) to provide information about the repository. These formats are
supported:
| File Name | Rendered As...
|-------------------|---------------
| `README` | Plain Text
| `README.txt` | Plain Text
| `README.remarkup` | Remarkup
| `README.md` | Remarkup
| `README.rainbow` | Rainbow
Basics: Encoding
================
Before content from the repository can be shown in the web UI or embedded in
other contexts like email, it must be converted to UTF-8.
Most source code is written in UTF-8 or a subset of UTF-8 (like plain ASCII)
already, so everything will work fine. The majority of repositories do not need
to adjust this setting.
If your repository is primarily written in some other encoding, specify it here
so Phabricator can convert from it properly when reading content to embed in
a webpage or email.
Basics: Dangerous Changes
=========================
By default, repositories are protected against dangerous changes. Dangerous
changes are operations which rewrite or destroy repository history (for
example, by deleting or rewriting branches). Normally, these take the form
of `git push --force` or similar.
It is normally a good idea to leave this protection enabled because most
scalable workflows rarely rewrite repository history and it's easy to make
mistakes which are expensive to correct if this protection is disabled.
If you do occasionally need to rewite published history, you can treat this
option like a safety: disable it, perform required rewrites, then enable it
again.
If you fully disable this at the repository level, you can still use Herald to
selectively protect certain branches or grant this power to a limited set of
users.
This option is only available in Git and Mercurial, because it is impossible
to make dangerous changes in Subversion.
This option has no effect if a repository is not hosted because Phabricator
can not prevent dangerous changes in a remote repository it is merely
observing.
Basics: Deactivate Repository
=============================
Repositories can be deactivated. Deactivating a repository has these effects:
- the repository will no longer be updated;
- users will no longer be able to clone/fetch/checkout the repository;
- users will no longer be able to push to the repository; and
- the repository will be hidden from view in default queries.
When repositories are created for the first time, they are deactivated. This
gives you an opportuinty to customize settings, like adjusting policies or
configuring a URI to observe. You must activate a repository before it will
start working normally.
Basics: Delete Repository
=========================
Repositories can not be deleted from the web UI, so this option is always
disabled. Clicking it gives you information about how to delete a repository.
Repositories can only be deleted from the command line, with `bin/remove`:
```
$ ./bin/remove destroy <repository>
```
WARNING: This command will issue you a dire warning about the severity of the
action you are taking. Heed this warning. You are **strongly discouraged** from
destroying repositories. Instead, deactivate them.
Policies
========
The **Policies** section of the management interface allows you to review and
manage repository access policies.
You can configure granular access policies for each repository to control who
can view, clone, administate, and push to the repository.
Policies: View
==============
The view policy for a repository controls who can view the repository from
the web UI and clone, fetch, or check it out from Phabricator.
Users who can view a repository can also access the "Manage" interface to
review information about the repository and examine the edit history, but can
not make any changes.
Policies: Edit
==============
The edit policy for a repository controls who can change repository settings
using the "Manage" interface. In essence, this is permission to administrate
the repository.
You must be able to view a repository to edit it.
You do not need this permission to push changes to a repository.
Policies: Push
==============
The push policy for a repository controls who can push changes to the
repository.
This policy has no effect if Phabricator is not hosting the repository, because
it can not control who is allowed to make changes to a remote repository it is
merely observing.
You must also be able to view a repository to push to it.
You do not need to be able to edit a repository to push to it.
Further restrictions on who can push (and what they can push) can be configured
for hosted repositories with Herald, which allows you to write more
sophisticated rules that evaluate when Phabricator receives a push. To get
started with Herald, see @{article:Herald User Guide}.
Additionally, Git and Mercurial repositories have a setting which allows
you to **Prevent Dangerous Changes**. This setting is enabled by default and
will prevent any users from pushing changes which rewrite or destroy history.
URIs
====
The **URIs** panel allows you to add and manage URIs which Phabricator will
fetch from, serve from, and push to.
These options are covered in detail in @{article:Diffusion User Guide: URIs}.
+Branches
+========
+
+The **Branches** panel allows you to configure how Phabricator interacts with
+branches.
+
+This panel is not available for Subversion repositories, because Subversion
+does not have formal branches.
+
+You can configure **Default Branch**. This controls which branch is shown by
+default in the UI. If no branch is provided, Phabricator will use `master` in
+Git and `default` in Mercurial.
+
+If you want Diffusion to ignore some branches in the repository, you can
+configure **Track Only**. Other branches will be ignored. If you do not specify
+any branches, all branches are tracked.
+
+When specifying branches, you should enter one branch name per line. You can
+use regular expressions to match branches by wrapping an expression in
+`regexp(...)`. For example:
+
+| Example | Effect |
+|---------|--------|
+| `master` | Track only `master`.
+| `regexp(/^release-/)` | Track all branches which start with `release-`.
+| `regexp(/^(?!temp-)/)` | Do not track branches which start with `temp-`.
+
+
+Actions
+======
+
+The **Actions** panel can configure notifications and publishing behavior.
+
+Normally, Phabricator publishes notifications when it discovers new commits.
+You can disable publishing for a repository by turning off **Publish/Noitfy**.
+This will disable notifications, feed, and Herald (including audits and build
+plans) for this repository.
+
+When Phabricator discovers a new commit, it can automatically close associated
+revisions and tasks. If you don't want Phabricator to close objects when it
+discovers new commits, disable **Autoclose** for the repository.
+
+
Repository Identifiers and Names
================================
Repositories have several short identifiers which you can use to refer to the
repository. For example, if you use command-line administrative tools to
interact with a repository, you'll provide one of these identifiers:
```
$ ./bin/repository update <identifier>
```
The identifiers available for a repository depend on which options are
configured. Each repository may have several identifiers:
- An **ID** identifier, like `R123`. This is available for all repositories.
- A **callsign** identifier, like `rXY`. This is available for repositories
with a callsign.
- A **short name** identifier, like `xylophone`. This is available for
repositories with a short name.
All three identifiers can be used to refer to the repository in cases where
the intent is unambiguous, but only the first two forms work in ambiguous
contexts.
For example, if you type `R123` or `rXY` into a comment, Phabricator will
recognize them as references to the repository. If you type `xylophone`, it
assumes you mean the word "xylophone".
Only the `R123` identifier is immutable: the others can be changed later by
adjusting the callsign or short name for the repository.
Commit Identifiers
==================
Diffusion uses repository identifiers and information about the commit itself
to generate globally unique identifers for each commit, like `rE12345`.
Each commit may have several identifiers:
- A repository **ID** identifier, like `R123:abcdef123...`.
- A repository **callsign** identifier, like `rXYZabcdef123...`. This only
works if a repository has a callsign.
- Any unique prefix of the commit hash.
Git and Mercurial use commit hashes to identify commits, and Phabricator will
recognize a commit if the hash prefix is unique and sufficiently long. Commit
hashes qualified with a repository identifier must be at least 5 characters
long; unqualified commit hashes must be at least 7 characters long.
In Subversion, commit identifiers are sequential integers and prefixes can not
be used to identify them.
When rendering the name of a Git or Mercurial commit hash, Phabricator tends to
shorten it to 12 characters. This "short length" is relatively long compared to
Git itself (which often uses 7 characters). See this post on the LKML for a
historical explanation of Git's occasional internal use of 7-character hashes:
https://lkml.org/lkml/2010/10/28/287
Because 7-character hashes are likely to collide for even moderately large
repositories, Diffusion generally uses either a 12-character prefix (which makes
collisions very unlikely) or the full 40-character hash (which makes collisions
astronomically unlikely).
Next Steps
==========
Continue by:
- returning to the @{article:Diffusion User Guide}.

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jul 29, 8:27 AM (3 w, 20 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
188359
Default Alt Text
(58 KB)

Event Timeline