diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php
index 508a76afa..c5ec96673 100644
--- a/src/Composer/Downloader/FileDownloader.php
+++ b/src/Composer/Downloader/FileDownloader.php
@@ -80,7 +80,11 @@ class FileDownloader implements DownloaderInterface
if (404 === $e->getCode() && 'github.com' === parse_url($processUrl, PHP_URL_HOST)) {
$message = "\n".'Could not fetch '.$processUrl.', enter your GitHub credentials to access private repos';
$gitHubUtil = new GitHub($this->io, $this->config, null, $this->rfs);
- $gitHubUtil->authorizeOAuth('github.com', $message);
+ if (!$gitHubUtil->authorizeOAuth('github.com')
+ && (!$this->io->isInteractive() || !$gitHubUtil->authorizeOAuthInteractively('github.com', $message))
+ ) {
+ throw $e;
+ }
$this->rfs->copy(parse_url($processUrl, PHP_URL_HOST), $processUrl, $fileName);
} else {
throw $e;
diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php
index c80b57634..c7c1774b8 100644
--- a/src/Composer/Downloader/GitDownloader.php
+++ b/src/Composer/Downloader/GitDownloader.php
@@ -285,19 +285,24 @@ class GitDownloader extends VcsDownloader
$command = call_user_func($commandCallable, $url);
if (0 !== $this->process->execute($command, $handler)) {
// private github repository without git access, try https with auth
- if (preg_match('{^git@(github.com):(.+?)\.git$}i', $url, $match) && $this->io->isInteractive()) {
+ if (preg_match('{^git@(github.com):(.+?)\.git$}i', $url, $match)) {
if (!$this->io->hasAuthorization($match[1])) {
- $message = 'Cloning failed using an ssh key for authentication, enter your GitHub credentials to access private repos';
$gitHubUtil = new GitHub($this->io, $this->config, $this->process);
- $gitHubUtil->authorizeOAuth($match[1], $message);
+ $message = 'Cloning failed using an ssh key for authentication, enter your GitHub credentials to access private repos';
+
+ if (!$gitHubUtil->authorizeOAuth($match[1]) && $this->io->isInteractive()) {
+ $gitHubUtil->authorizeOAuthInteractively($match[1], $message);
+ }
}
- $auth = $this->io->getAuthorization($match[1]);
- $url = 'https://'.$auth['username'] . ':' . $auth['password'] . '@'.$match[1].'/'.$match[2].'.git';
+ if ($this->io->hasAuthorization($match[1])) {
+ $auth = $this->io->getAuthorization($match[1]);
+ $url = 'https://'.$auth['username'] . ':' . $auth['password'] . '@'.$match[1].'/'.$match[2].'.git';
- $command = call_user_func($commandCallable, $url);
- if (0 === $this->process->execute($command, $handler)) {
- return;
+ $command = call_user_func($commandCallable, $url);
+ if (0 === $this->process->execute($command, $handler)) {
+ return;
+ }
}
}
diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php
index 7c53970cd..fea55c462 100755
--- a/src/Composer/Repository/Vcs/GitHubDriver.php
+++ b/src/Composer/Repository/Vcs/GitHubDriver.php
@@ -244,6 +244,8 @@ class GitHubDriver extends VcsDriver
try {
return parent::getContents($url);
} catch (TransportException $e) {
+ $gitHubUtil = new GitHub($this->io, $this->config, $this->process, $this->remoteFilesystem);
+
switch ($e->getCode()) {
case 401:
case 404:
@@ -252,17 +254,25 @@ class GitHubDriver extends VcsDriver
throw $e;
}
- if (!$this->io->isInteractive()) {
- return $this->attemptCloneFallback($e);
+ if ($gitHubUtil->authorizeOAuth($this->originUrl)) {
+ return parent::getContents($url);
}
- $this->authorizeOAuth('Your GitHub credentials are required to fetch private repository metadata ('.$this->url.')');
+ if (!$this->io->isInteractive()) {
+ return $this->attemptCloneFallback();
+ }
+
+ $gitHubUtil->authorizeOAuthInteractively($this->originUrl, 'Your GitHub credentials are required to fetch private repository metadata ('.$this->url.')');
return parent::getContents($url);
case 403:
+ if (!$this->io->hasAuthorization($this->originUrl) && $gitHubUtil->authorizeOAuth($this->originUrl)) {
+ return parent::getContents($url);
+ }
+
if (!$this->io->isInteractive() && $fetchingRepoData) {
- return $this->attemptCloneFallback($e);
+ return $this->attemptCloneFallback();
}
$rateLimited = false;
@@ -278,7 +288,7 @@ class GitHubDriver extends VcsDriver
throw $e;
}
- $this->authorizeOAuth('API limit exhausted. Enter your GitHub credentials to get a larger API limit ('.$this->url.')');
+ $gitHubUtil->authorizeOAuthInteractively($this->originUrl, 'API limit exhausted. Enter your GitHub credentials to get a larger API limit ('.$this->url.')');
return parent::getContents($url);
}
@@ -346,10 +356,4 @@ class GitHubDriver extends VcsDriver
throw $e;
}
}
-
- protected function authorizeOAuth($message)
- {
- $gitHubUtil = new GitHub($this->io, $this->config, $this->process, $this->remoteFilesystem);
- $gitHubUtil->authorizeOAuth($this->originUrl, $message);
- }
}
diff --git a/src/Composer/Util/GitHub.php b/src/Composer/Util/GitHub.php
index ba5fcd351..33e5443f7 100644
--- a/src/Composer/Util/GitHub.php
+++ b/src/Composer/Util/GitHub.php
@@ -44,20 +44,36 @@ class GitHub
}
/**
- * Authorizes a GitHub domain via OAuth
+ * Attempts to authorize a GitHub domain via OAuth
*
* @param string $originUrl The host this GitHub instance is located at
- * @param string $message The reason this authorization is required
+ * @return bool true on success
*/
- public function authorizeOAuth($originUrl, $message = null)
+ public function authorizeOAuth($originUrl)
{
+ if ('github.com' !== $originUrl) {
+ return false;
+ }
+
// if available use token from git config
if (0 === $this->process->execute('git config github.accesstoken', $output)) {
$this->io->setAuthorization($originUrl, trim($output), 'x-oauth-basic');
- return;
+ return true;
}
+ return false;
+ }
+
+ /**
+ * Authorizes a GitHub domain interactively via OAuth
+ *
+ * @param string $originUrl The host this GitHub instance is located at
+ * @param string $message The reason this authorization is required
+ * @return bool true on success
+ */
+ public function authorizeOAuthInteractively($originUrl, $message = null)
+ {
$attemptCounter = 0;
if ($message) {
@@ -105,7 +121,7 @@ class GitHub
$githubTokens[$originUrl] = $contents['token'];
$this->config->getConfigSource()->addConfigSetting('github-oauth', $githubTokens);
- return;
+ return true;
}
throw new \RuntimeException("Invalid GitHub credentials 5 times in a row, aborting.");
diff --git a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php
index df8fcc6a5..ccde42a00 100644
--- a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php
+++ b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php
@@ -264,30 +264,35 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase
$process->expects($this->at(0))
->method('execute')
- ->with($this->stringContains($repoSshUrl))
- ->will($this->returnValue(0));
+ ->with($this->equalTo('git config github.accesstoken'))
+ ->will($this->returnValue(1));
$process->expects($this->at(1))
->method('execute')
- ->with($this->stringContains('git tag'));
+ ->with($this->stringContains($repoSshUrl))
+ ->will($this->returnValue(0));
$process->expects($this->at(2))
+ ->method('execute')
+ ->with($this->stringContains('git tag'));
+
+ $process->expects($this->at(3))
->method('splitLines')
->will($this->returnValue(array($identifier)));
- $process->expects($this->at(3))
+ $process->expects($this->at(4))
->method('execute')
->with($this->stringContains('git branch --no-color --no-abbrev -v'));
- $process->expects($this->at(4))
+ $process->expects($this->at(5))
->method('splitLines')
->will($this->returnValue(array(' test_master edf93f1fccaebd8764383dc12016d0a1a9672d89 Fix test & behavior')));
- $process->expects($this->at(5))
+ $process->expects($this->at(6))
->method('execute')
->with($this->stringContains('git branch --no-color'));
- $process->expects($this->at(6))
+ $process->expects($this->at(7))
->method('splitLines')
->will($this->returnValue(array('* test_master')));