Merge pull request #1370 from MikeMcQuaid/better-github-scopes

Improve GitHub API scopes output.
This commit is contained in:
Mike McQuaid 2016-11-02 12:00:27 -04:00 committed by GitHub
commit dc47fb3364
2 changed files with 33 additions and 17 deletions

View File

@ -47,13 +47,16 @@ module Homebrew
if ARGV.include?("--new-issue") || ARGV.switch?("n") if ARGV.include?("--new-issue") || ARGV.switch?("n")
if GitHub.api_credentials_type == :none if GitHub.api_credentials_type == :none
puts "You can create a personal access token: https://github.com/settings/tokens" puts <<-EOS.undent
puts "and then set HOMEBREW_GITHUB_API_TOKEN as authentication method." You can create a new personal access token:
puts #{GitHub::ALL_SCOPES_URL}
and then set the new HOMEBREW_GITHUB_API_TOKEN as the authentication method.
EOS
login! login!
end end
url = new_issue(f.tap, "#{f.name} failed to build on #{MacOS.full_version}", url) url = create_issue(f.tap, "#{f.name} failed to build on #{MacOS.full_version}", url)
end end
puts url if url puts url if url
@ -103,13 +106,17 @@ module Homebrew
end end
def create_gist(files, description) def create_gist(files, description)
url = "https://api.github.com/gists"
data = { "public" => true, "files" => files, "description" => description } data = { "public" => true, "files" => files, "description" => description }
GitHub.open("https://api.github.com/gists", data)["html_url"] scopes = GitHub::CREATE_GIST_SCOPES
GitHub.open(url, data: data, scopes: scopes)["html_url"]
end end
def new_issue(repo, title, body) def create_issue(repo, title, body)
url = "https://api.github.com/repos/#{repo}/issues"
data = { "title" => title, "body" => body } data = { "title" => title, "body" => body }
GitHub.open("https://api.github.com/repos/#{repo}/issues", data)["html_url"] scopes = GitHub::CREATE_ISSUE_SCOPES
GitHub.open(url, data: data, scopes: scopes)["html_url"]
end end
def gist_logs def gist_logs

View File

