From e6a2ce1ab542b52b890b05c234bc2b314dc99f5f Mon Sep 17 00:00:00 2001 From: Issy Long Date: Mon, 6 Feb 2023 15:24:20 +0100 Subject: [PATCH] cmd/gist-logs: On 404, the PAT probably needs more permissions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - This 404 error is from GitHub, and GitHub doesn't give us any more informations about scopes for the gist endpoint (for some reason). But we can safely assume, as it happens a lot, that "Error: Not Found" (404) is because the user hasn't granted their `HOMEBREW_GITHUB_API_TOKEN` the `gist` scope. Before: ```shell $ HOMEBREW_GITHUB_API_TOKEN= brew gist-logs -p logrotate Error: Not Found ``` After: ```shell ❯ HOMEBREW_GITHUB_API_TOKEN= brew gist-logs logrotate Error: Your GitHub API token likely doesn't have the `gist` scope. Create a GitHub personal access token: https://github.com/settings/tokens/new?scopes=gist&description=Homebrew echo 'export HOMEBREW_GITHUB_API_TOKEN=your_token_here' >> ~/.zshrc ``` --- Library/Homebrew/cmd/gist-logs.rb | 10 +++++++++- Library/Homebrew/utils/github/api.rb | 25 ++++++++++++++----------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Library/Homebrew/cmd/gist-logs.rb b/Library/Homebrew/cmd/gist-logs.rb index 81a76f7036322a..1931724d358977 100644 --- a/Library/Homebrew/cmd/gist-logs.rb +++ b/Library/Homebrew/cmd/gist-logs.rb @@ -63,7 +63,15 @@ def gistify_logs(f, args:) else "#{f.name} (#{f.full_name}) on #{OS_VERSION} - Homebrew build logs" end - url = GitHub.create_gist(files, descr, private: args.private?) + + begin + url = GitHub.create_gist(files, descr, private: args.private?) + rescue GitHub::API::HTTPNotFoundError + odie <<~EOS + Your GitHub API token likely doesn't have the `gist` scope. + #{GitHub.pat_blurb(GitHub::CREATE_GIST_SCOPES)} + EOS + end url = GitHub.create_issue(f.tap, "#{f.name} failed to build on #{MacOS.full_version}", url) if args.new_issue? diff --git a/Library/Homebrew/utils/github/api.rb b/Library/Homebrew/utils/github/api.rb index 2855ca4eeac0b6..1a012970b79a6a 100644 --- a/Library/Homebrew/utils/github/api.rb +++ b/Library/Homebrew/utils/github/api.rb @@ -5,7 +5,18 @@ require "utils/shell" require "utils/formatter" +# A module that interfaces with GitHub, code like PAT scopes, credential handling and API errors. module GitHub + def self.pat_blurb(scopes) + <<~EOS + Create a GitHub personal access token: + #{Formatter.url( + "https://github.com/settings/tokens/new?scopes=#{scopes.join(",")}&description=Homebrew", + )} + #{Utils::Shell.set_variable_in_profile("HOMEBREW_GITHUB_API_TOKEN", "your_token_here")} + EOS + end + API_URL = "https://api.github.com" API_MAX_PAGES = 50 API_MAX_ITEMS = 5000 @@ -14,14 +25,6 @@ module GitHub CREATE_ISSUE_FORK_OR_PR_SCOPES = ["repo"].freeze CREATE_WORKFLOW_SCOPES = ["workflow"].freeze ALL_SCOPES = (CREATE_GIST_SCOPES + CREATE_ISSUE_FORK_OR_PR_SCOPES + CREATE_WORKFLOW_SCOPES).freeze - ALL_SCOPES_URL = Formatter.url( - "https://github.com/settings/tokens/new?scopes=#{ALL_SCOPES.join(",")}&description=Homebrew", - ).freeze - CREATE_GITHUB_PAT_MESSAGE = <<~EOS - Create a GitHub personal access token: - #{ALL_SCOPES_URL} - #{Utils::Shell.set_variable_in_profile("HOMEBREW_GITHUB_API_TOKEN", "your_token_here")} - EOS GITHUB_PERSONAL_ACCESS_TOKEN_REGEX = /^(?:[a-f0-9]{40}|gh[po]_\w{36,251})$/.freeze # Helper functions to access the GitHub API. @@ -49,7 +52,7 @@ def initialize(github_message) class RateLimitExceededError < Error def initialize(reset, github_message) @github_message = github_message - new_pat_message = ", or:\n#{CREATE_GITHUB_PAT_MESSAGE}" if API.credentials.blank? + new_pat_message = ", or:\n#{pat_blurb}" if API.credentials.blank? super <<~EOS GitHub API Error: #{github_message} Try again in #{pretty_ratelimit_reset(reset)}#{new_pat_message} @@ -87,7 +90,7 @@ def initialize(github_message) class MissingAuthenticationError < Error def initialize message = +"No GitHub credentials found in macOS Keychain or environment.\n" - message << CREATE_GITHUB_PAT_MESSAGE + message << pat_blurb super message end end @@ -177,7 +180,7 @@ def credentials_error_message(response_headers, needed_scopes) Your #{what} credentials do not have sufficient scope! Scopes required: #{needed_scopes} Scopes present: #{credentials_scopes} - #{CREATE_GITHUB_PAT_MESSAGE} + #{pat_blurb} EOS end