jira-ruby 2.1.3

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 (154) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.travis.yml +9 -0
  4. data/Gemfile +14 -0
  5. data/Guardfile +14 -0
  6. data/LICENSE +19 -0
  7. data/README.md +427 -0
  8. data/Rakefile +31 -0
  9. data/example.rb +224 -0
  10. data/http-basic-example.rb +113 -0
  11. data/jira-ruby.gemspec +35 -0
  12. data/lib/jira-ruby.rb +49 -0
  13. data/lib/jira/base.rb +525 -0
  14. data/lib/jira/base_factory.rb +46 -0
  15. data/lib/jira/client.rb +308 -0
  16. data/lib/jira/has_many_proxy.rb +42 -0
  17. data/lib/jira/http_client.rb +112 -0
  18. data/lib/jira/http_error.rb +14 -0
  19. data/lib/jira/jwt_client.rb +67 -0
  20. data/lib/jira/oauth_client.rb +114 -0
  21. data/lib/jira/railtie.rb +10 -0
  22. data/lib/jira/request_client.rb +31 -0
  23. data/lib/jira/resource/agile.rb +79 -0
  24. data/lib/jira/resource/applinks.rb +39 -0
  25. data/lib/jira/resource/attachment.rb +50 -0
  26. data/lib/jira/resource/board.rb +91 -0
  27. data/lib/jira/resource/board_configuration.rb +9 -0
  28. data/lib/jira/resource/comment.rb +12 -0
  29. data/lib/jira/resource/component.rb +8 -0
  30. data/lib/jira/resource/createmeta.rb +44 -0
  31. data/lib/jira/resource/field.rb +83 -0
  32. data/lib/jira/resource/filter.rb +15 -0
  33. data/lib/jira/resource/issue.rb +141 -0
  34. data/lib/jira/resource/issuelink.rb +20 -0
  35. data/lib/jira/resource/issuelinktype.rb +14 -0
  36. data/lib/jira/resource/issuetype.rb +8 -0
  37. data/lib/jira/resource/priority.rb +8 -0
  38. data/lib/jira/resource/project.rb +41 -0
  39. data/lib/jira/resource/rapidview.rb +67 -0
  40. data/lib/jira/resource/remotelink.rb +26 -0
  41. data/lib/jira/resource/resolution.rb +8 -0
  42. data/lib/jira/resource/serverinfo.rb +18 -0
  43. data/lib/jira/resource/sprint.rb +105 -0
  44. data/lib/jira/resource/sprint_report.rb +8 -0
  45. data/lib/jira/resource/status.rb +8 -0
  46. data/lib/jira/resource/transition.rb +29 -0
  47. data/lib/jira/resource/user.rb +30 -0
  48. data/lib/jira/resource/version.rb +8 -0
  49. data/lib/jira/resource/watcher.rb +35 -0
  50. data/lib/jira/resource/webhook.rb +37 -0
  51. data/lib/jira/resource/worklog.rb +14 -0
  52. data/lib/jira/tasks.rb +0 -0
  53. data/lib/jira/version.rb +3 -0
  54. data/lib/tasks/generate.rake +18 -0
  55. data/spec/integration/attachment_spec.rb +32 -0
  56. data/spec/integration/comment_spec.rb +52 -0
  57. data/spec/integration/component_spec.rb +39 -0
  58. data/spec/integration/field_spec.rb +32 -0
  59. data/spec/integration/issue_spec.rb +93 -0
  60. data/spec/integration/issuelinktype_spec.rb +26 -0
  61. data/spec/integration/issuetype_spec.rb +24 -0
  62. data/spec/integration/priority_spec.rb +24 -0
  63. data/spec/integration/project_spec.rb +49 -0
  64. data/spec/integration/rapidview_spec.rb +74 -0
  65. data/spec/integration/resolution_spec.rb +26 -0
  66. data/spec/integration/status_spec.rb +24 -0
  67. data/spec/integration/transition_spec.rb +49 -0
  68. data/spec/integration/user_spec.rb +41 -0
  69. data/spec/integration/version_spec.rb +39 -0
  70. data/spec/integration/watcher_spec.rb +62 -0
  71. data/spec/integration/webhook.rb +25 -0
  72. data/spec/integration/worklog_spec.rb +51 -0
  73. data/spec/jira/base_factory_spec.rb +45 -0
  74. data/spec/jira/base_spec.rb +598 -0
  75. data/spec/jira/client_spec.rb +291 -0
  76. data/spec/jira/has_many_proxy_spec.rb +46 -0
  77. data/spec/jira/http_client_spec.rb +328 -0
  78. data/spec/jira/http_error_spec.rb +24 -0
  79. data/spec/jira/jwt_uri_builder_spec.rb +59 -0
  80. data/spec/jira/oauth_client_spec.rb +162 -0
  81. data/spec/jira/request_client_spec.rb +41 -0
  82. data/spec/jira/resource/agile_spec.rb +135 -0
  83. data/spec/jira/resource/attachment_spec.rb +138 -0
  84. data/spec/jira/resource/board_spec.rb +224 -0
  85. data/spec/jira/resource/createmeta_spec.rb +258 -0
  86. data/spec/jira/resource/field_spec.rb +85 -0
  87. data/spec/jira/resource/filter_spec.rb +97 -0
  88. data/spec/jira/resource/issue_spec.rb +227 -0
  89. data/spec/jira/resource/issuelink_spec.rb +14 -0
  90. data/spec/jira/resource/project_factory_spec.rb +11 -0
  91. data/spec/jira/resource/project_spec.rb +123 -0
  92. data/spec/jira/resource/sprint_spec.rb +90 -0
  93. data/spec/jira/resource/user_factory_spec.rb +31 -0
  94. data/spec/jira/resource/worklog_spec.rb +22 -0
  95. data/spec/mock_responses/board/1.json +33 -0
  96. data/spec/mock_responses/board/1_issues.json +62 -0
  97. data/spec/mock_responses/component.post.json +28 -0
  98. data/spec/mock_responses/component/10000.invalid.put.json +5 -0
  99. data/spec/mock_responses/component/10000.json +39 -0
  100. data/spec/mock_responses/component/10000.put.json +39 -0
  101. data/spec/mock_responses/empty_issues.json +8 -0
  102. data/spec/mock_responses/field.json +32 -0
  103. data/spec/mock_responses/field/1.json +15 -0
  104. data/spec/mock_responses/issue.json +1108 -0
  105. data/spec/mock_responses/issue.post.json +5 -0
  106. data/spec/mock_responses/issue/10002.invalid.put.json +6 -0
  107. data/spec/mock_responses/issue/10002.json +126 -0
  108. data/spec/mock_responses/issue/10002.put.missing_field_update.json +6 -0
  109. data/spec/mock_responses/issue/10002/attachments/10000.json +20 -0
  110. data/spec/mock_responses/issue/10002/comment.json +65 -0
  111. data/spec/mock_responses/issue/10002/comment.post.json +29 -0
  112. data/spec/mock_responses/issue/10002/comment/10000.json +29 -0
  113. data/spec/mock_responses/issue/10002/comment/10000.put.json +29 -0
  114. data/spec/mock_responses/issue/10002/transitions.json +49 -0
  115. data/spec/mock_responses/issue/10002/transitions.post.json +1 -0
  116. data/spec/mock_responses/issue/10002/watchers.json +13 -0
  117. data/spec/mock_responses/issue/10002/worklog.json +98 -0
  118. data/spec/mock_responses/issue/10002/worklog.post.json +30 -0
  119. data/spec/mock_responses/issue/10002/worklog/10000.json +31 -0
  120. data/spec/mock_responses/issue/10002/worklog/10000.put.json +30 -0
  121. data/spec/mock_responses/issueLinkType.json +25 -0
  122. data/spec/mock_responses/issueLinkType/10000.json +7 -0
  123. data/spec/mock_responses/issuetype.json +42 -0
  124. data/spec/mock_responses/issuetype/5.json +8 -0
  125. data/spec/mock_responses/jira/rest/webhooks/1.0/webhook.json +11 -0
  126. data/spec/mock_responses/jira/rest/webhooks/1.0/webhook/2.json +11 -0
  127. data/spec/mock_responses/priority.json +42 -0
  128. data/spec/mock_responses/priority/1.json +8 -0
  129. data/spec/mock_responses/project.json +12 -0
  130. data/spec/mock_responses/project/SAMPLEPROJECT.issues.json +1108 -0
  131. data/spec/mock_responses/project/SAMPLEPROJECT.json +84 -0
  132. data/spec/mock_responses/rapidview.json +10 -0
  133. data/spec/mock_responses/rapidview/SAMPLEPROJECT.issues.full.json +276 -0
  134. data/spec/mock_responses/rapidview/SAMPLEPROJECT.issues.json +111 -0
  135. data/spec/mock_responses/rapidview/SAMPLEPROJECT.json +6 -0
  136. data/spec/mock_responses/resolution.json +15 -0
  137. data/spec/mock_responses/resolution/1.json +7 -0
  138. data/spec/mock_responses/sprint/1_issues.json +125 -0
  139. data/spec/mock_responses/status.json +37 -0
  140. data/spec/mock_responses/status/1.json +7 -0
  141. data/spec/mock_responses/user_username=admin.json +17 -0
  142. data/spec/mock_responses/version.post.json +7 -0
  143. data/spec/mock_responses/version/10000.invalid.put.json +5 -0
  144. data/spec/mock_responses/version/10000.json +11 -0
  145. data/spec/mock_responses/version/10000.put.json +7 -0
  146. data/spec/mock_responses/webhook.json +11 -0
  147. data/spec/mock_responses/webhook/webhook.json +11 -0
  148. data/spec/spec_helper.rb +21 -0
  149. data/spec/support/clients_helper.rb +16 -0
  150. data/spec/support/matchers/have_attributes.rb +11 -0
  151. data/spec/support/matchers/have_many.rb +9 -0
  152. data/spec/support/matchers/have_one.rb +5 -0
  153. data/spec/support/shared_examples/integration.rb +177 -0
  154. metadata +491 -0
