Merge branch '2.0'

main
Jordi Boggiano 3 years ago
commit 40c7a725e1
No known key found for this signature in database
GPG Key ID: 7BBD42C429EC80BC

@ -1,3 +1,10 @@
### [2.0.13] 2021-04-27
* Security: Fixed command injection vulnerability in HgDriver/HgDownloader and hardened other VCS drivers and downloaders (GHSA-h5h8-pc6h-jvvx / CVE-2021-29472)
* Fixed install step at the end of the init command to take new dependencies into account correctly
* Fixed `update --lock` listing updates which were not really happening (#9812)
* Fixed support for --no-dev combined with --locked in outdated and show commands (#9788)
### [2.0.12] 2021-04-01 ### [2.0.12] 2021-04-01
* Fixed support for new GitHub OAuth token format (#9757) * Fixed support for new GitHub OAuth token format (#9757)
@ -196,6 +203,10 @@
* Fixed suggest output being very spammy, it now is only one line long and shows more rarely * Fixed suggest output being very spammy, it now is only one line long and shows more rarely
* Fixed conflict rules like e.g. >=5 from matching dev-master, as it is not normalized to 9999999-dev internally anymore * Fixed conflict rules like e.g. >=5 from matching dev-master, as it is not normalized to 9999999-dev internally anymore
### [1.10.22] 2021-04-27
* Security: Fixed command injection vulnerability in HgDriver/HgDownloader and hardened other VCS drivers and downloaders (GHSA-h5h8-pc6h-jvvx / CVE-2021-29472)
### [1.10.21] 2021-04-01 ### [1.10.21] 2021-04-01
* Fixed support for new GitHub OAuth token format * Fixed support for new GitHub OAuth token format
@ -1132,6 +1143,7 @@
* Initial release * Initial release
[2.0.13]: https://github.com/composer/composer/compare/2.0.12...2.0.13
[2.0.12]: https://github.com/composer/composer/compare/2.0.11...2.0.12 [2.0.12]: https://github.com/composer/composer/compare/2.0.11...2.0.12
[2.0.11]: https://github.com/composer/composer/compare/2.0.10...2.0.11 [2.0.11]: https://github.com/composer/composer/compare/2.0.10...2.0.11
[2.0.10]: https://github.com/composer/composer/compare/2.0.9...2.0.10 [2.0.10]: https://github.com/composer/composer/compare/2.0.9...2.0.10
@ -1150,6 +1162,7 @@
[2.0.0-alpha3]: https://github.com/composer/composer/compare/2.0.0-alpha2...2.0.0-alpha3 [2.0.0-alpha3]: https://github.com/composer/composer/compare/2.0.0-alpha2...2.0.0-alpha3
[2.0.0-alpha2]: https://github.com/composer/composer/compare/2.0.0-alpha1...2.0.0-alpha2 [2.0.0-alpha2]: https://github.com/composer/composer/compare/2.0.0-alpha1...2.0.0-alpha2
[2.0.0-alpha1]: https://github.com/composer/composer/compare/1.10.7...2.0.0-alpha1 [2.0.0-alpha1]: https://github.com/composer/composer/compare/1.10.7...2.0.0-alpha1
[1.10.22]: https://github.com/composer/composer/compare/1.10.21...1.10.22
[1.10.21]: https://github.com/composer/composer/compare/1.10.20...1.10.21 [1.10.21]: https://github.com/composer/composer/compare/1.10.20...1.10.21
[1.10.20]: https://github.com/composer/composer/compare/1.10.19...1.10.20 [1.10.20]: https://github.com/composer/composer/compare/1.10.19...1.10.20
[1.10.19]: https://github.com/composer/composer/compare/1.10.18...1.10.19 [1.10.19]: https://github.com/composer/composer/compare/1.10.18...1.10.19

@ -40,15 +40,15 @@ class FossilDownloader extends VcsDownloader
$ref = ProcessExecutor::escape($package->getSourceReference()); $ref = ProcessExecutor::escape($package->getSourceReference());
$repoFile = $path . '.fossil'; $repoFile = $path . '.fossil';
$this->io->writeError("Cloning ".$package->getSourceReference()); $this->io->writeError("Cloning ".$package->getSourceReference());
$command = sprintf('fossil clone %s %s', $url, ProcessExecutor::escape($repoFile)); $command = sprintf('fossil clone -- %s %s', $url, ProcessExecutor::escape($repoFile));
if (0 !== $this->process->execute($command, $ignoredOutput)) { if (0 !== $this->process->execute($command, $ignoredOutput)) {
throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
} }
$command = sprintf('fossil open %s --nested', ProcessExecutor::escape($repoFile)); $command = sprintf('fossil open --nested -- %s', ProcessExecutor::escape($repoFile));
if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) { if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) {
throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
} }
$command = sprintf('fossil update %s', $ref); $command = sprintf('fossil update -- %s', $ref);
if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) { if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) {
throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
} }

@ -94,10 +94,10 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
$command = $command =
'git clone --no-checkout %cachePath% %path% --dissociate --reference %cachePath% ' 'git clone --no-checkout %cachePath% %path% --dissociate --reference %cachePath% '
. '&& cd '.$flag.'%path% ' . '&& cd '.$flag.'%path% '
. '&& git remote set-url origin %sanitizedUrl% && git remote add composer %sanitizedUrl%'; . '&& git remote set-url origin -- %sanitizedUrl% && git remote add composer -- %sanitizedUrl%';
} else { } else {
$msg = "Cloning ".$this->getShortHash($ref); $msg = "Cloning ".$this->getShortHash($ref);
$command = 'git clone --no-checkout %url% %path% && cd '.$flag.'%path% && git remote add composer %url% && git fetch composer && git remote set-url origin %sanitizedUrl% && git remote set-url composer %sanitizedUrl%'; $command = 'git clone --no-checkout -- %url% %path% && cd '.$flag.'%path% && git remote add composer -- %url% && git fetch composer && git remote set-url origin -- %sanitizedUrl% && git remote set-url composer -- %sanitizedUrl%';
if (getenv('COMPOSER_DISABLE_NETWORK')) { if (getenv('COMPOSER_DISABLE_NETWORK')) {
throw new \RuntimeException('The required git reference for '.$package->getName().' is not in cache and network is disabled, aborting'); throw new \RuntimeException('The required git reference for '.$package->getName().' is not in cache and network is disabled, aborting');
} }
@ -151,10 +151,10 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
if (!empty($this->cachedPackages[$target->getId()][$ref])) { if (!empty($this->cachedPackages[$target->getId()][$ref])) {
$msg = "Checking out ".$this->getShortHash($ref).' from cache'; $msg = "Checking out ".$this->getShortHash($ref).' from cache';
$command = '(git rev-parse --quiet --verify %ref% || (git remote set-url composer %cachePath% && git fetch composer && git fetch --tags composer)) && git remote set-url composer %sanitizedUrl%'; $command = '(git rev-parse --quiet --verify %ref% || (git remote set-url composer -- %cachePath% && git fetch composer && git fetch --tags composer)) && git remote set-url composer -- %sanitizedUrl%';
} else { } else {
$msg = "Checking out ".$this->getShortHash($ref); $msg = "Checking out ".$this->getShortHash($ref);
$command = '(git remote set-url composer %url% && git rev-parse --quiet --verify %ref% || (git fetch composer && git fetch --tags composer)) && git remote set-url composer %sanitizedUrl%'; $command = '(git remote set-url composer -- %url% && git rev-parse --quiet --verify %ref% || (git fetch composer && git fetch --tags composer)) && git remote set-url composer -- %sanitizedUrl%';
if (getenv('COMPOSER_DISABLE_NETWORK')) { if (getenv('COMPOSER_DISABLE_NETWORK')) {
throw new \RuntimeException('The required git reference for '.$target->getName().' is not in cache and network is disabled, aborting'); throw new \RuntimeException('The required git reference for '.$target->getName().' is not in cache and network is disabled, aborting');
} }
@ -484,7 +484,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
protected function updateOriginUrl($path, $url) protected function updateOriginUrl($path, $url)
{ {
$this->process->execute(sprintf('git remote set-url origin %s', ProcessExecutor::escape($url)), $output, $path); $this->process->execute(sprintf('git remote set-url origin -- %s', ProcessExecutor::escape($url)), $output, $path);
$this->setPushUrl($path, $url); $this->setPushUrl($path, $url);
} }
@ -497,7 +497,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
if (!in_array('ssh', $protocols, true)) { if (!in_array('ssh', $protocols, true)) {
$pushUrl = 'https://' . $match[1] . '/'.$match[2].'/'.$match[3].'.git'; $pushUrl = 'https://' . $match[1] . '/'.$match[2].'/'.$match[3].'.git';
} }
$cmd = sprintf('git remote set-url --push origin %s', ProcessExecutor::escape($pushUrl)); $cmd = sprintf('git remote set-url --push origin -- %s', ProcessExecutor::escape($pushUrl));
$this->process->execute($cmd, $ignoredOutput, $path); $this->process->execute($cmd, $ignoredOutput, $path);
} }
} }

