jira-ruby 2.2.0 → 3.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  4. data/.github/dependabot.yml +6 -0
  5. data/.github/workflows/CI.yml +28 -0
  6. data/.github/workflows/codeql.yml +100 -0
  7. data/.github/workflows/rubocop.yml +18 -0
  8. data/.rubocop.yml +188 -0
  9. data/Gemfile +11 -3
  10. data/Guardfile +2 -0
  11. data/README.md +121 -20
  12. data/Rakefile +4 -5
  13. data/jira-ruby.gemspec +11 -17
  14. data/lib/jira/base.rb +37 -28
  15. data/lib/jira/base_factory.rb +4 -1
  16. data/lib/jira/client.rb +65 -46
  17. data/lib/jira/has_many_proxy.rb +4 -2
  18. data/lib/jira/http_client.rb +18 -13
  19. data/lib/jira/http_error.rb +4 -0
  20. data/lib/jira/jwt_client.rb +18 -42
  21. data/lib/jira/oauth_client.rb +6 -3
  22. data/lib/jira/railtie.rb +2 -0
  23. data/lib/jira/request_client.rb +5 -1
  24. data/lib/jira/resource/agile.rb +7 -9
  25. data/lib/jira/resource/applinks.rb +5 -3
  26. data/lib/jira/resource/attachment.rb +43 -3
  27. data/lib/jira/resource/board.rb +5 -3
  28. data/lib/jira/resource/board_configuration.rb +2 -0
  29. data/lib/jira/resource/comment.rb +2 -0
  30. data/lib/jira/resource/component.rb +2 -0
  31. data/lib/jira/resource/createmeta.rb +3 -1
  32. data/lib/jira/resource/field.rb +9 -4
  33. data/lib/jira/resource/filter.rb +2 -0
  34. data/lib/jira/resource/issue.rb +35 -44
  35. data/lib/jira/resource/issue_picker_suggestions.rb +4 -1
  36. data/lib/jira/resource/issue_picker_suggestions_issue.rb +2 -0
  37. data/lib/jira/resource/issuelink.rb +2 -0
  38. data/lib/jira/resource/issuelinktype.rb +2 -0
  39. data/lib/jira/resource/issuetype.rb +2 -0
  40. data/lib/jira/resource/priority.rb +2 -0
  41. data/lib/jira/resource/project.rb +4 -2
  42. data/lib/jira/resource/rapidview.rb +5 -3
  43. data/lib/jira/resource/remotelink.rb +2 -0
  44. data/lib/jira/resource/resolution.rb +2 -0
  45. data/lib/jira/resource/serverinfo.rb +2 -0
  46. data/lib/jira/resource/sprint.rb +14 -23
  47. data/lib/jira/resource/status.rb +7 -1
  48. data/lib/jira/resource/status_category.rb +10 -0
  49. data/lib/jira/resource/suggested_issue.rb +2 -0
  50. data/lib/jira/resource/transition.rb +2 -0
  51. data/lib/jira/resource/user.rb +3 -1
  52. data/lib/jira/resource/version.rb +2 -0
  53. data/lib/jira/resource/watcher.rb +2 -1
  54. data/lib/jira/resource/webhook.rb +4 -2
  55. data/lib/jira/resource/worklog.rb +3 -2
  56. data/lib/jira/version.rb +3 -1
  57. data/lib/jira-ruby.rb +5 -3
  58. data/lib/tasks/generate.rake +4 -2
  59. data/spec/data/files/short.txt +1 -0
  60. data/spec/integration/attachment_spec.rb +3 -3
  61. data/spec/integration/comment_spec.rb +8 -8
  62. data/spec/integration/component_spec.rb +7 -7
  63. data/spec/integration/field_spec.rb +3 -3
  64. data/spec/integration/issue_spec.rb +20 -16
  65. data/spec/integration/issuelinktype_spec.rb +3 -3
  66. data/spec/integration/issuetype_spec.rb +3 -3
  67. data/spec/integration/priority_spec.rb +3 -3
  68. data/spec/integration/project_spec.rb +7 -7
  69. data/spec/integration/rapidview_spec.rb +9 -9
  70. data/spec/integration/resolution_spec.rb +3 -3
  71. data/spec/integration/status_category_spec.rb +20 -0
  72. data/spec/integration/status_spec.rb +4 -8
  73. data/spec/integration/transition_spec.rb +2 -2
  74. data/spec/integration/user_spec.rb +22 -8
  75. data/spec/integration/version_spec.rb +7 -7
  76. data/spec/integration/watcher_spec.rb +17 -18
  77. data/spec/integration/webhook.rb +5 -4
  78. data/spec/integration/worklog_spec.rb +8 -8
  79. data/spec/jira/base_factory_spec.rb +2 -1
  80. data/spec/jira/base_spec.rb +55 -41
  81. data/spec/jira/client_spec.rb +48 -34
  82. data/spec/jira/has_many_proxy_spec.rb +3 -3
  83. data/spec/jira/http_client_spec.rb +98 -26
  84. data/spec/jira/http_error_spec.rb +2 -2
  85. data/spec/jira/oauth_client_spec.rb +30 -8
  86. data/spec/jira/request_client_spec.rb +4 -4
  87. data/spec/jira/resource/agile_spec.rb +28 -28
  88. data/spec/jira/resource/attachment_spec.rb +142 -52
  89. data/spec/jira/resource/board_spec.rb +21 -20
  90. data/spec/jira/resource/createmeta_spec.rb +48 -48
  91. data/spec/jira/resource/field_spec.rb +30 -12
  92. data/spec/jira/resource/filter_spec.rb +4 -4
  93. data/spec/jira/resource/issue_picker_suggestions_spec.rb +18 -18
  94. data/spec/jira/resource/issue_spec.rb +44 -38
  95. data/spec/jira/resource/jira_picker_suggestions_issue_spec.rb +3 -3
  96. data/spec/jira/resource/project_factory_spec.rb +3 -2
  97. data/spec/jira/resource/project_spec.rb +16 -16
  98. data/spec/jira/resource/sprint_spec.rb +70 -3
  99. data/spec/jira/resource/status_spec.rb +21 -0
  100. data/spec/jira/resource/user_factory_spec.rb +4 -4
  101. data/spec/jira/resource/worklog_spec.rb +3 -3
  102. data/spec/mock_responses/sprint/1.json +13 -0
  103. data/spec/mock_responses/status/1.json +8 -1
  104. data/spec/mock_responses/status.json +40 -5
  105. data/spec/mock_responses/statuscategory/1.json +7 -0
  106. data/spec/mock_responses/statuscategory.json +30 -0
  107. data/spec/mock_responses/{user_username=admin.json → user_accountId=1234567890abcdef01234567.json} +2 -1
  108. data/spec/spec_helper.rb +1 -0
  109. data/spec/support/clients_helper.rb +3 -5
  110. data/spec/support/shared_examples/integration.rb +25 -28
  111. metadata +25 -257
  112. data/.travis.yml +0 -9
  113. data/example.rb +0 -232
  114. data/http-basic-example.rb +0 -113
  115. data/lib/jira/resource/sprint_report.rb +0 -8
  116. data/lib/jira/tasks.rb +0 -0
  117. data/spec/jira/jwt_uri_builder_spec.rb +0 -59