@@ -0,0 +1,14 @@
1
+ require 'forwardable'
2
+ module JIRA
3
+ class HTTPError < StandardError
4
+ extend Forwardable
5
+
6
+ def_instance_delegators :@response, :code
7
+ attr_reader :response, :message
8
+
9
+ def initialize(response)
10
+ @response = response
11
+ @message = response.try(:message).presence || response.try(:body)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,67 @@
1
+ require 'atlassian/jwt'
2
+
3
+ module JIRA
4
+ class JwtClient < HttpClient
5
+ def make_request(http_method, url, body = '', headers = {})
6
+ @http_method = http_method
7
+
8
+ super(http_method, url, body, headers)
9
+ end
10
+
11
+ def make_multipart_request(url, data, headers = {})
12
+ @http_method = :post
13
+
14
+ super(url, data, headers)
15
+ end
16
+
17
+ class JwtUriBuilder
18
+ attr_reader :request_url, :http_method, :shared_secret, :site, :issuer
19
+
20
+ def initialize(request_url, http_method, shared_secret, site, issuer)
21
+ @request_url = request_url
22
+ @http_method = http_method
23
+ @shared_secret = shared_secret
24
+ @site = site
25
+ @issuer = issuer
26
+ end
27
+
28
+ def build
29
+ uri = URI.parse(request_url)
30
+ new_query = URI.decode_www_form(String(uri.query)) << ['jwt', jwt_header]
31
+ uri.query = URI.encode_www_form(new_query)
32
+
33
+ return uri.to_s unless uri.is_a?(URI::HTTP)
34
+
35
+ uri.request_uri
36
+ end
37
+
38
+ private
39
+
40
+ def jwt_header
41
+ claim = Atlassian::Jwt.build_claims \
42
+ issuer,
43
+ request_url,
44
+ http_method.to_s,
45
+ site,
46
+ (Time.now - 60).to_i,
47
+ (Time.now + 86_400).to_i
48
+
49
+ JWT.encode claim, shared_secret
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ attr_reader :http_method
56
+
57
+ def request_path(url)
58
+ JwtUriBuilder.new(
59
+ url,
60
+ http_method.to_s,
61
+ @options[:shared_secret],
62
+ @options[:site],
63
+ @options[:issuer]
64
+ ).build
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,114 @@
1
+ require 'oauth'
2
+ require 'json'
3
+ require 'forwardable'
4
+
5
+ module JIRA
6
+ class OauthClient < RequestClient
7
+ DEFAULT_OPTIONS = {
8
+ signature_method: 'RSA-SHA1',
9
+ request_token_path: '/plugins/servlet/oauth/request-token',
10
+ authorize_path: '/plugins/servlet/oauth/authorize',
11
+ access_token_path: '/plugins/servlet/oauth/access-token',
12
+ private_key_file: 'rsakey.pem',
13
+ consumer_key: nil,
14
+ consumer_secret: nil
15
+ }.freeze
16
+
17
+ # This exception is thrown when the client is used before the OAuth access token
18
+ # has been initialized.
19
+ class UninitializedAccessTokenError < StandardError
20
+ def message
21
+ 'init_access_token must be called before using the client'
22
+ end
23
+ end
24
+
25
+ extend Forwardable
26
+
27
+ attr_accessor :consumer
28
+ attr_reader :options
29
+
30
+ def_instance_delegators :@consumer, :key, :secret, :get_request_token
31
+
32
+ def initialize(options)
33
+ @options = DEFAULT_OPTIONS.merge(options)
34
+ @consumer = init_oauth_consumer(@options)
35
+ end
36
+
37
+ def init_oauth_consumer(_options)
38
+ @options[:request_token_path] = @options[:context_path] + @options[:request_token_path]
39
+ @options[:authorize_path] = @options[:context_path] + @options[:authorize_path]
40
+ @options[:access_token_path] = @options[:context_path] + @options[:access_token_path]
41
+ # proxy_address does not exist in oauth's gem context but proxy does
42
+ @options[:proxy] = @options[:proxy_address] if @options[:proxy_address]
43
+ OAuth::Consumer.new(@options[:consumer_key], @options[:consumer_secret], @options)
44
+ end
45
+
46
+ # Returns the current request token if it is set, else it creates
47
+ # and sets a new token.
48
+ def request_token(options = {}, *arguments, &block)
49
+ @request_token ||= get_request_token(options, *arguments, block)
50
+ end
51
+
52
+ # Sets the request token from a given token and secret.
53
+ def set_request_token(token, secret)
54
+ @request_token = OAuth::RequestToken.new(@consumer, token, secret)
55
+ end
56
+
57
+ # Initialises and returns a new access token from the params hash
58
+ # returned by the OAuth transaction.
59
+ def init_access_token(params)
60
+ @access_token = request_token.get_access_token(params)
61
+ end
62
+
63
+ # Sets the access token from a preexisting token and secret.
64
+ def set_access_token(token, secret)
65
+ @access_token = OAuth::AccessToken.new(@consumer, token, secret)
66
+ @authenticated = true
67
+ @access_token
68
+ end
69
+
70
+ # Returns the current access token. Raises an
71
+ # JIRA::Client::UninitializedAccessTokenError exception if it is not set.
72
+ def access_token
73
+ raise UninitializedAccessTokenError unless @access_token
74
+ @access_token
75
+ end
76
+
77
+ def make_request(http_method, url, body = '', headers = {})
78
+ # When using oauth_2legged we need to add an empty oauth_token parameter to every request.
79
+ if @options[:auth_type] == :oauth_2legged
80
+ oauth_params_str = 'oauth_token='
81
+ uri = URI.parse(url)
82
+ uri.query = if uri.query.to_s == ''
83
+ oauth_params_str
84
+ else
85
+ uri.query + '&' + oauth_params_str
86
+ end
87
+ url = uri.to_s
88
+ end
89
+
90
+ case http_method
91
+ when :delete, :get, :head
92
+ response = access_token.send http_method, url, headers
93
+ when :post, :put
94
+ response = access_token.send http_method, url, body, headers
95
+ end
96
+ @authenticated = true
97
+ response
98
+ end
99
+
100
+ def make_multipart_request(url, data, headers = {})
101
+ request = Net::HTTP::Post::Multipart.new url, data, headers
102
+
103
+ access_token.sign! request
104
+
105
+ response = consumer.http.request(request)
106
+ @authenticated = true
107
+ response
108
+ end
109
+
110
+ def authenticated?
111
+ @authenticated
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,10 @@
1
+ require 'jira-ruby'
2
+ require 'rails'
3
+
4
+ module JIRA
5
+ class Railtie < Rails::Railtie
6
+ rake_tasks do
7
+ load 'tasks/generate.rake'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,31 @@
1
+ require 'oauth'
2
+ require 'json'
3
+ require 'net/https'
4
+
5
+ module JIRA
6
+ class RequestClient
7
+ # Returns the response if the request was successful (HTTP::2xx) and
8
+ # raises a JIRA::HTTPError if it was not successful, with the response
9
+ # attached.
10
+
11
+ def request(*args)
12
+ response = make_request(*args)
13
+ raise HTTPError, response unless response.is_a?(Net::HTTPSuccess)
14
+ response
15
+ end
16
+
17
+ def request_multipart(*args)
18
+ response = make_multipart_request(*args)
19
+ raise HTTPError, response unless response.is_a?(Net::HTTPSuccess)
20
+ response
21
+ end
22
+
23
+ def make_request(*args)
24
+ raise NotImplementedError
25
+ end
26
+
27
+ def make_multipart_request(*args)
28
+ raise NotImplementedError
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,79 @@
1
+ require 'cgi'
2
+
3
+ module JIRA
4
+ module Resource
5
+ class AgileFactory < JIRA::BaseFactory # :nodoc:
6
+ end
7
+
8
+ class Agile < JIRA::Base
9
+ # @param client [JIRA::Client]
10
+ # @param options [Hash<Symbol, Object>]
11
+ # @return [Hash]
12
+ def self.all(client, options = {})
13
+ opts = options.empty? ? '' : "?#{hash_to_query_string(options)}"
14
+ response = client.get(path_base(client) + "/board#{opts}")
15
+ parse_json(response.body)
16
+ end
17
+
18
+ def self.get_backlog_issues(client, board_id, options = {})
19
+ options[:maxResults] ||= 100
20
+ response = client.get(path_base(client) + "/board/#{board_id}/backlog?#{hash_to_query_string(options)}")
21
+ parse_json(response.body)
22
+ end
23
+
24
+ def self.get_board_issues(client, board_id, options = {})
25
+ response = client.get(path_base(client) + "/board/#{board_id}/issue?#{hash_to_query_string(options)}")
26
+ json = parse_json(response.body)
27
+ # To get Issue objects with the same structure as for Issue.all
28
+ return {} if json['issues'].size.zero?
29
+ issue_ids = json['issues'].map do |issue|
30
+ issue['id']
31
+ end
32
+ client.Issue.jql("id IN(#{issue_ids.join(', ')})")
33
+ end
34
+
35
+ def self.get_sprints(client, board_id, options = {})
36
+ options[:maxResults] ||= 100
37
+ response = client.get(path_base(client) + "/board/#{board_id}/sprint?#{hash_to_query_string(options)}")
38
+ parse_json(response.body)
39
+ end
40
+
41
+ def self.get_sprint_issues(client, sprint_id, options = {})
42
+ options[:maxResults] ||= 100
43
+ response = client.get(path_base(client) + "/sprint/#{sprint_id}/issue?#{hash_to_query_string(options)}")
44
+ parse_json(response.body)
45
+ end
46
+
47
+ def self.get_projects_full(client, board_id, _options = {})
48
+ response = client.get(path_base(client) + "/board/#{board_id}/project/full")
49
+ parse_json(response.body)
50
+ end
51
+
52
+ def self.get_projects(client, board_id, options = {})
53
+ options[:maxResults] ||= 100
54
+ create_meta_url = path_base(client) + "/board/#{board_id}/project"
55
+ params = hash_to_query_string(options)
56
+
57
+ response = client.get("#{create_meta_url}?#{params}")
58
+ parse_json(response.body)
59
+ end
60
+
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
+ private
69
+
70
+ def self.path_base(client)
71
+ client.options[:context_path] + '/rest/agile/1.0'
72
+ end
73
+
74
+ def path_base(client)
75
+ self.class.path_base(client)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,39 @@
1
+ module JIRA
2
+ module Resource
3
+ class ApplicationLinkFactory < JIRA::BaseFactory # :nodoc:
4
+ delegate_to_target_class :manifest
5
+ end
6
+
7
+ class ApplicationLink < JIRA::Base
8
+ REST_BASE_PATH = '/rest/applinks/1.0'.freeze
9
+
10
+ def self.endpoint_name
11
+ 'listApplicationlinks'
12
+ end
13
+
14
+ def self.full_url(client)
15
+ client.options[:context_path] + REST_BASE_PATH
16
+ end
17
+
18
+ def self.collection_path(client, prefix = '/')
19
+ full_url(client) + prefix + endpoint_name
20
+ end
21
+
22
+ def self.all(client, options = {})
23
+ response = client.get(collection_path(client))
24
+ json = parse_json(response.body)
25
+ json = json['list']
26
+ json.map do |attrs|
27
+ new(client, { attrs: attrs }.merge(options))
28
+ end
29
+ end
30
+
31
+ def self.manifest(client)
32
+ url = full_url(client) + '/manifest'
33
+ response = client.get(url)
34
+ json = parse_json(response.body)
35
+ JIRA::Base.new(client, attrs: json)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,50 @@
1
+ require 'net/http/post/multipart'
2
+
3
+ module JIRA
4
+ module Resource
5
+ class AttachmentFactory < JIRA::BaseFactory # :nodoc:
6
+ delegate_to_target_class :meta
7
+ end
8
+
9
+ class Attachment < JIRA::Base
10
+ belongs_to :issue
11
+ has_one :author, class: JIRA::Resource::User
12
+
13
+ def self.endpoint_name
14
+ 'attachments'
15
+ end
16
+
17
+ def self.meta(client)
18
+ response = client.get(client.options[:rest_base_path] + '/attachment/meta')
19
+ parse_json(response.body)
20
+ end
21
+
22
+ def save!(attrs, path = url)
23
+ file = attrs['file'] || attrs[:file] # Keep supporting 'file' parameter as a string for backward compatibility
24
+ mime_type = attrs[:mimeType] || 'application/binary'
25
+
26
+ headers = { 'X-Atlassian-Token' => 'nocheck' }
27
+ data = { 'file' => UploadIO.new(file, mime_type, file) }
28
+
29
+ response = client.post_multipart(path, data , headers)
30
+
31
+ set_attributes(attrs, response)
32
+
33
+ @expanded = false
34
+ true
35
+ end
36
+
37
+ private
38
+
39
+ def set_attributes(attributes, response)
40
+ set_attrs(attributes, false)
41
+ return if response.body.nil? || response.body.length < 2
42
+
43
+ json = self.class.parse_json(response.body)
44
+ attachment = json[0]
45
+
46
+ set_attrs(attachment)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,91 @@
1
+ require 'cgi'
2
+
3
+ module JIRA
4
+ module Resource
5
+ class BoardFactory < JIRA::BaseFactory # :nodoc:
6
+ end
7
+
8
+ class Board < JIRA::Base
9
+ def self.all(client)
10
+ path = path_base(client) + '/board'
11
+ response = client.get(path)
12
+ json = parse_json(response.body)
13
+ results = json['values']
14
+
15
+ until json['isLast']
16
+ params = { 'startAt' => (json['startAt'] + json['maxResults']).to_s }
17
+ response = client.get(url_with_query_params(path, params))
18
+ json = parse_json(response.body)
19
+ results += json['values']
20
+ end
21
+
22
+ results.map do |board|
23
+ client.Board.build(board)
24
+ end
25
+ end
26
+
27
+ def self.find(client, key, _options = {})
28
+ response = client.get(path_base(client) + "/board/#{key}")
29
+ json = parse_json(response.body)
30
+ client.Board.build(json)
31
+ end
32
+
33
+ def issues(params = {})
34
+ path = path_base(client) + "/board/#{id}/issue"
35
+ response = client.get(url_with_query_params(path, params))
36
+ json = self.class.parse_json(response.body)
37
+ results = json['issues']
38
+
39
+ while (json['startAt'] + json['maxResults']) < json['total']
40
+ params['startAt'] = (json['startAt'] + json['maxResults'])
41
+ response = client.get(url_with_query_params(path, params))
42
+ json = self.class.parse_json(response.body)
43
+ results += json['issues']
44
+ end
45
+
46
+ results.map { |issue| client.Issue.build(issue) }
47
+ end
48
+
49
+ def configuration(params = {})
50
+ path = path_base(client) + "/board/#{id}/configuration"
51
+ response = client.get(url_with_query_params(path, params))
52
+ json = self.class.parse_json(response.body)
53
+ client.BoardConfiguration.build(json)
54
+ end
55
+
56
+ # options
57
+ # - state ~ future, active, closed, you can define multiple states separated by commas, e.g. state=active,closed
58
+ # - maxResults ~ default: 50 (JIRA API), 1000 (this library)
59
+ # - startAt ~ base index, starts at 0
60
+ def sprints(options = {})
61
+ # options.reverse_merge!(DEFAULT_OPTIONS)
62
+ response = client.get(path_base(client) + "/board/#{id}/sprint?#{options.to_query}")
63
+ json = self.class.parse_json(response.body)
64
+ json['values'].map do |sprint|
65
+ sprint['rapidview_id'] = id
66
+ client.Sprint.build(sprint)
67
+ end
68
+ end
69
+
70
+ def project
71
+ response = client.get(path_base(client) + "/board/#{id}/project")
72
+ json = self.class.parse_json(response.body)
73
+ json['values'][0]
74
+ end
75
+
76
+ def add_issue_to_backlog(issue)
77
+ client.post(path_base(client) + '/backlog/issue', { issues: [issue.id] }.to_json)
78
+ end
79
+
80
+ private
81
+
82
+ def self.path_base(client)
83
+ client.options[:context_path] + '/rest/agile/1.0'
84
+ end
85
+
86
+ def path_base(client)
87
+ self.class.path_base(client)
88
+ end
89
+ end
90
+ end
91
+ end