From 7e649fac41d844835bc86e1131dde465366cc0df Mon Sep 17 00:00:00 2001 From: johnstevenson Date: Thu, 7 Nov 2019 09:53:22 +0000 Subject: [PATCH 1/3] Fix Windows test regression from commit 149250a Commit: 149250ab92feadd9fe045b54d6e42f33d185a595 ProcessExecutor::escape handled a false value inconsistently across platforms, returning an emtpy string on Windows, otherwise `''`. This is fixed to return `""` on Windows. The GitDownloaderTest code has been appropriately updated. --- src/Composer/Util/ProcessExecutor.php | 2 +- tests/Composer/Test/Downloader/GitDownloaderTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Composer/Util/ProcessExecutor.php b/src/Composer/Util/ProcessExecutor.php index d72a02981..00b2e7547 100644 --- a/src/Composer/Util/ProcessExecutor.php +++ b/src/Composer/Util/ProcessExecutor.php @@ -155,7 +155,7 @@ class ProcessExecutor //@see https://bugs.php.net/bug.php?id=43784 //@see https://bugs.php.net/bug.php?id=49446 if ('\\' === DIRECTORY_SEPARATOR) { - if ('' === $argument) { + if ((string) $argument === '') { return escapeshellarg($argument); } diff --git a/tests/Composer/Test/Downloader/GitDownloaderTest.php b/tests/Composer/Test/Downloader/GitDownloaderTest.php index cd3375464..9ff169925 100644 --- a/tests/Composer/Test/Downloader/GitDownloaderTest.php +++ b/tests/Composer/Test/Downloader/GitDownloaderTest.php @@ -734,7 +734,7 @@ composer https://github.com/old/url (push) $cmd = str_replace('cd ', 'cd /D ', $cmd); $cmd = str_replace('composerPath', getcwd().'/composerPath', $cmd); - return str_replace('""', '', strtr($cmd, "'", '"')); + return strtr($cmd, "'", '"'); } return $cmd; From b8471156175c2133df61432b4455b709cbfc33f9 Mon Sep 17 00:00:00 2001 From: Stephan Vock Date: Thu, 7 Nov 2019 00:43:19 +0100 Subject: [PATCH 2/3] Git: fix authentication handling for private GitHub repositories --- src/Composer/Util/Git.php | 6 +- tests/Composer/Test/Util/GitTest.php | 145 +++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 tests/Composer/Test/Util/GitTest.php diff --git a/src/Composer/Util/Git.php b/src/Composer/Util/Git.php index 15c46d080..81c685011 100644 --- a/src/Composer/Util/Git.php +++ b/src/Composer/Util/Git.php @@ -85,7 +85,9 @@ class Git } // failed to checkout, first check git accessibility - $this->throwException('Failed to clone ' . $url . ' via ' . implode(', ', $protocols) . ' protocols, aborting.' . "\n\n" . implode("\n", $messages), $url); + if (!$this->io->hasAuthentication($match[1]) && !$this->io->isInteractive()) { + $this->throwException('Failed to clone ' . $url . ' via ' . implode(', ', $protocols) . ' protocols, aborting.' . "\n\n" . implode("\n", $messages), $url); + } } // if we have a private github url and the ssh protocol is disabled then we skip it and directly fallback to https @@ -97,7 +99,7 @@ class Git if ($bypassSshForGitHub || 0 !== $this->process->execute($command, $ignoredOutput, $cwd)) { // private github repository without ssh key access, try https with auth if (preg_match('{^git@' . self::getGitHubDomainsRegex($this->config) . ':(.+?)\.git$}i', $url, $match) - || preg_match('{^(https?)://' . self::getGitHubDomainsRegex($this->config) . '/(.*)}', $url, $match) + || preg_match('{^https?://' . self::getGitHubDomainsRegex($this->config) . '/(.*)}', $url, $match) ) { if (!$this->io->hasAuthentication($match[1])) { $gitHubUtil = new GitHub($this->io, $this->config, $this->process); diff --git a/tests/Composer/Test/Util/GitTest.php b/tests/Composer/Test/Util/GitTest.php new file mode 100644 index 000000000..7aa66be12 --- /dev/null +++ b/tests/Composer/Test/Util/GitTest.php @@ -0,0 +1,145 @@ +io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); + $this->config = $this->getMockBuilder('Composer\Config')->disableOriginalConstructor()->getMock(); + $this->process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->disableOriginalConstructor()->getMock(); + $this->fs = $this->getMockBuilder('Composer\Util\Filesystem')->disableOriginalConstructor()->getMock(); + $this->git = new Git($this->io, $this->config, $this->process, $this->fs); + } + + /** + * @dataProvider publicGithubNoCredentialsProvider + */ + public function testRunCommandPublicGitHubRepositoryNotInitialClone($protocol, $expectedUrl) + { + $that = $this; + $commandCallable = function ($url) use ($that, $expectedUrl) { + $that->assertSame($expectedUrl, $url); + + return 'git command'; + }; + + $this->mockConfig($protocol); + + $this->process + ->expects($this->once()) + ->method('execute') + ->with($this->equalTo('git command')) + ->willReturn(0); + + $this->git->runCommand($commandCallable, 'https://github.com/acme/repo', null, true); + } + + public function publicGithubNoCredentialsProvider() + { + return array( + array('ssh', 'git@github.com:acme/repo'), + array('https', 'https://github.com/acme/repo'), + ); + } + + /** + * @expectedException \RuntimeException + */ + public function testRunCommandPrivateGitHubRepositoryNotInitialCloneNotInteractiveWithoutAuthentication() + { + $that = $this; + $commandCallable = function ($url) use ($that) { + $that->assertSame('https://github.com/acme/repo', $url); + + return 'git command'; + }; + + $this->mockConfig('https'); + + $this->process + ->method('execute') + ->willReturnMap(array( + array('git command', null, null, 1), + array('git --version', null, null, 0), + )); + + $this->git->runCommand($commandCallable, 'https://github.com/acme/repo', null, true); + } + + /** + * @dataProvider privateGithubWithCredentialsProvider + */ + public function testRunCommandPrivateGitHubRepositoryNotInitialCloneNotInteractiveWithAuthentication($gitUrl, $protocol, $gitHubToken, $expectedUrl) + { + $commandCallable = function ($url) use ($expectedUrl) { + if ($url !== $expectedUrl) { + return 'git command failing'; + } + + return 'git command ok'; + }; + + $this->mockConfig($protocol); + + $this->process + ->method('execute') + ->willReturnMap(array( + array('git command failing', null, null, 1), + array('git command ok', null, null, 0), + )); + + $this->io + ->method('isInteractive') + ->willReturn(false); + + $this->io + ->method('hasAuthentication') + ->with($this->equalTo('github.com')) + ->willReturn(true); + + $this->io + ->method('getAuthentication') + ->with($this->equalTo('github.com')) + ->willReturn(array('username' => 'token', 'password' => $gitHubToken)); + + $this->git->runCommand($commandCallable, $gitUrl, null, true); + } + + public function privateGithubWithCredentialsProvider() + { + return array( + array('git@github.com:acme/repo.git', 'ssh', 'MY_GITHUB_TOKEN', 'https://token:MY_GITHUB_TOKEN@github.com/acme/repo.git'), + array('https://github.com/acme/repo', 'https', 'MY_GITHUB_TOKEN', 'https://token:MY_GITHUB_TOKEN@github.com/acme/repo.git'), + ); + } + + private function mockConfig($protocol) + { + $this->config + ->method('get') + ->willReturnMap(array( + array('github-domains', 0, array('github.com')), + array('github-protocols', 0, array($protocol)), + )); + } +} From 0bd3f27693530e41b98d7b835adf37302bc6e968 Mon Sep 17 00:00:00 2001 From: Cyril VERLOOP Date: Sat, 16 Nov 2019 16:17:49 +0100 Subject: [PATCH 3/3] Do not show commit signature for git log. --- src/Composer/Repository/Vcs/GitDriver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Repository/Vcs/GitDriver.php b/src/Composer/Repository/Vcs/GitDriver.php index 4a14974fb..cc6e3edb4 100644 --- a/src/Composer/Repository/Vcs/GitDriver.php +++ b/src/Composer/Repository/Vcs/GitDriver.php @@ -143,7 +143,7 @@ class GitDriver extends VcsDriver public function getChangeDate($identifier) { $this->process->execute(sprintf( - 'git log -1 --format=%%at %s', + 'git -c log.showSignature=false log -1 --format=%%at %s', ProcessExecutor::escape($identifier) ), $output, $this->repoDir);