@@ -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'].size.zero?
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] + '/rest/agile/1.0'
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'.freeze
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: attrs }.merge(options))
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) + '/manifest'
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] + '/attachment/meta')
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 , headers)
69
+ response = client.post_multipart(path, data, headers)
30
70
 
31
71
  set_attributes(attrs, response)
32
72
 
@@ -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) + '/board'
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) + '/backlog/issue', { issues: [issue.id] }.to_json)
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] + '/rest/agile/1.0'
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 BoardConfigurationFactory < JIRA::BaseFactory # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JIRA
2
4
  module Resource
3
5
  class CommentFactory < JIRA::BaseFactory # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JIRA
2
4
  module Resource
3
5
  class ComponentFactory < JIRA::BaseFactory # :nodoc:
@@ -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: attrs)
41
+ new(client, attrs:)
40
42
  end
41
43
  end
42
44
  end
@@ -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
- end
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, &block)
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(method_name, *args, &block)
82
+ super
78
83
  end
79
84
  end
80
85
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JIRA
2
4
  module Resource
3
5
  class FilterFactory < JIRA::BaseFactory # :nodoc:
@@ -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, class: JIRA::Resource::User,
11
- nested_under: 'fields'
12
- has_one :assignee, class: JIRA::Resource::User,
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 :priority, nested_under: 'fields'
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 :attachments, nested_under: 'fields',
29
- attribute_key: 'attachment'
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
- nested_under: 'fields'
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, validate_query: true })
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
- url << "&fields=#{options[:fields].map { |value| CGI.escape(client.Field.name_to_id(value)) }.join(',')}" if options[:fields]
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] == 0)
83
- return json['total']
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'] && @attrs['fields']['worklog'] && (@attrs['fields']['worklog']['total'] > @attrs['fields']['worklog']['maxResults'])
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? { |k| attrs['fields'].key?(k) }
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, &block)
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(method_name, *args, &block)
123
+ super
133
124
  end
