tracker_api 1.7.1 → 1.11.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -1
- data/README.md +16 -0
- data/lib/tracker_api.rb +19 -0
- data/lib/tracker_api/client.rb +16 -35
- data/lib/tracker_api/endpoints/attachment.rb +38 -0
- data/lib/tracker_api/endpoints/attachments.rb +22 -0
- data/lib/tracker_api/endpoints/blockers.rb +20 -0
- data/lib/tracker_api/endpoints/comment.rb +9 -2
- data/lib/tracker_api/endpoints/iteration.rb +35 -0
- data/lib/tracker_api/endpoints/release.rb +17 -0
- data/lib/tracker_api/endpoints/releases.rb +20 -0
- data/lib/tracker_api/endpoints/reviews.rb +21 -0
- data/lib/tracker_api/endpoints/search.rb +1 -1
- data/lib/tracker_api/endpoints/stories.rb +10 -0
- data/lib/tracker_api/error.rb +12 -2
- data/lib/tracker_api/file_utility.rb +16 -0
- data/lib/tracker_api/resources/activity.rb +1 -1
- data/lib/tracker_api/resources/blocker.rb +18 -0
- data/lib/tracker_api/resources/comment.rb +35 -0
- data/lib/tracker_api/resources/cycle_time_details.rb +21 -0
- data/lib/tracker_api/resources/daily_history_container.rb +13 -0
- data/lib/tracker_api/resources/epic.rb +9 -0
- data/lib/tracker_api/resources/file_attachment.rb +37 -0
- data/lib/tracker_api/resources/iteration.rb +14 -0
- data/lib/tracker_api/resources/project.rb +13 -0
- data/lib/tracker_api/resources/release.rb +29 -0
- data/lib/tracker_api/resources/review.rb +19 -0
- data/lib/tracker_api/resources/review_type.rb +15 -0
- data/lib/tracker_api/resources/story.rb +49 -6
- data/lib/tracker_api/version.rb +1 -1
- data/lib/virtus/attribute/nullify_blank.rb +1 -1
- data/test/client_test.rb +52 -52
- data/test/comment_test.rb +46 -4
- data/test/error_test.rb +47 -0
- data/test/file_attachment_test.rb +19 -0
- data/test/iteration_test.rb +31 -0
- data/test/minitest_helper.rb +5 -2
- data/test/project_test.rb +59 -47
- data/test/release_test.rb +22 -0
- data/test/story_test.rb +65 -52
- data/test/task_test.rb +3 -3
- data/test/vcr/cassettes/create_attachments.json +1 -0
- data/test/vcr/cassettes/create_comment.json +1 -1
- data/test/vcr/cassettes/create_comment_with_attachment.json +1 -0
- data/test/vcr/cassettes/create_story_comment.json +1 -1
- data/test/vcr/cassettes/delete_an_attachment.json +1 -0
- data/test/vcr/cassettes/delete_attachments.json +1 -0
- data/test/vcr/cassettes/delete_comment.json +1 -0
- data/test/vcr/cassettes/delete_comments.json +1 -0
- data/test/vcr/cassettes/get_current_iteration.json +1 -1
- data/test/vcr/cassettes/get_cycle_time_details.json +1 -0
- data/test/vcr/cassettes/get_daily_history_container.json +1 -0
- data/test/vcr/cassettes/get_releases.json +1 -0
- data/test/vcr/cassettes/get_story_in_epic.json +1 -1
- data/test/vcr/cassettes/get_story_reviews.json +1 -0
- data/test/vcr/cassettes/release_stories.json +1 -0
- data/test/vcr/cassettes/search_project.json +1 -1
- data/test/workspace_test.rb +5 -5
- data/tracker_api.gemspec +3 -2
- metadata +68 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cce8ed0f32ae28c44915d1a2aa0dff3f7deb44f9
|
4
|
+
data.tar.gz: 6478d86c0e8e8e826e0ffd50b8111758f0dec9c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 34b10827d2868cf6e0de4039ef23444b412fcb5d162e6fca2a20258f22d3ceede1e45cb4f7e829cb57ccd8a66a3506144e53eed8f7ae6954b2d2196c6244e0f1
|
7
|
+
data.tar.gz: 69eb1bbad1ea7a6ef35b84e36c9b856ebc300eda60369769c242a9ec77fd5cf3c436c7280101341f657d46beab1fc382e16bbb43c074bcb6b89c97b74d71105b
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -68,9 +68,20 @@ comments = story.comments # co
|
|
68
68
|
|
69
69
|
comment = story.create_comment(text: "Use the force!") # Create a new comment on the story
|
70
70
|
|
71
|
+
comment = story.create_comment(text: "Use the force again !", # Create a new comment on the story with
|
72
|
+
files: ['path/to/an/existing/file']) # file attachments
|
73
|
+
|
71
74
|
comment.text += " (please be careful)"
|
72
75
|
comment.save # Update text of an existing comment
|
76
|
+
comment.delete # Delete an existing comment
|
77
|
+
|
78
|
+
comment.create_attachments(files: ['path/to/an/existing/file']) # Add attachments to existing comment
|
79
|
+
comment.delete_attachments # Delete all attachments from a comment
|
73
80
|
|
81
|
+
attachments = comment.attachments # Get attachments associated with a comment
|
82
|
+
attachments.first.delete # Delete a specific attachment
|
83
|
+
|
84
|
+
comment.attachments(reload: true) # Re-load the attachments after modification
|
74
85
|
task = story.tasks.first # Get story tasks
|
75
86
|
task.complete = true
|
76
87
|
task.save # Mark a task complete
|
@@ -95,6 +106,10 @@ client.project(project_id).stories(fields: ':default,tasks') # Eage
|
|
95
106
|
story.comments(fields: ':default,person') # Eagerly get comments and the person that made the comment for a story
|
96
107
|
```
|
97
108
|
|
109
|
+
## Error Handling
|
110
|
+
`TrackerApi::Errors::ClientError` is raised for 4xx HTTP status codes
|
111
|
+
`TrackerApi::Errors::ServerError` is raised for 5xx HTTP status codes
|
112
|
+
|
98
113
|
## Warning
|
99
114
|
|
100
115
|
Direct mutation of an attribute value skips coercion and dirty tracking. Please use direct assignment or the specialized add_* methods to get expected behavior.
|
@@ -118,6 +133,7 @@ story.save
|
|
118
133
|
|
119
134
|
- Add missing resources and endpoints
|
120
135
|
- Add create, update, delete for resources
|
136
|
+
- Error handling for [error responses](https://www.pivotaltracker.com/help/api#Error_Responses)
|
121
137
|
|
122
138
|
## Semantic Versioning
|
123
139
|
http://semver.org/
|
data/lib/tracker_api.rb
CHANGED
@@ -3,6 +3,8 @@ require 'tracker_api/version'
|
|
3
3
|
# dependencies
|
4
4
|
require 'faraday'
|
5
5
|
require 'faraday_middleware'
|
6
|
+
require 'pathname'
|
7
|
+
require 'mimemagic'
|
6
8
|
|
7
9
|
if defined?(ActiveSupport)
|
8
10
|
require 'active_support/core_ext/object/blank'
|
@@ -26,15 +28,20 @@ module TrackerApi
|
|
26
28
|
autoload :Error, 'tracker_api/error'
|
27
29
|
autoload :Client, 'tracker_api/client'
|
28
30
|
autoload :Logger, 'tracker_api/logger'
|
31
|
+
autoload :FileUtility, 'tracker_api/file_utility'
|
29
32
|
|
30
33
|
module Errors
|
31
34
|
class UnexpectedData < StandardError; end
|
35
|
+
class ClientError < Error; end
|
36
|
+
class ServerError < Error; end
|
32
37
|
end
|
33
38
|
|
34
39
|
module Endpoints
|
35
40
|
autoload :Activity, 'tracker_api/endpoints/activity'
|
41
|
+
autoload :Blockers, 'tracker_api/endpoints/blockers'
|
36
42
|
autoload :Epic, 'tracker_api/endpoints/epic'
|
37
43
|
autoload :Epics, 'tracker_api/endpoints/epics'
|
44
|
+
autoload :Iteration, 'tracker_api/endpoints/iteration'
|
38
45
|
autoload :Iterations, 'tracker_api/endpoints/iterations'
|
39
46
|
autoload :Labels, 'tracker_api/endpoints/labels'
|
40
47
|
autoload :Me, 'tracker_api/endpoints/me'
|
@@ -55,6 +62,11 @@ module TrackerApi
|
|
55
62
|
autoload :Webhook, 'tracker_api/endpoints/webhook'
|
56
63
|
autoload :Webhooks, 'tracker_api/endpoints/webhooks'
|
57
64
|
autoload :StoryTransitions, 'tracker_api/endpoints/story_transitions'
|
65
|
+
autoload :Attachment, 'tracker_api/endpoints/attachment'
|
66
|
+
autoload :Attachments, 'tracker_api/endpoints/attachments'
|
67
|
+
autoload :Releases, 'tracker_api/endpoints/releases'
|
68
|
+
autoload :Release, 'tracker_api/endpoints/release'
|
69
|
+
autoload :Reviews, 'tracker_api/endpoints/reviews'
|
58
70
|
end
|
59
71
|
|
60
72
|
module Resources
|
@@ -64,6 +76,7 @@ module TrackerApi
|
|
64
76
|
end
|
65
77
|
autoload :Activity, 'tracker_api/resources/activity'
|
66
78
|
autoload :Account, 'tracker_api/resources/account'
|
79
|
+
autoload :Blocker, 'tracker_api/resources/blocker'
|
67
80
|
autoload :Change, 'tracker_api/resources/change'
|
68
81
|
autoload :Epic, 'tracker_api/resources/epic'
|
69
82
|
autoload :EpicsSearchResult, 'tracker_api/resources/epics_search_result'
|
@@ -85,5 +98,11 @@ module TrackerApi
|
|
85
98
|
autoload :Comment, 'tracker_api/resources/comment'
|
86
99
|
autoload :Webhook, 'tracker_api/resources/webhook'
|
87
100
|
autoload :StoryTransition, 'tracker_api/resources/story_transition'
|
101
|
+
autoload :FileAttachment, 'tracker_api/resources/file_attachment'
|
102
|
+
autoload :Release, 'tracker_api/resources/release'
|
103
|
+
autoload :CycleTimeDetails, 'tracker_api/resources/cycle_time_details'
|
104
|
+
autoload :DailyHistoryContainer, 'tracker_api/resources/daily_history_container'
|
105
|
+
autoload :Review, 'tracker_api/resources/review'
|
106
|
+
autoload :ReviewType, 'tracker_api/resources/review_type'
|
88
107
|
end
|
89
108
|
end
|
data/lib/tracker_api/client.rb
CHANGED
@@ -25,7 +25,7 @@ module TrackerApi
|
|
25
25
|
@url = Addressable::URI.parse(url).to_s
|
26
26
|
@api_version = options.fetch(:api_version, '/services/v5')
|
27
27
|
@logger = options.fetch(:logger, ::Logger.new(nil))
|
28
|
-
adapter = options.fetch(:adapter
|
28
|
+
adapter = options.fetch(:adapter) { defined?(JRUBY_VERSION) ? :net_http : :excon }
|
29
29
|
connection_options = options.fetch(:connection_options, { ssl: { verify: true } })
|
30
30
|
@auto_paginate = options.fetch(:auto_paginate, true)
|
31
31
|
@token = options[:token]
|
@@ -36,7 +36,7 @@ module TrackerApi
|
|
36
36
|
@connection = Faraday.new({ url: @url }.merge(connection_options)) do |builder|
|
37
37
|
# response
|
38
38
|
builder.use Faraday::Response::RaiseError
|
39
|
-
builder.response :json
|
39
|
+
builder.response :json, content_type: /\bjson/ # e.g., 'application/json; charset=utf-8'
|
40
40
|
|
41
41
|
# request
|
42
42
|
builder.request :multipart
|
@@ -48,40 +48,15 @@ module TrackerApi
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
#
|
51
|
+
# HTTP requests methods
|
52
52
|
#
|
53
53
|
# @param path [String] The path, relative to api endpoint
|
54
54
|
# @param options [Hash] Query and header params for request
|
55
55
|
# @return [Faraday::Response]
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
# Make a HTTP POST request
|
61
|
-
#
|
62
|
-
# @param path [String] The path, relative to api endpoint
|
63
|
-
# @param options [Hash] Query and header params for request
|
64
|
-
# @return [Faraday::Response]
|
65
|
-
def post(path, options = {})
|
66
|
-
request(:post, parse_query_and_convenience_headers(path, options))
|
67
|
-
end
|
68
|
-
|
69
|
-
# Make a HTTP PUT request
|
70
|
-
#
|
71
|
-
# @param path [String] The path, relative to api endpoint
|
72
|
-
# @param options [Hash] Query and header params for request
|
73
|
-
# @return [Faraday::Response]
|
74
|
-
def put(path, options = {})
|
75
|
-
request(:put, parse_query_and_convenience_headers(path, options))
|
76
|
-
end
|
77
|
-
|
78
|
-
# Make a HTTP DELETE request
|
79
|
-
#
|
80
|
-
# @param path [String] The path, relative to api endpoint
|
81
|
-
# @param options [Hash] Query and header params for request
|
82
|
-
# @return [Faraday::Response]
|
83
|
-
def delete(path, options = {})
|
84
|
-
request(:delete, parse_query_and_convenience_headers(path, options))
|
56
|
+
%i{get post patch put delete}.each do |verb|
|
57
|
+
define_method verb do |path, options = {}|
|
58
|
+
request(verb, parse_query_and_convenience_headers(path, options))
|
59
|
+
end
|
85
60
|
end
|
86
61
|
|
87
62
|
# Make one or more HTTP GET requests, optionally fetching
|
@@ -215,7 +190,8 @@ module TrackerApi
|
|
215
190
|
opts[:params] = options[:params] || {}
|
216
191
|
opts[:token] = options[:token] || @token
|
217
192
|
headers = { 'User-Agent' => USER_AGENT,
|
218
|
-
'X-TrackerToken' => opts.fetch(:token)
|
193
|
+
'X-TrackerToken' => opts.fetch(:token),
|
194
|
+
'Accept' => 'application/json' }.merge(options.fetch(:headers, {}))
|
219
195
|
|
220
196
|
CONVENIENCE_HEADERS.each do |h|
|
221
197
|
if header = options[h]
|
@@ -247,8 +223,13 @@ module TrackerApi
|
|
247
223
|
req.body = body
|
248
224
|
end
|
249
225
|
response
|
250
|
-
rescue Faraday::
|
251
|
-
|
226
|
+
rescue Faraday::ClientError, Faraday::ServerError => e
|
227
|
+
status_code = e.response[:status]
|
228
|
+
case status_code
|
229
|
+
when 400..499 then raise TrackerApi::Errors::ClientError.new(e)
|
230
|
+
when 500..599 then raise TrackerApi::Errors::ServerError.new(e)
|
231
|
+
else raise "Expected 4xx or 5xx HTTP status code; got #{status_code} instead."
|
232
|
+
end
|
252
233
|
end
|
253
234
|
|
254
235
|
class Pagination
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module TrackerApi
|
2
|
+
module Endpoints
|
3
|
+
class Attachment
|
4
|
+
attr_accessor :client
|
5
|
+
|
6
|
+
def initialize(client)
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
def create(comment, file)
|
11
|
+
data = client.post("/projects/#{comment.project_id}/uploads", body: FileUtility.get_file_upload(file)).body
|
12
|
+
Resources::FileAttachment.new({ comment: comment }.merge(data))
|
13
|
+
end
|
14
|
+
|
15
|
+
# TODO : Discuss before implementing this as it orphans the file.
|
16
|
+
# It deletes source, but the file name appears in the comments
|
17
|
+
# def delete(comment, file_attachment_id)
|
18
|
+
# client.delete("/projects/#{comment.project_id}/stories/#{comment.story_id}/comments/#{comment.id}/file_attachments/#{file_attachment_id}").body
|
19
|
+
# end
|
20
|
+
|
21
|
+
def get(comment)
|
22
|
+
data = client.get("/projects/#{comment.project_id}/stories/#{comment.story_id}/comments/#{comment.id}?fields=file_attachments").body["file_attachments"]
|
23
|
+
raise Errors::UnexpectedData, 'Array of file attachments expected' unless data.is_a? Array
|
24
|
+
|
25
|
+
data.map do |file_attachment|
|
26
|
+
Resources::FileAttachment.new({ comment: comment }.merge(file_attachment))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# TODO : Implement this properly.
|
31
|
+
# This results in either content of the file or an S3 link.
|
32
|
+
# the S3 link is also present in big_url attribute.
|
33
|
+
# def download(download_path)
|
34
|
+
# client.get(download_path, url: '').body
|
35
|
+
# end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module TrackerApi
|
2
|
+
module Endpoints
|
3
|
+
class Attachments
|
4
|
+
attr_accessor :client
|
5
|
+
|
6
|
+
def initialize(client)
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def create(comment, files)
|
12
|
+
return [] if files.to_a.empty?
|
13
|
+
#Check files before upload to make it all or none.
|
14
|
+
FileUtility.check_files_exist(files)
|
15
|
+
attachment = Endpoints::Attachment.new(client)
|
16
|
+
files.map do | file |
|
17
|
+
attachment.create(comment, file)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module TrackerApi
|
2
|
+
module Endpoints
|
3
|
+
class Blockers
|
4
|
+
attr_accessor :client
|
5
|
+
|
6
|
+
def initialize(client)
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
def get(project_id, story_id, params = {})
|
11
|
+
data = client.get("/projects/#{project_id}/stories/#{story_id}/blockers", params: params).body
|
12
|
+
raise Errors::UnexpectedData, 'Array of Blockers expected' unless data.is_a? Array
|
13
|
+
|
14
|
+
data.map do |blocker|
|
15
|
+
Resources::Blocker.new({ client: client, project_id: project_id }.merge(blocker))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -15,13 +15,20 @@ module TrackerApi
|
|
15
15
|
def update(comment, params={})
|
16
16
|
raise ArgumentError, 'Valid comment required to update.' unless comment.instance_of?(Resources::Comment)
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
path = "/projects/#{comment.project_id}/stories/#{comment.story_id}/comments/#{comment.id}"
|
19
|
+
path += "?fields=:default,file_attachments" if params.represented.file_attachment_ids_to_add.present? || params.represented.file_attachment_ids_to_remove.present?
|
20
|
+
data = client.put(path, params: params).body
|
20
21
|
|
21
22
|
comment.attributes = data
|
22
23
|
comment.clean!
|
23
24
|
comment
|
24
25
|
end
|
26
|
+
|
27
|
+
def delete(comment)
|
28
|
+
raise ArgumentError, 'Valid comment required to update.' unless comment.instance_of?(Resources::Comment)
|
29
|
+
|
30
|
+
client.delete("/projects/#{comment.project_id}/stories/#{comment.story_id}/comments/#{comment.id}").body
|
31
|
+
end
|
25
32
|
end
|
26
33
|
end
|
27
34
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module TrackerApi
|
2
|
+
module Endpoints
|
3
|
+
class Iteration
|
4
|
+
attr_accessor :client
|
5
|
+
|
6
|
+
def initialize(client)
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
def get(project_id, iteration_number)
|
11
|
+
data = client.get("/projects/#{project_id}/iterations/#{iteration_number}").body
|
12
|
+
|
13
|
+
Resources::Iteration.new({ client: client, project_id: project_id }.merge(data))
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_analytics_cycle_time_details(project_id, iteration_number)
|
17
|
+
data = client.paginate("/projects/#{project_id}/iterations/#{iteration_number}/analytics/cycle_time_details")
|
18
|
+
raise Errors::UnexpectedData, 'Array of cycle time details expected' unless data.is_a? Array
|
19
|
+
|
20
|
+
data.map do |cycle_time_details|
|
21
|
+
Resources::CycleTimeDetails.new(
|
22
|
+
{ project_id: project_id, iteration_number: iteration_number }.merge(cycle_time_details)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_history(project_id, iteration_number)
|
28
|
+
data = client.get("/projects/#{project_id}/history/iterations/#{iteration_number}/days").body
|
29
|
+
raise Errors::UnexpectedData, 'Hash of history data expected' unless data.is_a? Hash
|
30
|
+
|
31
|
+
Resources::DailyHistoryContainer.new({ project_id: project_id, iteration_number: iteration_number }.merge(data))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module TrackerApi
|
2
|
+
module Endpoints
|
3
|
+
class Release
|
4
|
+
attr_accessor :client
|
5
|
+
|
6
|
+
def initialize(client)
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
def get(project_id, id, params={})
|
11
|
+
data = client.get("/projects/#{project_id}/releases/#{id}", params: params).body
|
12
|
+
|
13
|
+
Resources::Release.new({ client: client }.merge(data))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module TrackerApi
|
2
|
+
module Endpoints
|
3
|
+
class Releases
|
4
|
+
attr_accessor :client
|
5
|
+
|
6
|
+
def initialize(client)
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
def get(project_id, params={})
|
11
|
+
data = client.paginate("/projects/#{project_id}/releases", params: params)
|
12
|
+
raise Errors::UnexpectedData, 'Array of releases expected' unless data.is_a? Array
|
13
|
+
|
14
|
+
data.map do |release|
|
15
|
+
Resources::Release.new({ client: client, project_id: project_id }.merge(release))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module TrackerApi
|
2
|
+
module Endpoints
|
3
|
+
class Reviews
|
4
|
+
attr_accessor :client
|
5
|
+
|
6
|
+
def initialize(client)
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
def get(project_id, story_id, params={})
|
11
|
+
params[:fields] ||= ":default,review_type"
|
12
|
+
data = client.paginate("/projects/#{project_id}/stories/#{story_id}/reviews", params: params)
|
13
|
+
raise Errors::UnexpectedData, 'Successful responses to this request return an array containing zero or more instances of the review resource. This response was not an array.' unless data.is_a? Array
|
14
|
+
|
15
|
+
data.map do |review|
|
16
|
+
Resources::Review.new({ client: client, project_id: project_id }.merge(review))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -10,7 +10,7 @@ module TrackerApi
|
|
10
10
|
def get(project_id, query, options={})
|
11
11
|
raise ArgumentError, 'Valid query string required to search' unless query.is_a?(String)
|
12
12
|
|
13
|
-
options
|
13
|
+
options[:params] = { query: query }
|
14
14
|
data = client.get("/projects/#{project_id}/search", options).body
|
15
15
|
|
16
16
|
raise Errors::UnexpectedData, 'Hash of search results expect' unless data.is_a? Hash
|
@@ -17,6 +17,16 @@ module TrackerApi
|
|
17
17
|
Resources::Story.new({ client: client, project_id: project_id }.merge(story))
|
18
18
|
end
|
19
19
|
end
|
20
|
+
|
21
|
+
def get_release(project_id, release_id, params={})
|
22
|
+
data = client.paginate("/projects/#{project_id}/releases/#{release_id}/stories", params: params)
|
23
|
+
|
24
|
+
raise Errors::UnexpectedData, 'Array of stories expected' unless data.is_a? Array
|
25
|
+
|
26
|
+
data.map do |story|
|
27
|
+
Resources::Story.new({ client: client, project_id: project_id }.merge(story))
|
28
|
+
end
|
29
|
+
end
|
20
30
|
end
|
21
31
|
end
|
22
32
|
end
|