class Fbe::Graph

License
MIT
Copyright
Copyright © 2024-2025 Zerocracy
Author

Yegor Bugayenko (yegor256@gmail.com)
A client to GitHub GraphQL.

def client

Returns:
  • (GraphQL::Client) - A configured GraphQL client for GitHub
def client
  @client ||=
    begin
      http = HTTP.new(@token, @host)
      schema = GraphQL::Client.load_schema(http)
      c = GraphQL::Client.new(schema:, execute: http)
      c.allow_dynamic_queries = true
      c
    end
end

def initialize(token:, host: 'api.github.com')

def initialize(token:, host: 'api.github.com')
  @token = token
  @host = host
end

def issue_type_event(node_id)

Returns:
  • (Hash) - A hash with issue type event

Parameters:
  • node_id (String) -- ID of the event object
def issue_type_event(node_id)
  result = query(
    <<~GRAPHQL
      {
        node(id: "#{node_id}") {
          __typename
          ... on IssueTypeAddedEvent {
            id
            createdAt
            issueType { ...IssueTypeFragment }
            actor { ...ActorFragment }
          }
          ... on IssueTypeChangedEvent {
            id
            createdAt
            issueType { ...IssueTypeFragment }
            prevIssueType { ...IssueTypeFragment }
            actor { ...ActorFragment }
          }
          ... on IssueTypeRemovedEvent {
            id
            createdAt
            issueType { ...IssueTypeFragment }
            actor { ...ActorFragment }
          }
        }
      }
      fragment ActorFragment on Actor {
        __typename
        login
        ... on User { databaseId name email }
        ... on Bot { databaseId }
        ... on EnterpriseUserAccount { user { databaseId name email } }
        ... on Mannequin { claimant { databaseId name email } }
      }
      fragment IssueTypeFragment on IssueType {
        id
        name
        description
      }
    GRAPHQL
  ).to_h
  return unless result['node']
  type = result.dig('node', '__typename')
  prev_issue_type =
    if type == 'IssueTypeChangedEvent'
      {
        'id' => result.dig('node', 'prevIssueType', 'id'),
        'name' => result.dig('node', 'prevIssueType', 'name'),
        'description' => result.dig('node', 'prevIssueType', 'description')
      }
    end
  {
    'type' => type,
    'created_at' => Time.parse(result.dig('node', 'createdAt')),
    'issue_type' => {
      'id' => result.dig('node', 'issueType', 'id'),
      'name' => result.dig('node', 'issueType', 'name'),
      'description' => result.dig('node', 'issueType', 'description')
    },
    'prev_issue_type' => prev_issue_type,
    'actor' => {
      'login' => result.dig('node', 'actor', 'login'),
      'type' => result.dig('node', 'actor', '__typename'),
      'id' => result.dig('node', 'actor', 'databaseId') ||
        result.dig('node', 'actor', 'user', 'databaseId') ||
        result.dig('node', 'actor', 'claimant', 'databaseId'),
      'name' => result.dig('node', 'actor', 'name') ||
        result.dig('node', 'actor', 'user', 'name') ||
        result.dig('node', 'actor', 'claimant', 'name'),
      'email' => result.dig('node', 'actor', 'email') ||
        result.dig('node', 'actor', 'user', 'email') ||
        result.dig('node', 'actor', 'claimant', 'email')
    }
  }
end

def query(qry)

Returns:
  • (GraphQL::Client::Response) - The query result data

Parameters:
  • qry (String) -- The GraphQL query to execute
def query(qry)
  result = client.query(client.parse(qry))
  result.data
end

def resolved_conversations(owner, name, number)

Returns:
  • (Array) - An array of resolved conversation threads with their comments

Parameters:
  • number (Integer) -- The pull request number
  • name (String) -- The repository name
  • owner (String) -- The repository owner (username or organization)
def resolved_conversations(owner, name, number)
  result = query(
    <<~GRAPHQL
      {
        repository(owner: "#{owner}", name: "#{name}") {
          pullRequest(number: #{number}) {
            reviewThreads(first: 100) {
              nodes {
                id
                isResolved
                comments(first: 100) {
                  nodes {
                    id
                    body
                    author {
                      login
                    }
                    createdAt
                  }
                }
              }
            }
          }
        }
      }
    GRAPHQL
  )
  result&.to_h&.dig('repository', 'pullRequest', 'reviewThreads', 'nodes')&.select do |thread|
    thread['isResolved']
  end || []
end

def total_commits(owner, name, branch)

Returns:
  • (Integer) - The total number of commits in the branch

Parameters:
  • branch (String) -- The branch name (e.g., "master" or "main")
  • name (String) -- The repository name
  • owner (String) -- The repository owner (username or organization)
def total_commits(owner, name, branch)
  result = query(
    <<~GRAPHQL
      {
        repository(owner: "#{owner}", name: "#{name}") {
          ref(qualifiedName: "#{branch}") {
            target {
              ... on Commit {
                history {
                  totalCount
                }
              }
            }
          }
        }
      }
    GRAPHQL
  )
  result.repository.ref.target.history.total_count
end

def total_issues_and_pulls(owner, name)

Returns:
  • (Hash) - A hash with 'issues' and 'pulls' counts

Parameters:
  • name (String) -- The repository name
  • owner (String) -- The repository owner (username or organization)
def total_issues_and_pulls(owner, name)
  result = query(
    <<~GRAPHQL
      {
        repository(owner: "#{owner}", name: "#{name}") {
          issues {
            totalCount
          }
          pullRequests {
            totalCount
          }
        }
      }
    GRAPHQL
  ).to_h
  {
    'issues' => result.dig('repository', 'issues', 'totalCount') || 0,
    'pulls' => result.dig('repository', 'pullRequests', 'totalCount') || 0
  }
end