134
125
  end
135
126
  else
136
- super(method_name, *args, &block)
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, show_sub_tasks: nil, show_sub_tasks_parent: 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 << "&currentJQL=#{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 IssuePickerSuggestionsIssueFactory < JIRA::BaseFactory # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JIRA
2
4
  module Resource
3
5
  class IssuelinkFactory < JIRA::BaseFactory # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JIRA
2
4
  module Resource
3
5
  class IssuelinktypeFactory < JIRA::BaseFactory # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JIRA
2
4
  module Resource
3
5
  class IssuetypeFactory < JIRA::BaseFactory # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JIRA
2
4
  module Resource
3
5
  class PriorityFactory < JIRA::BaseFactory # :nodoc:
@@ -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] + '/search'
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] + '/user/assignable/search'
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) + '/rapidview')
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: options.fetch(:include_future, false) }
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] + '/rest/greenhopper/1.0'
61
+ "#{client.options[:context_path]}/rest/greenhopper/1.0"
60
62
  end
61
63
 
62
64
  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 RemotelinkFactory < JIRA::BaseFactory # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JIRA
2
4
  module Resource
3
5
  class ResolutionFactory < JIRA::BaseFactory # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JIRA
2
4
  module Resource
3
5
  class ServerInfoFactory < JIRA::BaseFactory # :nodoc:
@@ -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 = 'sprint = ' + id.to_s
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
- request_body = { issues: [issue.id] }.to_json
22
- response = client.post("#{agile_path}/issue", request_body)
23
- true
23
+ add_issues([issue])
24
24
  end
25
25
 
26
- def sprint_report
27
- get_sprint_details_attribute('sprint_report')
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/greenhopper/1.0/rapid/charts/sprintreport?rapidViewId=#{rapidview_id}&sprintId=#{id}"
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 = Date.parse(json['sprint']['startDate']) unless json['sprint']['startDate'] == 'None'
60
- @end_date = Date.parse(json['sprint']['endDate']) unless json['sprint']['endDate'] == 'None'
61
- @completed_date = Date.parse(json['sprint']['completeDate']) unless json['sprint']['completeDate'] == 'None'
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)
@@ -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; end
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
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JIRA
4
+ module Resource
5
+ class StatusCategoryFactory < JIRA::BaseFactory # :nodoc:
6
+ end
7
+
8
+ class StatusCategory < JIRA::Base; end
9
+ end
10
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JIRA
2
4
  module Resource
3
5
  class SuggestedIssueFactory < JIRA::BaseFactory # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JIRA
2
4
  module Resource
3
5
  class TransitionFactory < JIRA::BaseFactory # :nodoc: