Page MenuHomestyx hydra

No OneTemporary

diff --git a/resources/sql/patches/20131121.repocredentials.1.col.sql b/resources/sql/patches/20131121.repocredentials.1.col.sql
new file mode 100644
index 0000000000..9471c7189b
--- /dev/null
+++ b/resources/sql/patches/20131121.repocredentials.1.col.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {$NAMESPACE}_repository.repository
+ ADD credentialPHID VARCHAR(64) COLLATE utf8_bin;
diff --git a/resources/sql/patches/20131121.repocredentials.2.mig.php b/resources/sql/patches/20131121.repocredentials.2.mig.php
new file mode 100644
index 0000000000..d9735d6b5b
--- /dev/null
+++ b/resources/sql/patches/20131121.repocredentials.2.mig.php
@@ -0,0 +1,104 @@
+<?php
+
+$table = new PhabricatorRepository();
+$conn_w = $table->establishConnection('w');
+$viewer = PhabricatorUser::getOmnipotentUser();
+
+$map = array();
+foreach (new LiskMigrationIterator($table) as $repository) {
+ $callsign = $repository->getCallsign();
+ echo "Examining repository {$callsign}...\n";
+
+ if ($repository->getCredentialPHID()) {
+ echo "...already has a Credential.\n";
+ continue;
+ }
+
+ $uri = $repository->getRemoteURI();
+ if (!$uri) {
+ echo "...no remote URI.\n";
+ continue;
+ }
+
+ $uri = new PhutilURI($uri);
+
+ $proto = strtolower($uri->getProtocol());
+ if ($proto == 'http' || $proto == 'https' || $proto == 'svn') {
+ $username = $repository->getDetail('http-login');
+ $secret = $repository->getDetail('http-pass');
+ $type = PassphraseCredentialTypePassword::CREDENTIAL_TYPE;
+ } else {
+ $username = $repository->getDetail('ssh-login');
+ $file = $repository->getDetail('ssh-keyfile');
+ if ($file) {
+ $secret = $file;
+ $type = PassphraseCredentialTypeSSHPrivateKeyFile::CREDENTIAL_TYPE;
+ } else {
+ $secret = $repository->getDetail('ssh-key');
+ $type = PassphraseCredentialTypeSSHPrivateKeyText::CREDENTIAL_TYPE;
+ }
+ }
+
+ if (!$username || !$secret) {
+ echo "...no credentials set.\n";
+ continue;
+ }
+
+ $map[$type][$username][$secret][] = $repository;
+ echo "...will migrate.\n";
+}
+
+$passphrase = new PassphraseSecret();
+$passphrase->openTransaction();
+$table->openTransaction();
+
+foreach ($map as $credential_type => $credential_usernames) {
+ $type = PassphraseCredentialType::getTypeByConstant($credential_type);
+ foreach ($credential_usernames as $username => $credential_secrets) {
+ foreach ($credential_secrets as $secret_plaintext => $repositories) {
+ $callsigns = mpull($repositories, 'getCallsign');
+ $name = pht(
+ 'Migrated Repository Credential (%s)',
+ implode(', ', $callsigns));
+
+ echo "Creating: {$name}...\n";
+
+ $secret = id(new PassphraseSecret())
+ ->setSecretData($secret_plaintext)
+ ->save();
+
+ $secret_id = $secret->getID();
+
+ $credential = PassphraseCredential::initializeNewCredential($viewer)
+ ->setCredentialType($type->getCredentialType())
+ ->setProvidesType($type->getProvidesType())
+ ->setViewPolicy(PhabricatorPolicies::POLICY_ADMIN)
+ ->setEditPolicy(PhabricatorPolicies::POLICY_ADMIN)
+ ->setName($name)
+ ->setUsername($username)
+ ->setSecretID($secret_id)
+ ->save();
+
+ foreach ($repositories as $repository) {
+ queryfx(
+ $conn_w,
+ 'UPDATE %T SET credentialPHID = %s WHERE id = %d',
+ $table->getTableName(),
+ $credential->getPHID(),
+ $repository->getID());
+
+ $edge_type = PhabricatorEdgeConfig::TYPE_OBJECT_USES_CREDENTIAL;
+
+ id(new PhabricatorEdgeEditor())
+ ->setActor($viewer)
+ ->addEdge($repository->getPHID(), $edge_type, $credential->getPHID())
+ ->save();
+ }
+ }
+ }
+}
+
+$table->saveTransaction();
+$passphrase->saveTransaction();
+
+echo "Done.\n";
diff --git a/scripts/ssh/ssh-connect.php b/scripts/ssh/ssh-connect.php
index 2f28778565..03e1caa77a 100755
--- a/scripts/ssh/ssh-connect.php
+++ b/scripts/ssh/ssh-connect.php
@@ -1,71 +1,57 @@
#!/usr/bin/env php
<?php
// This is a wrapper script for Git, Mercurial, and Subversion. It primarily
// serves to inject "-o StrictHostKeyChecking=no" into the SSH arguments.
$root = dirname(dirname(dirname(__FILE__)));
require_once $root.'/scripts/__init_script__.php';
$target_name = getenv('PHABRICATOR_SSH_TARGET');
if (!$target_name) {
throw new Exception(pht("No 'PHABRICATOR_SSH_TARGET' in environment!"));
}
+$viewer = PhabricatorUser::getOmnipotentUser();
+
$repository = id(new PhabricatorRepositoryQuery())
- ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->setViewer($viewer)
->withCallsigns(array($target_name))
->executeOne();
if (!$repository) {
throw new Exception(pht('No repository with callsign "%s"!', $target_name));
}
$pattern = array();
$arguments = array();
$pattern[] = 'ssh';
$pattern[] = '-o';
$pattern[] = 'StrictHostKeyChecking=no';
-$login = $repository->getSSHLogin();
-if (strlen($login)) {
- $pattern[] = '-l';
- $pattern[] = '%P';
- $arguments[] = new PhutilOpaqueEnvelope($login);
-}
-
-$ssh_identity = null;
-
-$key = $repository->getDetail('ssh-key');
-$keyfile = $repository->getDetail('ssh-keyfile');
-if ($keyfile) {
- $ssh_identity = $keyfile;
-} else if ($key) {
- $tmpfile = new TempFile('phabricator-repository-ssh-key');
- chmod($tmpfile, 0600);
- Filesystem::writeFile($tmpfile, $key);
- $ssh_identity = (string)$tmpfile;
-}
+$credential_phid = $repository->getCredentialPHID();
+if ($credential_phid) {
+ $key = PassphraseSSHKey::loadFromPHID($credential_phid, $viewer);
-if ($ssh_identity) {
- $pattern[] = '-i';
- $pattern[] = '%P';
- $arguments[] = new PhutilOpaqueEnvelope($keyfile);
+ $pattern[] = '-l %P';
+ $arguments[] = $key->getUsernameEnvelope();
+ $pattern[] = '-i %P';
+ $arguments[] = $key->getKeyfileEnvelope();
}
$pattern[] = '--';
$passthru_args = array_slice($argv, 1);
foreach ($passthru_args as $passthru_arg) {
$pattern[] = '%s';
$arguments[] = $passthru_arg;
}
$pattern = implode(' ', $pattern);
array_unshift($arguments, $pattern);
$err = newv('PhutilExecPassthru', $arguments)
->execute();
exit($err);
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php b/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php
index 36ad1feb83..6bb3b0f70c 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php
@@ -1,818 +1,768 @@
<?php
final class DiffusionRepositoryCreateController
extends DiffusionRepositoryEditController {
private $edit;
private $repository;
public function willProcessRequest(array $data) {
parent::willProcessRequest($data);
$this->edit = $data['edit'];
}
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
// NOTE: We can end up here via either "Create Repository", or via
// "Import Repository", or via "Edit Remote". In the latter case, we show
// only a few of the pages.
$repository = null;
switch ($this->edit) {
case 'remote':
$repository = $this->getDiffusionRequest()->getRepository();
// Make sure we have CAN_EDIT.
PhabricatorPolicyFilter::requireCapability(
$viewer,
$repository,
PhabricatorPolicyCapability::CAN_EDIT);
$this->setRepository($repository);
$cancel_uri = $this->getRepositoryControllerURI($repository, 'edit/');
break;
case 'import':
case 'create':
$this->requireApplicationCapability(
DiffusionCapabilityCreateRepositories::CAPABILITY);
$cancel_uri = $this->getApplicationURI('new/');
break;
default:
throw new Exception("Invalid edit operation!");
}
$form = id(new PHUIPagedFormView())
->setUser($viewer)
->setCancelURI($cancel_uri);
switch ($this->edit) {
case 'remote':
$title = pht('Edit Remote');
$form
->addPage('remote-uri', $this->buildRemoteURIPage())
->addPage('auth', $this->buildAuthPage());
break;
case 'create':
$title = pht('Create Repository');
$form
->addPage('vcs', $this->buildVCSPage())
->addPage('name', $this->buildNamePage())
->addPage('done', $this->buildDonePage());
break;
case 'import':
$title = pht('Import Repository');
$form
->addPage('vcs', $this->buildVCSPage())
->addPage('name', $this->buildNamePage())
->addPage('remote-uri', $this->buildRemoteURIPage())
->addPage('auth', $this->buildAuthPage())
->addPage('done', $this->buildDonePage());
break;
}
if ($request->isFormPost()) {
$form->readFromRequest($request);
if ($form->isComplete()) {
$is_create = ($this->edit === 'import' || $this->edit === 'create');
$is_auth = ($this->edit == 'import' || $this->edit == 'remote');
$is_init = ($this->edit == 'create');
if ($is_create) {
$repository = PhabricatorRepository::initializeNewRepository(
$viewer);
}
$template = id(new PhabricatorRepositoryTransaction());
$type_name = PhabricatorRepositoryTransaction::TYPE_NAME;
$type_vcs = PhabricatorRepositoryTransaction::TYPE_VCS;
$type_activate = PhabricatorRepositoryTransaction::TYPE_ACTIVATE;
$type_local_path = PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH;
$type_remote_uri = PhabricatorRepositoryTransaction::TYPE_REMOTE_URI;
- $type_ssh_login = PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN;
- $type_ssh_key = PhabricatorRepositoryTransaction::TYPE_SSH_KEY;
- $type_ssh_keyfile = PhabricatorRepositoryTransaction::TYPE_SSH_KEYFILE;
- $type_http_login = PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN;
- $type_http_pass = PhabricatorRepositoryTransaction::TYPE_HTTP_PASS;
$type_hosting = PhabricatorRepositoryTransaction::TYPE_HOSTING;
+ $type_credential = PhabricatorRepositoryTransaction::TYPE_CREDENTIAL;
$xactions = array();
// If we're creating a new repository, set all this core stuff.
if ($is_create) {
$callsign = $form->getPage('name')
->getControl('callsign')->getValue();
// We must set this to a unique value to save the repository
// initially, and it's immutable, so we don't bother using
// transactions to apply this change.
$repository->setCallsign($callsign);
// Put the repository in "Importing" mode until we finish
// parsing it.
$repository->setDetail('importing', true);
$xactions[] = id(clone $template)
->setTransactionType($type_name)
->setNewValue(
$form->getPage('name')->getControl('name')->getValue());
$xactions[] = id(clone $template)
->setTransactionType($type_vcs)
->setNewValue(
$form->getPage('vcs')->getControl('vcs')->getValue());
$activate = $form->getPage('done')
->getControl('activate')->getValue();
$xactions[] = id(clone $template)
->setTransactionType($type_activate)
->setNewValue(
($activate == 'start'));
$default_local_path = PhabricatorEnv::getEnvConfig(
'repository.default-local-path');
$default_local_path = rtrim($default_local_path, '/');
$default_local_path = $default_local_path.'/'.$callsign.'/';
$xactions[] = id(clone $template)
->setTransactionType($type_local_path)
->setNewValue($default_local_path);
}
if ($is_init) {
$xactions[] = id(clone $template)
->setTransactionType($type_hosting)
->setNewValue(true);
}
if ($is_auth) {
$xactions[] = id(clone $template)
->setTransactionType($type_remote_uri)
->setNewValue(
$form->getPage('remote-uri')->getControl('remoteURI')
->getValue());
$xactions[] = id(clone $template)
- ->setTransactionType($type_ssh_login)
+ ->setTransactionType($type_credential)
->setNewValue(
- $form->getPage('auth')->getControl('ssh-login')->getValue());
-
- $xactions[] = id(clone $template)
- ->setTransactionType($type_ssh_key)
- ->setNewValue(
- $form->getPage('auth')->getControl('ssh-key')->getValue());
-
- $xactions[] = id(clone $template)
- ->setTransactionType($type_ssh_keyfile)
- ->setNewValue(
- $form->getPage('auth')->getControl('ssh-keyfile')->getValue());
-
- $xactions[] = id(clone $template)
- ->setTransactionType($type_http_login)
- ->setNewValue(
- $form->getPage('auth')->getControl('http-login')->getValue());
-
- $xactions[] = id(clone $template)
- ->setTransactionType($type_http_pass)
- ->setNewValue(
- $form->getPage('auth')->getControl('http-pass')->getValue());
+ $form->getPage('auth')->getControl('credential')->getValue());
}
id(new PhabricatorRepositoryEditor())
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->setActor($viewer)
->applyTransactions($repository, $xactions);
$repo_uri = $this->getRepositoryControllerURI($repository, 'edit/');
return id(new AphrontRedirectResponse())->setURI($repo_uri);
}
} else {
$dict = array();
if ($repository) {
$dict = array(
'remoteURI' => $repository->getRemoteURI(),
- 'ssh-login' => $repository->getDetail('ssh-login'),
- 'ssh-key' => $repository->getDetail('ssh-key'),
- 'ssh-keyfile' => $repository->getDetail('ssh-keyfile'),
- 'http-login' => $repository->getDetail('http-login'),
- 'http-pass' => $repository->getDetail('http-pass'),
+ 'credential' => $repository->getCredentialPHID(),
);
}
$form->readFromObject($dict);
}
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addCrumb(
id(new PhabricatorCrumbView())
->setName($title));
return $this->buildApplicationPage(
array(
$crumbs,
$form,
),
array(
'title' => $title,
'device' => true,
));
}
/* -( Page: VCS Type )----------------------------------------------------- */
private function buildVCSPage() {
$is_import = ($this->edit == 'import');
if ($is_import) {
$git_str = pht(
'Import a Git repository (for example, a repository hosted '.
'on GitHub).');
$hg_str = pht(
'Import a Mercurial repository (for example, a repository '.
'hosted on Bitbucket).');
$svn_str = pht('Import a Subversion repository.');
} else {
$git_str = pht('Create a new, empty Git repository.');
$hg_str = pht('Create a new, empty Mercurial repository.');
$svn_str = pht('Create a new, empty Subversion repository.');
}
$control = id(new AphrontFormRadioButtonControl())
->setName('vcs')
->setLabel(pht('Type'))
->addButton(
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT,
pht('Git'),
$git_str)
->addButton(
PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL,
pht('Mercurial'),
$hg_str)
->addButton(
PhabricatorRepositoryType::REPOSITORY_TYPE_SVN,
pht('Subversion'),
$svn_str);
if ($is_import) {
$control->addButton(
PhabricatorRepositoryType::REPOSITORY_TYPE_PERFORCE,
pht('Perforce'),
pht(
'Perforce is not directly supported, but you can import '.
'a Perforce repository as a Git repository using %s.',
phutil_tag(
'a',
array(
'href' =>
'http://www.perforce.com/product/components/git-fusion',
'target' => '_blank',
),
pht('Perforce Git Fusion'))),
'disabled',
$disabled = true);
}
return id(new PHUIFormPageView())
->setPageName(pht('Repository Type'))
->setUser($this->getRequest()->getUser())
->setValidateFormPageCallback(array($this, 'validateVCSPage'))
->addControl($control);
}
public function validateVCSPage(PHUIFormPageView $page) {
$valid = array(
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT => true,
PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL => true,
PhabricatorRepositoryType::REPOSITORY_TYPE_SVN => true,
);
$c_vcs = $page->getControl('vcs');
$v_vcs = $c_vcs->getValue();
if (!$v_vcs) {
$c_vcs->setError(pht('Required'));
$page->addPageError(
pht('You must select a version control system.'));
} else if (empty($valid[$v_vcs])) {
$c_vcs->setError(pht('Invalid'));
$page->addPageError(
pht('You must select a valid version control system.'));
}
return $c_vcs->isValid();
}
/* -( Page: Name and Callsign )-------------------------------------------- */
private function buildNamePage() {
return id(new PHUIFormPageView())
->setUser($this->getRequest()->getUser())
->setPageName(pht('Repository Name and Location'))
->setValidateFormPageCallback(array($this, 'validateNamePage'))
->addRemarkupInstructions(
pht(
'**Choose a human-readable name for this repository**, like '.
'"CompanyName Mobile App" or "CompanyName Backend Server". You '.
'can change this later.'))
->addControl(
id(new AphrontFormTextControl())
->setName('name')
->setLabel(pht('Name'))
->setCaption(pht('Human-readable repository name.')))
->addRemarkupInstructions(
pht(
'**Choose a "Callsign" for the repository.** This is a short, '.
'unique string which identifies commits elsewhere in Phabricator. '.
'For example, you might use `M` for your mobile app repository '.
'and `B` for your backend repository.'.
"\n\n".
'**Callsigns must be UPPERCASE**, and can not be edited after the '.
'repository is created. Generally, you should choose short '.
'callsigns.'))
->addControl(
id(new AphrontFormTextControl())
->setName('callsign')
->setLabel(pht('Callsign'))
->setCaption(pht('Short UPPERCASE identifier.')));
}
public function validateNamePage(PHUIFormPageView $page) {
$c_name = $page->getControl('name');
$v_name = $c_name->getValue();
if (!strlen($v_name)) {
$c_name->setError(pht('Required'));
$page->addPageError(
pht('You must choose a name for this repository.'));
}
$c_call = $page->getControl('callsign');
$v_call = $c_call->getValue();
if (!strlen($v_call)) {
$c_call->setError(pht('Required'));
$page->addPageError(
pht('You must choose a callsign for this repository.'));
} else if (!preg_match('/^[A-Z]+$/', $v_call)) {
$c_call->setError(pht('Invalid'));
$page->addPageError(
pht('The callsign must contain only UPPERCASE letters.'));
} else {
$exists = false;
try {
$repo = id(new PhabricatorRepositoryQuery())
->setViewer($this->getRequest()->getUser())
->withCallsigns(array($v_call))
->executeOne();
$exists = (bool)$repo;
} catch (PhabricatorPolicyException $ex) {
$exists = true;
}
if ($exists) {
$c_call->setError(pht('Not Unique'));
$page->addPageError(
pht(
'Another repository already uses that callsign. You must choose '.
'a unique callsign.'));
}
}
return $c_name->isValid() &&
$c_call->isValid();
}
/* -( Page: Remote URI )--------------------------------------------------- */
private function buildRemoteURIPage() {
return id(new PHUIFormPageView())
->setUser($this->getRequest()->getUser())
->setPageName(pht('Repository Remote URI'))
->setValidateFormPageCallback(array($this, 'validateRemoteURIPage'))
->setAdjustFormPageCallback(array($this, 'adjustRemoteURIPage'))
->addControl(
id(new AphrontFormTextControl())
->setName('remoteURI'));
}
public function adjustRemoteURIPage(PHUIFormPageView $page) {
$form = $page->getForm();
$is_git = false;
$is_svn = false;
$is_mercurial = false;
if ($this->getRepository()) {
$vcs = $this->getRepository()->getVersionControlSystem();
} else {
$vcs = $form->getPage('vcs')->getControl('vcs')->getValue();
}
switch ($vcs) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$is_git = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$is_svn = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$is_mercurial = true;
break;
default:
throw new Exception("Unsupported VCS!");
}
$has_local = ($is_git || $is_mercurial);
if ($is_git) {
$uri_label = pht('Remote URI');
$instructions = pht(
'Enter the URI to clone this Git repository from. It should usually '.
'look like one of these examples:'.
"\n\n".
"| Example Git Remote URIs |\n".
"| ----------------------- |\n".
"| `git@github.com:example/example.git` |\n".
"| `ssh://user@host.com/git/example.git` |\n".
"| `file:///local/path/to/repo` |\n".
"| `https://example.com/repository.git` |\n");
} else if ($is_mercurial) {
$uri_label = pht('Remote URI');
$instructions = pht(
'Enter the URI to clone this Mercurial repository from. It should '.
'usually look like one of these examples:'.
"\n\n".
"| Example Mercurial Remote URIs |\n".
"| ----------------------- |\n".
"| `ssh://hg@bitbucket.org/example/repository` |\n".
"| `file:///local/path/to/repo` |\n");
} else if ($is_svn) {
$uri_label = pht('Repository Root');
$instructions = pht(
'Enter the **Repository Root** for this Subversion repository. '.
'You can figure this out by running `svn info` in a working copy '.
'and looking at the value in the `Repository Root` field. It '.
'should be a URI and will usually look like these:'.
"\n\n".
"| Example Subversion Repository Root URIs |\n".
"| ------------------------------ |\n".
"| `http://svn.example.org/svnroot/` |\n".
"| `svn+ssh://svn.example.com/svnroot/` |\n".
"| `svn://svn.example.net/svnroot/` |\n".
"| `file:///local/path/to/svnroot/` |\n".
"\n\n".
"Make sure you specify the root of the repository, not a ".
"subdirectory.");
} else {
throw new Exception("Unsupported VCS!");
}
$page->addRemarkupInstructions($instructions, 'remoteURI');
$page->getControl('remoteURI')->setLabel($uri_label);
}
public function validateRemoteURIPage(PHUIFormPageView $page) {
$c_remote = $page->getControl('remoteURI');
$v_remote = $c_remote->getValue();
if (!strlen($v_remote)) {
$c_remote->setError(pht('Required'));
$page->addPageError(
pht("You must specify a URI."));
} else {
$proto = $this->getRemoteURIProtocol($v_remote);
if ($proto === 'file') {
if (!preg_match('@^file:///@', $v_remote)) {
$c_remote->setError(pht('Invalid'));
$page->addPageError(
pht(
"URIs using the 'file://' protocol should have three slashes ".
"(e.g., 'file:///absolute/path/to/file'). You only have two. ".
"Add another one."));
}
}
// Catch confusion between Git/SCP-style URIs and normal URIs. See T3619
// for discussion. This is usually a user adding "ssh://" to an implicit
// SSH Git URI.
if ($proto == 'ssh') {
if (preg_match('(^[^:@]+://[^/:]+:[^\d])', $v_remote)) {
$c_remote->setError(pht('Invalid'));
$page->addPageError(
pht(
"The Remote URI is not formatted correctly. Remote URIs ".
"with an explicit protocol should be in the form ".
"'proto://domain/path', not 'proto://domain:/path'. ".
"The ':/path' syntax is only valid in SCP-style URIs."));
}
}
switch ($proto) {
case 'ssh':
case 'http':
case 'https':
case 'file':
case 'git':
case 'svn':
case 'svn+ssh':
break;
default:
$c_remote->setError(pht('Invalid'));
$page->addPageError(
pht(
"The URI protocol is unrecognized. It should begin ".
"'ssh://', 'http://', 'https://', 'file://', 'git://', ".
"'svn://', 'svn+ssh://', or be in the form ".
"'git@domain.com:path'."));
break;
}
}
return $c_remote->isValid();
}
/* -( Page: Authentication )----------------------------------------------- */
public function buildAuthPage() {
return id(new PHUIFormPageView())
->setPageName(pht('Authentication'))
->setUser($this->getRequest()->getUser())
->setAdjustFormPageCallback(array($this, 'adjustAuthPage'))
->addControl(
- id(new AphrontFormTextControl())
- ->setName('ssh-login')
- ->setLabel('SSH User'))
- ->addControl(
- id(new AphrontFormTextAreaControl())
- ->setName('ssh-key')
- ->setLabel('SSH Private Key')
- ->setHeight(AphrontFormTextAreaControl::HEIGHT_SHORT)
- ->setCaption(
- hsprintf('Specify the entire private key, <em>or</em>...')))
- ->addControl(
- id(new AphrontFormTextControl())
- ->setName('ssh-keyfile')
- ->setLabel('SSH Private Key Path')
- ->setCaption(
- '...specify a path on disk where the daemon should '.
- 'look for a private key.'))
- ->addControl(
- id(new AphrontFormTextControl())
- ->setName('http-login')
- ->setLabel('Username'))
- ->addControl(
- id(new AphrontFormPasswordControl())
- ->setName('http-pass')
- ->setLabel('Password'));
+ id(new PassphraseCredentialControl())
+ ->setName('credential'));
}
public function adjustAuthPage($page) {
$form = $page->getForm();
- $remote_uri = $form->getPage('remote-uri')
- ->getControl('remoteURI')
- ->getValue();
-
if ($this->getRepository()) {
$vcs = $this->getRepository()->getVersionControlSystem();
} else {
$vcs = $form->getPage('vcs')->getControl('vcs')->getValue();
}
+ $remote_uri = $form->getPage('remote-uri')
+ ->getControl('remoteURI')
+ ->getValue();
$proto = $this->getRemoteURIProtocol($remote_uri);
$remote_user = $this->getRemoteURIUser($remote_uri);
- $page->getControl('ssh-login')->setHidden(true);
- $page->getControl('ssh-key')->setHidden(true);
- $page->getControl('ssh-keyfile')->setHidden(true);
- $page->getControl('http-login')->setHidden(true);
- $page->getControl('http-pass')->setHidden(true);
+ $c_credential = $page->getControl('credential');
+ $c_credential->setDefaultUsername($remote_user);
if ($this->isSSHProtocol($proto)) {
- $page->getControl('ssh-login')->setHidden(false);
- $page->getControl('ssh-key')->setHidden(false);
- $page->getControl('ssh-keyfile')->setHidden(false);
-
- $c_login = $page->getControl('ssh-login');
- if (!strlen($c_login->getValue())) {
- $c_login->setValue($remote_user);
- }
+ $c_credential->setLabel(pht('SSH Key'));
+ $c_credential->setCredentialType(
+ PassphraseCredentialTypeSSHPrivateKeyText::CREDENTIAL_TYPE);
+ $provides_type = PassphraseCredentialTypeSSHPrivateKey::PROVIDES_TYPE;
$page->addRemarkupInstructions(
pht(
- 'Enter the username and private key to use to connect to the '.
- 'the repository hosted at:'.
+ 'Choose or add the SSH credentials to use to connect to the the '.
+ 'repository hosted at:'.
"\n\n".
" lang=text\n".
- " %s".
- "\n\n".
- 'You can either copy/paste the entire private key, or put it '.
- 'somewhere on disk and provide the path to it.',
+ " %s",
$remote_uri),
- 'ssh-login');
-
+ 'credential');
} else if ($this->isUsernamePasswordProtocol($proto)) {
- $page->getControl('http-login')->setHidden(false);
- $page->getControl('http-pass')->setHidden(false);
+ $c_credential->setLabel(pht('Password'));
+ $c_credential->setAllowNull(true);
+ $c_credential->setCredentialType(
+ PassphraseCredentialTypePassword::CREDENTIAL_TYPE);
+ $provides_type = PassphraseCredentialTypePassword::PROVIDES_TYPE;
$page->addRemarkupInstructions(
pht(
- 'Enter the a username and pasword used to connect to the '.
+ 'Choose the a username and pasword used to connect to the '.
'repository hosted at:'.
"\n\n".
" lang=text\n".
" %s".
"\n\n".
"If this repository does not require a username or password, ".
- "you can leave these fields blank.",
+ "you can continue to the next step.",
$remote_uri),
- 'http-login');
+ 'credential');
} else if ($proto == 'file') {
+ $c_credential->setHidden(true);
$page->addRemarkupInstructions(
pht(
- 'You do not need to configure any authentication options for '.
- 'repositories accessed over the `file://` protocol. Continue '.
- 'to the next step.'),
- 'ssh-login');
+ 'You do not need to configure any credentials for repositories '.
+ 'accessed over the `file://` protocol. Continue to the next step.'),
+ 'credential');
} else {
throw new Exception("Unknown URI protocol!");
}
+
+ if ($provides_type) {
+ $viewer = $this->getRequest()->getUser();
+
+ $options = id(new PassphraseCredentialQuery())
+ ->setViewer($viewer)
+ ->withIsDestroyed(false)
+ ->withProvidesTypes(array($provides_type))
+ ->execute();
+
+ $c_credential->setOptions($options);
+ }
+
}
public function validateAuthPage(PHUIFormPageView $page) {
$form = $page->getForm();
$remote_uri = $form->getPage('remote')->getControl('remoteURI')->getValue();
$proto = $this->getRemoteURIProtocol($remote_uri);
- if ($this->isSSHProtocol($proto)) {
- $c_user = $page->getControl('ssh-login');
- $c_key = $page->getControl('ssh-key');
- $c_file = $page->getControl('ssh-keyfile');
+ $c_credential = $page->getControl('credential');
+ $v_credential = $c_credential->getValue();
- $v_user = $c_user->getValue();
- $v_key = $c_key->getValue();
- $v_file = $c_file->getValue();
+ // NOTE: We're using the omnipotent user here because the viewer might be
+ // editing a repository they're allowed to edit which uses a credential they
+ // are not allowed to see. This is fine, as long as they don't change it.
+ $credential = id(new PassphraseCredentialQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withPHIDs(array($v_credential))
+ ->executeOne();
- if (!strlen($v_user)) {
- $c_user->setError(pht('Required'));
+ if ($this->isSSHProtocol($proto)) {
+ if (!$credential) {
+ $c_credential->setError(pht('Required'));
$page->addPageError(
- pht('You must provide an SSH login username to connect over SSH.'));
+ pht('You must choose an SSH credential to connect over SSH.'));
}
- if (!strlen($v_key) && !strlen($v_file)) {
- $c_key->setError(pht('No Key'));
- $c_file->setError(pht('No Key'));
+ $ssh_type = PassphraseCredentialTypeSSHPrivateKey::PROVIDES_TYPE;
+ if ($credential->getProvidesType() !== $ssh_type) {
+ $c_credential->setError(pht('Invalid'));
$page->addPageError(
pht(
- 'You must provide either a private key or the path to a private '.
- 'key to connect over SSH.'));
- } else if (strlen($v_key) && strlen($v_file)) {
- $c_key->setError(pht('Ambiguous'));
- $c_file->setError(pht('Ambiguous'));
- $page->addPageError(
- pht(
- 'Provide either a private key or the path to a private key, not '.
- 'both.'));
- } else if (!preg_match('/PRIVATE KEY/', $v_key)) {
- $c_key->setError(pht('Invalid'));
+ 'You must choose an SSH credential, not some other type '.
+ 'of credential.'));
+ }
+
+ } else if ($this->isUsernamePasswordProtocol($proto)) {
+ if ($credential) {
+ $password_type = PassphraseCredentialTypePassword::PROVIDES_TYPE;
+ if ($credential->getProvidesType() !== $password_type) {
+ $c_credential->setError(pht('Invalid'));
$page->addPageError(
pht(
- 'The private key you provided is missing the PRIVATE KEY header. '.
- 'You should include the header and footer. (Did you provide a '.
- 'public key by mistake?)'));
+ 'You must choose a username/password credential, not some other '.
+ 'type of credential.'));
+ }
}
- return $c_user->isValid() &&
- $c_key->isValid() &&
- $c_file->isValid();
- } else if ($this->isUsernamePasswordProtocol($proto)) {
- return true;
+ return $c_credential->isValid();
} else {
return true;
}
}
/* -( Page: Done )--------------------------------------------------------- */
private function buildDonePage() {
$is_create = ($this->edit == 'create');
if ($is_create) {
$now_label = pht('Create Repository Now');
$now_caption = pht(
'Create the repository right away. This will create the repository '.
'using default settings.');
$wait_label = pht('Configure More Options First');
$wait_caption = pht(
'Configure more options before creating the repository. '.
'This will let you fine-tune settings. You can create the repository '.
'whenever you are ready.');
} else {
$now_label = pht('Start Import Now');
$now_caption = pht(
'Start importing the repository right away. This will import '.
'the entire repository using default settings.');
$wait_label = pht('Configure More Options First');
$wait_caption = pht(
'Configure more options before beginning the repository '.
'import. This will let you fine-tune settings. You can '.
'start the import whenever you are ready.');
}
return id(new PHUIFormPageView())
->setPageName(pht('Repository Ready!'))
->setValidateFormPageCallback(array($this, 'validateDonePage'))
->setUser($this->getRequest()->getUser())
->addControl(
id(new AphrontFormRadioButtonControl())
->setName('activate')
->setLabel(pht('Start Now'))
->addButton(
'start',
$now_label,
$now_caption)
->addButton(
'wait',
$wait_label,
$wait_caption));
}
public function validateDonePage(PHUIFormPageView $page) {
$c_activate = $page->getControl('activate');
$v_activate = $c_activate->getValue();
if ($v_activate != 'start' && $v_activate != 'wait') {
$c_activate->setError(pht('Required'));
$page->addPageError(
pht('Make a choice about repository activation.'));
}
return $c_activate->isValid();
}
/* -( Internal )----------------------------------------------------------- */
private function getRemoteURIProtocol($raw_uri) {
$uri = new PhutilURI($raw_uri);
if ($uri->getProtocol()) {
return strtolower($uri->getProtocol());
}
$git_uri = new PhutilGitURI($raw_uri);
if (strlen($git_uri->getDomain()) && strlen($git_uri->getPath())) {
return 'ssh';
}
return null;
}
private function getRemoteURIUser($raw_uri) {
$uri = new PhutilURI($raw_uri);
if ($uri->getUser()) {
return $uri->getUser();
}
$git_uri = new PhutilGitURI($raw_uri);
if (strlen($git_uri->getDomain()) && strlen($git_uri->getPath())) {
return $git_uri->getUser();
}
return null;
}
private function isSSHProtocol($proto) {
return ($proto == 'git' || $proto == 'ssh' || $proto == 'svn+ssh');
}
private function isUsernamePasswordProtocol($proto) {
return ($proto == 'http' || $proto == 'https' || $proto == 'svn');
}
private function setRepository(PhabricatorRepository $repository) {
$this->repository = $repository;
return $this;
}
private function getRepository() {
return $this->repository;
}
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php
index 5ba4423481..999ae7845f 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php
@@ -1,898 +1,906 @@
<?php
final class DiffusionRepositoryEditMainController
extends DiffusionRepositoryEditController {
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
$drequest = $this->diffusionRequest;
$repository = $drequest->getRepository();
PhabricatorPolicyFilter::requireCapability(
$viewer,
$repository,
PhabricatorPolicyCapability::CAN_EDIT);
$is_svn = false;
$is_git = false;
$is_hg = false;
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$is_git = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$is_svn = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$is_hg = true;
break;
}
$has_branches = ($is_git || $is_hg);
$has_local = $repository->usesLocalWorkingCopy();
$crumbs = $this->buildApplicationCrumbs($is_main = true);
$title = pht('Edit %s', $repository->getName());
$header = id(new PHUIHeaderView())
->setHeader($title);
if ($repository->isTracked()) {
$header->setStatus('oh-ok', '', pht('Active'));
} else {
$header->setStatus('policy-noone', '', pht('Inactive'));
}
$basic_actions = $this->buildBasicActions($repository);
$basic_properties =
$this->buildBasicProperties($repository, $basic_actions);
$policy_actions = $this->buildPolicyActions($repository);
$policy_properties =
$this->buildPolicyProperties($repository, $policy_actions);
$remote_properties = null;
if (!$repository->isHosted()) {
$remote_properties = $this->buildRemoteProperties(
$repository,
$this->buildRemoteActions($repository));
}
$encoding_actions = $this->buildEncodingActions($repository);
$encoding_properties =
$this->buildEncodingProperties($repository, $encoding_actions);
$hosting_properties = $this->buildHostingProperties(
$repository,
$this->buildHostingActions($repository));
$branches_properties = null;
if ($has_branches) {
$branches_properties = $this->buildBranchesProperties(
$repository,
$this->buildBranchesActions($repository));
}
$subversion_properties = null;
if ($is_svn) {
$subversion_properties = $this->buildSubversionProperties(
$repository,
$this->buildSubversionActions($repository));
}
$local_properties = null;
if ($has_local) {
$local_properties = $this->buildLocalProperties(
$repository,
$this->buildLocalActions($repository));
}
$actions_properties = $this->buildActionsProperties(
$repository,
$this->buildActionsActions($repository));
$xactions = id(new PhabricatorRepositoryTransactionQuery())
->setViewer($viewer)
->withObjectPHIDs(array($repository->getPHID()))
->execute();
$engine = id(new PhabricatorMarkupEngine())
->setViewer($viewer);
foreach ($xactions as $xaction) {
if ($xaction->getComment()) {
$engine->addObject(
$xaction->getComment(),
PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT);
}
}
$engine->process();
$xaction_view = id(new PhabricatorApplicationTransactionView())
->setUser($viewer)
->setObjectPHID($repository->getPHID())
->setTransactions($xactions)
->setMarkupEngine($engine);
$obj_box = id(new PHUIObjectBoxView())
->setHeader($header)
->addPropertyList($basic_properties)
->addPropertyList($policy_properties)
->addPropertyList($hosting_properties);
if ($remote_properties) {
$obj_box->addPropertyList($remote_properties);
}
if ($local_properties) {
$obj_box->addPropertyList($local_properties);
}
$obj_box->addPropertyList($encoding_properties);
if ($branches_properties) {
$obj_box->addPropertyList($branches_properties);
}
if ($subversion_properties) {
$obj_box->addPropertyList($subversion_properties);
}
$obj_box->addPropertyList($actions_properties);
return $this->buildApplicationPage(
array(
$crumbs,
$obj_box,
$xaction_view,
),
array(
'title' => $title,
'device' => true,
));
}
private function buildBasicActions(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser();
$view = id(new PhabricatorActionListView())
->setObjectURI($this->getRequest()->getRequestURI())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('edit')
->setName(pht('Edit Basic Information'))
->setHref($this->getRepositoryControllerURI($repository, 'edit/basic/'));
$view->addAction($edit);
$activate = id(new PhabricatorActionView())
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/activate/'))
->setWorkflow(true);
if ($repository->isTracked()) {
$activate
->setIcon('disable')
->setName(pht('Deactivate Repository'));
} else {
$activate
->setIcon('enable')
->setName(pht('Activate Repository'));
}
$view->addAction($activate);
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('Delete Repository'))
->setIcon('delete')
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/delete/'))
->setWorkflow(true));
return $view;
}
private function buildBasicProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions);
$type = PhabricatorRepositoryType::getNameForRepositoryType(
$repository->getVersionControlSystem());
$view->addProperty(pht('Type'), $type);
$view->addProperty(pht('Callsign'), $repository->getCallsign());
$view->addProperty(
pht('Status'),
$this->buildRepositoryStatus($repository));
$description = $repository->getDetail('description');
$view->addSectionHeader(pht('Description'));
if (!strlen($description)) {
$description = phutil_tag('em', array(), pht('No description provided.'));
} else {
$description = PhabricatorMarkupEngine::renderOneObject(
$repository,
'description',
$viewer);
}
$view->addTextContent($description);
return $view;
}
private function buildEncodingActions(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser();
$view = id(new PhabricatorActionListView())
->setObjectURI($this->getRequest()->getRequestURI())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('edit')
->setName(pht('Edit Text Encoding'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/encoding/'));
$view->addAction($edit);
return $view;
}
private function buildEncodingProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions)
->addSectionHeader(pht('Text Encoding'));
$encoding = $repository->getDetail('encoding');
if (!$encoding) {
$encoding = phutil_tag('em', array(), pht('Use Default (UTF-8)'));
}
$view->addProperty(pht('Encoding'), $encoding);
return $view;
}
private function buildPolicyActions(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser();
$view = id(new PhabricatorActionListView())
->setObjectURI($this->getRequest()->getRequestURI())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('edit')
->setName(pht('Edit Policies'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/policy/'));
$view->addAction($edit);
return $view;
}
private function buildPolicyProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions)
->addSectionHeader(pht('Policies'));
$descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
$viewer,
$repository);
$view->addProperty(
pht('Visible To'),
$descriptions[PhabricatorPolicyCapability::CAN_VIEW]);
$view->addProperty(
pht('Editable By'),
$descriptions[PhabricatorPolicyCapability::CAN_EDIT]);
$pushable = $repository->isHosted()
? $descriptions[DiffusionCapabilityPush::CAPABILITY]
: phutil_tag('em', array(), pht('Not a Hosted Repository'));
$view->addProperty(pht('Pushable By'), $pushable);
return $view;
}
private function buildBranchesActions(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser();
$view = id(new PhabricatorActionListView())
->setObjectURI($this->getRequest()->getRequestURI())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('edit')
->setName(pht('Edit Branches'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/branches/'));
$view->addAction($edit);
return $view;
}
private function buildBranchesProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions)
->addSectionHeader(pht('Branches'));
$default_branch = nonempty(
$repository->getHumanReadableDetail('default-branch'),
phutil_tag('em', array(), $repository->getDefaultBranch()));
$view->addProperty(pht('Default Branch'), $default_branch);
$track_only = nonempty(
$repository->getHumanReadableDetail('branch-filter', array()),
phutil_tag('em', array(), pht('Track All Branches')));
$view->addProperty(pht('Track Only'), $track_only);
$autoclose_only = nonempty(
$repository->getHumanReadableDetail('close-commits-filter', array()),
phutil_tag('em', array(), pht('Autoclose On All Branches')));
if ($repository->getDetail('disable-autoclose')) {
$autoclose_only = phutil_tag('em', array(), pht('Disabled'));
}
$view->addProperty(pht('Autoclose Only'), $autoclose_only);
return $view;
}
private function buildSubversionActions(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser();
$view = id(new PhabricatorActionListView())
->setObjectURI($this->getRequest()->getRequestURI())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('edit')
->setName(pht('Edit Subversion Info'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/subversion/'));
$view->addAction($edit);
return $view;
}
private function buildSubversionProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions)
->addSectionHeader(pht('Subversion'));
$svn_uuid = nonempty(
$repository->getUUID(),
phutil_tag('em', array(), pht('Not Configured')));
$view->addProperty(pht('Subversion UUID'), $svn_uuid);
$svn_subpath = nonempty(
$repository->getHumanReadableDetail('svn-subpath'),
phutil_tag('em', array(), pht('Import Entire Repository')));
$view->addProperty(pht('Import Only'), $svn_subpath);
return $view;
}
private function buildActionsActions(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser();
$view = id(new PhabricatorActionListView())
->setObjectURI($this->getRequest()->getRequestURI())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('edit')
->setName(pht('Edit Actions'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/actions/'));
$view->addAction($edit);
return $view;
}
private function buildActionsProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions)
->addSectionHeader(pht('Actions'));
$notify = $repository->getDetail('herald-disabled')
? pht('Off')
: pht('On');
$notify = phutil_tag('em', array(), $notify);
$view->addProperty(pht('Publish/Notify'), $notify);
$autoclose = $repository->getDetail('disable-autoclose')
? pht('Off')
: pht('On');
$autoclose = phutil_tag('em', array(), $autoclose);
$view->addProperty(pht('Autoclose'), $autoclose);
return $view;
}
private function buildRemoteActions(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser();
$view = id(new PhabricatorActionListView())
->setObjectURI($this->getRequest()->getRequestURI())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('edit')
->setName(pht('Edit Remote'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/remote/'));
$view->addAction($edit);
return $view;
}
private function buildRemoteProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions)
->addSectionHeader(pht('Remote'));
$view->addProperty(
pht('Remote URI'),
$repository->getHumanReadableDetail('remote-uri'));
+ $credential_phid = $repository->getCredentialPHID();
+ if ($credential_phid) {
+ $this->loadHandles(array($credential_phid));
+ $view->addProperty(
+ pht('Credential'),
+ $this->getHandle($credential_phid)->renderLink());
+ }
+
return $view;
}
private function buildLocalActions(PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser();
$view = id(new PhabricatorActionListView())
->setObjectURI($this->getRequest()->getRequestURI())
->setUser($viewer);
$edit = id(new PhabricatorActionView())
->setIcon('edit')
->setName(pht('Edit Local'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/local/'));
$view->addAction($edit);
return $view;
}
private function buildLocalProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
$viewer = $this->getRequest()->getUser();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setActionList($actions)
->addSectionHeader(pht('Local'));
$view->addProperty(
pht('Local Path'),
$repository->getHumanReadableDetail('local-path'));
return $view;
}
private function buildHostingActions(PhabricatorRepository $repository) {
$user = $this->getRequest()->getUser();
$view = id(new PhabricatorActionListView())
->setObjectURI($this->getRequest()->getRequestURI())
->setUser($user);
$edit = id(new PhabricatorActionView())
->setIcon('edit')
->setName(pht('Edit Hosting'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/hosting/'));
$view->addAction($edit);
return $view;
}
private function buildHostingProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
$user = $this->getRequest()->getUser();
$view = id(new PHUIPropertyListView())
->setUser($user)
->setActionList($actions)
->addSectionHeader(pht('Hosting'));
$hosting = $repository->isHosted()
? pht('Hosted on Phabricator')
: pht('Hosted Elsewhere');
$view->addProperty(pht('Hosting'), phutil_tag('em', array(), $hosting));
$view->addProperty(
pht('Serve over HTTP'),
phutil_tag(
'em',
array(),
PhabricatorRepository::getProtocolAvailabilityName(
$repository->getServeOverHTTP())));
$view->addProperty(
pht('Serve over SSH'),
phutil_tag(
'em',
array(),
PhabricatorRepository::getProtocolAvailabilityName(
$repository->getServeOverSSH())));
return $view;
}
private function buildRepositoryStatus(
PhabricatorRepository $repository) {
$viewer = $this->getRequest()->getUser();
$view = new PHUIStatusListView();
$messages = id(new PhabricatorRepositoryStatusMessage())
->loadAllWhere('repositoryID = %d', $repository->getID());
$messages = mpull($messages, null, 'getStatusType');
if ($repository->isTracked()) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('accept-green')
->setTarget(pht('Repository Active')));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('warning')
->setTarget(pht('Repository Inactive'))
->setNote(
pht('Activate this repository to begin or resume import.')));
return $view;
}
$binaries = array();
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()) {
if ($repository->getServeOverHTTP() != PhabricatorRepository::SERVE_OFF) {
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$binaries[] = 'git-http-backend';
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$binaries[] = 'svnserve';
$binaries[] = 'svnadmin';
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$binaries[] = 'hg';
break;
}
}
if ($repository->getServeOverSSH() != PhabricatorRepository::SERVE_OFF) {
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';
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$binaries[] = 'hg';
break;
}
}
}
$binaries = array_unique($binaries);
foreach ($binaries as $binary) {
$where = Filesystem::resolveBinary($binary);
if (!$where) {
$config_href = '/config/edit/environment.append-paths/';
$config_link = phutil_tag(
'a',
array(
'href' => $config_href,
),
'environment.append-paths');
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('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.",
$config_link)));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('accept-green')
->setTarget(
pht('Found Binary %s', phutil_tag('tt', array(), $binary)))
->setNote(phutil_tag('tt', array(), $where)));
}
}
$doc_href = PhabricatorEnv::getDocLink(
'article/Managing_Daemons_with_phd.html');
$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) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('accept-green')
->setTarget(pht('Pull Daemon Running')));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('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('accept-green')
->setTarget(pht('Task Daemon Running')));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('warning-red')
->setTarget(pht('Task Daemon Not Running'))
->setNote($daemon_instructions));
}
if ($repository->usesLocalWorkingCopy()) {
$local_parent = dirname($repository->getLocalPath());
if (Filesystem::pathExists($local_parent)) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('accept-green')
->setTarget(pht('Storage Directory OK'))
->setNote(phutil_tag('tt', array(), $local_parent)));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('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('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('accept-green')
->setTarget(pht('Working Copy OK'))
->setNote(phutil_tag('tt', array(), $local_path)));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('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('time-green')
->setTarget(pht('Initializing Working Copy'))
->setNote(pht('Daemons are initializing the working copy.')));
return $view;
default:
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('warning-red')
->setTarget(pht('Unknown Init Status'))
->setNote($message->getStatusCode()));
return $view;
}
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('time-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:
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('warning-red')
->setTarget(pht('Update Error'))
->setNote($message->getParameter('message')));
return $view;
case PhabricatorRepositoryStatusMessage::CODE_OKAY:
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('accept-green')
->setTarget(pht('Updates OK'))
->setNote(
pht(
'Last updated %s.',
phabricator_datetime($message->getEpoch(), $viewer))));
break;
}
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('time-orange')
->setTarget(pht('Waiting For Update'))
->setNote(
pht('Waiting for daemons to read updates.')));
}
if ($repository->isImporting()) {
$progress = queryfx_all(
$repository->establishConnection('r'),
'SELECT importStatus, count(*) N FROM %T WHERE repositoryID = %d
GROUP BY importStatus',
id(new PhabricatorRepositoryCommit())->getTableName(),
$repository->getID());
$done = 0;
$total = 0;
foreach ($progress as $row) {
$total += $row['N'] * 4;
$status = $row['importStatus'];
if ($status & PhabricatorRepositoryCommit::IMPORTED_MESSAGE) {
$done += $row['N'];
}
if ($status & PhabricatorRepositoryCommit::IMPORTED_CHANGE) {
$done += $row['N'];
}
if ($status & PhabricatorRepositoryCommit::IMPORTED_OWNERS) {
$done += $row['N'];
}
if ($status & PhabricatorRepositoryCommit::IMPORTED_HERALD) {
$done += $row['N'];
}
}
if ($total) {
$percentage = 100 * ($done / $total);
} else {
$percentage = 0;
}
$percentage = sprintf('%.1f%%', $percentage);
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('time-green')
->setTarget(pht('Importing'))
->setNote(
pht('%s Complete', $percentage)));
} else {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('accept-green')
->setTarget(pht('Fully Imported')));
}
if (idx($messages, PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE)) {
$view->addItem(
id(new PHUIStatusItemView())
->setIcon('up')
->setTarget(pht('Prioritized'))
->setNote(pht('This repository will be updated soon.')));
}
return $view;
}
}
diff --git a/src/applications/passphrase/application/PhabricatorApplicationPassphrase.php b/src/applications/passphrase/application/PhabricatorApplicationPassphrase.php
index 493372262b..f2951353ed 100644
--- a/src/applications/passphrase/application/PhabricatorApplicationPassphrase.php
+++ b/src/applications/passphrase/application/PhabricatorApplicationPassphrase.php
@@ -1,46 +1,46 @@
<?php
final class PhabricatorApplicationPassphrase extends PhabricatorApplication {
public function getBaseURI() {
return '/passphrase/';
}
public function getShortDescription() {
return pht('Credential Management');
}
public function getIconName() {
return 'passphrase';
}
public function getTitleGlyph() {
return "\xE2\x97\x88";
}
public function getFlavorText() {
return pht('Put your secrets in a lockbox.');
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
- public function isBeta() {
- return true;
+ public function canUninstall() {
+ return false;
}
public function getRoutes() {
return array(
'/K(?P<id>\d+)' => 'PassphraseCredentialViewController',
'/passphrase/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PassphraseCredentialListController',
'create/' => 'PassphraseCredentialCreateController',
'edit/(?:(?P<id>\d+)/)?' => 'PassphraseCredentialEditController',
'destroy/(?P<id>\d+)/' => 'PassphraseCredentialDestroyController',
'reveal/(?P<id>\d+)/' => 'PassphraseCredentialRevealController',
));
}
}
diff --git a/src/applications/passphrase/keys/PassphraseAbstractKey.php b/src/applications/passphrase/keys/PassphraseAbstractKey.php
index 76cba1b39e..cf532d3fac 100644
--- a/src/applications/passphrase/keys/PassphraseAbstractKey.php
+++ b/src/applications/passphrase/keys/PassphraseAbstractKey.php
@@ -1,66 +1,74 @@
<?php
abstract class PassphraseAbstractKey extends Phobject {
private $credential;
protected function requireCredential() {
if (!$this->credential) {
throw new Exception(pht("Credential is required!"));
}
return $this->credential;
}
private function loadCredential(
$phid,
PhabricatorUser $viewer) {
$credential = id(new PassphraseCredentialQuery())
->setViewer($viewer)
->withPHIDs(array($phid))
->needSecrets(true)
->executeOne();
if (!$credential) {
throw new Exception(pht('Failed to load credential "%s"!', $phid));
}
return $credential;
}
private function validateCredential(
PassphraseCredential $credential,
$provides_type) {
- $type = $credential->getCredentialType();
- if ($type->getProvides() !== $provides_type) {
+ $type = $credential->getCredentialTypeImplementation();
+
+ if (!$type) {
+ throw new Exception(
+ pht(
+ 'Credential "%s" is of unknown type "%s"!',
+ 'K'.$credential->getID(),
+ $credential->getCredentialType()));
+ }
+
+ if ($type->getProvidesType() !== $provides_type) {
throw new Exception(
pht(
'Credential "%s" must provide "%s", but provides "%s"!',
'K'.$credential->getID(),
$provides_type,
- $type->getProvides()));
+ $type->getProvidesType()));
}
-
}
protected function loadAndValidateFromPHID(
$phid,
PhabricatorUser $viewer,
$type) {
$credential = $this->loadCredential($phid, $viewer);
$this->validateCredential($credential, $type);
$this->credential = $credential;
return $this;
}
public function getUsernameEnvelope() {
$credential = $this->requireCredential();
return new PhutilOpaqueEnvelope($credential->getUsername());
}
}
diff --git a/src/applications/passphrase/storage/PassphraseCredential.php b/src/applications/passphrase/storage/PassphraseCredential.php
index 880bf5f170..75c68766c0 100644
--- a/src/applications/passphrase/storage/PassphraseCredential.php
+++ b/src/applications/passphrase/storage/PassphraseCredential.php
@@ -1,76 +1,81 @@
<?php
final class PassphraseCredential extends PassphraseDAO
implements PhabricatorPolicyInterface {
protected $name;
protected $credentialType;
protected $providesType;
protected $viewPolicy;
protected $editPolicy;
protected $description;
protected $username;
protected $secretID;
protected $isDestroyed;
private $secret = self::ATTACHABLE;
public static function initializeNewCredential(PhabricatorUser $actor) {
return id(new PassphraseCredential())
->setName('')
->setUsername('')
->setDescription('')
->setIsDestroyed(0)
->setViewPolicy($actor->getPHID())
->setEditPolicy($actor->getPHID());
}
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(
PassphrasePHIDTypeCredential::TYPECONST);
}
public function attachSecret(PhutilOpaqueEnvelope $secret = null) {
$this->secret = $secret;
return $this;
}
public function getSecret() {
return $this->assertAttached($this->secret);
}
+ public function getCredentialTypeImplementation() {
+ $type = $this->getCredentialType();
+ return PassphraseCredentialType::getTypeByConstant($type);
+ }
+
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
public function getPolicy($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return $this->getViewPolicy();
case PhabricatorPolicyCapability::CAN_EDIT:
return $this->getEditPolicy();
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return false;
}
public function describeAutomaticCapability($capability) {
return null;
}
}
diff --git a/src/applications/repository/conduit/ConduitAPI_repository_create_Method.php b/src/applications/repository/conduit/ConduitAPI_repository_create_Method.php
index cb6237bbd1..630e7c0d53 100644
--- a/src/applications/repository/conduit/ConduitAPI_repository_create_Method.php
+++ b/src/applications/repository/conduit/ConduitAPI_repository_create_Method.php
@@ -1,139 +1,134 @@
<?php
/**
* @group conduit
*/
final class ConduitAPI_repository_create_Method
extends ConduitAPI_repository_Method {
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodStatusDescription() {
return "Repository methods are new and subject to change.";
}
public function getMethodDescription() {
return "Create a new repository (Admin Only).";
}
public function defineParamTypes() {
return array(
'name' => 'required string',
'vcs' => 'required enum<git, hg, svn>',
'callsign' => 'required string',
'description' => 'optional string',
'encoding' => 'optional string',
'tracking' => 'optional bool',
'uri' => 'optional string',
- 'sshUser' => 'optional string',
- 'sshKey' => 'optional string',
- 'sshKeyFile' => 'optional string',
- 'httpUser' => 'optional string',
- 'httpPassword' => 'optional string',
+ 'credentialPHID' => 'optional string',
'localPath' => 'optional string',
'svnSubpath' => 'optional string',
'branchFilter' => 'optional list<string>',
'closeCommitsFilter' => 'optional list<string>',
'pullFrequency' => 'optional int',
'defaultBranch' => 'optional string',
'heraldEnabled' => 'optional bool, default = true',
'autocloseEnabled' => 'optional bool, default = true',
'svnUUID' => 'optional string',
);
}
public function defineReturnType() {
return 'nonempty dict';
}
public function defineErrorTypes() {
return array(
'ERR-PERMISSIONS' =>
'You do not have the authority to call this method.',
'ERR-DUPLICATE' =>
'Duplicate repository callsign.',
'ERR-BAD-CALLSIGN' =>
'Callsign is required and must be ALL UPPERCASE LETTERS.',
'ERR-UNKNOWN-REPOSITORY-VCS' =>
'Unknown repository VCS type.',
);
}
protected function execute(ConduitAPIRequest $request) {
$application = id(new PhabricatorApplicationQuery())
->setViewer($request->getUser())
->withClasses(array('PhabricatorApplicationDiffusion'))
->executeOne();
PhabricatorPolicyFilter::requireCapability(
$request->getUser(),
$application,
DiffusionCapabilityCreateRepositories::CAPABILITY);
// TODO: This has some duplication with (and lacks some of the validation
// of) the web workflow; refactor things so they can share more code as this
// stabilizes. Specifically, this should move to transactions since they
// work properly now.
$repository = PhabricatorRepository::initializeNewRepository(
$request->getUser());
$repository->setName($request->getValue('name'));
$callsign = $request->getValue('callsign');
if (!preg_match('/^[A-Z]+$/', $callsign)) {
throw new ConduitException('ERR-BAD-CALLSIGN');
}
$repository->setCallsign($callsign);
$vcs = $request->getValue('vcs');
$map = array(
'git' => PhabricatorRepositoryType::REPOSITORY_TYPE_GIT,
'hg' => PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL,
'svn' => PhabricatorRepositoryType::REPOSITORY_TYPE_SVN,
);
if (empty($map[$vcs])) {
throw new ConduitException('ERR-UNKNOWN-REPOSITORY-VCS');
}
$repository->setVersionControlSystem($map[$vcs]);
+ $repository->setCredentialPHID($request->getValue('credentialPHID'));
+
$details = array(
'encoding' => $request->getValue('encoding'),
'description' => $request->getValue('description'),
'tracking-enabled' => (bool)$request->getValue('tracking', true),
'remote-uri' => $request->getValue('uri'),
'local-path' => $request->getValue('localPath'),
'branch-filter' => array_fill_keys(
$request->getValue('branchFilter', array()),
true),
'close-commits-filter' => array_fill_keys(
$request->getValue('closeCommitsFilter', array()),
true),
'pull-frequency' => $request->getValue('pullFrequency'),
'default-branch' => $request->getValue('defaultBranch'),
- 'ssh-login' => $request->getValue('sshUser'),
- 'ssh-key' => $request->getValue('sshKey'),
- 'ssh-keyfile' => $request->getValue('sshKeyFile'),
'herald-disabled' => !$request->getValue('heraldEnabled', true),
'svn-subpath' => $request->getValue('svnSubpath'),
'disable-autoclose' => !$request->getValue('autocloseEnabled', true),
);
foreach ($details as $key => $value) {
$repository->setDetail($key, $value);
}
try {
$repository->save();
} catch (AphrontQueryDuplicateKeyException $ex) {
throw new ConduitException('ERR-DUPLICATE');
}
return $repository->toDictionary();
}
}
diff --git a/src/applications/repository/editor/PhabricatorRepositoryEditor.php b/src/applications/repository/editor/PhabricatorRepositoryEditor.php
index cf28febdf0..e534402391 100644
--- a/src/applications/repository/editor/PhabricatorRepositoryEditor.php
+++ b/src/applications/repository/editor/PhabricatorRepositoryEditor.php
@@ -1,289 +1,296 @@
<?php
final class PhabricatorRepositoryEditor
extends PhabricatorApplicationTransactionEditor {
public function getTransactionTypes() {
$types = parent::getTransactionTypes();
$types[] = PhabricatorRepositoryTransaction::TYPE_VCS;
$types[] = PhabricatorRepositoryTransaction::TYPE_ACTIVATE;
$types[] = PhabricatorRepositoryTransaction::TYPE_NAME;
$types[] = PhabricatorRepositoryTransaction::TYPE_DESCRIPTION;
$types[] = PhabricatorRepositoryTransaction::TYPE_ENCODING;
$types[] = PhabricatorRepositoryTransaction::TYPE_DEFAULT_BRANCH;
$types[] = PhabricatorRepositoryTransaction::TYPE_TRACK_ONLY;
$types[] = PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE_ONLY;
$types[] = PhabricatorRepositoryTransaction::TYPE_UUID;
$types[] = PhabricatorRepositoryTransaction::TYPE_SVN_SUBPATH;
$types[] = PhabricatorRepositoryTransaction::TYPE_NOTIFY;
$types[] = PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE;
$types[] = PhabricatorRepositoryTransaction::TYPE_REMOTE_URI;
$types[] = PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN;
$types[] = PhabricatorRepositoryTransaction::TYPE_SSH_KEY;
$types[] = PhabricatorRepositoryTransaction::TYPE_SSH_KEYFILE;
$types[] = PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN;
$types[] = PhabricatorRepositoryTransaction::TYPE_HTTP_PASS;
$types[] = PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH;
$types[] = PhabricatorRepositoryTransaction::TYPE_HOSTING;
$types[] = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP;
$types[] = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH;
$types[] = PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY;
+ $types[] = PhabricatorRepositoryTransaction::TYPE_CREDENTIAL;
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
return $types;
}
protected function getCustomTransactionOldValue(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorRepositoryTransaction::TYPE_VCS:
return $object->getVersionControlSystem();
case PhabricatorRepositoryTransaction::TYPE_ACTIVATE:
return $object->isTracked();
case PhabricatorRepositoryTransaction::TYPE_NAME:
return $object->getName();
case PhabricatorRepositoryTransaction::TYPE_DESCRIPTION:
return $object->getDetail('description');
case PhabricatorRepositoryTransaction::TYPE_ENCODING:
return $object->getDetail('encoding');
case PhabricatorRepositoryTransaction::TYPE_DEFAULT_BRANCH:
return $object->getDetail('default-branch');
case PhabricatorRepositoryTransaction::TYPE_TRACK_ONLY:
return array_keys($object->getDetail('branch-filter', array()));
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE_ONLY:
return array_keys($object->getDetail('close-commits-filter', array()));
case PhabricatorRepositoryTransaction::TYPE_UUID:
return $object->getUUID();
case PhabricatorRepositoryTransaction::TYPE_SVN_SUBPATH:
return $object->getDetail('svn-subpath');
case PhabricatorRepositoryTransaction::TYPE_NOTIFY:
return (int)!$object->getDetail('herald-disabled');
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
return (int)!$object->getDetail('disable-autoclose');
case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI:
return $object->getDetail('remote-uri');
- case PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN:
- return $object->getDetail('ssh-login');
- case PhabricatorRepositoryTransaction::TYPE_SSH_KEY:
- return $object->getDetail('ssh-key');
- case PhabricatorRepositoryTransaction::TYPE_SSH_KEYFILE:
- return $object->getDetail('ssh-keyfile');
- case PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN:
- return $object->getDetail('http-login');
- case PhabricatorRepositoryTransaction::TYPE_HTTP_PASS:
- return $object->getDetail('http-pass');
case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH:
return $object->getDetail('local-path');
case PhabricatorRepositoryTransaction::TYPE_HOSTING:
return $object->isHosted();
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP:
return $object->getServeOverHTTP();
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH:
return $object->getServeOverSSH();
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
return $object->getPushPolicy();
+ case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
+ return $object->getCredentialPHID();
}
}
protected function getCustomTransactionNewValue(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorRepositoryTransaction::TYPE_ACTIVATE:
case PhabricatorRepositoryTransaction::TYPE_NAME:
case PhabricatorRepositoryTransaction::TYPE_DESCRIPTION:
case PhabricatorRepositoryTransaction::TYPE_ENCODING:
case PhabricatorRepositoryTransaction::TYPE_DEFAULT_BRANCH:
case PhabricatorRepositoryTransaction::TYPE_TRACK_ONLY:
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE_ONLY:
case PhabricatorRepositoryTransaction::TYPE_UUID:
case PhabricatorRepositoryTransaction::TYPE_SVN_SUBPATH:
case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI:
case PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN:
case PhabricatorRepositoryTransaction::TYPE_SSH_KEY:
case PhabricatorRepositoryTransaction::TYPE_SSH_KEYFILE:
case PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN:
case PhabricatorRepositoryTransaction::TYPE_HTTP_PASS:
case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH:
case PhabricatorRepositoryTransaction::TYPE_VCS:
case PhabricatorRepositoryTransaction::TYPE_HOSTING:
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP:
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH:
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
+ case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
return $xaction->getNewValue();
case PhabricatorRepositoryTransaction::TYPE_NOTIFY:
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
return (int)$xaction->getNewValue();
}
}
protected function applyCustomInternalTransaction(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorRepositoryTransaction::TYPE_VCS:
$object->setVersionControlSystem($xaction->getNewValue());
break;
case PhabricatorRepositoryTransaction::TYPE_ACTIVATE:
$object->setDetail('tracking-enabled', $xaction->getNewValue());
break;
case PhabricatorRepositoryTransaction::TYPE_NAME:
$object->setName($xaction->getNewValue());
break;
case PhabricatorRepositoryTransaction::TYPE_DESCRIPTION:
$object->setDetail('description', $xaction->getNewValue());
break;
case PhabricatorRepositoryTransaction::TYPE_DEFAULT_BRANCH:
$object->setDetail('default-branch', $xaction->getNewValue());
break;
case PhabricatorRepositoryTransaction::TYPE_TRACK_ONLY:
$object->setDetail(
'branch-filter',
array_fill_keys($xaction->getNewValue(), true));
break;
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE_ONLY:
$object->setDetail(
'close-commits-filter',
array_fill_keys($xaction->getNewValue(), true));
break;
case PhabricatorRepositoryTransaction::TYPE_UUID:
$object->setUUID($xaction->getNewValue());
break;
case PhabricatorRepositoryTransaction::TYPE_SVN_SUBPATH:
$object->setDetail('svn-subpath', $xaction->getNewValue());
break;
case PhabricatorRepositoryTransaction::TYPE_NOTIFY:
$object->setDetail('herald-disabled', (int)!$xaction->getNewValue());
break;
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
$object->setDetail('disable-autoclose', (int)!$xaction->getNewValue());
break;
case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI:
$object->setDetail('remote-uri', $xaction->getNewValue());
break;
- case PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN:
- $object->setDetail('ssh-login', $xaction->getNewValue());
- break;
- case PhabricatorRepositoryTransaction::TYPE_SSH_KEY:
- $object->setDetail('ssh-key', $xaction->getNewValue());
- break;
- case PhabricatorRepositoryTransaction::TYPE_SSH_KEYFILE:
- $object->setDetail('ssh-keyfile', $xaction->getNewValue());
- break;
- case PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN:
- $object->setDetail('http-login', $xaction->getNewValue());
- break;
- case PhabricatorRepositoryTransaction::TYPE_HTTP_PASS:
- $object->setDetail('http-pass', $xaction->getNewValue());
- break;
case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH:
$object->setDetail('local-path', $xaction->getNewValue());
break;
case PhabricatorRepositoryTransaction::TYPE_HOSTING:
return $object->setHosted($xaction->getNewValue());
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP:
return $object->setServeOverHTTP($xaction->getNewValue());
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH:
return $object->setServeOverSSH($xaction->getNewValue());
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
return $object->setPushPolicy($xaction->getNewValue());
+ case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
+ return $object->setCredentialPHID($xaction->getNewValue());
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
// a garbage encoding name. Note that we're converting from UTF-8 to
// the target encoding, because mbstring is fine with converting from
// a nonsense encoding.
$encoding = $xaction->getNewValue();
if (strlen($encoding)) {
try {
phutil_utf8_convert('.', $encoding, 'UTF-8');
} catch (Exception $ex) {
throw new PhutilProxyException(
pht(
"Error setting repository encoding '%s': %s'",
$encoding,
$ex->getMessage()),
$ex);
}
}
$object->setDetail('encoding', $encoding);
break;
}
}
protected function applyCustomExternalTransaction(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
- return;
+
+ switch ($xaction->getTransactionType()) {
+ case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
+ // Adjust the object <-> credential edge for this repository.
+
+ $old_phid = $xaction->getOldValue();
+ $new_phid = $xaction->getNewValue();
+
+ $editor = id(new PhabricatorEdgeEditor())
+ ->setActor($this->requireActor());
+
+ $edge_type = PhabricatorEdgeConfig::TYPE_OBJECT_USES_CREDENTIAL;
+ $src_phid = $object->getPHID();
+
+ if ($old_phid) {
+ $editor->removeEdge($src_phid, $edge_type, $old_phid);
+ }
+
+ if ($new_phid) {
+ $editor->addEdge($src_phid, $edge_type, $new_phid);
+ }
+
+ $editor->save();
+ break;
+ }
+
}
protected function mergeTransactions(
PhabricatorApplicationTransaction $u,
PhabricatorApplicationTransaction $v) {
$type = $u->getTransactionType();
switch ($type) {
}
return parent::mergeTransactions($u, $v);
}
protected function transactionHasEffect(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
$old = $xaction->getOldValue();
$new = $xaction->getNewValue();
$type = $xaction->getTransactionType();
switch ($type) {
}
return parent::transactionHasEffect($object, $xaction);
}
protected function requireCapabilities(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorRepositoryTransaction::TYPE_ACTIVATE:
case PhabricatorRepositoryTransaction::TYPE_NAME:
case PhabricatorRepositoryTransaction::TYPE_DESCRIPTION:
case PhabricatorRepositoryTransaction::TYPE_ENCODING:
case PhabricatorRepositoryTransaction::TYPE_DEFAULT_BRANCH:
case PhabricatorRepositoryTransaction::TYPE_TRACK_ONLY:
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE_ONLY:
case PhabricatorRepositoryTransaction::TYPE_UUID:
case PhabricatorRepositoryTransaction::TYPE_SVN_SUBPATH:
case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI:
case PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN:
case PhabricatorRepositoryTransaction::TYPE_SSH_KEY:
case PhabricatorRepositoryTransaction::TYPE_SSH_KEYFILE:
case PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN:
case PhabricatorRepositoryTransaction::TYPE_HTTP_PASS:
case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH:
case PhabricatorRepositoryTransaction::TYPE_VCS:
case PhabricatorRepositoryTransaction::TYPE_NOTIFY:
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
case PhabricatorRepositoryTransaction::TYPE_HOSTING:
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP:
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH:
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
+ case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
PhabricatorPolicyFilter::requireCapability(
$this->requireActor(),
$object,
PhabricatorPolicyCapability::CAN_EDIT);
break;
}
}
}
diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php
index c77a6a62c7..af00bb58e8 100644
--- a/src/applications/repository/storage/PhabricatorRepository.php
+++ b/src/applications/repository/storage/PhabricatorRepository.php
@@ -1,1012 +1,1001 @@
<?php
/**
* @task uri Repository URI Management
*/
final class PhabricatorRepository extends PhabricatorRepositoryDAO
implements
PhabricatorPolicyInterface,
PhabricatorFlaggableInterface,
PhabricatorMarkupInterface {
/**
* Shortest hash we'll recognize in raw "a829f32" form.
*/
const MINIMUM_UNQUALIFIED_HASH = 7;
/**
* Shortest hash we'll recognize in qualified "rXab7ef2f8" form.
*/
const MINIMUM_QUALIFIED_HASH = 5;
const TABLE_PATH = 'repository_path';
const TABLE_PATHCHANGE = 'repository_pathchange';
const TABLE_FILESYSTEM = 'repository_filesystem';
const TABLE_SUMMARY = 'repository_summary';
const TABLE_BADCOMMIT = 'repository_badcommit';
const TABLE_LINTMESSAGE = 'repository_lintmessage';
const SERVE_OFF = 'off';
const SERVE_READONLY = 'readonly';
const SERVE_READWRITE = 'readwrite';
protected $name;
protected $callsign;
protected $uuid;
protected $viewPolicy;
protected $editPolicy;
protected $pushPolicy;
protected $versionControlSystem;
protected $details = array();
-
- private $sshKeyfile;
+ protected $credentialPHID;
private $commitCount = self::ATTACHABLE;
private $mostRecentCommit = self::ATTACHABLE;
public static function initializeNewRepository(PhabricatorUser $actor) {
$app = id(new PhabricatorApplicationQuery())
->setViewer($actor)
->withClasses(array('PhabricatorApplicationDiffusion'))
->executeOne();
$view_policy = $app->getPolicy(DiffusionCapabilityDefaultView::CAPABILITY);
$edit_policy = $app->getPolicy(DiffusionCapabilityDefaultEdit::CAPABILITY);
$push_policy = $app->getPolicy(DiffusionCapabilityDefaultPush::CAPABILITY);
return id(new PhabricatorRepository())
->setViewPolicy($view_policy)
->setEditPolicy($edit_policy)
->setPushPolicy($push_policy);
}
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_SERIALIZATION => array(
'details' => self::SERIALIZATION_JSON,
),
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(
PhabricatorRepositoryPHIDTypeRepository::TYPECONST);
}
public function toDictionary() {
return array(
'name' => $this->getName(),
'phid' => $this->getPHID(),
'callsign' => $this->getCallsign(),
'vcs' => $this->getVersionControlSystem(),
'uri' => PhabricatorEnv::getProductionURI($this->getURI()),
'remoteURI' => (string)$this->getPublicRemoteURI(),
'tracking' => $this->getDetail('tracking-enabled'),
'description' => $this->getDetail('description'),
);
}
public function getDetail($key, $default = null) {
return idx($this->details, $key, $default);
}
public function getHumanReadableDetail($key, $default = null) {
$value = $this->getDetail($key, $default);
switch ($key) {
case 'branch-filter':
case 'close-commits-filter':
$value = array_keys($value);
$value = implode(', ', $value);
break;
}
return $value;
}
public function setDetail($key, $value) {
$this->details[$key] = $value;
return $this;
}
public function attachCommitCount($count) {
$this->commitCount = $count;
return $this;
}
public function getCommitCount() {
return $this->assertAttached($this->commitCount);
}
public function attachMostRecentCommit(
PhabricatorRepositoryCommit $commit = null) {
$this->mostRecentCommit = $commit;
return $this;
}
public function getMostRecentCommit() {
return $this->assertAttached($this->mostRecentCommit);
}
public function getDiffusionBrowseURIForPath(
PhabricatorUser $user,
$path,
$line = null,
$branch = null) {
$drequest = DiffusionRequest::newFromDictionary(
array(
'user' => $user,
'repository' => $this,
'path' => $path,
'branch' => $branch,
));
return $drequest->generateURI(
array(
'action' => 'browse',
'line' => $line,
));
}
public function getLocalPath() {
return $this->getDetail('local-path');
}
public function getSubversionBaseURI($commit = null) {
$subpath = $this->getDetail('svn-subpath');
if (!strlen($subpath)) {
$subpath = null;
}
return $this->getSubversionPathURI($subpath, $commit);
}
public function getSubversionPathURI($path = null, $commit = null) {
$vcs = $this->getVersionControlSystem();
if ($vcs != PhabricatorRepositoryType::REPOSITORY_TYPE_SVN) {
throw new Exception("Not a subversion repository!");
}
if ($this->isHosted()) {
$uri = 'file://'.$this->getLocalPath();
} else {
$uri = $this->getDetail('remote-uri');
}
$uri = rtrim($uri, '/');
if (strlen($path)) {
$path = rawurlencode($path);
$path = str_replace('%2F', '/', $path);
$uri = $uri.'/'.ltrim($path, '/');
}
if ($path !== null || $commit !== null) {
$uri .= '@';
}
if ($commit !== null) {
$uri .= $commit;
}
return $uri;
}
/* -( Remote Command Execution )------------------------------------------- */
public function execRemoteCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
return $this->newRemoteCommandFuture($args)->resolve();
}
public function execxRemoteCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
return $this->newRemoteCommandFuture($args)->resolvex();
}
public function getRemoteCommandFuture($pattern /* , $arg, ... */) {
$args = func_get_args();
return $this->newRemoteCommandFuture($args);
}
public function passthruRemoteCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
return $this->newRemoteCommandPassthru($args)->execute();
}
private function newRemoteCommandFuture(array $argv) {
$argv = $this->formatRemoteCommand($argv);
$future = newv('ExecFuture', $argv);
$future->setEnv($this->getRemoteCommandEnvironment());
return $future;
}
private function newRemoteCommandPassthru(array $argv) {
$argv = $this->formatRemoteCommand($argv);
$passthru = newv('PhutilExecPassthru', $argv);
$passthru->setEnv($this->getRemoteCommandEnvironment());
return $passthru;
}
/* -( Local Command Execution )-------------------------------------------- */
public function execLocalCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
return $this->newLocalCommandFuture($args)->resolve();
}
public function execxLocalCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
return $this->newLocalCommandFuture($args)->resolvex();
}
public function getLocalCommandFuture($pattern /* , $arg, ... */) {
$args = func_get_args();
return $this->newLocalCommandFuture($args);
}
public function passthruLocalCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
return $this->newLocalCommandPassthru($args)->execute();
}
private function newLocalCommandFuture(array $argv) {
$this->assertLocalExists();
$argv = $this->formatLocalCommand($argv);
$future = newv('ExecFuture', $argv);
$future->setEnv($this->getLocalCommandEnvironment());
if ($this->usesLocalWorkingCopy()) {
$future->setCWD($this->getLocalPath());
}
return $future;
}
private function newLocalCommandPassthru(array $argv) {
$this->assertLocalExists();
$argv = $this->formatLocalCommand($argv);
$future = newv('PhutilExecPassthru', $argv);
$future->setEnv($this->getLocalCommandEnvironment());
if ($this->usesLocalWorkingCopy()) {
$future->setCWD($this->getLocalPath());
}
return $future;
}
/* -( Command Infrastructure )--------------------------------------------- */
private function getSSHWrapper() {
$root = dirname(phutil_get_library_root('phabricator'));
return $root.'/bin/ssh-connect';
}
private function getCommonCommandEnvironment() {
$env = array(
// NOTE: Force the language to "C", which overrides locale settings.
// This makes stuff print in English instead of, e.g., French, so we can
// parse the output of some commands, error messages, etc.
'LANG' => 'C',
);
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
// NOTE: See T2965. Some time after Git 1.7.5.4, Git started fataling if
// it can not read $HOME. For many users, $HOME points at /root (this
// seems to be a default result of Apache setup). Instead, explicitly
// point $HOME at a readable, empty directory so that Git looks for the
// config file it's after, fails to locate it, and moves on. This is
// really silly, but seems like the least damaging approach to
// mitigating the issue.
$root = dirname(phutil_get_library_root('phabricator'));
$env['HOME'] = $root.'/support/empty/';
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
// NOTE: This overrides certain configuration, extensions, and settings
// which make Mercurial commands do random unusual things.
$env['HGPLAIN'] = 1;
break;
default:
throw new Exception("Unrecognized version control system.");
}
return $env;
}
private function getLocalCommandEnvironment() {
return $this->getCommonCommandEnvironment();
}
private function getRemoteCommandEnvironment() {
$env = $this->getCommonCommandEnvironment();
if ($this->shouldUseSSH()) {
// NOTE: This is read by `bin/ssh-connect`, and tells it which credentials
// to use.
$env['PHABRICATOR_SSH_TARGET'] = $this->getCallsign();
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
// Force SVN to use `bin/ssh-connect`.
$env['SVN_SSH'] = $this->getSSHWrapper();
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
// Force Git to use `bin/ssh-connect`.
$env['GIT_SSH'] = $this->getSSHWrapper();
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
// We force Mercurial through `bin/ssh-connect` too, but it uses a
// command-line flag instead of an environmental variable.
break;
default:
throw new Exception("Unrecognized version control system.");
}
}
return $env;
}
private function formatRemoteCommand(array $args) {
$pattern = $args[0];
$args = array_slice($args, 1);
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
- if ($this->shouldUseHTTP()) {
- $pattern =
- "svn ".
- "--non-interactive ".
- "--no-auth-cache ".
- "--trust-server-cert ".
- "--username %P ".
- "--password %P ".
- $pattern;
- array_unshift(
- $args,
- new PhutilOpaqueEnvelope($this->getDetail('http-login')),
- new PhutilOpaqueEnvelope($this->getDetail('http-pass')));
- } else if ($this->shouldUseSVNProtocol()) {
- $pattern =
- "svn ".
- "--non-interactive ".
- "--no-auth-cache ".
- "--username %P ".
- "--password %P ".
- $pattern;
- array_unshift(
- $args,
- new PhutilOpaqueEnvelope($this->getDetail('http-login')),
- new PhutilOpaqueEnvelope($this->getDetail('http-pass')));
+ if ($this->shouldUseHTTP() || $this->shouldUseSVNProtocol()) {
+ $flags = array();
+ $flag_args = array();
+ $flags[] = '--non-interactive';
+ $flags[] = '--no-auth-cache';
+ if ($this->shouldUseHTTP()) {
+ $flags[] = '--trust-server-cert';
+ }
+
+ $credential_phid = $this->getCredentialPHID();
+ if ($credential_phid) {
+ $key = PassphrasePasswordKey::loadFromPHID(
+ $credential_phid,
+ PhabricatorUser::getOmnipotentUser());
+ $flags[] = '--username %P';
+ $flags[] = '--password %P';
+ $flag_args[] = $key->getUsernameEnvelope();
+ $flag_args[] = $key->getPasswordEnvelope();
+ }
+
+ $flags = implode(' ', $flags);
+ $pattern = "svn {$flags} {$pattern}";
+ $args = array_mergev(array($flag_args, $args));
} else {
$pattern = "svn --non-interactive {$pattern}";
}
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$pattern = "git {$pattern}";
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
if ($this->shouldUseSSH()) {
$pattern = "hg --config ui.ssh=%s {$pattern}";
array_unshift(
$args,
$this->getSSHWrapper());
} else {
$pattern = "hg {$pattern}";
}
break;
default:
throw new Exception("Unrecognized version control system.");
}
array_unshift($args, $pattern);
return $args;
}
private function formatLocalCommand(array $args) {
$pattern = $args[0];
$args = array_slice($args, 1);
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$pattern = "svn --non-interactive {$pattern}";
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$pattern = "git {$pattern}";
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$pattern = "hg {$pattern}";
break;
default:
throw new Exception("Unrecognized version control system.");
}
array_unshift($args, $pattern);
return $args;
}
public function getSSHLogin() {
return $this->getDetail('ssh-login');
}
public function getURI() {
return '/diffusion/'.$this->getCallsign().'/';
}
public function isTracked() {
return $this->getDetail('tracking-enabled', false);
}
public function getDefaultBranch() {
$default = $this->getDetail('default-branch');
if (strlen($default)) {
return $default;
}
$default_branches = array(
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT => 'master',
PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL => 'default',
);
return idx($default_branches, $this->getVersionControlSystem());
}
public function getDefaultArcanistBranch() {
return coalesce($this->getDefaultBranch(), 'svn');
}
private function isBranchInFilter($branch, $filter_key) {
$vcs = $this->getVersionControlSystem();
$is_git = ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_GIT);
$use_filter = ($is_git);
if ($use_filter) {
$filter = $this->getDetail($filter_key, array());
if ($filter && empty($filter[$branch])) {
return false;
}
}
// By default, all branches pass.
return true;
}
public function shouldTrackBranch($branch) {
return $this->isBranchInFilter($branch, 'branch-filter');
}
public function shouldAutocloseBranch($branch) {
if ($this->isImporting()) {
return false;
}
if ($this->getDetail('disable-autoclose', false)) {
return false;
}
return $this->isBranchInFilter($branch, 'close-commits-filter');
}
public function shouldAutocloseCommit(
PhabricatorRepositoryCommit $commit,
PhabricatorRepositoryCommitData $data) {
if ($this->getDetail('disable-autoclose', false)) {
return false;
}
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
return true;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
return true;
default:
throw new Exception("Unrecognized version control system.");
}
$branches = $data->getCommitDetail('seenOnBranches', array());
foreach ($branches as $branch) {
if ($this->shouldAutocloseBranch($branch)) {
return true;
}
}
return false;
}
public function formatCommitName($commit_identifier) {
$vcs = $this->getVersionControlSystem();
$type_git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
$type_hg = PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL;
$is_git = ($vcs == $type_git);
$is_hg = ($vcs == $type_hg);
if ($is_git || $is_hg) {
$short_identifier = substr($commit_identifier, 0, 12);
} else {
$short_identifier = $commit_identifier;
}
return 'r'.$this->getCallsign().$short_identifier;
}
public function isImporting() {
return (bool)$this->getDetail('importing', false);
}
/* -( Repository URI Management )------------------------------------------ */
/**
* Get the remote URI for this repository.
*
* @return string
* @task uri
*/
public function getRemoteURI() {
return (string)$this->getRemoteURIObject();
}
/**
* Get the remote URI for this repository, without authentication information.
*
* @return string Repository URI.
* @task uri
*/
public function getPublicRemoteURI() {
$uri = $this->getRemoteURIObject();
// Make sure we don't leak anything if this repo is using HTTP Basic Auth
// with the credentials in the URI or something zany like that.
// If repository is not accessed over SSH we remove both username and
// password.
if (!$this->shouldUseSSH()) {
$uri->setUser(null);
$uri->setPass(null);
}
return (string)$uri;
}
/**
* Get the protocol for the repository's remote.
*
* @return string Protocol, like "ssh" or "git".
* @task uri
*/
public function getRemoteProtocol() {
$uri = $this->getRemoteURIObject();
if ($uri instanceof PhutilGitURI) {
return 'ssh';
} else {
return $uri->getProtocol();
}
}
/**
* Get a parsed object representation of the repository's remote URI. This
* may be a normal URI (returned as a @{class@libphutil:PhutilURI}) or a git
* URI (returned as a @{class@libphutil:PhutilGitURI}).
*
* @return wild A @{class@libphutil:PhutilURI} or
* @{class@libphutil:PhutilGitURI}.
* @task uri
*/
public function getRemoteURIObject() {
$raw_uri = $this->getDetail('remote-uri');
if (!$raw_uri) {
return new PhutilURI('');
}
if (!strncmp($raw_uri, '/', 1)) {
return new PhutilURI('file://'.$raw_uri);
}
$uri = new PhutilURI($raw_uri);
if ($uri->getProtocol()) {
if ($this->isSSHProtocol($uri->getProtocol())) {
if ($this->getSSHLogin()) {
$uri->setUser($this->getSSHLogin());
}
}
return $uri;
}
$uri = new PhutilGitURI($raw_uri);
if ($uri->getDomain()) {
if ($this->getSSHLogin()) {
$uri->setUser($this->getSSHLogin());
}
return $uri;
}
throw new Exception("Remote URI '{$raw_uri}' could not be parsed!");
}
/**
* Determine if we should connect to the remote using SSH flags and
* credentials.
*
* @return bool True to use the SSH protocol.
* @task uri
*/
private function shouldUseSSH() {
if ($this->isHosted()) {
return false;
}
$protocol = $this->getRemoteProtocol();
if ($this->isSSHProtocol($protocol)) {
$key = $this->getDetail('ssh-key');
$keyfile = $this->getDetail('ssh-keyfile');
if ($key || $keyfile) {
return true;
}
}
return false;
}
/**
* Determine if we should connect to the remote using HTTP flags and
* credentials.
*
* @return bool True to use the HTTP protocol.
* @task uri
*/
private function shouldUseHTTP() {
if ($this->isHosted()) {
return false;
}
$protocol = $this->getRemoteProtocol();
- if ($protocol == 'http' || $protocol == 'https') {
- return (bool)$this->getDetail('http-login');
- } else {
- return false;
- }
+ return ($protocol == 'http' || $protocol == 'https');
}
/**
* Determine if we should connect to the remote using SVN flags and
* credentials.
*
* @return bool True to use the SVN protocol.
* @task uri
*/
private function shouldUseSVNProtocol() {
if ($this->isHosted()) {
return false;
}
$protocol = $this->getRemoteProtocol();
- if ($protocol == 'svn') {
- return (bool)$this->getDetail('http-login');
- } else {
- return false;
- }
+ return ($protocol == 'svn');
}
/**
* Determine if a protocol is SSH or SSH-like.
*
* @param string A protocol string, like "http" or "ssh".
* @return bool True if the protocol is SSH-like.
* @task uri
*/
private function isSSHProtocol($protocol) {
return ($protocol == 'ssh' || $protocol == 'svn+ssh');
}
public function delete() {
$this->openTransaction();
$paths = id(new PhabricatorOwnersPath())
->loadAllWhere('repositoryPHID = %s', $this->getPHID());
foreach ($paths as $path) {
$path->delete();
}
$projects = id(new PhabricatorRepositoryArcanistProject())
->loadAllWhere('repositoryID = %d', $this->getID());
foreach ($projects as $project) {
// note each project deletes its PhabricatorRepositorySymbols
$project->delete();
}
$commits = id(new PhabricatorRepositoryCommit())
->loadAllWhere('repositoryID = %d', $this->getID());
foreach ($commits as $commit) {
// note PhabricatorRepositoryAuditRequests and
// PhabricatorRepositoryCommitData are deleted here too.
$commit->delete();
}
$conn_w = $this->establishConnection('w');
queryfx(
$conn_w,
'DELETE FROM %T WHERE repositoryID = %d',
self::TABLE_FILESYSTEM,
$this->getID());
queryfx(
$conn_w,
'DELETE FROM %T WHERE repositoryID = %d',
self::TABLE_PATHCHANGE,
$this->getID());
queryfx(
$conn_w,
'DELETE FROM %T WHERE repositoryID = %d',
self::TABLE_SUMMARY,
$this->getID());
$result = parent::delete();
$this->saveTransaction();
return $result;
}
public function isGit() {
$vcs = $this->getVersionControlSystem();
return ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_GIT);
}
public function isSVN() {
$vcs = $this->getVersionControlSystem();
return ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_SVN);
}
public function isHg() {
$vcs = $this->getVersionControlSystem();
return ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL);
}
public function isHosted() {
return (bool)$this->getDetail('hosting-enabled', false);
}
public function setHosted($enabled) {
return $this->setDetail('hosting-enabled', $enabled);
}
public function getServeOverHTTP() {
if ($this->isSVN()) {
return self::SERVE_OFF;
}
$serve = $this->getDetail('serve-over-http', self::SERVE_OFF);
return $this->normalizeServeConfigSetting($serve);
}
public function setServeOverHTTP($mode) {
return $this->setDetail('serve-over-http', $mode);
}
public function getServeOverSSH() {
$serve = $this->getDetail('serve-over-ssh', self::SERVE_OFF);
return $this->normalizeServeConfigSetting($serve);
}
public function setServeOverSSH($mode) {
return $this->setDetail('serve-over-ssh', $mode);
}
public static function getProtocolAvailabilityName($constant) {
switch ($constant) {
case self::SERVE_OFF:
return pht('Off');
case self::SERVE_READONLY:
return pht('Read Only');
case self::SERVE_READWRITE:
return pht('Read/Write');
default:
return pht('Unknown');
}
}
private function normalizeServeConfigSetting($value) {
switch ($value) {
case self::SERVE_OFF:
case self::SERVE_READONLY:
return $value;
case self::SERVE_READWRITE:
if ($this->isHosted()) {
return self::SERVE_READWRITE;
} else {
return self::SERVE_READONLY;
}
default:
return self::SERVE_OFF;
}
}
/**
* Raise more useful errors when there are basic filesystem problems.
*/
private function assertLocalExists() {
if (!$this->usesLocalWorkingCopy()) {
return;
}
$local = $this->getLocalPath();
Filesystem::assertExists($local);
Filesystem::assertIsDirectory($local);
Filesystem::assertReadable($local);
}
/**
* Determine if the working copy is bare or not. In Git, this corresponds
* to `--bare`. In Mercurial, `--noupdate`.
*/
public function isWorkingCopyBare() {
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
return false;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$local = $this->getLocalPath();
if (Filesystem::pathExists($local.'/.git')) {
return false;
} else {
return true;
}
}
}
public function usesLocalWorkingCopy() {
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
return $this->isHosted();
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
return true;
}
}
public function canDestroyWorkingCopy() {
if ($this->isHosted()) {
// Never destroy hosted working copies.
return false;
}
$default_path = PhabricatorEnv::getEnvConfig(
'repository.default-local-path');
return Filesystem::isDescendant($this->getLocalPath(), $default_path);
}
public function writeStatusMessage(
$status_type,
$status_code,
array $parameters = array()) {
$table = new PhabricatorRepositoryStatusMessage();
$conn_w = $table->establishConnection('w');
$table_name = $table->getTableName();
if ($status_code === null) {
queryfx(
$conn_w,
'DELETE FROM %T WHERE repositoryID = %d AND statusType = %s',
$table_name,
$this->getID(),
$status_type);
} else {
queryfx(
$conn_w,
'INSERT INTO %T
(repositoryID, statusType, statusCode, parameters, epoch)
VALUES (%d, %s, %s, %s, %d)
ON DUPLICATE KEY UPDATE
statusCode = VALUES(statusCode),
parameters = VALUES(parameters),
epoch = VALUES(epoch)',
$table_name,
$this->getID(),
$status_type,
$status_code,
json_encode($parameters),
time());
}
return $this;
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
DiffusionCapabilityPush::CAPABILITY,
);
}
public function getPolicy($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return $this->getViewPolicy();
case PhabricatorPolicyCapability::CAN_EDIT:
return $this->getEditPolicy();
case DiffusionCapabilityPush::CAPABILITY:
return $this->getPushPolicy();
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $user) {
return false;
}
public function describeAutomaticCapability($capability) {
return null;
}
/* -( PhabricatorMarkupInterface )----------------------------------------- */
public function getMarkupFieldKey($field) {
$hash = PhabricatorHash::digestForIndex($this->getMarkupText($field));
return "repo:{$hash}";
}
public function newMarkupEngine($field) {
return PhabricatorMarkupEngine::newMarkupEngine(array());
}
public function getMarkupText($field) {
return $this->getDetail('description');
}
public function didMarkupText(
$field,
$output,
PhutilMarkupEngine $engine) {
require_celerity_resource('phabricator-remarkup-css');
return phutil_tag(
'div',
array(
'class' => 'phabricator-remarkup',
),
$output);
}
public function shouldUseMarkupCache($field) {
return true;
}
}
diff --git a/src/applications/repository/storage/PhabricatorRepositoryTransaction.php b/src/applications/repository/storage/PhabricatorRepositoryTransaction.php
index e40c139cf4..84c74276ab 100644
--- a/src/applications/repository/storage/PhabricatorRepositoryTransaction.php
+++ b/src/applications/repository/storage/PhabricatorRepositoryTransaction.php
@@ -1,364 +1,367 @@
<?php
final class PhabricatorRepositoryTransaction
extends PhabricatorApplicationTransaction {
const TYPE_VCS = 'repo:vcs';
const TYPE_ACTIVATE = 'repo:activate';
const TYPE_NAME = 'repo:name';
const TYPE_DESCRIPTION = 'repo:description';
const TYPE_ENCODING = 'repo:encoding';
const TYPE_DEFAULT_BRANCH = 'repo:default-branch';
const TYPE_TRACK_ONLY = 'repo:track-only';
const TYPE_AUTOCLOSE_ONLY = 'repo:autoclose-only';
const TYPE_SVN_SUBPATH = 'repo:svn-subpath';
const TYPE_UUID = 'repo:uuid';
const TYPE_NOTIFY = 'repo:notify';
const TYPE_AUTOCLOSE = 'repo:autoclose';
const TYPE_REMOTE_URI = 'repo:remote-uri';
- const TYPE_SSH_LOGIN = 'repo:ssh-login';
- const TYPE_SSH_KEY = 'repo:ssh-key';
- const TYPE_SSH_KEYFILE = 'repo:ssh-keyfile';
- const TYPE_HTTP_LOGIN = 'repo:http-login';
- const TYPE_HTTP_PASS = 'repo:http-pass';
const TYPE_LOCAL_PATH = 'repo:local-path';
const TYPE_HOSTING = 'repo:hosting';
const TYPE_PROTOCOL_HTTP = 'repo:serve-http';
const TYPE_PROTOCOL_SSH = 'repo:serve-ssh';
const TYPE_PUSH_POLICY = 'repo:push-policy';
+ const TYPE_CREDENTIAL = 'repo:credential';
+
+ // TODO: Clean up these legacy transaction types.
+ const TYPE_SSH_LOGIN = 'repo:ssh-login';
+ const TYPE_SSH_KEY = 'repo:ssh-key';
+ const TYPE_SSH_KEYFILE = 'repo:ssh-keyfile';
+ const TYPE_HTTP_LOGIN = 'repo:http-login';
+ const TYPE_HTTP_PASS = 'repo:http-pass';
public function getApplicationName() {
return 'repository';
}
public function getApplicationTransactionType() {
return PhabricatorRepositoryPHIDTypeRepository::TYPECONST;
}
public function getApplicationTransactionCommentObject() {
return null;
}
public function getRequiredHandlePHIDs() {
$phids = parent::getRequiredHandlePHIDs();
$old = $this->getOldValue();
$new = $this->getNewValue();
switch ($this->getTransactionType()) {
case self::TYPE_PUSH_POLICY:
$phids[] = $old;
$phids[] = $new;
break;
}
return $phids;
}
public function shouldHide() {
$old = $this->getOldValue();
$new = $this->getNewValue();
switch ($this->getTransactionType()) {
case self::TYPE_REMOTE_URI:
case self::TYPE_SSH_LOGIN:
case self::TYPE_SSH_KEY:
case self::TYPE_SSH_KEYFILE:
case self::TYPE_HTTP_LOGIN:
case self::TYPE_HTTP_PASS:
// Hide null vs empty string changes.
return (!strlen($old) && !strlen($new));
case self::TYPE_LOCAL_PATH:
case self::TYPE_NAME:
// Hide these on create, they aren't interesting and we have an
// explicit "create" transaction.
if (!strlen($old)) {
return true;
}
break;
}
return parent::shouldHide();
}
public function getIcon() {
switch ($this->getTransactionType()) {
case self::TYPE_VCS:
return 'create';
}
return parent::getIcon();
}
public function getColor() {
switch ($this->getTransactionType()) {
case self::TYPE_VCS:
return 'green';
}
return parent::getIcon();
}
public function getTitle() {
$author_phid = $this->getAuthorPHID();
$old = $this->getOldValue();
$new = $this->getNewValue();
switch ($this->getTransactionType()) {
case self::TYPE_VCS:
return pht(
'%s created this repository.',
$this->renderHandleLink($author_phid));
case self::TYPE_ACTIVATE:
if ($new) {
return pht(
'%s activated this repository.',
$this->renderHandleLink($author_phid));
} else {
return pht(
'%s deactivated this repository.',
$this->renderHandleLink($author_phid));
}
case self::TYPE_NAME:
return pht(
'%s renamed this repository from "%s" to "%s".',
$this->renderHandleLink($author_phid),
$old,
$new);
case self::TYPE_DESCRIPTION:
return pht(
'%s updated the description of this repository.',
$this->renderHandleLink($author_phid));
case self::TYPE_ENCODING:
if (strlen($old) && !strlen($new)) {
return pht(
'%s removed the "%s" encoding configured for this repository.',
$this->renderHandleLink($author_phid),
$old);
} else if (strlen($new) && !strlen($old)) {
return pht(
'%s set the encoding for this repository to "%s".',
$this->renderHandleLink($author_phid),
$new);
} else {
return pht(
'%s changed the repository encoding from "%s" to "%s".',
$this->renderHandleLink($author_phid),
$old,
$new);
}
case self::TYPE_DEFAULT_BRANCH:
if (!strlen($new)) {
return pht(
'%s removed "%s" as the default branch.',
$this->renderHandleLink($author_phid),
$old);
} else if (!strlen($old)) {
return pht(
'%s set the default branch to "%s".',
$this->renderHandleLink($author_phid),
$new);
} else {
return pht(
'%s changed the default branch from "%s" to "%s".',
$this->renderHandleLink($author_phid),
$old,
$new);
}
break;
case self::TYPE_TRACK_ONLY:
if (!$new) {
return pht(
'%s set this repository to track all branches.',
$this->renderHandleLink($author_phid));
} else if (!$old) {
return pht(
'%s set this repository to track branches: %s.',
$this->renderHandleLink($author_phid),
implode(', ', $new));
} else {
return pht(
'%s changed track branches from "%s" to "%s".',
$this->renderHandleLink($author_phid),
implode(', ', $old),
implode(', ', $new));
}
break;
case self::TYPE_AUTOCLOSE_ONLY:
if (!$new) {
return pht(
'%s set this repository to autoclose on all branches.',
$this->renderHandleLink($author_phid));
} else if (!$old) {
return pht(
'%s set this repository to autoclose on branches: %s.',
$this->renderHandleLink($author_phid),
implode(', ', $new));
} else {
return pht(
'%s changed autoclose branches from "%s" to "%s".',
$this->renderHandleLink($author_phid),
implode(', ', $old),
implode(', ', $new));
}
break;
case self::TYPE_UUID:
if (!strlen($new)) {
return pht(
'%s removed "%s" as the repository UUID.',
$this->renderHandleLink($author_phid),
$old);
} else if (!strlen($old)) {
return pht(
'%s set the repository UUID to "%s".',
$this->renderHandleLink($author_phid),
$new);
} else {
return pht(
'%s changed the repository UUID from "%s" to "%s".',
$this->renderHandleLink($author_phid),
$old,
$new);
}
break;
case self::TYPE_SVN_SUBPATH:
if (!strlen($new)) {
return pht(
'%s removed "%s" as the Import Only path.',
$this->renderHandleLink($author_phid),
$old);
} else if (!strlen($old)) {
return pht(
'%s set the repository to import only "%s".',
$this->renderHandleLink($author_phid),
$new);
} else {
return pht(
'%s changed the import path from "%s" to "%s".',
$this->renderHandleLink($author_phid),
$old,
$new);
}
break;
case self::TYPE_NOTIFY:
if ($new) {
return pht(
'%s enabled notifications and publishing for this repository.',
$this->renderHandleLink($author_phid));
} else {
return pht(
'%s disabled notifications and publishing for this repository.',
$this->renderHandleLink($author_phid));
}
break;
case self::TYPE_AUTOCLOSE:
if ($new) {
return pht(
'%s enabled autoclose for this repository.',
$this->renderHandleLink($author_phid));
} else {
return pht(
'%s disabled autoclose for this repository.',
$this->renderHandleLink($author_phid));
}
break;
case self::TYPE_REMOTE_URI:
if (!strlen($old)) {
return pht(
'%s set the remote URI for this repository to "%s".',
$this->renderHandleLink($author_phid),
$new);
} else if (!strlen($new)) {
return pht(
'%s removed the remote URI for this repository.',
$this->renderHandleLink($author_phid));
} else {
return pht(
'%s changed the remote URI for this repository from "%s" to "%s".',
$this->renderHandleLink($author_phid),
$old,
$new);
}
break;
case self::TYPE_SSH_LOGIN:
return pht(
'%s updated the SSH login for this repository.',
$this->renderHandleLink($author_phid));
case self::TYPE_SSH_KEY:
return pht(
'%s updated the SSH key for this repository.',
$this->renderHandleLink($author_phid));
case self::TYPE_SSH_KEYFILE:
return pht(
'%s updated the SSH keyfile for this repository.',
$this->renderHandleLink($author_phid));
case self::TYPE_HTTP_LOGIN:
return pht(
'%s updated the HTTP login for this repository.',
$this->renderHandleLink($author_phid));
case self::TYPE_HTTP_PASS:
return pht(
'%s updated the HTTP password for this repository.',
$this->renderHandleLink($author_phid));
case self::TYPE_LOCAL_PATH:
return pht(
'%s changed the local path from "%s" to "%s".',
$this->renderHandleLink($author_phid),
$old,
$new);
case self::TYPE_HOSTING:
if ($new) {
return pht(
'%s changed this repository to be hosted on Phabricator.',
$this->renderHandleLink($author_phid));
} else {
return pht(
'%s changed this repository to track a remote elsewhere.',
$this->renderHandleLink($author_phid));
}
case self::TYPE_PROTOCOL_HTTP:
return pht(
'%s changed the availability of this repository over HTTP from '.
'"%s" to "%s".',
$this->renderHandleLink($author_phid),
PhabricatorRepository::getProtocolAvailabilityName($old),
PhabricatorRepository::getProtocolAvailabilityName($new));
case self::TYPE_PROTOCOL_SSH:
return pht(
'%s changed the availability of this repository over SSH from '.
'"%s" to "%s".',
$this->renderHandleLink($author_phid),
PhabricatorRepository::getProtocolAvailabilityName($old),
PhabricatorRepository::getProtocolAvailabilityName($new));
case self::TYPE_PUSH_POLICY:
return pht(
'%s changed the push policy of this repository from "%s" to "%s".',
$this->renderHandleLink($author_phid),
$this->renderPolicyName($old),
$this->renderPolicyName($new));
}
return parent::getTitle();
}
public function hasChangeDetails() {
switch ($this->getTransactionType()) {
case self::TYPE_DESCRIPTION:
return true;
}
return parent::hasChangeDetails();
}
public function renderChangeDetails(PhabricatorUser $viewer) {
$old = $this->getOldValue();
$new = $this->getNewValue();
$view = id(new PhabricatorApplicationTransactionTextDiffDetailView())
->setUser($viewer)
->setOldText($old)
->setNewText($new);
return $view->render();
}
}
diff --git a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
index 253633fddc..95ffc58695 100644
--- a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
+++ b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
@@ -1,1781 +1,1789 @@
<?php
final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
public function getNamespace() {
return 'phabricator';
}
private function getPatchPath($file) {
$root = dirname(phutil_get_library_root('phabricator'));
$path = $root.'/resources/sql/patches/'.$file;
// Make sure it exists.
Filesystem::readFile($path);
return $path;
}
public function getPatches() {
return array(
'db.audit' => array(
'type' => 'db',
'name' => 'audit',
'after' => array( /* First Patch */ ),
),
'db.calendar' => array(
'type' => 'db',
'name' => 'calendar',
),
'db.chatlog' => array(
'type' => 'db',
'name' => 'chatlog',
),
'db.conduit' => array(
'type' => 'db',
'name' => 'conduit',
),
'db.countdown' => array(
'type' => 'db',
'name' => 'countdown',
),
'db.daemon' => array(
'type' => 'db',
'name' => 'daemon',
),
'db.differential' => array(
'type' => 'db',
'name' => 'differential',
),
'db.draft' => array(
'type' => 'db',
'name' => 'draft',
),
'db.drydock' => array(
'type' => 'db',
'name' => 'drydock',
),
'db.feed' => array(
'type' => 'db',
'name' => 'feed',
),
'db.file' => array(
'type' => 'db',
'name' => 'file',
),
'db.flag' => array(
'type' => 'db',
'name' => 'flag',
),
'db.harbormaster' => array(
'type' => 'db',
'name' => 'harbormaster',
),
'db.herald' => array(
'type' => 'db',
'name' => 'herald',
),
'db.maniphest' => array(
'type' => 'db',
'name' => 'maniphest',
),
'db.meta_data' => array(
'type' => 'db',
'name' => 'meta_data',
),
'db.metamta' => array(
'type' => 'db',
'name' => 'metamta',
),
'db.oauth_server' => array(
'type' => 'db',
'name' => 'oauth_server',
),
'db.owners' => array(
'type' => 'db',
'name' => 'owners',
),
'db.pastebin' => array(
'type' => 'db',
'name' => 'pastebin',
),
'db.phame' => array(
'type' => 'db',
'name' => 'phame',
),
'db.phriction' => array(
'type' => 'db',
'name' => 'phriction',
),
'db.project' => array(
'type' => 'db',
'name' => 'project',
),
'db.repository' => array(
'type' => 'db',
'name' => 'repository',
),
'db.search' => array(
'type' => 'db',
'name' => 'search',
),
'db.slowvote' => array(
'type' => 'db',
'name' => 'slowvote',
),
'db.timeline' => array(
'type' => 'db',
'name' => 'timeline',
'dead' => true,
),
'db.user' => array(
'type' => 'db',
'name' => 'user',
),
'db.worker' => array(
'type' => 'db',
'name' => 'worker',
),
'db.xhpastview' => array(
'type' => 'db',
'name' => 'xhpastview',
),
'db.cache' => array(
'type' => 'db',
'name' => 'cache',
),
'db.fact' => array(
'type' => 'db',
'name' => 'fact',
),
'db.ponder' => array(
'type' => 'db',
'name' => 'ponder',
),
'db.xhprof' => array(
'type' => 'db',
'name' => 'xhprof',
),
'db.pholio' => array(
'type' => 'db',
'name' => 'pholio',
),
'db.conpherence' => array(
'type' => 'db',
'name' => 'conpherence',
),
'db.config' => array(
'type' => 'db',
'name' => 'config',
),
'db.token' => array(
'type' => 'db',
'name' => 'token',
),
'db.releeph' => array(
'type' => 'db',
'name' => 'releeph',
),
'db.phlux' => array(
'type' => 'db',
'name' => 'phlux',
),
'db.phortune' => array(
'type' => 'db',
'name' => 'phortune',
),
'db.phrequent' => array(
'type' => 'db',
'name' => 'phrequent',
),
'db.diviner' => array(
'type' => 'db',
'name' => 'diviner',
),
'db.auth' => array(
'type' => 'db',
'name' => 'auth',
),
'db.doorkeeper' => array(
'type' => 'db',
'name' => 'doorkeeper',
),
'db.legalpad' => array(
'type' => 'db',
'name' => 'legalpad',
),
'db.policy' => array(
'type' => 'db',
'name' => 'policy',
),
'db.nuance' => array(
'type' => 'db',
'name' => 'nuance',
),
'db.passphrase' => array(
'type' => 'db',
'name' => 'passphrase',
),
'0000.legacy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('0000.legacy.sql'),
'legacy' => 0,
),
'000.project.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('000.project.sql'),
'legacy' => 0,
),
'001.maniphest_projects.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('001.maniphest_projects.sql'),
'legacy' => 1,
),
'002.oauth.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('002.oauth.sql'),
'legacy' => 2,
),
'003.more_oauth.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('003.more_oauth.sql'),
'legacy' => 3,
),
'004.daemonrepos.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('004.daemonrepos.sql'),
'legacy' => 4,
),
'005.workers.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('005.workers.sql'),
'legacy' => 5,
),
'006.repository.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('006.repository.sql'),
'legacy' => 6,
),
'007.daemonlog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('007.daemonlog.sql'),
'legacy' => 7,
),
'008.repoopt.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('008.repoopt.sql'),
'legacy' => 8,
),
'009.repo_summary.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('009.repo_summary.sql'),
'legacy' => 9,
),
'010.herald.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('010.herald.sql'),
'legacy' => 10,
),
'011.badcommit.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('011.badcommit.sql'),
'legacy' => 11,
),
'012.dropphidtype.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('012.dropphidtype.sql'),
'legacy' => 12,
),
'013.commitdetail.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('013.commitdetail.sql'),
'legacy' => 13,
),
'014.shortcuts.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('014.shortcuts.sql'),
'legacy' => 14,
),
'015.preferences.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('015.preferences.sql'),
'legacy' => 15,
),
'016.userrealnameindex.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('016.userrealnameindex.sql'),
'legacy' => 16,
),
'017.sessionkeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('017.sessionkeys.sql'),
'legacy' => 17,
),
'018.owners.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('018.owners.sql'),
'legacy' => 18,
),
'019.arcprojects.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('019.arcprojects.sql'),
'legacy' => 19,
),
'020.pathcapital.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('020.pathcapital.sql'),
'legacy' => 20,
),
'021.xhpastview.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('021.xhpastview.sql'),
'legacy' => 21,
),
'022.differentialcommit.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('022.differentialcommit.sql'),
'legacy' => 22,
),
'023.dxkeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('023.dxkeys.sql'),
'legacy' => 23,
),
'024.mlistkeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('024.mlistkeys.sql'),
'legacy' => 24,
),
'025.commentopt.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('025.commentopt.sql'),
'legacy' => 25,
),
'026.diffpropkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('026.diffpropkey.sql'),
'legacy' => 26,
),
'027.metamtakeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('027.metamtakeys.sql'),
'legacy' => 27,
),
'028.systemagent.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('028.systemagent.sql'),
'legacy' => 28,
),
'029.cursors.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('029.cursors.sql'),
'legacy' => 29,
),
'030.imagemacro.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('030.imagemacro.sql'),
'legacy' => 30,
),
'031.workerrace.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('031.workerrace.sql'),
'legacy' => 31,
),
'032.viewtime.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('032.viewtime.sql'),
'legacy' => 32,
),
'033.privtest.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('033.privtest.sql'),
'legacy' => 33,
),
'034.savedheader.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('034.savedheader.sql'),
'legacy' => 34,
),
'035.proxyimage.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('035.proxyimage.sql'),
'legacy' => 35,
),
'036.mailkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('036.mailkey.sql'),
'legacy' => 36,
),
'037.setuptest.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('037.setuptest.sql'),
'legacy' => 37,
),
'038.admin.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('038.admin.sql'),
'legacy' => 38,
),
'039.userlog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('039.userlog.sql'),
'legacy' => 39,
),
'040.transform.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('040.transform.sql'),
'legacy' => 40,
),
'041.heraldrepetition.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('041.heraldrepetition.sql'),
'legacy' => 41,
),
'042.commentmetadata.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('042.commentmetadata.sql'),
'legacy' => 42,
),
'043.pastebin.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('043.pastebin.sql'),
'legacy' => 43,
),
'044.countdown.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('044.countdown.sql'),
'legacy' => 44,
),
'045.timezone.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('045.timezone.sql'),
'legacy' => 45,
),
'046.conduittoken.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('046.conduittoken.sql'),
'legacy' => 46,
),
'047.projectstatus.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('047.projectstatus.sql'),
'legacy' => 47,
),
'048.relationshipkeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('048.relationshipkeys.sql'),
'legacy' => 48,
),
'049.projectowner.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('049.projectowner.sql'),
'legacy' => 49,
),
'050.taskdenormal.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('050.taskdenormal.sql'),
'legacy' => 50,
),
'051.projectfilter.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('051.projectfilter.sql'),
'legacy' => 51,
),
'052.pastelanguage.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('052.pastelanguage.sql'),
'legacy' => 52,
),
'053.feed.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('053.feed.sql'),
'legacy' => 53,
),
'054.subscribers.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('054.subscribers.sql'),
'legacy' => 54,
),
'055.add_author_to_files.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('055.add_author_to_files.sql'),
'legacy' => 55,
),
'056.slowvote.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('056.slowvote.sql'),
'legacy' => 56,
),
'057.parsecache.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('057.parsecache.sql'),
'legacy' => 57,
),
'058.missingkeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('058.missingkeys.sql'),
'legacy' => 58,
),
'059.engines.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('059.engines.php'),
'legacy' => 59,
),
'060.phriction.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('060.phriction.sql'),
'legacy' => 60,
),
'061.phrictioncontent.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('061.phrictioncontent.sql'),
'legacy' => 61,
),
'062.phrictionmenu.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('062.phrictionmenu.sql'),
'legacy' => 62,
),
'063.pasteforks.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('063.pasteforks.sql'),
'legacy' => 63,
),
'064.subprojects.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('064.subprojects.sql'),
'legacy' => 64,
),
'065.sshkeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('065.sshkeys.sql'),
'legacy' => 65,
),
'066.phrictioncontent.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('066.phrictioncontent.sql'),
'legacy' => 66,
),
'067.preferences.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('067.preferences.sql'),
'legacy' => 67,
),
'068.maniphestauxiliarystorage.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('068.maniphestauxiliarystorage.sql'),
'legacy' => 68,
),
'069.heraldxscript.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('069.heraldxscript.sql'),
'legacy' => 69,
),
'070.differentialaux.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('070.differentialaux.sql'),
'legacy' => 70,
),
'071.contentsource.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('071.contentsource.sql'),
'legacy' => 71,
),
'072.blamerevert.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('072.blamerevert.sql'),
'legacy' => 72,
),
'073.reposymbols.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('073.reposymbols.sql'),
'legacy' => 73,
),
'074.affectedpath.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('074.affectedpath.sql'),
'legacy' => 74,
),
'075.revisionhash.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('075.revisionhash.sql'),
'legacy' => 75,
),
'076.indexedlanguages.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('076.indexedlanguages.sql'),
'legacy' => 76,
),
'077.originalemail.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('077.originalemail.sql'),
'legacy' => 77,
),
'078.nametoken.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('078.nametoken.sql'),
'legacy' => 78,
),
'079.nametokenindex.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('079.nametokenindex.php'),
'legacy' => 79,
),
'080.filekeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('080.filekeys.sql'),
'legacy' => 80,
),
'081.filekeys.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('081.filekeys.php'),
'legacy' => 81,
),
'082.xactionkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('082.xactionkey.sql'),
'legacy' => 82,
),
'083.dxviewtime.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('083.dxviewtime.sql'),
'legacy' => 83,
),
'084.pasteauthorkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('084.pasteauthorkey.sql'),
'legacy' => 84,
),
'085.packagecommitrelationship.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('085.packagecommitrelationship.sql'),
'legacy' => 85,
),
'086.formeraffil.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('086.formeraffil.sql'),
'legacy' => 86,
),
'087.phrictiondelete.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('087.phrictiondelete.sql'),
'legacy' => 87,
),
'088.audit.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('088.audit.sql'),
'legacy' => 88,
),
'089.projectwiki.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('089.projectwiki.sql'),
'legacy' => 89,
),
'090.forceuniqueprojectnames.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('090.forceuniqueprojectnames.php'),
'legacy' => 90,
),
'091.uniqueslugkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('091.uniqueslugkey.sql'),
'legacy' => 91,
),
'092.dropgithubnotification.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('092.dropgithubnotification.sql'),
'legacy' => 92,
),
'093.gitremotes.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('093.gitremotes.php'),
'legacy' => 93,
),
'094.phrictioncolumn.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('094.phrictioncolumn.sql'),
'legacy' => 94,
),
'095.directory.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('095.directory.sql'),
'legacy' => 95,
),
'096.filename.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('096.filename.sql'),
'legacy' => 96,
),
'097.heraldruletypes.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('097.heraldruletypes.sql'),
'legacy' => 97,
),
'098.heraldruletypemigration.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('098.heraldruletypemigration.php'),
'legacy' => 98,
),
'099.drydock.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('099.drydock.sql'),
'legacy' => 99,
),
'100.projectxaction.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('100.projectxaction.sql'),
'legacy' => 100,
),
'101.heraldruleapplied.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('101.heraldruleapplied.sql'),
'legacy' => 101,
),
'102.heraldcleanup.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('102.heraldcleanup.php'),
'legacy' => 102,
),
'103.heraldedithistory.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('103.heraldedithistory.sql'),
'legacy' => 103,
),
'104.searchkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('104.searchkey.sql'),
'legacy' => 104,
),
'105.mimetype.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('105.mimetype.sql'),
'legacy' => 105,
),
'106.chatlog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('106.chatlog.sql'),
'legacy' => 106,
),
'107.oauthserver.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('107.oauthserver.sql'),
'legacy' => 107,
),
'108.oauthscope.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('108.oauthscope.sql'),
'legacy' => 108,
),
'109.oauthclientphidkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('109.oauthclientphidkey.sql'),
'legacy' => 109,
),
'110.commitaudit.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('110.commitaudit.sql'),
'legacy' => 110,
),
'111.commitauditmigration.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('111.commitauditmigration.php'),
'legacy' => 111,
),
'112.oauthaccesscoderedirecturi.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('112.oauthaccesscoderedirecturi.sql'),
'legacy' => 112,
),
'113.lastreviewer.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('113.lastreviewer.sql'),
'legacy' => 113,
),
'114.auditrequest.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('114.auditrequest.sql'),
'legacy' => 114,
),
'115.prepareutf8.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('115.prepareutf8.sql'),
'legacy' => 115,
),
'116.utf8-backup-first-expect-wait.sql' => array(
'type' => 'sql',
'name' =>
$this->getPatchPath('116.utf8-backup-first-expect-wait.sql'),
'legacy' => 116,
),
'117.repositorydescription.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('117.repositorydescription.php'),
'legacy' => 117,
),
'118.auditinline.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('118.auditinline.sql'),
'legacy' => 118,
),
'119.filehash.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('119.filehash.sql'),
'legacy' => 119,
),
'120.noop.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('120.noop.sql'),
'legacy' => 120,
),
'121.drydocklog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('121.drydocklog.sql'),
'legacy' => 121,
),
'122.flag.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('122.flag.sql'),
'legacy' => 122,
),
'123.heraldrulelog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('123.heraldrulelog.sql'),
'legacy' => 123,
),
'124.subpriority.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('124.subpriority.sql'),
'legacy' => 124,
),
'125.ipv6.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('125.ipv6.sql'),
'legacy' => 125,
),
'126.edges.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('126.edges.sql'),
'legacy' => 126,
),
'127.userkeybody.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('127.userkeybody.sql'),
'legacy' => 127,
),
'128.phabricatorcom.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('128.phabricatorcom.sql'),
'legacy' => 128,
),
'129.savedquery.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('129.savedquery.sql'),
'legacy' => 129,
),
'130.denormalrevisionquery.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('130.denormalrevisionquery.sql'),
'legacy' => 130,
),
'131.migraterevisionquery.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('131.migraterevisionquery.php'),
'legacy' => 131,
),
'132.phame.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('132.phame.sql'),
'legacy' => 132,
),
'133.imagemacro.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('133.imagemacro.sql'),
'legacy' => 133,
),
'134.emptysearch.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('134.emptysearch.sql'),
'legacy' => 134,
),
'135.datecommitted.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('135.datecommitted.sql'),
'legacy' => 135,
),
'136.sex.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('136.sex.sql'),
'legacy' => 136,
),
'137.auditmetadata.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('137.auditmetadata.sql'),
'legacy' => 137,
),
'138.notification.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('138.notification.sql'),
),
'holidays.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('holidays.sql'),
),
'userstatus.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('userstatus.sql'),
),
'emailtable.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('emailtable.sql'),
),
'emailtableport.sql' => array(
'type' => 'php',
'name' => $this->getPatchPath('emailtableport.php'),
),
'emailtableremove.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('emailtableremove.sql'),
),
'phiddrop.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('phiddrop.sql'),
),
'testdatabase.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('testdatabase.sql'),
),
'ldapinfo.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('ldapinfo.sql'),
),
'threadtopic.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('threadtopic.sql'),
),
'usertranslation.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('usertranslation.sql'),
),
'differentialbookmarks.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('differentialbookmarks.sql'),
),
'harbormasterobject.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('harbormasterobject.sql'),
),
'markupcache.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('markupcache.sql'),
),
'maniphestxcache.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('maniphestxcache.sql'),
),
'migrate-maniphest-dependencies.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('migrate-maniphest-dependencies.php'),
),
'migrate-differential-dependencies.php' => array(
'type' => 'php',
'name' => $this->getPatchPath(
'migrate-differential-dependencies.php'),
),
'phameblog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('phameblog.sql'),
),
'migrate-maniphest-revisions.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('migrate-maniphest-revisions.php'),
),
'daemonstatus.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('daemonstatus.sql'),
),
'symbolcontexts.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('symbolcontexts.sql'),
),
'migrate-project-edges.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('migrate-project-edges.php'),
),
'fact-raw.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('fact-raw.sql'),
),
'ponder.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('ponder.sql')
),
'policy-project.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('policy-project.sql'),
),
'daemonstatuskey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('daemonstatuskey.sql'),
),
'edgetype.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('edgetype.sql'),
),
'ponder-comments.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('ponder-comments.sql'),
),
'pastepolicy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('pastepolicy.sql'),
),
'xhprof.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('xhprof.sql'),
),
'draft-metadata.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('draft-metadata.sql'),
),
'phamedomain.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('phamedomain.sql'),
),
'ponder-mailkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('ponder-mailkey.sql'),
),
'ponder-mailkey-populate.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('ponder-mailkey-populate.php'),
),
'phamepolicy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('phamepolicy.sql'),
),
'phameoneblog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('phameoneblog.sql'),
),
'statustxt.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('statustxt.sql'),
),
'daemontaskarchive.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('daemontaskarchive.sql'),
),
'drydocktaskid.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('drydocktaskid.sql'),
),
'drydockresoucetype.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('drydockresourcetype.sql'),
),
'liskcounters.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('liskcounters.sql'),
),
'liskcounters.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('liskcounters.php'),
),
'dropfileproxyimage.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('dropfileproxyimage.sql'),
),
'repository-lint.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('repository-lint.sql'),
),
'liskcounters-task.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('liskcounters-task.sql'),
),
'pholio.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('pholio.sql'),
),
'owners-exclude.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('owners-exclude.sql'),
),
'20121209.pholioxactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20121209.pholioxactions.sql'),
),
'20121209.xmacroadd.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20121209.xmacroadd.sql'),
),
'20121209.xmacromigrate.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20121209.xmacromigrate.php'),
),
'20121209.xmacromigratekey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20121209.xmacromigratekey.sql'),
),
'20121220.generalcache.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20121220.generalcache.sql'),
),
'20121226.config.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20121226.config.sql'),
),
'20130101.confxaction.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130101.confxaction.sql'),
),
'20130102.metamtareceivedmailmessageidhash.sql' => array(
'type' => 'sql',
'name' =>
$this->getPatchPath('20130102.metamtareceivedmailmessageidhash.sql'),
),
'20130103.filemetadata.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130103.filemetadata.sql'),
),
'20130111.conpherence.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130111.conpherence.sql'),
),
'20130127.altheraldtranscript.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130127.altheraldtranscript.sql'),
),
'20130201.revisionunsubscribed.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130201.revisionunsubscribed.php'),
),
'20130201.revisionunsubscribed.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130201.revisionunsubscribed.sql'),
),
'20130131.conpherencepics.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130131.conpherencepics.sql'),
),
'20130214.chatlogchannel.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130214.chatlogchannel.sql'),
),
'20130214.chatlogchannelid.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130214.chatlogchannelid.sql'),
),
'20130214.token.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130214.token.sql'),
),
'20130215.phabricatorfileaddttl.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130215.phabricatorfileaddttl.sql'),
),
'20130217.cachettl.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130217.cachettl.sql'),
),
'20130218.updatechannelid.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130218.updatechannelid.php'),
),
'20130218.longdaemon.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130218.longdaemon.sql'),
),
'20130219.commitsummary.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130219.commitsummary.sql'),
),
'20130219.commitsummarymig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130219.commitsummarymig.php'),
),
'20130222.dropchannel.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130222.dropchannel.sql'),
),
'20130226.commitkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130226.commitkey.sql'),
),
'20131302.maniphestvalue.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131302.maniphestvalue.sql'),
),
'20130304.lintauthor.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130304.lintauthor.sql'),
),
'releeph.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('releeph.sql'),
),
'20130319.phabricatorfileexplicitupload.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath(
'20130319.phabricatorfileexplicitupload.sql')
),
'20130319.conpherence.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130319.conpherence.sql'),
),
'20130320.phlux.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130320.phlux.sql'),
),
'20130317.phrictionedge.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130317.phrictionedge.sql'),
),
'20130321.token.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130321.token.sql'),
),
'20130310.xactionmeta.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130310.xactionmeta.sql'),
),
'20130322.phortune.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130322.phortune.sql'),
),
'20130323.phortunepayment.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130323.phortunepayment.sql'),
),
'20130324.phortuneproduct.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130324.phortuneproduct.sql'),
),
'20130330.phrequent.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130330.phrequent.sql'),
),
'20130403.conpherencecache.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130403.conpherencecache.sql'),
),
'20130403.conpherencecachemig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130403.conpherencecachemig.php'),
),
'20130409.commitdrev.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130409.commitdrev.php'),
),
'20130417.externalaccount.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130417.externalaccount.sql'),
),
'20130423.updateexternalaccount.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130423.updateexternalaccount.sql'),
),
'20130423.phortunepaymentrevised.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130423.phortunepaymentrevised.sql'),
),
'20130423.conpherenceindices.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130423.conpherenceindices.sql'),
),
'20130426.search_savedquery.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130426.search_savedquery.sql'),
),
'20130502.countdownrevamp1.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130502.countdownrevamp1.sql'),
),
'20130502.countdownrevamp2.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130502.countdownrevamp2.php'),
),
'20130502.countdownrevamp3.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130502.countdownrevamp3.sql'),
),
'20130507.releephrqsimplifycols.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130507.releephrqsimplifycols.sql'),
),
'20130507.releephrqmailkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130507.releephrqmailkey.sql'),
),
'20130507.releephrqmailkeypop.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130507.releephrqmailkeypop.php'),
),
'20130508.search_namedquery.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130508.search_namedquery.sql'),
),
'20130508.releephtransactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130508.releephtransactions.sql'),
),
'20130508.releephtransactionsmig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130508.releephtransactionsmig.php'),
),
'20130513.receviedmailstatus.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130513.receviedmailstatus.sql'),
),
'20130519.diviner.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130519.diviner.sql'),
),
'20130521.dropconphimages.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130521.dropconphimages.sql'),
),
'20130523.maniphest_owners.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130523.maniphest_owners.sql'),
),
'20130524.repoxactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130524.repoxactions.sql'),
),
'20130529.macroauthor.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130529.macroauthor.sql'),
),
'20130529.macroauthormig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130529.macroauthormig.php'),
),
'20130530.sessionhash.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130530.sessionhash.php'),
),
'20130530.macrodatekey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130530.macrodatekey.sql'),
),
'20130530.pastekeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130530.pastekeys.sql'),
),
'20130531.filekeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130531.filekeys.sql'),
),
'20130602.morediviner.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130602.morediviner.sql'),
),
'20130602.namedqueries.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130602.namedqueries.sql'),
),
'20130606.userxactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130606.userxactions.sql'),
),
'20130607.xaccount.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130607.xaccount.sql'),
),
'20130611.migrateoauth.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130611.migrateoauth.php'),
),
'20130611.nukeldap.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130611.nukeldap.php'),
),
'20130613.authdb.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130613.authdb.sql'),
),
'20130619.authconf.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130619.authconf.php'),
),
'20130620.diffxactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130620.diffxactions.sql'),
),
'20130621.diffcommentphid.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130621.diffcommentphid.sql'),
),
'20130621.diffcommentphidmig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130621.diffcommentphidmig.php'),
),
'20130621.diffcommentunphid.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130621.diffcommentunphid.sql'),
),
'20130622.doorkeeper.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130622.doorkeeper.sql'),
),
'20130628.legalpadv0.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130628.legalpadv0.sql'),
),
'20130701.conduitlog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130701.conduitlog.sql'),
),
'legalpad-mailkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('legalpad-mailkey.sql'),
),
'legalpad-mailkey-populate.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('legalpad-mailkey-populate.php'),
),
'20130703.legalpaddocdenorm.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130703.legalpaddocdenorm.sql'),
),
'20130703.legalpaddocdenorm.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130703.legalpaddocdenorm.php'),
),
'20130709.legalpadsignature.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130709.legalpadsignature.sql'),
),
'20130709.droptimeline.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130709.droptimeline.sql'),
),
'20130711.trimrealnames.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130711.trimrealnames.php'),
),
'20130714.votexactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130714.votexactions.sql'),
),
'20130715.votecomments.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130715.votecomments.php'),
),
'20130715.voteedges.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130715.voteedges.sql'),
),
'20130711.pholioimageobsolete.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130711.pholioimageobsolete.sql'),
),
'20130711.pholioimageobsolete.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130711.pholioimageobsolete.php'),
),
'20130711.pholioimageobsolete2.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130711.pholioimageobsolete2.sql'),
),
'20130716.archivememberlessprojects.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130716.archivememberlessprojects.php'),
),
'20130722.pholioreplace.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130722.pholioreplace.sql'),
),
'20130723.taskstarttime.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130723.taskstarttime.sql'),
),
'20130727.ponderquestionstatus.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130727.ponderquestionstatus.sql'),
),
'20130726.ponderxactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130726.ponderxactions.sql'),
),
'20130728.ponderunique.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130728.ponderunique.php'),
),
'20130728.ponderuniquekey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130728.ponderuniquekey.sql'),
),
'20130728.ponderxcomment.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130728.ponderxcomment.php'),
),
'20130801.pastexactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130801.pastexactions.sql'),
),
'20130801.pastexactions.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130801.pastexactions.php'),
),
'20130805.pastemailkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130805.pastemailkey.sql'),
),
'20130805.pasteedges.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130805.pasteedges.sql'),
),
'20130805.pastemailkeypop.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130805.pastemailkeypop.php'),
),
'20130802.heraldphid.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130802.heraldphid.sql'),
),
'20130802.heraldphids.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130802.heraldphids.php'),
),
'20130802.heraldphidukey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130802.heraldphidukey.sql'),
),
'20130802.heraldxactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130802.heraldxactions.sql'),
),
'20130731.releephrepoid.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130731.releephrepoid.sql'),
),
'20130731.releephproject.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130731.releephproject.sql'),
),
'20130731.releephcutpointidentifier.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130731.releephcutpointidentifier.sql'),
),
'20130814.usercustom.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130814.usercustom.sql'),
),
'20130820.releephxactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130820.releephxactions.sql'),
),
'20130826.divinernode.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130826.divinernode.sql'),
),
'20130820.filexactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130820.filexactions.sql'),
),
'20130820.filemailkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130820.filemailkey.sql'),
),
'20130820.file-mailkey-populate.php' => array(
'type' => 'php',
'name' =>
$this->getPatchPath('20130820.file-mailkey-populate.php'),
),
'20130912.maniphest.1.touch.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130912.maniphest.1.touch.sql'),
),
'20130912.maniphest.2.created.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130912.maniphest.2.created.sql'),
),
'20130912.maniphest.3.nameindex.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130912.maniphest.3.nameindex.sql'),
),
'20130912.maniphest.4.fillindex.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130912.maniphest.4.fillindex.php'),
),
'20130913.maniphest.1.migratesearch.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130913.maniphest.1.migratesearch.php'),
),
'20130914.usercustom.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130914.usercustom.sql'),
),
'20130915.maniphestcustom.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130915.maniphestcustom.sql'),
),
'20130915.maniphestmigrate.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130915.maniphestmigrate.php'),
),
'20130919.mfieldconf.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130919.mfieldconf.php'),
),
'20130920.repokeyspolicy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130920.repokeyspolicy.sql'),
),
'20130921.mtransactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130921.mtransactions.sql'),
),
'20130921.xmigratemaniphest.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130921.xmigratemaniphest.php'),
),
'20130923.mrename.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130923.mrename.sql'),
),
'20130924.mdraftkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130924.mdraftkey.sql'),
),
'20130925.mpolicy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130925.mpolicy.sql'),
),
'20130925.xpolicy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130925.xpolicy.sql'),
),
'20130926.dcustom.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130926.dcustom.sql'),
),
'20130926.dinkeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130926.dinkeys.sql'),
),
'20130927.audiomacro.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130927.audiomacro.sql'),
),
'20130929.filepolicy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130929.filepolicy.sql'),
),
'20131004.dxedgekey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131004.dxedgekey.sql'),
),
'20131004.dxreviewers.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20131004.dxreviewers.php'),
),
'20131006.hdisable.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131006.hdisable.sql'),
),
'20131010.pstorage.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131010.pstorage.sql'),
),
'20131015.cpolicy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131015.cpolicy.sql'),
),
'20130915.maniphestqdrop.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130915.maniphestqdrop.sql'),
),
'20130926.dinline.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130926.dinline.php'),
),
'20131020.pcustom.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131020.pcustom.sql'),
),
'20131020.col1.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131020.col1.sql'),
),
'20131020.pxaction.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131020.pxaction.sql'),
),
'20131020.pxactionmig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20131020.pxactionmig.php'),
),
'20131020.harbormaster.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131020.harbormaster.sql'),
),
'20131025.repopush.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131025.repopush.sql'),
),
'20131026.commitstatus.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131026.commitstatus.sql'),
),
'20131030.repostatusmessage.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131030.repostatusmessage.sql'),
),
'20131031.vcspassword.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131031.vcspassword.sql'),
),
'20131105.buildstep.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131105.buildstep.sql'),
),
'20131106.diffphid.1.col.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131106.diffphid.1.col.sql'),
),
'20131106.diffphid.2.mig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20131106.diffphid.2.mig.php'),
),
'20131106.diffphid.3.key.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131106.diffphid.3.key.sql'),
),
'20131106.nuance-v0.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131106.nuance-v0.sql'),
),
'20131107.buildlog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131107.buildlog.sql'),
),
'20131112.userverified.1.col.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131112.userverified.1.col.sql'),
),
'20131112.userverified.2.mig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20131112.userverified.2.mig.php'),
),
'20131118.ownerorder.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20131118.ownerorder.php'),
),
'20131119.passphrase.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131119.passphrase.sql'),
),
'20131120.nuancesourcetype.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131120.nuancesourcetype.sql'),
),
'20131121.passphraseedge.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131121.passphraseedge.sql'),
),
+ '20131121.repocredentials.1.col.sql' => array(
+ 'type' => 'sql',
+ 'name' => $this->getPatchPath('20131121.repocredentials.1.col.sql'),
+ ),
+ '20131121.repocredentials.2.mig.php' => array(
+ 'type' => 'php',
+ 'name' => $this->getPatchPath('20131121.repocredentials.2.mig.php'),
+ ),
);
}
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 3, 3:09 PM (9 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
165922
Default Alt Text
(195 KB)

Event Timeline