jira-ruby 2.3.0 → 3.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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 +94 -18
  12. data/Rakefile +3 -4
  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 +64 -46
  17. data/lib/jira/has_many_proxy.rb +4 -2
  18. data/lib/jira/http_client.rb +17 -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 +94 -27
  84. data/spec/jira/http_error_spec.rb +2 -2
  85. data/spec/jira/oauth_client_spec.rb +8 -6
  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 +17 -17
  94. data/spec/jira/resource/issue_spec.rb +43 -37
  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
  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:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JIRA
2
4
  module Resource
3
5
  class UserFactory < JIRA::BaseFactory # :nodoc:
@@ -13,7 +15,7 @@ module JIRA
13
15
  MAX_RESULTS = 1000
14
16
 
15
17
  def self.singular_path(client, key, prefix = '/')
16
- collection_path(client, prefix) + '?username=' + key
18
+ "#{collection_path(client, prefix)}?accountId=#{key}"
17
19
  end
18
20
 
19
21
  # Cannot retrieve more than 1,000 users through the api, please see: https://jira.atlassian.com/browse/JRASERVER-65089
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JIRA
2
4
  module Resource
3
5
  class VersionFactory < JIRA::BaseFactory # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JIRA
2
4
  module Resource
3
5
  class WatcherFactory < JIRA::BaseFactory # :nodoc:
@@ -29,7 +31,6 @@ module JIRA
29
31
  response = client.post(path, user_id.to_json)
30
32
  true
31
33
  end
32
-
33
34
  end
34
35
  end
35
36
  end