@ -30,7 +30,7 @@ class GzipDownloader extends ArchiveDownloader
// Try to use gunzip on *nix // Try to use gunzip on *nix
if (!Platform::isWindows()) { if (!Platform::isWindows()) {
$command = 'gzip -cd ' . ProcessExecutor::escape($file) . ' > ' . ProcessExecutor::escape($targetFilepath); $command = 'gzip -cd -- ' . ProcessExecutor::escape($file) . ' > ' . ProcessExecutor::escape($targetFilepath);
if (0 === $this->process->execute($command, $ignoredOutput)) { if (0 === $this->process->execute($command, $ignoredOutput)) {
return \React\Promise\resolve(); return \React\Promise\resolve();

@ -41,13 +41,13 @@ class HgDownloader extends VcsDownloader
$hgUtils = new HgUtils($this->io, $this->config, $this->process); $hgUtils = new HgUtils($this->io, $this->config, $this->process);
$cloneCommand = function ($url) use ($path) { $cloneCommand = function ($url) use ($path) {
return sprintf('hg clone %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($path)); return sprintf('hg clone -- %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($path));
}; };
$hgUtils->runCommand($cloneCommand, $url, $path); $hgUtils->runCommand($cloneCommand, $url, $path);
$ref = ProcessExecutor::escape($package->getSourceReference()); $ref = ProcessExecutor::escape($package->getSourceReference());
$command = sprintf('hg up %s', $ref); $command = sprintf('hg up -- %s', $ref);
if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) { if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) {
throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
} }
@ -70,7 +70,7 @@ class HgDownloader extends VcsDownloader
} }
$command = function ($url) use ($ref) { $command = function ($url) use ($ref) {
return sprintf('hg pull %s && hg up %s', ProcessExecutor::escape($url), ProcessExecutor::escape($ref)); return sprintf('hg pull -- %s && hg up -- %s', ProcessExecutor::escape($url), ProcessExecutor::escape($ref));
}; };
$hgUtils->runCommand($command, $url, $path); $hgUtils->runCommand($command, $url, $path);

