Search code examples
rubygithub-apioctokit

How to get a selected list of GitHub issues in octocat with Ruby?


Basically I am using octokit trying to add a particular set of GitHub issues, based on their issue number, to an issue list.

The summary of the code is similar to this:

require 'octokit'

client = Octokit::Client.new(access_token: ENV['GITHUB_OAUTH_TOKEN'], accept: 'application/vnd.github.v3+json')

REPO = 'USERNAME/SOME-GH-REPO'.freeze

#client.issue(REPO, 1)                     # Returns {}
#client.issues(REPO, :state => 'all')      # Returns [{}]

def pull_source_issues
    @client.auto_paginate = true

    ilist =[1,2,3]
    my_array = []

    ilist.each do |i|
        puts "Adding issue [#]: #{i} \t from: #{REPO}\n"
        my_array.push(@client.issue(REPO , "#{i}", :state => 'all'))   # works
        #@issues.push(@client.issue(REPO , "#{i}", :state => 'all'))   # fails!
    end
    @issues = my_array

    puts "Found #{issues.size} issues."
end

But it seem that I have to use the intermediate my_array, as pushing into @issues array immediately, fails.

Drawback

This way also seem very inefficient as I seem to make a request for each item, instead of fetching them all at the same time and then select the ones needed. In addition it also selects for pull requests, which is not wanted. (*Because PR's are also issues in GH.)

I often see the iterator looking like this:

@issues = @client.issues(@source_repo, :state => 'all')

@issues.each do |source_issue|
    print "Processing issue: #{source_issue.number}  (#{n}/#{issues.size})\r"
    if !source_issue.key?(:pull_request) || source_issue.pull_request.empty?
        # Add each issue to (new?) @issues here
    end
end

But I can't get that to work either.


How can I push() each issue into the @issues array immediately?
(And how can I do it more efficiently?)


Solution

  • Pushing elements in the @issues array will fail because it´s not initialized (@issues = []).

    After taking a look at the octokit documentation you have 2 possibilities. Unfortunately you can´t query multiple issues by their numbers with one request.

    You can either do:

    @issues = [1,2,3].map{ |issue_number| client.issue(REPO, issue_number, state: 'all') }
    .reject(&:pull_request)
    

    or:

    @issues = client.issues(REPO).select{ |issue| [1,2,3].include?(issue.number) }
    .reject(&:pull_request)
    

    It really depends on the number of issues in the repo and the number of issue numbers that you want to query. If you´re really just querying 3 issue numbers, i´d go with the first approach. Otherwise i´d stick to the latter.

    When working with expensive operations (such as making calls to an API) it´s also useful to create a lazy enumerator:

    [1,2,3].lazy.map{ |issue_number| client.issue(REPO, issue_number, state: 'all') }
    

    This will prevent the array from being built immediately and if you´d only want the first n elements, the remaining issues won´t get pulled.

    Also mind that when using the latter approach you´d need to go through the different pages or disable pagination.