Class: Ace::Review::Molecules::GhPrCommentFetcher

Inherits:
Object
  • Object
show all
Defined in:
lib/ace/review/molecules/gh_pr_comment_fetcher.rb

Overview

Fetch PR comments and reviews via gh CLI

Constant Summary collapse

BOT_PATTERNS =

Known bot usernames to filter out

%w[
  dependabot
  github-actions
  renovate
  codecov
  sonarcloud
  snyk
  mergify
  greenkeeper
].freeze
MAX_REVIEW_THREADS =

GraphQL query limits Note: These are hardcoded limits. PRs exceeding these will have truncated data.

100
MAX_COMMENTS_PER_THREAD =
50
REVIEW_THREADS_QUERY =

GraphQL query template for fetching review threads

<<~GRAPHQL
  query($owner: String!, $repo: String!, $number: Int!) {
    repository(owner: $owner, name: $repo) {
      pullRequest(number: $number) {
        reviewThreads(first: #{MAX_REVIEW_THREADS}) {
          totalCount
          pageInfo {
            hasNextPage
          }
          nodes {
            id
            isResolved
            path
            line
            comments(first: #{MAX_COMMENTS_PER_THREAD}) {
              totalCount
              pageInfo {
                hasNextPage
              }
              nodes {
                id
                body
                author { login }
                createdAt
              }
            }
          }
        }
      }
    }
  }
GRAPHQL

Class Method Summary collapse

Class Method Details

.fetch(pr_identifier, options = {}) ⇒ Hash

Fetch PR comments and reviews

Parameters:

  • pr_identifier (String)

    PR identifier (number, URL, or owner/repo#number)

  • options (Hash) (defaults to: {})

    Fetch options

Options Hash (options):

  • :max_retries (Integer)

    Maximum retry attempts (default: 3)

  • :initial_backoff (Integer)

    Initial backoff in seconds (default: 1)

  • :timeout (Integer)

    Timeout in seconds for gh CLI (default: 30)

  • :include_resolved (Boolean)

    Include resolved review threads (default: false)

  • :include_bots (Boolean)

    Include bot comments (default: false)

Returns:

  • (Hash)

    Result with :success, :comments, :reviews, :review_threads, :error



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/ace/review/molecules/gh_pr_comment_fetcher.rb', line 72

def self.fetch(pr_identifier, options = {})
  # Parse identifier to get gh CLI format using ace-git
  parsed = Ace::Git::Atoms::PrIdentifierParser.parse(pr_identifier)
  gh_format = parsed.gh_format

  # Default timeout for PR operations
  timeout = options[:timeout] || 30

  # Fetch comments and reviews as JSON
  # Fields: comments (issue-level), reviews (code review objects)
  fields = "comments,reviews,number,title,author"

  result = Ace::Review::Atoms::RetryWithBackoff.execute(options) do
    Ace::Git::Molecules::GhCliExecutor.execute("pr", ["view", gh_format, "--json", fields], timeout: timeout)
  end

  if result[:success]
    data = JSON.parse(result[:stdout])

    # Extract and structure comments
    comments = extract_comments(data, options)
    reviews = extract_reviews(data, options)

    # Fetch review threads via GraphQL (inline code comments)
    # Convert parsed to hash for fetch_review_threads which expects hash access
    review_threads = fetch_review_threads(parsed.to_h, options)

    {
      success: true,
      comments: comments,
      reviews: reviews,
      review_threads: review_threads,
      pr_number: data["number"],
      pr_title: data["title"],
      pr_author: data.dig("author", "login"),
      identifier: gh_format,
      parsed: parsed.to_h,
      raw_data: data
    }
  else
    handle_fetch_error(result, pr_identifier)
  end
rescue JSON::ParserError => e
  {
    success: false,
    error: "Failed to parse PR comments: #{e.message}"
  }
rescue Ace::Review::Errors::GhCliNotInstalledError, Ace::Review::Errors::GhAuthenticationError,
  Ace::Git::GhNotInstalledError, Ace::Git::GhAuthenticationError
  raise
rescue => e
  {
    success: false,
    error: "Failed to fetch PR comments: #{e.message}"
  }
end

.has_comments?(result) ⇒ Boolean

Check if there are any meaningful comments

Parameters:

  • result (Hash)

    Result from fetch

Returns:

  • (Boolean)

    true if there are comments, reviews, or review threads worth reporting



133
134
135
136
137
138
139
# File 'lib/ace/review/molecules/gh_pr_comment_fetcher.rb', line 133

def self.has_comments?(result)
  return false unless result[:success]

  (result[:comments]&.any? || false) ||
    (result[:reviews]&.any? || false) ||
    (result[:review_threads]&.any? || false)
end