Properly detect rate limit errors on github before outputting messages, fixes #6621
parent
9e7d48f70e
commit
e718f34ba4
|
@ -378,12 +378,7 @@ class GitHubDriver extends VcsDriver
|
|||
return $this->attemptCloneFallback();
|
||||
}
|
||||
|
||||
$rateLimited = false;
|
||||
foreach ($e->getHeaders() as $header) {
|
||||
if (preg_match('{^X-RateLimit-Remaining: *0$}i', trim($header))) {
|
||||
$rateLimited = true;
|
||||
}
|
||||
}
|
||||
$rateLimited = $githubUtil->isRateLimited($e->getHeaders());
|
||||
|
||||
if (!$this->io->hasAuthentication($this->originUrl)) {
|
||||
if (!$this->io->isInteractive()) {
|
||||
|
@ -397,7 +392,7 @@ class GitHubDriver extends VcsDriver
|
|||
}
|
||||
|
||||
if ($rateLimited) {
|
||||
$rateLimit = $this->getRateLimit($e->getHeaders());
|
||||
$rateLimit = $githubUtil->getRateLimit($e->getHeaders());
|
||||
$this->io->writeError(sprintf(
|
||||
'<error>GitHub API limit (%d calls/hr) is exhausted. You are already authorized so you have to wait until %s before doing more requests</error>',
|
||||
$rateLimit['limit'],
|
||||
|
@ -413,39 +408,6 @@ class GitHubDriver extends VcsDriver
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract ratelimit from response.
|
||||
*
|
||||
* @param array $headers Headers from Composer\Downloader\TransportException.
|
||||
*
|
||||
* @return array Associative array with the keys limit and reset.
|
||||
*/
|
||||
protected function getRateLimit(array $headers)
|
||||
{
|
||||
$rateLimit = array(
|
||||
'limit' => '?',
|
||||
'reset' => '?',
|
||||
);
|
||||
|
||||
foreach ($headers as $header) {
|
||||
$header = trim($header);
|
||||
if (false === strpos($header, 'X-RateLimit-')) {
|
||||
continue;
|
||||
}
|
||||
list($type, $value) = explode(':', $header, 2);
|
||||
switch ($type) {
|
||||
case 'X-RateLimit-Limit':
|
||||
$rateLimit['limit'] = (int) trim($value);
|
||||
break;
|
||||
case 'X-RateLimit-Reset':
|
||||
$rateLimit['reset'] = date('Y-m-d H:i:s', (int) trim($value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $rateLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch root identifier from GitHub
|
||||
*
|
||||
|
|
|
@ -126,4 +126,55 @@ class GitHub
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract ratelimit from response.
|
||||
*
|
||||
* @param array $headers Headers from Composer\Downloader\TransportException.
|
||||
*
|
||||
* @return array Associative array with the keys limit and reset.
|
||||
*/
|
||||
public function getRateLimit(array $headers)
|
||||
{
|
||||
$rateLimit = array(
|
||||
'limit' => '?',
|
||||
'reset' => '?',
|
||||
);
|
||||
|
||||
foreach ($headers as $header) {
|
||||
$header = trim($header);
|
||||
if (false === strpos($header, 'X-RateLimit-')) {
|
||||
continue;
|
||||
}
|
||||
list($type, $value) = explode(':', $header, 2);
|
||||
switch ($type) {
|
||||
case 'X-RateLimit-Limit':
|
||||
$rateLimit['limit'] = (int) trim($value);
|
||||
break;
|
||||
case 'X-RateLimit-Reset':
|
||||
$rateLimit['reset'] = date('Y-m-d H:i:s', (int) trim($value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $rateLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds whether a request failed due to rate limiting
|
||||
*
|
||||
* @param array $headers Headers from Composer\Downloader\TransportException.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isRateLimited(array $headers)
|
||||
{
|
||||
foreach ($headers as $header) {
|
||||
if (preg_match('{^X-RateLimit-Remaining: *0$}i', trim($header))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -327,7 +327,7 @@ class RemoteFilesystem
|
|||
$warning = $data['warning'];
|
||||
}
|
||||
}
|
||||
$this->promptAuthAndRetry($statusCode, $this->findStatusMessage($http_response_header), $warning);
|
||||
$this->promptAuthAndRetry($statusCode, $this->findStatusMessage($http_response_header), $warning, $http_response_header);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -639,11 +639,35 @@ class RemoteFilesystem
|
|||
}
|
||||
}
|
||||
|
||||
protected function promptAuthAndRetry($httpStatus, $reason = null, $warning = null)
|
||||
protected function promptAuthAndRetry($httpStatus, $reason = null, $warning = null, $headers = array())
|
||||
{
|
||||
if ($this->config && in_array($this->originUrl, $this->config->get('github-domains'), true)) {
|
||||
$message = "\n".'Could not fetch '.$this->fileUrl.', please create a GitHub OAuth token '.($httpStatus === 404 ? 'to access private repos' : 'to go over the API rate limit');
|
||||
$gitHubUtil = new GitHub($this->io, $this->config, null);
|
||||
$message = "\n";
|
||||
|
||||
$rateLimited = $gitHubUtil->isRateLimited($headers);
|
||||
if ($rateLimited) {
|
||||
$rateLimit = $gitHubUtil->getRateLimit($headers);
|
||||
if ($this->io->hasAuthentication($this->originUrl)) {
|
||||
$message = 'Review your configured GitHub OAuth token or enter a new one to go over the API rate limit.';
|
||||
} else {
|
||||
$message = 'Create a GitHub OAuth token to go over the API rate limit.';
|
||||
}
|
||||
|
||||
$message = sprintf(
|
||||
'GitHub API limit (%d calls/hr) is exhausted, could not fetch '.$this->fileUrl.'. '.$message.' You can also wait until %s for the rate limit to reset.',
|
||||
$rateLimit['limit'],
|
||||
$rateLimit['reset']
|
||||
)."\n";
|
||||
} else {
|
||||
$message .= 'Could not fetch '.$this->fileUrl.', please ';
|
||||
if ($this->io->hasAuthentication($this->originUrl)) {
|
||||
$message .= 'review your configured GitHub OAuth token or enter a new one to access private repos';
|
||||
} else {
|
||||
$message .= 'create a GitHub OAuth token to access private repos';
|
||||
}
|
||||
}
|
||||
|
||||
if (!$gitHubUtil->authorizeOAuth($this->originUrl)
|
||||
&& (!$this->io->isInteractive() || !$gitHubUtil->authorizeOAuthInteractively($this->originUrl, $message))
|
||||
) {
|
||||
|
|
Loading…
Reference in New Issue