Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/jira/base_factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def self.delegate_to_target_class(*method_names)
# The principle purpose of this class is to delegate methods to the corresponding
# non-factory class and automatically prepend the client argument to the argument
# list.
delegate_to_target_class :all, :find, :collection_path, :singular_path, :jql, :get_backlog_issues,
delegate_to_target_class :all, :find, :collection_path, :singular_path, :jql, :jql_paged, :get_backlog_issues,
:get_board_issues, :get_sprints, :get_sprint_issues, :get_projects, :get_projects_full

# This method needs special handling as it has a default argument value
Expand Down
69 changes: 51 additions & 18 deletions lib/jira/resource/issue.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,57 @@ def self.all(client)
result
end

# Get issues using JQL query.
# @param client [JIRA::Client]
# @param jql [String] the JQL query string to search with
# @param options [Hash] Jira API options for the search
# @return [Array<JIRA::Resource::Issue>] or [Integer] total count if max_results is 0
def self.jql(client, jql, options = { fields: nil, max_results: nil, expand: nil, reconcile_issues: nil })
issues = []
total = nil
next_page_token = nil
is_last = false

until is_last
result = jql_paged(client, jql, options.merge(next_page_token:))

issues.concat(result[:issues])
total = result[:total]
next_page_token = result[:next_page_token]
is_last = next_page_token.nil?
end
options[:max_results]&.zero? ? total : issues
end

# Get paged issues using JQL query.
# @param jql [String] the JQL query string to search with
# @param options [Hash] Jira API options for the search, including next_page_token
# @return [Hash] with format { issues: [JIRA::Resource::Issue], next_page_token: [String], total: [Integer] }
def self.jql_paged(client, jql, options = { fields: nil, max_results: nil, expand: nil, reconcile_issues: nil, next_page_token: nil })
url = jql_url(client, jql, options)
next_page_token = options[:next_page_token]
max_results = options[:max_results]

issues = []

page_url = url.dup
page_url << "&nextPageToken=#{next_page_token}" if next_page_token

response = client.get(page_url)
json = parse_json(response.body)
total = json['total']

unless max_results&.zero?
next_page_token = json['nextPageToken']
json['issues'].map do |issue|
issues << client.Issue.build(issue)
end
end

{ issues:, next_page_token:, total: }
end

def self.jql_url(client, jql, options)
url = client.options[:rest_base_path] + "/search/jql?jql=#{CGI.escape(jql)}"

if options[:fields]
Expand All @@ -95,24 +145,7 @@ def self.jql(client, jql, options = { fields: nil, max_results: nil, expand: nil
options[:expand] = [options[:expand]] if options[:expand].is_a?(String)
url << "&expand=#{options[:expand].to_a.map { |value| CGI.escape(value.to_s) }.join(',')}"
end

issues = []
next_page_token = nil
json = {}
while json['isLast'] != true
page_url = url.dup
page_url << "&nextPageToken=#{next_page_token}" if next_page_token

response = client.get(page_url)
json = parse_json(response.body)
return json['total'] if options[:max_results]&.zero?

next_page_token = json['nextPageToken']
json['issues'].map do |issue|
issues << client.Issue.build(issue)
end
end
issues
url
end

# Fetches the attributes for the specified resource from JIRA unless
Expand Down
34 changes: 34 additions & 0 deletions spec/jira/resource/issue_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,40 @@ class JIRAResourceDelegation < SimpleDelegator # :nodoc:
end
end

describe '.jql_paged' do
let(:issue) { double }
let(:response) { double }

before do
allow(response).to receive(:body).and_return(response_string)
allow(client).to receive(:Issue).and_return(issue)
allow(issue).to receive(:build).with({ 'key' => 'foo' }).and_return('1')
allow(issue).to receive(:build).with({ 'key' => 'bar' }).and_return('2')
allow(issue).to receive(:build).with({ 'key' => 'baz' }).and_return('3')
end

context 'without next_page_token (first page)' do
subject { described_class.jql_paged(client, 'foo bar', page_size: 2) }

before { expect(client).to receive(:get).with('/jira/rest/api/2/search/jql?jql=foo+bar').and_return(response) }

let(:response) { double }
let(:response_string) { '{"issues": [{"key":"foo"},{"key":"bar"}], "isLast": false, "nextPageToken": "abc"}' }

it { is_expected.to eq(issues: %w[1 2], next_page_token: 'abc', total: nil) }
end

context 'with next_page_token' do
subject { described_class.jql_paged(client, 'foo bar', page_size: 2, next_page_token: 'abc') }

let(:response_string) { '{"issues": [{"key":"baz"}], "isLast": true}' }

before { expect(client).to receive(:get).with('/jira/rest/api/2/search/jql?jql=foo+bar&nextPageToken=abc').and_return(double(body: response_string)) }

it { is_expected.to eq(issues: %w[3], next_page_token: nil, total: nil) }
end
end

it 'returns meta data available for editing an issue' do
subject = described_class.new(client, attrs: { 'fields' => { 'key' => 'TST=123' } })
response = double
Expand Down