jira-ruby 2.2.0 → 3.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/CI.yml +28 -0
- data/.github/workflows/codeql.yml +100 -0
- data/.github/workflows/rubocop.yml +18 -0
- data/.rubocop.yml +188 -0
- data/Gemfile +11 -3
- data/Guardfile +2 -0
- data/README.md +121 -20
- data/Rakefile +4 -5
- data/jira-ruby.gemspec +11 -17
- data/lib/jira/base.rb +37 -28
- data/lib/jira/base_factory.rb +4 -1
- data/lib/jira/client.rb +65 -46
- data/lib/jira/has_many_proxy.rb +4 -2
- data/lib/jira/http_client.rb +18 -13
- data/lib/jira/http_error.rb +4 -0
- data/lib/jira/jwt_client.rb +18 -42
- data/lib/jira/oauth_client.rb +6 -3
- data/lib/jira/railtie.rb +2 -0
- data/lib/jira/request_client.rb +5 -1
- data/lib/jira/resource/agile.rb +7 -9
- data/lib/jira/resource/applinks.rb +5 -3
- data/lib/jira/resource/attachment.rb +43 -3
- data/lib/jira/resource/board.rb +5 -3
- data/lib/jira/resource/board_configuration.rb +2 -0
- data/lib/jira/resource/comment.rb +2 -0
- data/lib/jira/resource/component.rb +2 -0
- data/lib/jira/resource/createmeta.rb +3 -1
- data/lib/jira/resource/field.rb +9 -4
- data/lib/jira/resource/filter.rb +2 -0
- data/lib/jira/resource/issue.rb +35 -44
- data/lib/jira/resource/issue_picker_suggestions.rb +4 -1
- data/lib/jira/resource/issue_picker_suggestions_issue.rb +2 -0
- data/lib/jira/resource/issuelink.rb +2 -0
- data/lib/jira/resource/issuelinktype.rb +2 -0
- data/lib/jira/resource/issuetype.rb +2 -0
- data/lib/jira/resource/priority.rb +2 -0
- data/lib/jira/resource/project.rb +4 -2
- data/lib/jira/resource/rapidview.rb +5 -3
- data/lib/jira/resource/remotelink.rb +2 -0
- data/lib/jira/resource/resolution.rb +2 -0
- data/lib/jira/resource/serverinfo.rb +2 -0
- data/lib/jira/resource/sprint.rb +14 -23
- data/lib/jira/resource/status.rb +7 -1
- data/lib/jira/resource/status_category.rb +10 -0
- data/lib/jira/resource/suggested_issue.rb +2 -0
- data/lib/jira/resource/transition.rb +2 -0
- data/lib/jira/resource/user.rb +3 -1
- data/lib/jira/resource/version.rb +2 -0
- data/lib/jira/resource/watcher.rb +2 -1
- data/lib/jira/resource/webhook.rb +4 -2
- data/lib/jira/resource/worklog.rb +3 -2
- data/lib/jira/version.rb +3 -1
- data/lib/jira-ruby.rb +5 -3
- data/lib/tasks/generate.rake +4 -2
- data/spec/data/files/short.txt +1 -0
- data/spec/integration/attachment_spec.rb +3 -3
- data/spec/integration/comment_spec.rb +8 -8
- data/spec/integration/component_spec.rb +7 -7
- data/spec/integration/field_spec.rb +3 -3
- data/spec/integration/issue_spec.rb +20 -16
- data/spec/integration/issuelinktype_spec.rb +3 -3
- data/spec/integration/issuetype_spec.rb +3 -3
- data/spec/integration/priority_spec.rb +3 -3
- data/spec/integration/project_spec.rb +7 -7
- data/spec/integration/rapidview_spec.rb +9 -9
- data/spec/integration/resolution_spec.rb +3 -3
- data/spec/integration/status_category_spec.rb +20 -0
- data/spec/integration/status_spec.rb +4 -8
- data/spec/integration/transition_spec.rb +2 -2
- data/spec/integration/user_spec.rb +22 -8
- data/spec/integration/version_spec.rb +7 -7
- data/spec/integration/watcher_spec.rb +17 -18
- data/spec/integration/webhook.rb +5 -4
- data/spec/integration/worklog_spec.rb +8 -8
- data/spec/jira/base_factory_spec.rb +2 -1
- data/spec/jira/base_spec.rb +55 -41
- data/spec/jira/client_spec.rb +48 -34
- data/spec/jira/has_many_proxy_spec.rb +3 -3
- data/spec/jira/http_client_spec.rb +98 -26
- data/spec/jira/http_error_spec.rb +2 -2
- data/spec/jira/oauth_client_spec.rb +30 -8
- data/spec/jira/request_client_spec.rb +4 -4
- data/spec/jira/resource/agile_spec.rb +28 -28
- data/spec/jira/resource/attachment_spec.rb +142 -52
- data/spec/jira/resource/board_spec.rb +21 -20
- data/spec/jira/resource/createmeta_spec.rb +48 -48
- data/spec/jira/resource/field_spec.rb +30 -12
- data/spec/jira/resource/filter_spec.rb +4 -4
- data/spec/jira/resource/issue_picker_suggestions_spec.rb +18 -18
- data/spec/jira/resource/issue_spec.rb +44 -38
- data/spec/jira/resource/jira_picker_suggestions_issue_spec.rb +3 -3
- data/spec/jira/resource/project_factory_spec.rb +3 -2
- data/spec/jira/resource/project_spec.rb +16 -16
- data/spec/jira/resource/sprint_spec.rb +70 -3
- data/spec/jira/resource/status_spec.rb +21 -0
- data/spec/jira/resource/user_factory_spec.rb +4 -4
- data/spec/jira/resource/worklog_spec.rb +3 -3
- data/spec/mock_responses/sprint/1.json +13 -0
- data/spec/mock_responses/status/1.json +8 -1
- data/spec/mock_responses/status.json +40 -5
- data/spec/mock_responses/statuscategory/1.json +7 -0
- data/spec/mock_responses/statuscategory.json +30 -0
- data/spec/mock_responses/{user_username=admin.json → user_accountId=1234567890abcdef01234567.json} +2 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/support/clients_helper.rb +3 -5
- data/spec/support/shared_examples/integration.rb +25 -28
- metadata +25 -257
- data/.travis.yml +0 -9
- data/example.rb +0 -232
- data/http-basic-example.rb +0 -113
- data/lib/jira/resource/sprint_report.rb +0 -8
- data/lib/jira/tasks.rb +0 -0
- data/spec/jira/jwt_uri_builder_spec.rb +0 -59
data/lib/jira/resource/agile.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cgi'
|
2
4
|
|
3
5
|
module JIRA
|
@@ -25,7 +27,8 @@ module JIRA
|
|
25
27
|
response = client.get(path_base(client) + "/board/#{board_id}/issue?#{hash_to_query_string(options)}")
|
26
28
|
json = parse_json(response.body)
|
27
29
|
# To get Issue objects with the same structure as for Issue.all
|
28
|
-
return {} if json['issues'].
|
30
|
+
return {} if json['issues'].empty?
|
31
|
+
|
29
32
|
issue_ids = json['issues'].map do |issue|
|
30
33
|
issue['id']
|
31
34
|
end
|
@@ -58,22 +61,17 @@ module JIRA
|
|
58
61
|
parse_json(response.body)
|
59
62
|
end
|
60
63
|
|
61
|
-
# def self.find(client, key, options = {})
|
62
|
-
# options[:maxResults] ||= 100
|
63
|
-
# fields = options[:fields].join(',') unless options[:fields].nil?
|
64
|
-
# response = client.get("/rest/api/latest/search?jql=sprint=#{key}&fields=#{fields}&maxResults=#{options[:maxResults]}")
|
65
|
-
# parse_json(response.body)
|
66
|
-
# end
|
67
|
-
|
68
64
|
private
|
69
65
|
|
70
66
|
def self.path_base(client)
|
71
|
-
client.options[:context_path]
|
67
|
+
"#{client.options[:context_path]}/rest/agile/1.0"
|
72
68
|
end
|
73
69
|
|
74
70
|
def path_base(client)
|
75
71
|
self.class.path_base(client)
|
76
72
|
end
|
73
|
+
|
74
|
+
private_class_method :path_base
|
77
75
|
end
|
78
76
|
end
|
79
77
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JIRA
|
2
4
|
module Resource
|
3
5
|
class ApplicationLinkFactory < JIRA::BaseFactory # :nodoc:
|
@@ -5,7 +7,7 @@ module JIRA
|
|
5
7
|
end
|
6
8
|
|
7
9
|
class ApplicationLink < JIRA::Base
|
8
|
-
REST_BASE_PATH = '/rest/applinks/1.0'
|
10
|
+
REST_BASE_PATH = '/rest/applinks/1.0'
|
9
11
|
|
10
12
|
def self.endpoint_name
|
11
13
|
'listApplicationlinks'
|
@@ -24,12 +26,12 @@ module JIRA
|
|
24
26
|
json = parse_json(response.body)
|
25
27
|
json = json['list']
|
26
28
|
json.map do |attrs|
|
27
|
-
new(client, { attrs:
|
29
|
+
new(client, { attrs: }.merge(options))
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
31
33
|
def self.manifest(client)
|
32
|
-
url = full_url(client)
|
34
|
+
url = "#{full_url(client)}/manifest"
|
33
35
|
response = client.get(url)
|
34
36
|
json = parse_json(response.body)
|
35
37
|
JIRA::Base.new(client, attrs: json)
|
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'net/http/post/multipart'
|
4
|
+
require 'open-uri'
|
2
5
|
|
3
6
|
module JIRA
|
4
7
|
module Resource
|
@@ -15,18 +18,55 @@ module JIRA
|
|
15
18
|
end
|
16
19
|
|
17
20
|
def self.meta(client)
|
18
|
-
response = client.get(client.options[:rest_base_path]
|
21
|
+
response = client.get("#{client.options[:rest_base_path]}/attachment/meta")
|
19
22
|
parse_json(response.body)
|
20
23
|
end
|
21
24
|
|
25
|
+
# Opens a file streaming the download of the attachment.
|
26
|
+
# @example Write file contents to a file.
|
27
|
+
# File.open('some-filename', 'wb') do |output|
|
28
|
+
# download_file do |file|
|
29
|
+
# IO.copy_stream(file, output)
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
# @example Stream file contents for an HTTP response.
|
33
|
+
# response.headers[ "Content-Type" ] = "application/octet-stream"
|
34
|
+
# download_file do |file|
|
35
|
+
# chunk = file.read(8000)
|
36
|
+
# while chunk.present? do
|
37
|
+
# response.stream.write(chunk)
|
38
|
+
# chunk = file.read(8000)
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
# response.stream.close
|
42
|
+
# @param [Hash] headers Any additional headers to call Jira.
|
43
|
+
# @yield |file|
|
44
|
+
# @yieldparam [IO] file The IO object streaming the download.
|
45
|
+
def download_file(headers = {}, &block)
|
46
|
+
default_headers = client.options[:default_headers]
|
47
|
+
URI.parse(content).open(default_headers.merge(headers), &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Downloads the file contents as a string object.
|
51
|
+
#
|
52
|
+
# Note that this reads the contents into a ruby string in memory.
|
53
|
+
# A file might be very large so it is recommend to avoid this unless you are certain about doing so.
|
54
|
+
# Use the download_file method instead and avoid calling the read method without a limit.
|
55
|
+
#
|
56
|
+
# @param [Hash] headers Any additional headers to call Jira.
|
57
|
+
# @return [String,NilClass] The file contents.
|
58
|
+
def download_contents(headers = {})
|
59
|
+
download_file(headers, &:read)
|
60
|
+
end
|
61
|
+
|
22
62
|
def save!(attrs, path = url)
|
23
63
|
file = attrs['file'] || attrs[:file] # Keep supporting 'file' parameter as a string for backward compatibility
|
24
64
|
mime_type = attrs[:mimeType] || 'application/binary'
|
25
65
|
|
26
66
|
headers = { 'X-Atlassian-Token' => 'nocheck' }
|
27
|
-
data = { 'file' => UploadIO.new(file, mime_type, file) }
|
67
|
+
data = { 'file' => Multipart::Post::UploadIO.new(file, mime_type, file) }
|
28
68
|
|
29
|
-
response = client.post_multipart(path, data
|
69
|
+
response = client.post_multipart(path, data, headers)
|
30
70
|
|
31
71
|
set_attributes(attrs, response)
|
32
72
|
|
data/lib/jira/resource/board.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cgi'
|
2
4
|
|
3
5
|
module JIRA
|
@@ -7,7 +9,7 @@ module JIRA
|
|
7
9
|
|
8
10
|
class Board < JIRA::Base
|
9
11
|
def self.all(client)
|
10
|
-
path = path_base(client)
|
12
|
+
path = "#{path_base(client)}/board"
|
11
13
|
response = client.get(path)
|
12
14
|
json = parse_json(response.body)
|
13
15
|
results = json['values']
|
@@ -74,13 +76,13 @@ module JIRA
|
|
74
76
|
end
|
75
77
|
|
76
78
|
def add_issue_to_backlog(issue)
|
77
|
-
client.post(path_base(client)
|
79
|
+
client.post("#{path_base(client)}/backlog/issue", { issues: [issue.id] }.to_json)
|
78
80
|
end
|
79
81
|
|
80
82
|
private
|
81
83
|
|
82
84
|
def self.path_base(client)
|
83
|
-
client.options[:context_path]
|
85
|
+
"#{client.options[:context_path]}/rest/agile/1.0"
|
84
86
|
end
|
85
87
|
|
86
88
|
def path_base(client)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JIRA
|
2
4
|
module Resource
|
3
5
|
class CreatemetaFactory < JIRA::BaseFactory # :nodoc:
|
@@ -36,7 +38,7 @@ module JIRA
|
|
36
38
|
|
37
39
|
json = parse_json(response.body)
|
38
40
|
json['projects'].map do |attrs|
|
39
|
-
new(client, attrs:
|
41
|
+
new(client, attrs:)
|
40
42
|
end
|
41
43
|
end
|
42
44
|
end
|
data/lib/jira/resource/field.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JIRA
|
2
4
|
module Resource
|
3
5
|
class FieldFactory < JIRA::BaseFactory # :nodoc:
|
@@ -26,20 +28,22 @@ module JIRA
|
|
26
28
|
# as a system field can't take precedence
|
27
29
|
fields.each do |f|
|
28
30
|
next if f.custom
|
31
|
+
|
29
32
|
name = safe_name(f.name)
|
30
33
|
field_map_reverse[f.id] = [f.name, name] # capture both the official name, and the mapped name
|
31
34
|
field_map[name] = f.id
|
32
35
|
end
|
33
36
|
|
34
|
-
fields.each do |f|
|
37
|
+
fields.each do |f| # rubocop:disable Style/CombinableLoops
|
35
38
|
next unless f.custom
|
39
|
+
|
36
40
|
name = if field_map.key? f.name
|
37
41
|
renamed = safer_name(f.name, f.id)
|
38
42
|
warn "Duplicate Field name #{f.name} #{f.id} - renaming as #{renamed}"
|
39
43
|
renamed
|
40
44
|
else
|
41
45
|
safe_name(f.name)
|
42
|
-
|
46
|
+
end
|
43
47
|
field_map_reverse[f.id] = [f.name, name] # capture both the official name, and the mapped name
|
44
48
|
field_map[name] = f.id
|
45
49
|
end
|
@@ -55,6 +59,7 @@ module JIRA
|
|
55
59
|
def self.name_to_id(client, field_name)
|
56
60
|
field_name = field_name.to_s
|
57
61
|
return field_name unless client.cache.field_map && client.cache.field_map[field_name]
|
62
|
+
|
58
63
|
client.cache.field_map[field_name]
|
59
64
|
end
|
60
65
|
|
@@ -66,7 +71,7 @@ module JIRA
|
|
66
71
|
end
|
67
72
|
end
|
68
73
|
|
69
|
-
def method_missing(method_name, *args, &
|
74
|
+
def method_missing(method_name, *args, &)
|
70
75
|
if attrs.key?(method_name.to_s)
|
71
76
|
attrs[method_name.to_s]
|
72
77
|
else
|
@@ -74,7 +79,7 @@ module JIRA
|
|
74
79
|
if attrs.key?(official_name)
|
75
80
|
attrs[official_name]
|
76
81
|
else
|
77
|
-
super
|
82
|
+
super
|
78
83
|
end
|
79
84
|
end
|
80
85
|
end
|
data/lib/jira/resource/filter.rb
CHANGED
data/lib/jira/resource/issue.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cgi'
|
2
4
|
require 'json'
|
3
5
|
|
@@ -7,44 +9,25 @@ module JIRA
|
|
7
9
|
end
|
8
10
|
|
9
11
|
class Issue < JIRA::Base
|
10
|
-
has_one :reporter,
|
11
|
-
|
12
|
-
has_one :
|
13
|
-
nested_under: 'fields'
|
14
|
-
has_one :project, nested_under: 'fields'
|
15
|
-
|
12
|
+
has_one :reporter, class: JIRA::Resource::User, nested_under: 'fields'
|
13
|
+
has_one :assignee, class: JIRA::Resource::User, nested_under: 'fields'
|
14
|
+
has_one :project, nested_under: 'fields'
|
16
15
|
has_one :issuetype, nested_under: 'fields'
|
17
|
-
|
18
|
-
has_one :
|
19
|
-
|
20
|
-
has_one :status, nested_under: 'fields'
|
21
|
-
|
16
|
+
has_one :priority, nested_under: 'fields'
|
17
|
+
has_one :status, nested_under: 'fields'
|
18
|
+
has_one :resolution, nested_under: 'fields'
|
22
19
|
has_many :transitions
|
23
|
-
|
24
20
|
has_many :components, nested_under: 'fields'
|
25
|
-
|
26
21
|
has_many :comments, nested_under: %w[fields comment]
|
27
|
-
|
28
|
-
has_many :
|
29
|
-
|
30
|
-
|
31
|
-
has_many :versions, nested_under: 'fields'
|
32
|
-
has_many :fixVersions, class: JIRA::Resource::Version,
|
33
|
-
nested_under: 'fields'
|
34
|
-
|
22
|
+
has_many :attachments, nested_under: 'fields', attribute_key: 'attachment'
|
23
|
+
has_many :versions, nested_under: 'fields'
|
24
|
+
has_many :fixVersions, class: JIRA::Resource::Version, nested_under: 'fields'
|
35
25
|
has_many :worklogs, nested_under: %w[fields worklog]
|
36
|
-
has_one :sprint, class: JIRA::Resource::Sprint,
|
37
|
-
|
38
|
-
|
39
|
-
has_many :closed_sprints, class: JIRA::Resource::Sprint,
|
40
|
-
nested_under: 'fields', attribute_key: 'closedSprints'
|
41
|
-
|
26
|
+
has_one :sprint, class: JIRA::Resource::Sprint, nested_under: 'fields'
|
27
|
+
has_many :closed_sprints, class: JIRA::Resource::Sprint, nested_under: 'fields', attribute_key: 'closedSprints'
|
42
28
|
has_many :issuelinks, nested_under: 'fields'
|
43
|
-
|
44
29
|
has_many :remotelink, class: JIRA::Resource::Remotelink
|
45
|
-
|
46
|
-
has_many :watchers, attribute_key: 'watches',
|
47
|
-
nested_under: %w[fields watches]
|
30
|
+
has_many :watchers, attribute_key: 'watches', nested_under: %w[fields watches]
|
48
31
|
|
49
32
|
def self.all(client)
|
50
33
|
start_at = 0
|
@@ -59,15 +42,21 @@ module JIRA
|
|
59
42
|
result.push(client.Issue.build(issue))
|
60
43
|
end
|
61
44
|
break if json['issues'].empty?
|
45
|
+
|
62
46
|
start_at += json['issues'].size
|
63
47
|
end
|
64
48
|
result
|
65
49
|
end
|
66
50
|
|
67
|
-
def self.jql(client, jql, options = { fields: nil, start_at: nil, max_results: nil, expand: nil,
|
51
|
+
def self.jql(client, jql, options = { fields: nil, start_at: nil, max_results: nil, expand: nil,
|
52
|
+
validate_query: true })
|
68
53
|
url = client.options[:rest_base_path] + "/search?jql=#{CGI.escape(jql)}"
|
69
54
|
|
70
|
-
|
55
|
+
if options[:fields]
|
56
|
+
url << "&fields=#{options[:fields].map do |value|
|
57
|
+
CGI.escape(client.Field.name_to_id(value))
|
58
|
+
end.join(',')}"
|
59
|
+
end
|
71
60
|
url << "&startAt=#{CGI.escape(options[:start_at].to_s)}" if options[:start_at]
|
72
61
|
url << "&maxResults=#{CGI.escape(options[:max_results].to_s)}" if options[:max_results]
|
73
62
|
url << '&validateQuery=false' if options[:validate_query] === false
|
@@ -79,9 +68,8 @@ module JIRA
|
|
79
68
|
|
80
69
|
response = client.get(url)
|
81
70
|
json = parse_json(response.body)
|
82
|
-
if options[:max_results] && (options[:max_results]
|
83
|
-
|
84
|
-
end
|
71
|
+
return json['total'] if options[:max_results] && (options[:max_results]).zero?
|
72
|
+
|
85
73
|
json['issues'].map do |issue|
|
86
74
|
client.Issue.build(issue)
|
87
75
|
end
|
@@ -92,14 +80,15 @@ module JIRA
|
|
92
80
|
# is not set
|
93
81
|
def fetch(reload = false, query_params = {})
|
94
82
|
return if expanded? && !reload
|
83
|
+
|
95
84
|
response = client.get(url_with_query_params(url, query_params))
|
96
85
|
set_attrs_from_response(response)
|
97
|
-
if @attrs && @attrs['fields'] &&
|
86
|
+
if @attrs && @attrs['fields'] &&
|
87
|
+
@attrs['fields']['worklog'] &&
|
88
|
+
(@attrs['fields']['worklog']['total'] > @attrs['fields']['worklog']['maxResults'])
|
98
89
|
worklog_url = client.options[:rest_base_path] + "/#{self.class.endpoint_name}/#{id}/worklog"
|
99
90
|
response = client.get(worklog_url)
|
100
|
-
unless response.body.nil? || (response.body.length < 2)
|
101
|
-
set_attrs({ 'fields' => { 'worklog' => self.class.parse_json(response.body) } }, false)
|
102
|
-
end
|
91
|
+
set_attrs({ 'fields' => { 'worklog' => self.class.parse_json(response.body) } }, false) unless response.body.nil? || (response.body.length < 2)
|
103
92
|
end
|
104
93
|
@expanded = true
|
105
94
|
end
|
@@ -113,14 +102,16 @@ module JIRA
|
|
113
102
|
end
|
114
103
|
|
115
104
|
def respond_to?(method_name, _include_all = false)
|
116
|
-
if attrs.key?('fields') && [method_name.to_s, client.Field.name_to_id(method_name)].any?
|
105
|
+
if attrs.key?('fields') && [method_name.to_s, client.Field.name_to_id(method_name)].any? do |k|
|
106
|
+
attrs['fields'].key?(k)
|
107
|
+
end
|
117
108
|
true
|
118
109
|
else
|
119
110
|
super(method_name)
|
120
111
|
end
|
121
112
|
end
|
122
113
|
|
123
|
-
def method_missing(method_name, *args, &
|
114
|
+
def method_missing(method_name, *args, &)
|
124
115
|
if attrs.key?('fields')
|
125
116
|
if attrs['fields'].key?(method_name.to_s)
|
126
117
|
attrs['fields'][method_name.to_s]
|
@@ -129,11 +120,11 @@ module JIRA
|
|
129
120
|
if attrs['fields'].key?(official_name)
|
130
121
|
attrs['fields'][official_name]
|
131
122
|
else
|
132
|
-
super
|
123
|
+
super
|
133
124
|
end
|
134
125
|
end
|
135
126
|
else
|
136
|
-
super
|
127
|
+
super
|
137
128
|
end
|
138
129
|
end
|
139
130
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JIRA
|
2
4
|
module Resource
|
3
5
|
class IssuePickerSuggestionsFactory < JIRA::BaseFactory # :nodoc:
|
@@ -6,7 +8,8 @@ module JIRA
|
|
6
8
|
class IssuePickerSuggestions < JIRA::Base
|
7
9
|
has_many :sections, class: JIRA::Resource::IssuePickerSuggestionsIssue
|
8
10
|
|
9
|
-
def self.all(client, query = '', options = { current_jql: nil, current_issue_key: nil, current_project_id: nil,
|
11
|
+
def self.all(client, query = '', options = { current_jql: nil, current_issue_key: nil, current_project_id: nil,
|
12
|
+
show_sub_tasks: nil, show_sub_tasks_parent: nil })
|
10
13
|
url = client.options[:rest_base_path] + "/issue/picker?query=#{CGI.escape(query)}"
|
11
14
|
|
12
15
|
url << "¤tJQL=#{CGI.escape(options[:current_jql])}" if options[:current_jql]
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JIRA
|
2
4
|
module Resource
|
3
5
|
class ProjectFactory < JIRA::BaseFactory # :nodoc:
|
@@ -15,7 +17,7 @@ module JIRA
|
|
15
17
|
|
16
18
|
# Returns all the issues for this project
|
17
19
|
def issues(options = {})
|
18
|
-
search_url = client.options[:rest_base_path]
|
20
|
+
search_url = "#{client.options[:rest_base_path]}/search"
|
19
21
|
query_params = { jql: "project=\"#{key}\"" }
|
20
22
|
query_params.update Base.query_params_for_search(options)
|
21
23
|
response = client.get(url_with_query_params(search_url, query_params))
|
@@ -26,7 +28,7 @@ module JIRA
|
|
26
28
|
end
|
27
29
|
|
28
30
|
def users(start_at: nil, max_results: nil)
|
29
|
-
users_url = client.options[:rest_base_path]
|
31
|
+
users_url = "#{client.options[:rest_base_path]}/user/assignable/search"
|
30
32
|
query_params = { project: key_value }
|
31
33
|
query_params['startAt'] = start_at if start_at
|
32
34
|
query_params['maxResults'] = max_results if max_results
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cgi'
|
2
4
|
|
3
5
|
module JIRA
|
@@ -7,7 +9,7 @@ module JIRA
|
|
7
9
|
|
8
10
|
class RapidView < JIRA::Base
|
9
11
|
def self.all(client)
|
10
|
-
response = client.get(path_base(client)
|
12
|
+
response = client.get("#{path_base(client)}/rapidview")
|
11
13
|
json = parse_json(response.body)
|
12
14
|
json['views'].map do |view|
|
13
15
|
client.RapidView.build(view)
|
@@ -44,7 +46,7 @@ module JIRA
|
|
44
46
|
|
45
47
|
def sprints(options = {})
|
46
48
|
params = { includeHistoricSprints: options.fetch(:include_historic, false),
|
47
|
-
includeFutureSprints:
|
49
|
+
includeFutureSprints: options.fetch(:include_future, false) }
|
48
50
|
response = client.get(path_base(client) + "/sprintquery/#{id}?#{params.to_query}")
|
49
51
|
json = self.class.parse_json(response.body)
|
50
52
|
json['sprints'].map do |sprint|
|
@@ -56,7 +58,7 @@ module JIRA
|
|
56
58
|
private
|
57
59
|
|
58
60
|
def self.path_base(client)
|
59
|
-
client.options[:context_path]
|
61
|
+
"#{client.options[:context_path]}/rest/greenhopper/1.0"
|
60
62
|
end
|
61
63
|
|
62
64
|
def path_base(client)
|
data/lib/jira/resource/sprint.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JIRA
|
2
4
|
module Resource
|
3
5
|
class SprintFactory < JIRA::BaseFactory # :nodoc:
|
@@ -12,19 +14,20 @@ module JIRA
|
|
12
14
|
|
13
15
|
# get all issues of sprint
|
14
16
|
def issues(options = {})
|
15
|
-
jql =
|
17
|
+
jql = "sprint = #{id}"
|
16
18
|
jql += " and updated >= '#{options[:updated]}'" if options[:updated]
|
17
19
|
Issue.jql(client, jql)
|
18
20
|
end
|
19
21
|
|
20
22
|
def add_issue(issue)
|
21
|
-
|
22
|
-
response = client.post("#{agile_path}/issue", request_body)
|
23
|
-
true
|
23
|
+
add_issues([issue])
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
|
26
|
+
def add_issues(issues)
|
27
|
+
issue_ids = issues.map(&:id)
|
28
|
+
request_body = { issues: issue_ids }.to_json
|
29
|
+
client.post("#{agile_path}/issue", request_body)
|
30
|
+
true
|
28
31
|
end
|
29
32
|
|
30
33
|
def start_date
|
@@ -42,13 +45,14 @@ module JIRA
|
|
42
45
|
def get_sprint_details_attribute(attribute_name)
|
43
46
|
attribute = instance_variable_get("@#{attribute_name}")
|
44
47
|
return attribute if attribute
|
48
|
+
|
45
49
|
get_sprint_details
|
46
50
|
instance_variable_get("@#{attribute_name}")
|
47
51
|
end
|
48
52
|
|
49
53
|
def get_sprint_details
|
50
54
|
search_url =
|
51
|
-
"#{client.options[:site]}#{client.options[:client_path]}/rest/
|
55
|
+
"#{client.options[:site]}#{client.options[:client_path]}/rest/agile/1.0/sprint/#{id}"
|
52
56
|
begin
|
53
57
|
response = client.get(search_url)
|
54
58
|
rescue StandardError
|
@@ -56,22 +60,9 @@ module JIRA
|
|
56
60
|
end
|
57
61
|
json = self.class.parse_json(response.body)
|
58
62
|
|
59
|
-
@start_date =
|
60
|
-
@end_date =
|
61
|
-
@
|
62
|
-
@sprint_report = client.SprintReport.build(json['contents'])
|
63
|
-
end
|
64
|
-
|
65
|
-
def rapidview_id
|
66
|
-
return @attrs['rapidview_id'] if @attrs['rapidview_id']
|
67
|
-
search_url = client.options[:site] + '/secure/GHGoToBoard.jspa?sprintId=' + id.to_s
|
68
|
-
begin
|
69
|
-
response = client.get(search_url)
|
70
|
-
rescue JIRA::HTTPError => error
|
71
|
-
return unless error.response.instance_of? Net::HTTPFound
|
72
|
-
rapid_view_match = /rapidView=(\d+)&/.match(error.response['location'])
|
73
|
-
@attrs['rapidview_id'] = rapid_view_match[1] unless rapid_view_match.nil?
|
74
|
-
end
|
63
|
+
@start_date = json['startDate'] && Date.parse(json['startDate'])
|
64
|
+
@end_date = json['endDate'] && Date.parse(json['endDate'])
|
65
|
+
@complete_date = json['completeDate'] && Date.parse(json['completeDate'])
|
75
66
|
end
|
76
67
|
|
77
68
|
def save(attrs = {}, _path = nil)
|
data/lib/jira/resource/status.rb
CHANGED
@@ -1,8 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'status_category'
|
4
|
+
|
1
5
|
module JIRA
|
2
6
|
module Resource
|
3
7
|
class StatusFactory < JIRA::BaseFactory # :nodoc:
|
4
8
|
end
|
5
9
|
|
6
|
-
class Status < JIRA::Base
|
10
|
+
class Status < JIRA::Base
|
11
|
+
has_one :status_category, class: JIRA::Resource::StatusCategory, attribute_key: 'statusCategory'
|
12
|
+
end
|
7
13
|
end
|
8
14
|
end
|