Disable git, svn, http protocols for VCS downloaders, fixes #4968
parent
cc14bb3ba9
commit
6f42b9c865
|
@ -1,5 +1,6 @@
|
||||||
### [1.0.0-beta1] - 2016-XX-XX
|
### [1.0.0-beta1] - 2016-XX-XX
|
||||||
|
|
||||||
|
* Break: By default we now disable any non-secure protocols (http, git, svn). This may lead to issues if you rely on those. See `secure-http` config option.
|
||||||
* Added VCS repo support for the GitLab API, see also `gitlab-oauth` and `gitlab-domains` config options
|
* Added VCS repo support for the GitLab API, see also `gitlab-oauth` and `gitlab-domains` config options
|
||||||
* Added `prohibits` / `why-not` command to show what blocks an upgrade to a given package:version pair
|
* Added `prohibits` / `why-not` command to show what blocks an upgrade to a given package:version pair
|
||||||
* Added --tree / -t to the `show` command to see all your installed packages in a tree view
|
* Added --tree / -t to the `show` command to see all your installed packages in a tree view
|
||||||
|
|
|
@ -26,7 +26,7 @@ class Config
|
||||||
'use-include-path' => false,
|
'use-include-path' => false,
|
||||||
'preferred-install' => 'auto',
|
'preferred-install' => 'auto',
|
||||||
'notify-on-install' => true,
|
'notify-on-install' => true,
|
||||||
'github-protocols' => array('git', 'https', 'ssh'),
|
'github-protocols' => array('https', 'ssh', 'git'),
|
||||||
'vendor-dir' => 'vendor',
|
'vendor-dir' => 'vendor',
|
||||||
'bin-dir' => '{$vendor-dir}/bin',
|
'bin-dir' => '{$vendor-dir}/bin',
|
||||||
'cache-dir' => '{$home}/cache',
|
'cache-dir' => '{$home}/cache',
|
||||||
|
@ -285,11 +285,15 @@ class Config
|
||||||
return $this->config[$key];
|
return $this->config[$key];
|
||||||
|
|
||||||
case 'github-protocols':
|
case 'github-protocols':
|
||||||
if (reset($this->config['github-protocols']) === 'http') {
|
$protos = $this->config['github-protocols'];
|
||||||
|
if ($this->config['secure-http'] && false !== ($index = array_search('git', $protos))) {
|
||||||
|
unset($protos[$index]);
|
||||||
|
}
|
||||||
|
if (reset($protos) === 'http') {
|
||||||
throw new \RuntimeException('The http protocol for github is not available anymore, update your config\'s github-protocols to use "https", "git" or "ssh"');
|
throw new \RuntimeException('The http protocol for github is not available anymore, update your config\'s github-protocols to use "https", "git" or "ssh"');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->config[$key];
|
return $protos;
|
||||||
|
|
||||||
case 'disable-tls':
|
case 'disable-tls':
|
||||||
return $this->config[$key] !== 'false' && (bool) $this->config[$key];
|
return $this->config[$key] !== 'false' && (bool) $this->config[$key];
|
||||||
|
|
|
@ -25,6 +25,8 @@ class HgDownloader extends VcsDownloader
|
||||||
*/
|
*/
|
||||||
public function doDownload(PackageInterface $package, $path, $url)
|
public function doDownload(PackageInterface $package, $path, $url)
|
||||||
{
|
{
|
||||||
|
$this->checkSecureHttp($url);
|
||||||
|
|
||||||
$url = ProcessExecutor::escape($url);
|
$url = ProcessExecutor::escape($url);
|
||||||
$ref = ProcessExecutor::escape($package->getSourceReference());
|
$ref = ProcessExecutor::escape($package->getSourceReference());
|
||||||
$this->io->writeError(" Cloning ".$package->getSourceReference());
|
$this->io->writeError(" Cloning ".$package->getSourceReference());
|
||||||
|
@ -43,6 +45,8 @@ class HgDownloader extends VcsDownloader
|
||||||
*/
|
*/
|
||||||
public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url)
|
public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url)
|
||||||
{
|
{
|
||||||
|
$this->checkSecureHttp($url);
|
||||||
|
|
||||||
$url = ProcessExecutor::escape($url);
|
$url = ProcessExecutor::escape($url);
|
||||||
$ref = ProcessExecutor::escape($target->getSourceReference());
|
$ref = ProcessExecutor::escape($target->getSourceReference());
|
||||||
$this->io->writeError(" Updating to ".$target->getSourceReference());
|
$this->io->writeError(" Updating to ".$target->getSourceReference());
|
||||||
|
@ -85,6 +89,13 @@ class HgDownloader extends VcsDownloader
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function checkSecureHttp($url)
|
||||||
|
{
|
||||||
|
if (preg_match('{^http:}i', $url) && $this->config->get('secure-http')) {
|
||||||
|
throw new TransportException("Your configuration does not allow connection to $url. See https://getcomposer.org/doc/06-config.md#secure-http for details.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -69,6 +69,10 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
|
||||||
$this->doDownload($package, $path, $url);
|
$this->doDownload($package, $path, $url);
|
||||||
break;
|
break;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
// rethrow phpunit exceptions to avoid hard to debug bug failures
|
||||||
|
if ($e instanceof \PHPUnit_Framework_Exception) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
if ($this->io->isDebug()) {
|
if ($this->io->isDebug()) {
|
||||||
$this->io->writeError('Failed: ['.get_class($e).'] '.$e->getMessage());
|
$this->io->writeError('Failed: ['.get_class($e).'] '.$e->getMessage());
|
||||||
} elseif (count($urls)) {
|
} elseif (count($urls)) {
|
||||||
|
|
|
@ -47,6 +47,10 @@ class HgDriver extends VcsDriver
|
||||||
throw new \RuntimeException('Can not clone '.$this->url.' to access package information. The "'.$cacheDir.'" directory is not writable by the current user.');
|
throw new \RuntimeException('Can not clone '.$this->url.' to access package information. The "'.$cacheDir.'" directory is not writable by the current user.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (preg_match('{^http:}i', $this->url) && $this->config->get('secure-http')) {
|
||||||
|
throw new TransportException("Your configuration does not allow connection to $url. See https://getcomposer.org/doc/06-config.md#secure-http for details.");
|
||||||
|
}
|
||||||
|
|
||||||
// update the repo if it is a valid hg repository
|
// update the repo if it is a valid hg repository
|
||||||
if (is_dir($this->repoDir) && 0 === $this->process->execute('hg summary', $output, $this->repoDir)) {
|
if (is_dir($this->repoDir) && 0 === $this->process->execute('hg summary', $output, $this->repoDir)) {
|
||||||
if (0 !== $this->process->execute('hg pull', $output, $this->repoDir)) {
|
if (0 !== $this->process->execute('hg pull', $output, $this->repoDir)) {
|
||||||
|
|
|
@ -39,6 +39,10 @@ class Git
|
||||||
|
|
||||||
public function runCommand($commandCallable, $url, $cwd, $initialClone = false)
|
public function runCommand($commandCallable, $url, $cwd, $initialClone = false)
|
||||||
{
|
{
|
||||||
|
if (preg_match('{^(http|git):}i', $url) && $this->config->get('secure-http')) {
|
||||||
|
throw new TransportException("Your configuration does not allow connection to $url. See https://getcomposer.org/doc/06-config.md#secure-http for details.");
|
||||||
|
}
|
||||||
|
|
||||||
if ($initialClone) {
|
if ($initialClone) {
|
||||||
$origCwd = $cwd;
|
$origCwd = $cwd;
|
||||||
$cwd = null;
|
$cwd = null;
|
||||||
|
@ -60,21 +64,20 @@ class Git
|
||||||
if (!is_array($protocols)) {
|
if (!is_array($protocols)) {
|
||||||
throw new \RuntimeException('Config value "github-protocols" must be an array, got '.gettype($protocols));
|
throw new \RuntimeException('Config value "github-protocols" must be an array, got '.gettype($protocols));
|
||||||
}
|
}
|
||||||
|
|
||||||
// public github, autoswitch protocols
|
// public github, autoswitch protocols
|
||||||
if (preg_match('{^(?:https?|git)://'.self::getGitHubDomainsRegex($this->config).'/(.*)}', $url, $match)) {
|
if (preg_match('{^(?:https?|git)://'.self::getGitHubDomainsRegex($this->config).'/(.*)}', $url, $match)) {
|
||||||
$messages = array();
|
$messages = array();
|
||||||
foreach ($protocols as $protocol) {
|
foreach ($protocols as $protocol) {
|
||||||
if ('ssh' === $protocol) {
|
if ('ssh' === $protocol) {
|
||||||
$url = "git@" . $match[1] . ":" . $match[2];
|
$protoUrl = "git@" . $match[1] . ":" . $match[2];
|
||||||
} else {
|
} else {
|
||||||
$url = $protocol ."://" . $match[1] . "/" . $match[2];
|
$protoUrl = $protocol ."://" . $match[1] . "/" . $match[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 === $this->process->execute(call_user_func($commandCallable, $url), $ignoredOutput, $cwd)) {
|
if (0 === $this->process->execute(call_user_func($commandCallable, $protoUrl), $ignoredOutput, $cwd)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$messages[] = '- ' . $url . "\n" . preg_replace('#^#m', ' ', $this->process->getErrorOutput());
|
$messages[] = '- ' . $protoUrl . "\n" . preg_replace('#^#m', ' ', $this->process->getErrorOutput());
|
||||||
if ($initialClone) {
|
if ($initialClone) {
|
||||||
$this->filesystem->removeDirectory($origCwd);
|
$this->filesystem->removeDirectory($origCwd);
|
||||||
}
|
}
|
||||||
|
@ -104,8 +107,8 @@ class Git
|
||||||
|
|
||||||
if ($this->io->hasAuthentication($match[1])) {
|
if ($this->io->hasAuthentication($match[1])) {
|
||||||
$auth = $this->io->getAuthentication($match[1]);
|
$auth = $this->io->getAuthentication($match[1]);
|
||||||
$url = 'https://'.rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@'.$match[1].'/'.$match[2].'.git';
|
$authUrl = 'https://'.rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@'.$match[1].'/'.$match[2].'.git';
|
||||||
$command = call_user_func($commandCallable, $url);
|
$command = call_user_func($commandCallable, $authUrl);
|
||||||
if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
|
if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -137,9 +140,9 @@ class Git
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($auth) {
|
if ($auth) {
|
||||||
$url = $match[1].rawurlencode($auth['username']).':'.rawurlencode($auth['password']).'@'.$match[2].$match[3];
|
$authUrl = $match[1].rawurlencode($auth['username']).':'.rawurlencode($auth['password']).'@'.$match[2].$match[3];
|
||||||
|
|
||||||
$command = call_user_func($commandCallable, $url);
|
$command = call_user_func($commandCallable, $authUrl);
|
||||||
if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
|
if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
|
||||||
$this->io->setAuthentication($match[2], $auth['username'], $auth['password']);
|
$this->io->setAuthentication($match[2], $auth['username'], $auth['password']);
|
||||||
$authHelper = new AuthHelper($this->io, $this->config);
|
$authHelper = new AuthHelper($this->io, $this->config);
|
||||||
|
|
|
@ -99,6 +99,10 @@ class Svn
|
||||||
*/
|
*/
|
||||||
public function execute($command, $url, $cwd = null, $path = null, $verbose = false)
|
public function execute($command, $url, $cwd = null, $path = null, $verbose = false)
|
||||||
{
|
{
|
||||||
|
if (preg_match('{^(http|svn):}i', $url) && $this->config->get('secure-http')) {
|
||||||
|
throw new TransportException("Your configuration does not allow connection to $url. See https://getcomposer.org/doc/06-config.md#secure-http for details.");
|
||||||
|
}
|
||||||
|
|
||||||
$svnCommand = $this->getCommand($command, $url, $path);
|
$svnCommand = $this->getCommand($command, $url, $path);
|
||||||
$output = null;
|
$output = null;
|
||||||
$io = $this->io;
|
$io = $this->io;
|
||||||
|
|
|
@ -196,12 +196,22 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
|
||||||
public function testOverrideGithubProtocols()
|
public function testOverrideGithubProtocols()
|
||||||
{
|
{
|
||||||
$config = new Config(false);
|
$config = new Config(false);
|
||||||
$config->merge(array('config' => array('github-protocols' => array('https', 'git'))));
|
$config->merge(array('config' => array('github-protocols' => array('https', 'ssh'))));
|
||||||
$config->merge(array('config' => array('github-protocols' => array('https'))));
|
$config->merge(array('config' => array('github-protocols' => array('https'))));
|
||||||
|
|
||||||
$this->assertEquals(array('https'), $config->get('github-protocols'));
|
$this->assertEquals(array('https'), $config->get('github-protocols'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testGitDisabledByDefaultInGithubProtocols()
|
||||||
|
{
|
||||||
|
$config = new Config(false);
|
||||||
|
$config->merge(array('config' => array('github-protocols' => array('https', 'git'))));
|
||||||
|
$this->assertEquals(array('https'), $config->get('github-protocols'));
|
||||||
|
|
||||||
|
$config->merge(array('config' => array('secure-http' => false)));
|
||||||
|
$this->assertEquals(array('https', 'git'), $config->get('github-protocols'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @group TLS
|
* @group TLS
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -123,13 +123,18 @@ class GitDownloaderTest extends TestCase
|
||||||
->will($this->returnValue('1.0.0'));
|
->will($this->returnValue('1.0.0'));
|
||||||
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
|
|
||||||
$expectedGitCommand = $this->winCompat("git clone --no-checkout 'git://github.com/mirrors/composer' 'composerPath' && cd 'composerPath' && git remote add composer 'git://github.com/mirrors/composer' && git fetch composer");
|
$expectedGitCommand = $this->winCompat("git clone --no-checkout 'https://github.com/mirrors/composer' 'composerPath' && cd 'composerPath' && git remote add composer 'https://github.com/mirrors/composer' && git fetch composer");
|
||||||
$processExecutor->expects($this->at(0))
|
$processExecutor->expects($this->at(0))
|
||||||
->method('execute')
|
->method('execute')
|
||||||
->with($this->equalTo($expectedGitCommand))
|
->with($this->equalTo($expectedGitCommand))
|
||||||
->will($this->returnValue(1));
|
->will($this->returnValue(1));
|
||||||
|
|
||||||
$expectedGitCommand = $this->winCompat("git clone --no-checkout 'https://github.com/mirrors/composer' 'composerPath' && cd 'composerPath' && git remote add composer 'https://github.com/mirrors/composer' && git fetch composer");
|
$processExecutor->expects($this->at(1))
|
||||||
|
->method('getErrorOutput')
|
||||||
|
->with()
|
||||||
|
->will($this->returnValue('Error1'));
|
||||||
|
|
||||||
|
$expectedGitCommand = $this->winCompat("git clone --no-checkout 'git@github.com:mirrors/composer' 'composerPath' && cd 'composerPath' && git remote add composer 'git@github.com:mirrors/composer' && git fetch composer");
|
||||||
$processExecutor->expects($this->at(2))
|
$processExecutor->expects($this->at(2))
|
||||||
->method('execute')
|
->method('execute')
|
||||||
->with($this->equalTo($expectedGitCommand))
|
->with($this->equalTo($expectedGitCommand))
|
||||||
|
@ -141,7 +146,7 @@ class GitDownloaderTest extends TestCase
|
||||||
->with($this->equalTo($expectedGitCommand), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
|
->with($this->equalTo($expectedGitCommand), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
|
||||||
->will($this->returnValue(0));
|
->will($this->returnValue(0));
|
||||||
|
|
||||||
$expectedGitCommand = $this->winCompat("git remote set-url --push origin 'git@github.com:composer/composer.git'");
|
$expectedGitCommand = $this->winCompat("git remote set-url --push origin 'https://github.com/composer/composer.git'");
|
||||||
$processExecutor->expects($this->at(4))
|
$processExecutor->expects($this->at(4))
|
||||||
->method('execute')
|
->method('execute')
|
||||||
->with($this->equalTo($expectedGitCommand), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
|
->with($this->equalTo($expectedGitCommand), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
|
||||||
|
@ -164,15 +169,15 @@ class GitDownloaderTest extends TestCase
|
||||||
public function pushUrlProvider()
|
public function pushUrlProvider()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array('git', 'git@github.com:composer/composer.git'),
|
array('ssh', 'git@github.com:composer/composer', 'https://github.com/composer/composer.git'),
|
||||||
array('https', 'https://github.com/composer/composer.git'),
|
array('https', 'https://github.com/composer/composer', 'https://github.com/composer/composer.git'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider pushUrlProvider
|
* @dataProvider pushUrlProvider
|
||||||
*/
|
*/
|
||||||
public function testDownloadAndSetPushUrlUseCustomVariousProtocolsForGithub($protocol, $pushUrl)
|
public function testDownloadAndSetPushUrlUseCustomVariousProtocolsForGithub($protocol, $url, $pushUrl)
|
||||||
{
|
{
|
||||||
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
$packageMock->expects($this->any())
|
$packageMock->expects($this->any())
|
||||||
|
@ -189,7 +194,7 @@ class GitDownloaderTest extends TestCase
|
||||||
->will($this->returnValue('1.0.0'));
|
->will($this->returnValue('1.0.0'));
|
||||||
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
|
|
||||||
$expectedGitCommand = $this->winCompat("git clone --no-checkout '{$protocol}://github.com/composer/composer' 'composerPath' && cd 'composerPath' && git remote add composer '{$protocol}://github.com/composer/composer' && git fetch composer");
|
$expectedGitCommand = $this->winCompat("git clone --no-checkout '{$url}' 'composerPath' && cd 'composerPath' && git remote add composer '{$url}' && git fetch composer");
|
||||||
$processExecutor->expects($this->at(0))
|
$processExecutor->expects($this->at(0))
|
||||||
->method('execute')
|
->method('execute')
|
||||||
->with($this->equalTo($expectedGitCommand))
|
->with($this->equalTo($expectedGitCommand))
|
||||||
|
@ -252,7 +257,7 @@ class GitDownloaderTest extends TestCase
|
||||||
|
|
||||||
public function testUpdate()
|
public function testUpdate()
|
||||||
{
|
{
|
||||||
$expectedGitUpdateCommand = $this->winCompat("git remote set-url composer 'git://github.com/composer/composer' && git fetch composer && git fetch --tags composer");
|
$expectedGitUpdateCommand = $this->winCompat("git remote set-url composer 'https://github.com/composer/composer' && git fetch composer && git fetch --tags composer");
|
||||||
|
|
||||||
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
$packageMock->expects($this->any())
|
$packageMock->expects($this->any())
|
||||||
|
@ -309,7 +314,7 @@ class GitDownloaderTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testUpdateThrowsRuntimeExceptionIfGitCommandFails()
|
public function testUpdateThrowsRuntimeExceptionIfGitCommandFails()
|
||||||
{
|
{
|
||||||
$expectedGitUpdateCommand = $this->winCompat("git remote set-url composer 'git://github.com/composer/composer' && git fetch composer && git fetch --tags composer");
|
$expectedGitUpdateCommand = $this->winCompat("git remote set-url composer 'https://github.com/composer/composer' && git fetch composer && git fetch --tags composer");
|
||||||
|
|
||||||
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
$packageMock->expects($this->any())
|
$packageMock->expects($this->any())
|
||||||
|
@ -354,7 +359,7 @@ class GitDownloaderTest extends TestCase
|
||||||
$this->markTestIncomplete('This test is disabled until https://github.com/composer/composer/issues/4973 is resolved');
|
$this->markTestIncomplete('This test is disabled until https://github.com/composer/composer/issues/4973 is resolved');
|
||||||
|
|
||||||
$expectedFirstGitUpdateCommand = $this->winCompat("git remote set-url composer '' && git fetch composer && git fetch --tags composer");
|
$expectedFirstGitUpdateCommand = $this->winCompat("git remote set-url composer '' && git fetch composer && git fetch --tags composer");
|
||||||
$expectedSecondGitUpdateCommand = $this->winCompat("git remote set-url composer 'git://github.com/composer/composer' && git fetch composer && git fetch --tags composer");
|
$expectedSecondGitUpdateCommand = $this->winCompat("git remote set-url composer 'https://github.com/composer/composer' && git fetch composer && git fetch --tags composer");
|
||||||
|
|
||||||
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
$packageMock->expects($this->any())
|
$packageMock->expects($this->any())
|
||||||
|
|
|
@ -47,9 +47,9 @@ class SvnDriverTest extends TestCase
|
||||||
{
|
{
|
||||||
$console = $this->getMock('Composer\IO\IOInterface');
|
$console = $this->getMock('Composer\IO\IOInterface');
|
||||||
|
|
||||||
$output = "svn: OPTIONS of 'http://corp.svn.local/repo':";
|
$output = "svn: OPTIONS of 'https://corp.svn.local/repo':";
|
||||||
$output .= " authorization failed: Could not authenticate to server:";
|
$output .= " authorization failed: Could not authenticate to server:";
|
||||||
$output .= " rejected Basic challenge (http://corp.svn.local/)";
|
$output .= " rejected Basic challenge (https://corp.svn.local/)";
|
||||||
|
|
||||||
$process = $this->getMock('Composer\Util\ProcessExecutor');
|
$process = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
$process->expects($this->at(1))
|
$process->expects($this->at(1))
|
||||||
|
@ -63,7 +63,7 @@ class SvnDriverTest extends TestCase
|
||||||
->will($this->returnValue(0));
|
->will($this->returnValue(0));
|
||||||
|
|
||||||
$repoConfig = array(
|
$repoConfig = array(
|
||||||
'url' => 'http://till:secret@corp.svn.local/repo',
|
'url' => 'https://till:secret@corp.svn.local/repo',
|
||||||
);
|
);
|
||||||
|
|
||||||
$svn = new SvnDriver($repoConfig, $console, $this->config, $process);
|
$svn = new SvnDriver($repoConfig, $console, $this->config, $process);
|
||||||
|
|
Loading…
Reference in New Issue