protected function getContents($url, $tryClone = false)
{
try {
return parent::getContents($url);
} catch (TransportException $e) {
switch ($e->getCode()) {
case 401:
case 404:
if (!$this->io->isInteractive() && $tryClone) {
return $this->attemptCloneFallback($e);
}
$this->io->write('Your GitHub credentials are required to fetch private repository metadata (<info>'.$this->url.'</info>):');
$this->authorizeOauth();
return parent::getContents($url);
case 403:
if (!$this->io->isInteractive() && $tryClone) {
return $this->attemptCloneFallback($e);
}
$rateLimited = false;
foreach ($e->getHeaders() as $header) {
if (preg_match('{^X-RateLimit-Remaining: *0$}i', trim($header))) {
$rateLimited = true;
}
}
if (!$this->io->hasAuthorization($this->originUrl)) {
if (!$this->io->isInteractive()) {
$this->io->write('<error>GitHub API limit exhausted. Failed to get metadata for the '.$this->url.' repository, try running in interactive mode so that you can enter your GitHub credentials to increase the API limit</error>');
throw $e;
}
$this->io->write('API limit exhausted. Enter your GitHub credentials to get a larger API limit (<info>'.$this->url.'</info>):');
$this->authorizeOauth();
return parent::getContents($url);
}
if ($rateLimited) {
$this->io->write('<error>GitHub API limit exhausted. You are already authorized so you will have to wait a while before doing more requests</error>');
}
throw $e;
default:
throw $e;
}
}
}
/**
/**
* Fetch root identifier from GitHub
* Fetch root identifier from GitHub
*
*
@ -243,73 +299,83 @@ class GitHubDriver extends VcsDriver
// If this repository may be private (hard to say for sure,
// GitHub returns 404 for private repositories) and we
// cannot ask for authentication credentials (because we
// are not interactive) then we fallback to GitDriver.
$this->gitDriver = new GitDriver(
$this->generateSshUrl(),
$this->io,
$this->config,
$this->process,
$this->remoteFilesystem
);
$this->gitDriver->initialize();
return;
} catch (\RuntimeException $e) {
$this->gitDriver = null;
$this->io->write('<error>Failed to clone the '.$this->generateSshUrl().' repository, try running in interactive mode so that you can enter your GitHub credentials</error>');
throw $e;
}
}
protected function authorizeOAuth()
{
$attemptCounter = 0;
$attemptCounter = 0;
while (null === $this->rootIdentifier) {
if (5 == $attemptCounter++) {
$this->io->write('The credentials will be swapped for an OAuth token stored in '.$this->config->get('home').'/config.json, your password will not be stored');
throw new \RuntimeException("Either you have entered invalid credentials or this GitHub repository does not exists (404)");
$this->io->write('To revoke access to this token you can visit https://github.com/settings/applications');
// If this repository may be private (hard to say for sure,
// GitHub returns 404 for private repositories) and we
// cannot ask for authentication credentials (because we
// are not interactive) then we fallback to GitDriver.
$this->gitDriver = new GitDriver(
$this->generateSshUrl(),
$this->io,
$this->config,
$this->process,
$this->remoteFilesystem
);
$this->gitDriver->initialize();
return;
} catch (\RuntimeException $e) {
$this->gitDriver = null;
if (!$this->io->isInteractive()) {
$this->io->write('<error>Failed to clone the '.$this->generateSshUrl().' repository, try running in interactive mode so that you can enter your username and password</error>');
if (!$this->io->hasAuthorization($this->originUrl)) {
if (!$this->io->isInteractive()) {
$this->io->write('<error>API limit exhausted. Failed to clone the '.$this->generateSshUrl().' repository, try running in interactive mode so that you can enter your username and password to increase the API limit</error>');
throw $e;
}
$this->io->write('API limit exhausted. Authentication required for larger API limit (<info>'.$this->url.'</info>):');