@ -33,7 +33,7 @@ class RarDownloader extends ArchiveDownloader
// Try to use unrar on *nix // Try to use unrar on *nix
if (!Platform::isWindows()) { if (!Platform::isWindows()) {
$command = 'unrar x ' . ProcessExecutor::escape($file) . ' ' . ProcessExecutor::escape($path) . ' >/dev/null && chmod -R u+w ' . ProcessExecutor::escape($path); $command = 'unrar x -- ' . ProcessExecutor::escape($file) . ' ' . ProcessExecutor::escape($path) . ' >/dev/null && chmod -R u+w ' . ProcessExecutor::escape($path);
if (0 === $this->process->execute($command, $ignoredOutput)) { if (0 === $this->process->execute($command, $ignoredOutput)) {
return \React\Promise\resolve(); return \React\Promise\resolve();

@ -190,7 +190,7 @@ class SvnDownloader extends VcsDownloader
{ {
if (preg_match('{@(\d+)$}', $fromReference) && preg_match('{@(\d+)$}', $toReference)) { if (preg_match('{@(\d+)$}', $fromReference) && preg_match('{@(\d+)$}', $toReference)) {
// retrieve the svn base url from the checkout folder // retrieve the svn base url from the checkout folder
$command = sprintf('svn info --non-interactive --xml %s', ProcessExecutor::escape($path)); $command = sprintf('svn info --non-interactive --xml -- %s', ProcessExecutor::escape($path));
if (0 !== $this->process->execute($command, $output, $path)) { if (0 !== $this->process->execute($command, $output, $path)) {
throw new \RuntimeException( throw new \RuntimeException(
'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput() 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()

@ -94,13 +94,13 @@ class FossilDriver extends VcsDriver
$fs->ensureDirectoryExists($this->checkoutDir); $fs->ensureDirectoryExists($this->checkoutDir);
if (0 !== $this->process->execute(sprintf('fossil clone %s %s', ProcessExecutor::escape($this->url), ProcessExecutor::escape($this->repoFile)), $output)) { if (0 !== $this->process->execute(sprintf('fossil clone -- %s %s', ProcessExecutor::escape($this->url), ProcessExecutor::escape($this->repoFile)), $output)) {
$output = $this->process->getErrorOutput(); $output = $this->process->getErrorOutput();
throw new \RuntimeException('Failed to clone '.$this->url.' to repository ' . $this->repoFile . "\n\n" .$output); throw new \RuntimeException('Failed to clone '.$this->url.' to repository ' . $this->repoFile . "\n\n" .$output);
} }
if (0 !== $this->process->execute(sprintf('fossil open %s --nested', ProcessExecutor::escape($this->repoFile)), $output, $this->checkoutDir)) { if (0 !== $this->process->execute(sprintf('fossil open --nested -- %s', ProcessExecutor::escape($this->repoFile)), $output, $this->checkoutDir)) {
$output = $this->process->getErrorOutput(); $output = $this->process->getErrorOutput();
throw new \RuntimeException('Failed to open repository '.$this->repoFile.' in ' . $this->checkoutDir . "\n\n" .$output); throw new \RuntimeException('Failed to open repository '.$this->repoFile.' in ' . $this->checkoutDir . "\n\n" .$output);
@ -149,7 +149,7 @@ class FossilDriver extends VcsDriver
*/ */
public function getFileContent($file, $identifier) public function getFileContent($file, $identifier)
{ {
$command = sprintf('fossil cat -r %s %s', ProcessExecutor::escape($identifier), ProcessExecutor::escape($file)); $command = sprintf('fossil cat -r %s -- %s', ProcessExecutor::escape($identifier), ProcessExecutor::escape($file));
$this->process->execute($command, $content, $this->checkoutDir); $this->process->execute($command, $content, $this->checkoutDir);
if (!trim($content)) { if (!trim($content)) {

@ -230,7 +230,7 @@ class GitDriver extends VcsDriver
try { try {
$gitUtil->runCommand(function ($url) { $gitUtil->runCommand(function ($url) {
return 'git ls-remote --heads ' . ProcessExecutor::escape($url); return 'git ls-remote --heads -- ' . ProcessExecutor::escape($url);
}, $url, sys_get_temp_dir()); }, $url, sys_get_temp_dir());
} catch (\RuntimeException $e) { } catch (\RuntimeException $e) {
return false; return false;

@ -67,7 +67,7 @@ class HgDriver extends VcsDriver
$repoDir = $this->repoDir; $repoDir = $this->repoDir;
$command = function ($url) use ($repoDir) { $command = function ($url) use ($repoDir) {
return sprintf('hg clone --noupdate %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($repoDir)); return sprintf('hg clone --noupdate -- %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($repoDir));
}; };
$hgUtils->runCommand($command, $this->url, null); $hgUtils->runCommand($command, $this->url, null);
@ -228,7 +228,7 @@ class HgDriver extends VcsDriver
} }
$process = new ProcessExecutor($io); $process = new ProcessExecutor($io);
$exit = $process->execute(sprintf('hg identify %s', ProcessExecutor::escape($url)), $ignored); $exit = $process->execute(sprintf('hg identify -- %s', ProcessExecutor::escape($url)), $ignored);
return $exit === 0; return $exit === 0;
} }

@ -306,7 +306,7 @@ class SvnDriver extends VcsDriver
$process = new ProcessExecutor($io); $process = new ProcessExecutor($io);
$exit = $process->execute( $exit = $process->execute(
"svn info --non-interactive ".ProcessExecutor::escape($url), "svn info --non-interactive -- ".ProcessExecutor::escape($url),
$ignoredOutput $ignoredOutput
); );

@ -261,7 +261,7 @@ class Git
$commandCallable = function ($url) { $commandCallable = function ($url) {
$sanitizedUrl = preg_replace('{://([^@]+?):(.+?)@}', '://', $url); $sanitizedUrl = preg_replace('{://([^@]+?):(.+?)@}', '://', $url);
return sprintf('git remote set-url origin %s && git remote update --prune origin && git remote set-url origin %s && git gc --auto', ProcessExecutor::escape($url), ProcessExecutor::escape($sanitizedUrl)); return sprintf('git remote set-url origin -- %s && git remote update --prune origin && git remote set-url origin -- %s && git gc --auto', ProcessExecutor::escape($url), ProcessExecutor::escape($sanitizedUrl));
}; };
$this->runCommand($commandCallable, $url, $dir); $this->runCommand($commandCallable, $url, $dir);
} catch (\Exception $e) { } catch (\Exception $e) {
@ -277,7 +277,7 @@ class Git
$this->filesystem->removeDirectory($dir); $this->filesystem->removeDirectory($dir);
$commandCallable = function ($url) use ($dir) { $commandCallable = function ($url) use ($dir) {
return sprintf('git clone --mirror %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($dir)); return sprintf('git clone --mirror -- %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($dir));
}; };
$this->runCommand($commandCallable, $url, $dir, true); $this->runCommand($commandCallable, $url, $dir, true);

@ -224,7 +224,7 @@ class Svn
protected function getCommand($cmd, $url, $path = null) protected function getCommand($cmd, $url, $path = null)
{ {
$cmd = sprintf( $cmd = sprintf(
'%s %s%s %s', '%s %s%s -- %s',
$cmd, $cmd,
'--non-interactive ', '--non-interactive ',
$this->getCredentialString(), $this->getCredentialString(),

@ -69,19 +69,19 @@ class FossilDownloaderTest extends TestCase
->will($this->returnValue(array('http://fossil.kd2.org/kd2fw/'))); ->will($this->returnValue(array('http://fossil.kd2.org/kd2fw/')));
$processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$expectedFossilCommand = $this->getCmd('fossil clone \'http://fossil.kd2.org/kd2fw/\' \'repo.fossil\''); $expectedFossilCommand = $this->getCmd('fossil clone -- \'http://fossil.kd2.org/kd2fw/\' \'repo.fossil\'');
$processExecutor->expects($this->at(0)) $processExecutor->expects($this->at(0))
->method('execute') ->method('execute')
->with($this->equalTo($expectedFossilCommand)) ->with($this->equalTo($expectedFossilCommand))
->will($this->returnValue(0)); ->will($this->returnValue(0));
$expectedFossilCommand = $this->getCmd('fossil open \'repo.fossil\' --nested'); $expectedFossilCommand = $this->getCmd('fossil open --nested -- \'repo.fossil\'');
$processExecutor->expects($this->at(1)) $processExecutor->expects($this->at(1))
->method('execute') ->method('execute')
->with($this->equalTo($expectedFossilCommand)) ->with($this->equalTo($expectedFossilCommand))
->will($this->returnValue(0)); ->will($this->returnValue(0));
$expectedFossilCommand = $this->getCmd('fossil update \'trunk\''); $expectedFossilCommand = $this->getCmd('fossil update -- \'trunk\'');
$processExecutor->expects($this->at(2)) $processExecutor->expects($this->at(2))
->method('execute') ->method('execute')
->with($this->equalTo($expectedFossilCommand)) ->with($this->equalTo($expectedFossilCommand))

@ -109,7 +109,7 @@ class GitDownloaderTest extends TestCase
->will($this->returnValue('dev-master')); ->will($this->returnValue('dev-master'));
$processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$expectedGitCommand = $this->winCompat("git clone --no-checkout 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git remote add composer 'https://example.com/composer/composer' && git fetch composer && git remote set-url origin 'https://example.com/composer/composer' && git remote set-url composer 'https://example.com/composer/composer'"); $expectedGitCommand = $this->winCompat("git clone --no-checkout -- 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git remote add composer -- 'https://example.com/composer/composer' && git fetch composer && git remote set-url origin -- 'https://example.com/composer/composer' && git remote set-url composer -- 'https://example.com/composer/composer'");
$processExecutor->expects($this->at(0)) $processExecutor->expects($this->at(0))
->method('execute') ->method('execute')
->with($this->equalTo($expectedGitCommand)) ->with($this->equalTo($expectedGitCommand))
@ -158,7 +158,7 @@ class GitDownloaderTest extends TestCase
$filesystem = new \Composer\Util\Filesystem; $filesystem = new \Composer\Util\Filesystem;
$filesystem->removeDirectory($cachePath); $filesystem->removeDirectory($cachePath);
$expectedGitCommand = $this->winCompat(sprintf("git clone --mirror 'https://example.com/composer/composer' '%s'", $cachePath)); $expectedGitCommand = $this->winCompat(sprintf("git clone --mirror -- 'https://example.com/composer/composer' '%s'", $cachePath));
$processExecutor->expects($this->at(0)) $processExecutor->expects($this->at(0))
->method('execute') ->method('execute')
->with($this->equalTo($expectedGitCommand)) ->with($this->equalTo($expectedGitCommand))
@ -180,7 +180,7 @@ class GitDownloaderTest extends TestCase
->with($this->equalTo($this->winCompat('git rev-parse --quiet --verify \'1234567890123456789012345678901234567890^{commit}\'')), $this->equalTo(null), $this->equalTo($this->winCompat($cachePath))) ->with($this->equalTo($this->winCompat('git rev-parse --quiet --verify \'1234567890123456789012345678901234567890^{commit}\'')), $this->equalTo(null), $this->equalTo($this->winCompat($cachePath)))
->will($this->returnValue(0)); ->will($this->returnValue(0));
$expectedGitCommand = $this->winCompat(sprintf("git clone --no-checkout '%1\$s' 'composerPath' --dissociate --reference '%1\$s' && cd 'composerPath' && git remote set-url origin 'https://example.com/composer/composer' && git remote add composer 'https://example.com/composer/composer'", $cachePath)); $expectedGitCommand = $this->winCompat(sprintf("git clone --no-checkout '%1\$s' 'composerPath' --dissociate --reference '%1\$s' && cd 'composerPath' && git remote set-url origin -- 'https://example.com/composer/composer' && git remote add composer -- 'https://example.com/composer/composer'", $cachePath));
$processExecutor->expects($this->at(3)) $processExecutor->expects($this->at(3))
->method('execute') ->method('execute')
->with($this->equalTo($expectedGitCommand)) ->with($this->equalTo($expectedGitCommand))
@ -221,7 +221,7 @@ class GitDownloaderTest extends TestCase
->will($this->returnValue('1.0.0')); ->will($this->returnValue('1.0.0'));
$processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$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 && git remote set-url origin 'https://github.com/mirrors/composer' && git remote set-url composer 'https://github.com/mirrors/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 && git remote set-url origin -- 'https://github.com/mirrors/composer' && git remote set-url composer -- 'https://github.com/mirrors/composer'");
$processExecutor->expects($this->at(0)) $processExecutor->expects($this->at(0))
->method('execute') ->method('execute')
->with($this->equalTo($expectedGitCommand)) ->with($this->equalTo($expectedGitCommand))
@ -232,19 +232,19 @@ class GitDownloaderTest extends TestCase
->with() ->with()
->will($this->returnValue('Error1')); ->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 && git remote set-url origin 'git@github.com:mirrors/composer' && git remote set-url composer 'git@github.com:mirrors/composer'"); $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 && git remote set-url origin -- 'git@github.com:mirrors/composer' && git remote set-url composer -- 'git@github.com:mirrors/composer'");
$processExecutor->expects($this->at(2)) $processExecutor->expects($this->at(2))
->method('execute') ->method('execute')
->with($this->equalTo($expectedGitCommand)) ->with($this->equalTo($expectedGitCommand))
->will($this->returnValue(0)); ->will($this->returnValue(0));
$expectedGitCommand = $this->winCompat("git remote set-url origin 'https://github.com/composer/composer'"); $expectedGitCommand = $this->winCompat("git remote set-url origin -- 'https://github.com/composer/composer'");
$processExecutor->expects($this->at(3)) $processExecutor->expects($this->at(3))
->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')))
->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 -- 'git@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')))
@ -299,13 +299,13 @@ class GitDownloaderTest extends TestCase
->will($this->returnValue('1.0.0')); ->will($this->returnValue('1.0.0'));
$processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$expectedGitCommand = $this->winCompat("git clone --no-checkout '{$url}' 'composerPath' && cd 'composerPath' && git remote add composer '{$url}' && git fetch composer && git remote set-url origin '{$url}' && git remote set-url composer '{$url}'"); $expectedGitCommand = $this->winCompat("git clone --no-checkout -- '{$url}' 'composerPath' && cd 'composerPath' && git remote add composer -- '{$url}' && git fetch composer && git remote set-url origin -- '{$url}' && git remote set-url composer -- '{$url}'");
$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(0)); ->will($this->returnValue(0));
$expectedGitCommand = $this->winCompat("git remote set-url --push origin '{$pushUrl}'"); $expectedGitCommand = $this->winCompat("git remote set-url --push origin -- '{$pushUrl}'");
$processExecutor->expects($this->at(1)) $processExecutor->expects($this->at(1))
->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')))
@ -327,7 +327,7 @@ class GitDownloaderTest extends TestCase
public function testDownloadThrowsRuntimeExceptionIfGitCommandFails() public function testDownloadThrowsRuntimeExceptionIfGitCommandFails()
{ {
$expectedGitCommand = $this->winCompat("git clone --no-checkout 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git remote add composer 'https://example.com/composer/composer' && git fetch composer && git remote set-url origin 'https://example.com/composer/composer' && git remote set-url composer 'https://example.com/composer/composer'"); $expectedGitCommand = $this->winCompat("git clone --no-checkout -- 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git remote add composer -- 'https://example.com/composer/composer' && git fetch composer && git remote set-url origin -- 'https://example.com/composer/composer' && git remote set-url composer -- 'https://example.com/composer/composer'");
$packageMock = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock(); $packageMock = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock();
$packageMock->expects($this->any()) $packageMock->expects($this->any())
->method('getSourceReference') ->method('getSourceReference')
@ -376,7 +376,7 @@ class GitDownloaderTest extends TestCase
public function testUpdate() public function testUpdate()
{ {
$expectedGitUpdateCommand = $this->winCompat("(git remote set-url composer 'https://github.com/composer/composer' && git rev-parse --quiet --verify 'ref^{commit}' || (git fetch composer && git fetch --tags composer)) && git remote set-url composer 'https://github.com/composer/composer'"); $expectedGitUpdateCommand = $this->winCompat("(git remote set-url composer -- 'https://github.com/composer/composer' && git rev-parse --quiet --verify 'ref^{commit}' || (git fetch composer && git fetch --tags composer)) && git remote set-url composer -- 'https://github.com/composer/composer'");
$packageMock = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock(); $packageMock = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock();
$packageMock->expects($this->any()) $packageMock->expects($this->any())
@ -407,7 +407,7 @@ class GitDownloaderTest extends TestCase
public function testUpdateWithNewRepoUrl() public function testUpdateWithNewRepoUrl()
{ {
$expectedGitUpdateCommand = $this->winCompat("(git remote set-url composer 'https://github.com/composer/composer' && git rev-parse --quiet --verify 'ref^{commit}' || (git fetch composer && git fetch --tags composer)) && git remote set-url composer 'https://github.com/composer/composer'"); $expectedGitUpdateCommand = $this->winCompat("(git remote set-url composer -- 'https://github.com/composer/composer' && git rev-parse --quiet --verify 'ref^{commit}' || (git fetch composer && git fetch --tags composer)) && git remote set-url composer -- 'https://github.com/composer/composer'");
$packageMock = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock(); $packageMock = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock();
$packageMock->expects($this->any()) $packageMock->expects($this->any())
@ -462,11 +462,11 @@ composer https://github.com/old/url (push)
})); }));
$processExecutor->expects($this->at(7)) $processExecutor->expects($this->at(7))
->method('execute') ->method('execute')
->with($this->equalTo($this->winCompat("git remote set-url origin 'https://github.com/composer/composer'")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir))) ->with($this->equalTo($this->winCompat("git remote set-url origin -- 'https://github.com/composer/composer'")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir)))
->will($this->returnValue(0)); ->will($this->returnValue(0));
$processExecutor->expects($this->at(8)) $processExecutor->expects($this->at(8))
->method('execute') ->method('execute')
->with($this->equalTo($this->winCompat("git remote set-url --push origin 'git@github.com:composer/composer.git'")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir))) ->with($this->equalTo($this->winCompat("git remote set-url --push origin -- 'git@github.com:composer/composer.git'")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir)))
->will($this->returnValue(0)); ->will($this->returnValue(0));
$this->fs->ensureDirectoryExists($this->workingDir.'/.git'); $this->fs->ensureDirectoryExists($this->workingDir.'/.git');
@ -482,8 +482,8 @@ composer https://github.com/old/url (push)
*/ */
public function testUpdateThrowsRuntimeExceptionIfGitCommandFails() public function testUpdateThrowsRuntimeExceptionIfGitCommandFails()
{ {
$expectedGitUpdateCommand = $this->winCompat("(git remote set-url composer 'https://github.com/composer/composer' && git rev-parse --quiet --verify 'ref^{commit}' || (git fetch composer && git fetch --tags composer)) && git remote set-url composer 'https://github.com/composer/composer'"); $expectedGitUpdateCommand = $this->winCompat("(git remote set-url composer -- 'https://github.com/composer/composer' && git rev-parse --quiet --verify 'ref^{commit}' || (git fetch composer && git fetch --tags composer)) && git remote set-url composer -- 'https://github.com/composer/composer'");
$expectedGitUpdateCommand2 = $this->winCompat("(git remote set-url composer 'git@github.com:composer/composer' && git rev-parse --quiet --verify 'ref^{commit}' || (git fetch composer && git fetch --tags composer)) && git remote set-url composer 'git@github.com:composer/composer'"); $expectedGitUpdateCommand2 = $this->winCompat("(git remote set-url composer -- 'git@github.com:composer/composer' && git rev-parse --quiet --verify 'ref^{commit}' || (git fetch composer && git fetch --tags composer)) && git remote set-url composer -- 'git@github.com:composer/composer'");
$packageMock = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock(); $packageMock = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock();
$packageMock->expects($this->any()) $packageMock->expects($this->any())
@ -526,8 +526,8 @@ composer https://github.com/old/url (push)
public function testUpdateDoesntThrowsRuntimeExceptionIfGitCommandFailsAtFirstButIsAbleToRecover() public function testUpdateDoesntThrowsRuntimeExceptionIfGitCommandFailsAtFirstButIsAbleToRecover()
{ {
$expectedFirstGitUpdateCommand = $this->winCompat("(git remote set-url composer '".(Platform::isWindows() ? 'C:\\\\' : '/')."' && git rev-parse --quiet --verify 'ref^{commit}' || (git fetch composer && git fetch --tags composer)) && git remote set-url composer '".(Platform::isWindows() ? 'C:\\\\' : '/')."'"); $expectedFirstGitUpdateCommand = $this->winCompat("(git remote set-url composer -- '".(Platform::isWindows() ? 'C:\\\\' : '/')."' && git rev-parse --quiet --verify 'ref^{commit}' || (git fetch composer && git fetch --tags composer)) && git remote set-url composer -- '".(Platform::isWindows() ? 'C:\\\\' : '/')."'");
$expectedSecondGitUpdateCommand = $this->winCompat("(git remote set-url composer 'https://github.com/composer/composer' && git rev-parse --quiet --verify 'ref^{commit}' || (git fetch composer && git fetch --tags composer)) && git remote set-url composer 'https://github.com/composer/composer'"); $expectedSecondGitUpdateCommand = $this->winCompat("(git remote set-url composer -- 'https://github.com/composer/composer' && git rev-parse --quiet --verify 'ref^{commit}' || (git fetch composer && git fetch --tags composer)) && git remote set-url composer -- 'https://github.com/composer/composer'");
$packageMock = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock(); $packageMock = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock();
$packageMock->expects($this->any()) $packageMock->expects($this->any())

@ -69,13 +69,13 @@ class HgDownloaderTest extends TestCase
->will($this->returnValue(array('https://mercurial.dev/l3l0/composer'))); ->will($this->returnValue(array('https://mercurial.dev/l3l0/composer')));
$processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$expectedGitCommand = $this->getCmd('hg clone \'https://mercurial.dev/l3l0/composer\' \'composerPath\''); $expectedGitCommand = $this->getCmd('hg clone -- \'https://mercurial.dev/l3l0/composer\' \'composerPath\'');
$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(0)); ->will($this->returnValue(0));
$expectedGitCommand = $this->getCmd('hg up \'ref\''); $expectedGitCommand = $this->getCmd('hg up -- \'ref\'');
$processExecutor->expects($this->at(1)) $processExecutor->expects($this->at(1))
->method('execute') ->method('execute')
->with($this->equalTo($expectedGitCommand)) ->with($this->equalTo($expectedGitCommand))
@ -122,7 +122,7 @@ class HgDownloaderTest extends TestCase
->method('execute') ->method('execute')
->with($this->equalTo($expectedHgCommand)) ->with($this->equalTo($expectedHgCommand))
->will($this->returnValue(0)); ->will($this->returnValue(0));
$expectedHgCommand = $this->getCmd("hg pull 'https://github.com/l3l0/composer' && hg up 'ref'"); $expectedHgCommand = $this->getCmd("hg pull -- 'https://github.com/l3l0/composer' && hg up -- 'ref'");
$processExecutor->expects($this->at(1)) $processExecutor->expects($this->at(1))
->method('execute') ->method('execute')
->with($this->equalTo($expectedHgCommand)) ->with($this->equalTo($expectedHgCommand))

@ -60,7 +60,7 @@ class SvnTest extends TestCase
$reflMethod->setAccessible(true); $reflMethod->setAccessible(true);
$this->assertEquals( $this->assertEquals(
$this->getCmd("svn ls --non-interactive 'http://svn.example.org'"), $this->getCmd("svn ls --non-interactive -- 'http://svn.example.org'"),
$reflMethod->invokeArgs($svn, array('svn ls', $url)) $reflMethod->invokeArgs($svn, array('svn ls', $url))
); );
} }

Loading…
Cancel
Save