diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php index e5fe253a2..177644735 100644 --- a/src/Composer/Downloader/GitDownloader.php +++ b/src/Composer/Downloader/GitDownloader.php @@ -61,7 +61,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface GitUtil::cleanEnv(); $cachePath = $this->config->get('cache-vcs-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $url).'/'; - $gitVersion = $this->gitUtil->getVersion(); + $gitVersion = GitUtil::getVersion($this->process); // --dissociate option is only available since git 2.3.0-rc0 if ($gitVersion && version_compare($gitVersion, '2.3.0-rc0', '>=') && Cache::isUsable($cachePath)) { @@ -479,7 +479,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface protected function getCommitLogs($fromReference, $toReference, $path) { $path = $this->normalizePath($path); - $command = sprintf('git log %s..%s --pretty=format:"%%h - %%an: %%s"', ProcessExecutor::escape($fromReference), ProcessExecutor::escape($toReference)); + $command = sprintf('git log %s..%s --pretty=format:"%%h - %%an: %%s"'.GitUtil::getNoShowSignatureFlag($this->process), ProcessExecutor::escape($fromReference), ProcessExecutor::escape($toReference)); if (0 !== $this->process->execute($command, $output, $path)) { throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); diff --git a/src/Composer/Package/Locker.php b/src/Composer/Package/Locker.php index 8cc3d1eb8..6009082cd 100644 --- a/src/Composer/Package/Locker.php +++ b/src/Composer/Package/Locker.php @@ -432,7 +432,7 @@ class Locker case 'git': GitUtil::cleanEnv(); - if (0 === $this->process->execute('git log -n1 --pretty=%ct '.ProcessExecutor::escape($sourceRef), $output, $path) && preg_match('{^\s*\d+\s*$}', $output)) { + if (0 === $this->process->execute('git log -n1 --pretty=%ct '.ProcessExecutor::escape($sourceRef).GitUtil::getNoShowSignatureFlag($this->process), $output, $path) && preg_match('{^\s*\d+\s*$}', $output)) { $datetime = new \DateTime('@'.trim($output), new \DateTimeZone('UTC')); } break; diff --git a/src/Composer/Package/Version/VersionGuesser.php b/src/Composer/Package/Version/VersionGuesser.php index 353ad00fb..b42fb6274 100644 --- a/src/Composer/Package/Version/VersionGuesser.php +++ b/src/Composer/Package/Version/VersionGuesser.php @@ -172,7 +172,7 @@ class VersionGuesser } if (!$commit) { - $command = 'git log --pretty="%H" -n1 HEAD'; + $command = 'git log --pretty="%H" -n1 HEAD'.GitUtil::getNoShowSignatureFlag($this->process); if (0 === $this->process->execute($command, $output, $path)) { $commit = trim($output) ?: null; } diff --git a/src/Composer/Repository/PathRepository.php b/src/Composer/Repository/PathRepository.php index 27803455f..dc9659e5f 100644 --- a/src/Composer/Repository/PathRepository.php +++ b/src/Composer/Repository/PathRepository.php @@ -22,6 +22,7 @@ use Composer\Util\Platform; use Composer\Util\ProcessExecutor; use Composer\Util\Filesystem; use Composer\Util\Url; +use Composer\Util\Git as GitUtil; /** * This repository allows installing local packages that are not necessarily under their own VCS. @@ -182,7 +183,7 @@ class PathRepository extends ArrayRepository implements ConfigurableRepositoryIn } $output = ''; - if (is_dir($path . DIRECTORY_SEPARATOR . '.git') && 0 === $this->process->execute('git log -n1 --pretty=%H', $output, $path)) { + if (is_dir($path . DIRECTORY_SEPARATOR . '.git') && 0 === $this->process->execute('git log -n1 --pretty=%H'.GitUtil::getNoShowSignatureFlag($this->process), $output, $path)) { $package['dist']['reference'] = trim($output); } diff --git a/src/Composer/Repository/VcsRepository.php b/src/Composer/Repository/VcsRepository.php index 1351c4694..b663f0f11 100644 --- a/src/Composer/Repository/VcsRepository.php +++ b/src/Composer/Repository/VcsRepository.php @@ -232,7 +232,11 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt // broken package, version doesn't match tag if ($data['version_normalized'] !== $parsedTag) { if ($isVeryVerbose) { - $this->io->writeError('Skipped tag '.$tag.', tag ('.$parsedTag.') does not match version ('.$data['version_normalized'].') in composer.json'); + if (preg_match('{(^dev-|[.-]?dev$)}i', $parsedTag)) { + $this->io->writeError('Skipped tag '.$tag.', invalid tag name, tags can not use dev prefixes or suffixes'); + } else { + $this->io->writeError('Skipped tag '.$tag.', tag ('.$parsedTag.') does not match version ('.$data['version_normalized'].') in composer.json'); + } } continue; } diff --git a/src/Composer/Util/Git.php b/src/Composer/Util/Git.php index a4b5a7336..c53c0a11a 100644 --- a/src/Composer/Util/Git.php +++ b/src/Composer/Util/Git.php @@ -20,7 +20,7 @@ use Composer\IO\IOInterface; */ class Git { - private static $version; + private static $version = false; /** @var IOInterface */ protected $io; @@ -297,6 +297,16 @@ class Git return false; } + public static function getNoShowSignatureFlag(ProcessExecutor $process) + { + $gitVersion = self::getVersion($process); + if ($gitVersion && version_compare($gitVersion, '2.10.0-rc0', '>=')) { + return ' --no-show-signature'; + } + + return ''; + } + private function checkRefIsInMirror($url, $dir, $ref) { if (is_dir($dir) && 0 === $this->process->execute('git rev-parse --git-dir', $output, $dir) && trim($output) === '.') { @@ -393,16 +403,18 @@ class Git * * @return string|null The git version number. */ - public function getVersion() + public static function getVersion(ProcessExecutor $process = null) { - if (isset(self::$version)) { - return self::$version; - } - if (0 !== $this->process->execute('git --version', $output)) { - return; - } - if (preg_match('/^git version (\d+(?:\.\d+)+)/m', $output, $matches)) { - return self::$version = $matches[1]; + if (false === self::$version) { + self::$version = null; + if (!$process) { + $process = new ProcessExecutor; + } + if (0 === $process->execute('git --version', $output) && preg_match('/^git version (\d+(?:\.\d+)+)/m', $output, $matches)) { + self::$version = $matches[1]; + } } + + return self::$version; } } diff --git a/tests/Composer/Test/Downloader/GitDownloaderTest.php b/tests/Composer/Test/Downloader/GitDownloaderTest.php index 4c1e37806..933fa26b1 100644 --- a/tests/Composer/Test/Downloader/GitDownloaderTest.php +++ b/tests/Composer/Test/Downloader/GitDownloaderTest.php @@ -18,6 +18,8 @@ use Composer\Test\TestCase; use Composer\Util\Filesystem; use Composer\Util\Platform; use Prophecy\Argument; +use Composer\Util\ProcessExecutor; +use Composer\Util\Git as GitUtil; class GitDownloaderTest extends TestCase { @@ -30,6 +32,8 @@ class GitDownloaderTest extends TestCase { $this->skipIfNotExecutable('git'); + $this->initGitVersion('1.0.0'); + $this->fs = new Filesystem; $this->workingDir = $this->getUniqueTmpDirectory(); } @@ -40,10 +44,15 @@ class GitDownloaderTest extends TestCase $this->fs->removeDirectory($this->workingDir); } + $this->initGitVersion(false); + } + + private function initGitVersion($version) + { // reset the static version cache $refl = new \ReflectionProperty('Composer\Util\Git', 'version'); $refl->setAccessible(true); - $refl->setValue(null, null); + $refl->setValue(null, $version); } protected function setupConfig($config = null) @@ -103,32 +112,23 @@ class GitDownloaderTest extends TestCase ->will($this->returnValue('dev-master')); $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $processExecutor->expects($this->at(0)) - ->method('execute') - ->with($this->equalTo($this->winCompat('git --version'))) - ->will($this->returnCallback(function ($command, &$output = null) { - $output = 'git version 1.0.0'; - - return 0; - })); - $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(1)) + $processExecutor->expects($this->at(0)) ->method('execute') ->with($this->equalTo($expectedGitCommand)) ->will($this->returnValue(0)); - $processExecutor->expects($this->at(2)) + $processExecutor->expects($this->at(1)) ->method('execute') ->with($this->equalTo($this->winCompat("git branch -r")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) ->will($this->returnValue(0)); - $processExecutor->expects($this->at(3)) + $processExecutor->expects($this->at(2)) ->method('execute') ->with($this->equalTo($this->winCompat("git checkout 'master' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) ->will($this->returnValue(0)); - $processExecutor->expects($this->at(4)) + $processExecutor->expects($this->at(3)) ->method('execute') ->with($this->equalTo($this->winCompat("git reset --hard '1234567890123456789012345678901234567890' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) ->will($this->returnValue(0)); @@ -157,14 +157,7 @@ class GitDownloaderTest extends TestCase ->will($this->returnValue('dev-master')); $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $processExecutor->expects($this->at(0)) - ->method('execute') - ->with($this->equalTo($this->winCompat('git --version'))) - ->will($this->returnCallback(function ($command, &$output = null) { - $output = 'git version 2.3.1'; - - return 0; - })); + $this->initGitVersion('2.17.0'); $config = new Config; $this->setupConfig($config); @@ -174,7 +167,7 @@ class GitDownloaderTest extends TestCase $filesystem->removeDirectory($cachePath); $expectedGitCommand = $this->winCompat(sprintf("git clone --mirror 'https://example.com/composer/composer' '%s'", $cachePath)); - $processExecutor->expects($this->at(1)) + $processExecutor->expects($this->at(0)) ->method('execute') ->with($this->equalTo($expectedGitCommand)) ->will($this->returnCallback(function () use ($cachePath) { @@ -182,7 +175,7 @@ class GitDownloaderTest extends TestCase return 0; })); - $processExecutor->expects($this->at(2)) + $processExecutor->expects($this->at(1)) ->method('execute') ->with($this->equalTo('git rev-parse --git-dir'), $this->anything(), $this->equalTo($this->winCompat($cachePath))) ->will($this->returnCallback(function ($command, &$output = null) { @@ -190,28 +183,28 @@ class GitDownloaderTest extends TestCase return 0; })); - $processExecutor->expects($this->at(3)) + $processExecutor->expects($this->at(2)) ->method('execute') ->with($this->equalTo($this->winCompat('git rev-parse --quiet --verify \'1234567890123456789012345678901234567890^{commit}\'')), $this->equalTo(null), $this->equalTo($this->winCompat($cachePath))) ->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)); - $processExecutor->expects($this->at(4)) + $processExecutor->expects($this->at(3)) ->method('execute') ->with($this->equalTo($expectedGitCommand)) ->will($this->returnValue(0)); - $processExecutor->expects($this->at(5)) + $processExecutor->expects($this->at(4)) ->method('execute') ->with($this->equalTo($this->winCompat("git branch -r")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) ->will($this->returnValue(0)); - $processExecutor->expects($this->at(6)) + $processExecutor->expects($this->at(5)) ->method('execute') ->with($this->equalTo($this->winCompat("git checkout 'master' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) ->will($this->returnValue(0)); - $processExecutor->expects($this->at(7)) + $processExecutor->expects($this->at(6)) ->method('execute') ->with($this->equalTo($this->winCompat("git reset --hard '1234567890123456789012345678901234567890' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) ->will($this->returnValue(0)); @@ -241,50 +234,41 @@ class GitDownloaderTest extends TestCase ->will($this->returnValue('1.0.0')); $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $processExecutor->expects($this->at(0)) - ->method('execute') - ->with($this->equalTo($this->winCompat('git --version'))) - ->will($this->returnCallback(function ($command, &$output = null) { - $output = 'git version 1.0.0'; - - return 0; - })); - $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(1)) + $processExecutor->expects($this->at(0)) ->method('execute') ->with($this->equalTo($expectedGitCommand)) ->will($this->returnValue(1)); - $processExecutor->expects($this->at(2)) + $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 && git remote set-url origin 'git@github.com:mirrors/composer' && git remote set-url composer 'git@github.com:mirrors/composer'"); - $processExecutor->expects($this->at(3)) + $processExecutor->expects($this->at(2)) ->method('execute') ->with($this->equalTo($expectedGitCommand)) ->will($this->returnValue(0)); $expectedGitCommand = $this->winCompat("git remote set-url origin 'https://github.com/composer/composer'"); - $processExecutor->expects($this->at(4)) + $processExecutor->expects($this->at(3)) ->method('execute') ->with($this->equalTo($expectedGitCommand), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) ->will($this->returnValue(0)); $expectedGitCommand = $this->winCompat("git remote set-url --push origin 'git@github.com:composer/composer.git'"); - $processExecutor->expects($this->at(5)) + $processExecutor->expects($this->at(4)) ->method('execute') ->with($this->equalTo($expectedGitCommand), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) ->will($this->returnValue(0)); - $processExecutor->expects($this->at(6)) + $processExecutor->expects($this->at(5)) ->method('execute') ->with($this->equalTo('git branch -r')) ->will($this->returnValue(0)); - $processExecutor->expects($this->at(7)) + $processExecutor->expects($this->at(6)) ->method('execute') ->with($this->equalTo($this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) ->will($this->returnValue(0)); @@ -328,28 +312,19 @@ class GitDownloaderTest extends TestCase ->will($this->returnValue('1.0.0')); $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $processExecutor->expects($this->at(0)) - ->method('execute') - ->with($this->equalTo($this->winCompat('git --version'))) - ->will($this->returnCallback(function ($command, &$output = null) { - $output = 'git version 1.0.0'; - - return 0; - })); - $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(1)) + $processExecutor->expects($this->at(0)) ->method('execute') ->with($this->equalTo($expectedGitCommand)) ->will($this->returnValue(0)); $expectedGitCommand = $this->winCompat("git remote set-url --push origin '{$pushUrl}'"); - $processExecutor->expects($this->at(2)) + $processExecutor->expects($this->at(1)) ->method('execute') ->with($this->equalTo($expectedGitCommand), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) ->will($this->returnValue(0)); - $processExecutor->expects($this->exactly(5)) + $processExecutor->expects($this->exactly(4)) ->method('execute') ->will($this->returnValue(0)); @@ -375,14 +350,6 @@ class GitDownloaderTest extends TestCase ->will($this->returnValue(array('https://example.com/composer/composer'))); $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); $processExecutor->expects($this->at(0)) - ->method('execute') - ->with($this->equalTo($this->winCompat('git --version'))) - ->will($this->returnCallback(function ($command, &$output = null) { - $output = 'git version 1.0.0'; - - return 0; - })); - $processExecutor->expects($this->at(1)) ->method('execute') ->with($this->equalTo($expectedGitCommand)) ->will($this->returnValue(1)); diff --git a/tests/Composer/Test/Package/Version/VersionGuesserTest.php b/tests/Composer/Test/Package/Version/VersionGuesserTest.php index 9527b628f..29619ea45 100644 --- a/tests/Composer/Test/Package/Version/VersionGuesserTest.php +++ b/tests/Composer/Test/Package/Version/VersionGuesserTest.php @@ -16,6 +16,8 @@ use Composer\Config; use Composer\Package\Version\VersionGuesser; use Composer\Semver\VersionParser; use Composer\Test\TestCase; +use Composer\Util\Git as GitUtil; +use Composer\Util\ProcessExecutor; class VersionGuesserTest extends TestCase { @@ -30,7 +32,7 @@ class VersionGuesserTest extends TestCase { $branch = 'default'; - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') + $executor = $this->getMockBuilder('Composer\\Util\\ProcessExecutor') ->setMethods(array('execute')) ->disableArgumentCloning() ->disableOriginalConstructor() @@ -40,6 +42,8 @@ class VersionGuesserTest extends TestCase $self = $this; $step = 0; + GitUtil::getVersion(new ProcessExecutor); + $executor ->expects($this->at($step)) ->method('execute') @@ -65,8 +69,8 @@ class VersionGuesserTest extends TestCase $executor ->expects($this->at($step)) ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self) { - $self->assertEquals('git log --pretty="%H" -n1 HEAD', $command); + ->willReturnCallback(function ($command, &$output) use ($self, $executor) { + $self->assertEquals('git log --pretty="%H" -n1 HEAD'.GitUtil::getNoShowSignatureFlag($executor), $command); return 128; })