@ -6,6 +6,11 @@ module GitHub
ISSUES_URI = URI.parse("https://api.github.com/search/issues") ISSUES_URI = URI.parse("https://api.github.com/search/issues")
CREATE_GIST_SCOPES = ["gist"].freeze
CREATE_ISSUE_SCOPES = ["public_repo"].freeze
ALL_SCOPES = (CREATE_GIST_SCOPES + CREATE_ISSUE_SCOPES).freeze
ALL_SCOPES_URL = Formatter.url("https://github.com/settings/tokens/new?scopes=#{ALL_SCOPES.join(",")}&description=Homebrew").freeze
Error = Class.new(RuntimeError) Error = Class.new(RuntimeError)
HTTPNotFoundError = Class.new(Error) HTTPNotFoundError = Class.new(Error)
@ -14,7 +19,7 @@ module GitHub
super <<-EOS.undent super <<-EOS.undent
GitHub API Error: #{error} GitHub API Error: #{error}
Try again in #{pretty_ratelimit_reset(reset)}, or create a personal access token: Try again in #{pretty_ratelimit_reset(reset)}, or create a personal access token:
#{Formatter.url("https://github.com/settings/tokens/new?scopes=&description=Homebrew")} #{ALL_SCOPES_URL}
and then set the token as: export HOMEBREW_GITHUB_API_TOKEN="your_new_token" and then set the token as: export HOMEBREW_GITHUB_API_TOKEN="your_new_token"
EOS EOS
end end
@ -38,7 +43,7 @@ module GitHub
Clear them with: Clear them with:
printf "protocol=https\\nhost=github.com\\n" | git credential-osxkeychain erase printf "protocol=https\\nhost=github.com\\n" | git credential-osxkeychain erase
Or create a personal access token: Or create a personal access token:
#{Formatter.url("https://github.com/settings/tokens/new?scopes=&description=Homebrew")} #{ALL_SCOPES_URL}
and then set the token as: export HOMEBREW_GITHUB_API_TOKEN="your_new_token" and then set the token as: export HOMEBREW_GITHUB_API_TOKEN="your_new_token"
EOS EOS
end end
@ -92,28 +97,32 @@ module GitHub
end end
end end
def api_credentials_error_message(response_headers) def api_credentials_error_message(response_headers, needed_scopes)
return if response_headers.empty? return if response_headers.empty?
@api_credentials_error_message_printed ||= begin @api_credentials_error_message_printed ||= begin
unauthorized = (response_headers["http/1.1"] == "401 Unauthorized") unauthorized = (response_headers["http/1.1"] == "401 Unauthorized")
scopes = response_headers["x-accepted-oauth-scopes"].to_s.split(", ") scopes = response_headers["x-accepted-oauth-scopes"].to_s.split(", ")
needed_human_scopes = needed_scopes.join(", ")
needed_human_scopes = "none" if needed_human_scopes.empty?
if !unauthorized && scopes.empty? if !unauthorized && scopes.empty?
credentials_scopes = response_headers["x-oauth-scopes"].to_s.split(", ") credentials_scopes = response_headers["x-oauth-scopes"]
case GitHub.api_credentials_type case GitHub.api_credentials_type
when :keychain when :keychain
onoe <<-EOS.undent onoe <<-EOS.undent
Your macOS keychain GitHub credentials do not have sufficient scope! Your macOS keychain GitHub credentials do not have sufficient scope!
Scopes they need: #{needed_human_scopes}
Scopes they have: #{credentials_scopes} Scopes they have: #{credentials_scopes}
Create a personal access token: #{Formatter.url("https://github.com/settings/tokens")} Create a personal access token: #{ALL_SCOPES_URL}
and then set HOMEBREW_GITHUB_API_TOKEN as the authentication method instead. and then set HOMEBREW_GITHUB_API_TOKEN as the authentication method instead.
EOS EOS
when :environment when :environment
onoe <<-EOS.undent onoe <<-EOS.undent
Your HOMEBREW_GITHUB_API_TOKEN does not have sufficient scope! Your HOMEBREW_GITHUB_API_TOKEN does not have sufficient scope!
Scopes they need: #{needed_human_scopes}
Scopes it has: #{credentials_scopes} Scopes it has: #{credentials_scopes}
Create a new personal access token: #{Formatter.url("https://github.com/settings/tokens")} Create a new personal access token: #{ALL_SCOPES_URL}
and then set the new HOMEBREW_GITHUB_API_TOKEN as the authentication method instead. and then set the new HOMEBREW_GITHUB_API_TOKEN as the authentication method instead.
EOS EOS
end end
@ -122,7 +131,7 @@ module GitHub
end end
end end
def open(url, data = nil) def open(url, data: nil, scopes: [].freeze)
# This is a no-op if the user is opting out of using the GitHub API. # This is a no-op if the user is opting out of using the GitHub API.
return if ENV["HOMEBREW_NO_GITHUB_API"] return if ENV["HOMEBREW_NO_GITHUB_API"]
@ -172,7 +181,7 @@ module GitHub
begin begin
if !http_code.start_with?("2") && !status.success? if !http_code.start_with?("2") && !status.success?
raise_api_error(output, errors, http_code, headers) raise_api_error(output, errors, http_code, headers, scopes)
end end
json = Utils::JSON.load output json = Utils::JSON.load output
if block_given? if block_given?
@ -185,7 +194,7 @@ module GitHub
end end
end end
def raise_api_error(output, errors, http_code, headers) def raise_api_error(output, errors, http_code, headers, scopes)
meta = {} meta = {}
headers.lines.each do |l| headers.lines.each do |l|
key, _, value = l.delete(":").partition(" ") key, _, value = l.delete(":").partition(" ")
@ -200,7 +209,7 @@ module GitHub
raise RateLimitExceededError.new(reset, error) raise RateLimitExceededError.new(reset, error)
end end
GitHub.api_credentials_error_message(meta) GitHub.api_credentials_error_message(meta, scopes)
case http_code case http_code
when "401", "403" when "401", "403"