tracker_api 1.8.0 → 1.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +2 -1
- data/README.md +4 -0
- data/lib/tracker_api.rb +12 -0
- data/lib/tracker_api/client.rb +8 -6
- data/lib/tracker_api/endpoints/blockers.rb +20 -0
- 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/review.rb +21 -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/resources/blocker.rb +18 -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/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 +35 -0
- data/lib/tracker_api/resources/review_type.rb +15 -0
- data/lib/tracker_api/resources/story.rb +26 -0
- data/lib/tracker_api/version.rb +1 -1
- data/test/client_test.rb +52 -52
- data/test/comment_test.rb +13 -13
- data/test/error_test.rb +8 -2
- data/test/file_attachment_test.rb +4 -4
- 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/review_test.rb +27 -0
- data/test/story_test.rb +65 -48
- data/test/task_test.rb +3 -3
- data/test/vcr/cassettes/create_attachments.json +1 -1
- data/test/vcr/cassettes/create_comment_with_attachment.json +1 -1
- data/test/vcr/cassettes/delete_an_attachment.json +1 -1
- data/test/vcr/cassettes/delete_attachments.json +1 -1
- 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_reviews.json +1 -0
- data/test/vcr/cassettes/release_stories.json +1 -0
- data/test/vcr/cassettes/save_review.json +1 -0
- data/test/vcr/cassettes/search_project.json +1 -1
- data/test/workspace_test.rb +5 -5
- data/tracker_api.gemspec +1 -1
- metadata +35 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7d0c3f349c8d57bc33c44401068ae359892d33a8d8ed2c5c20ed96110fe02b3b
|
4
|
+
data.tar.gz: adac66edc9ddf17883734c6908b1cce46cbac8b932702a7c3f31573b0ad38b13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea30f0006b6dff8684c3d46381d65ddfc00d3a481fbcea3489f844c7bb2c687b065e618114af8cd4392c63d770fcf1ad1ea86aad1305a5c8fca4f95ba58d7150
|
7
|
+
data.tar.gz: e67ea8cd72e9947862bdd58230aecea038e311a14ecb081f65545003f2fb3d7924c680c55a4d34a1711492f9509a2da6c368d1c93689c7b9f92f2a91e8faf267
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -86,6 +86,10 @@ task = story.tasks.first # Get
|
|
86
86
|
task.complete = true
|
87
87
|
task.save # Mark a task complete
|
88
88
|
|
89
|
+
review = story.reviews.first # Mark a review as complete
|
90
|
+
review.status = 'pass'
|
91
|
+
review.save
|
92
|
+
|
89
93
|
epics = project.epics # Get all epics for a project
|
90
94
|
epic = epics.first
|
91
95
|
label = epic.label # Get an epic's label
|
data/lib/tracker_api.rb
CHANGED
@@ -38,8 +38,10 @@ module TrackerApi
|
|
38
38
|
|
39
39
|
module Endpoints
|
40
40
|
autoload :Activity, 'tracker_api/endpoints/activity'
|
41
|
+
autoload :Blockers, 'tracker_api/endpoints/blockers'
|
41
42
|
autoload :Epic, 'tracker_api/endpoints/epic'
|
42
43
|
autoload :Epics, 'tracker_api/endpoints/epics'
|
44
|
+
autoload :Iteration, 'tracker_api/endpoints/iteration'
|
43
45
|
autoload :Iterations, 'tracker_api/endpoints/iterations'
|
44
46
|
autoload :Labels, 'tracker_api/endpoints/labels'
|
45
47
|
autoload :Me, 'tracker_api/endpoints/me'
|
@@ -62,6 +64,10 @@ module TrackerApi
|
|
62
64
|
autoload :StoryTransitions, 'tracker_api/endpoints/story_transitions'
|
63
65
|
autoload :Attachment, 'tracker_api/endpoints/attachment'
|
64
66
|
autoload :Attachments, 'tracker_api/endpoints/attachments'
|
67
|
+
autoload :Releases, 'tracker_api/endpoints/releases'
|
68
|
+
autoload :Release, 'tracker_api/endpoints/release'
|
69
|
+
autoload :Review, 'tracker_api/endpoints/review'
|
70
|
+
autoload :Reviews, 'tracker_api/endpoints/reviews'
|
65
71
|
end
|
66
72
|
|
67
73
|
module Resources
|
@@ -71,6 +77,7 @@ module TrackerApi
|
|
71
77
|
end
|
72
78
|
autoload :Activity, 'tracker_api/resources/activity'
|
73
79
|
autoload :Account, 'tracker_api/resources/account'
|
80
|
+
autoload :Blocker, 'tracker_api/resources/blocker'
|
74
81
|
autoload :Change, 'tracker_api/resources/change'
|
75
82
|
autoload :Epic, 'tracker_api/resources/epic'
|
76
83
|
autoload :EpicsSearchResult, 'tracker_api/resources/epics_search_result'
|
@@ -93,5 +100,10 @@ module TrackerApi
|
|
93
100
|
autoload :Webhook, 'tracker_api/resources/webhook'
|
94
101
|
autoload :StoryTransition, 'tracker_api/resources/story_transition'
|
95
102
|
autoload :FileAttachment, 'tracker_api/resources/file_attachment'
|
103
|
+
autoload :Release, 'tracker_api/resources/release'
|
104
|
+
autoload :CycleTimeDetails, 'tracker_api/resources/cycle_time_details'
|
105
|
+
autoload :DailyHistoryContainer, 'tracker_api/resources/daily_history_container'
|
106
|
+
autoload :Review, 'tracker_api/resources/review'
|
107
|
+
autoload :ReviewType, 'tracker_api/resources/review_type'
|
96
108
|
end
|
97
109
|
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
|
@@ -190,7 +190,8 @@ module TrackerApi
|
|
190
190
|
opts[:params] = options[:params] || {}
|
191
191
|
opts[:token] = options[:token] || @token
|
192
192
|
headers = { 'User-Agent' => USER_AGENT,
|
193
|
-
'X-TrackerToken' => opts.fetch(:token)
|
193
|
+
'X-TrackerToken' => opts.fetch(:token),
|
194
|
+
'Accept' => 'application/json' }.merge(options.fetch(:headers, {}))
|
194
195
|
|
195
196
|
CONVENIENCE_HEADERS.each do |h|
|
196
197
|
if header = options[h]
|
@@ -222,11 +223,12 @@ module TrackerApi
|
|
222
223
|
req.body = body
|
223
224
|
end
|
224
225
|
response
|
225
|
-
rescue Faraday::
|
226
|
-
|
226
|
+
rescue Faraday::ClientError, Faraday::ServerError => e
|
227
|
+
status_code = e.response[:status]
|
228
|
+
case status_code
|
227
229
|
when 400..499 then raise TrackerApi::Errors::ClientError.new(e)
|
228
230
|
when 500..599 then raise TrackerApi::Errors::ServerError.new(e)
|
229
|
-
else raise "Expected 4xx or 5xx HTTP status code"
|
231
|
+
else raise "Expected 4xx or 5xx HTTP status code; got #{status_code} instead."
|
230
232
|
end
|
231
233
|
end
|
232
234
|
|
@@ -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
|
@@ -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 Review
|
4
|
+
attr_accessor :client
|
5
|
+
|
6
|
+
def initialize(client)
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
def update(review, params = {})
|
11
|
+
raise ArgumentError, 'Valid review required to update.' unless review.instance_of?(Resources::Review)
|
12
|
+
|
13
|
+
data = client.put("/projects/#{review.project_id}/stories/#{review.story_id}/reviews/#{review.id}", params: params).body
|
14
|
+
|
15
|
+
review.attributes = data
|
16
|
+
review.clean!
|
17
|
+
review
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
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
|
data/lib/tracker_api/error.rb
CHANGED
@@ -5,14 +5,24 @@ module TrackerApi
|
|
5
5
|
def initialize(wrapped_exception)
|
6
6
|
@wrapped_exception = wrapped_exception
|
7
7
|
@response = wrapped_exception.response
|
8
|
-
message = if wrapped_exception.is_a?(Faraday::
|
8
|
+
message = if wrapped_exception.is_a?(Faraday::ParsingError)
|
9
9
|
wrapped_exception.message
|
10
|
-
elsif
|
10
|
+
elsif faraday_response_error?(wrapped_exception)
|
11
11
|
wrapped_exception.response.inspect
|
12
12
|
else
|
13
13
|
wrapped_exception.instance_variable_get(:@wrapped_exception).inspect
|
14
14
|
end
|
15
15
|
super(message)
|
16
16
|
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# faraday 16.0 re-organized their errors. The errors we're interested in,
|
21
|
+
# Faraday::ClientError before 16.0 and Faraday::ServerError introduced in
|
22
|
+
# 16.0, are represented by this conditional.
|
23
|
+
def faraday_response_error?(wrapped_exception)
|
24
|
+
wrapped_exception.is_a?(Faraday::Error) &&
|
25
|
+
wrapped_exception.respond_to?(:response)
|
26
|
+
end
|
17
27
|
end
|
18
28
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module TrackerApi
|
2
|
+
module Resources
|
3
|
+
class Blocker
|
4
|
+
include Shared::Base
|
5
|
+
|
6
|
+
attribute :client
|
7
|
+
attribute :project_id, Integer
|
8
|
+
|
9
|
+
attribute :story_id, Integer
|
10
|
+
attribute :person_id, Integer
|
11
|
+
attribute :description, String
|
12
|
+
attribute :resolved, Boolean
|
13
|
+
attribute :created_at, DateTime
|
14
|
+
attribute :updated_at, DateTime
|
15
|
+
attribute :kind, String
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module TrackerApi
|
2
|
+
module Resources
|
3
|
+
class CycleTimeDetails
|
4
|
+
include Shared::Base
|
5
|
+
|
6
|
+
attribute :project_id, Integer
|
7
|
+
attribute :iteration_number, Integer
|
8
|
+
attribute :total_cycle_time, Integer
|
9
|
+
attribute :started_time, Integer
|
10
|
+
attribute :started_count, Integer
|
11
|
+
attribute :finished_time, Integer
|
12
|
+
attribute :finished_count, Integer
|
13
|
+
attribute :delivered_time, Integer
|
14
|
+
attribute :delivered_count, Integer
|
15
|
+
attribute :rejected_time, Integer
|
16
|
+
attribute :rejected_count, Integer
|
17
|
+
attribute :story_id, Integer
|
18
|
+
attribute :kind, String
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module TrackerApi
|
2
|
+
module Resources
|
3
|
+
class DailyHistoryContainer
|
4
|
+
include Shared::Base
|
5
|
+
|
6
|
+
attribute :project_id, Integer
|
7
|
+
attribute :iteration_number, Integer
|
8
|
+
attribute :header, [String]
|
9
|
+
attribute :data, [Enumerable]
|
10
|
+
attribute :kind, String
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -24,6 +24,20 @@ module TrackerApi
|
|
24
24
|
def stories=(data)
|
25
25
|
super.each { |s| s.client = client }
|
26
26
|
end
|
27
|
+
|
28
|
+
# Provides a list of all the cycle_time_details of each story in the iteration.
|
29
|
+
#
|
30
|
+
# @return [Array[CycleTimeDetails]] array of cycle_time_details of iterations in this project
|
31
|
+
def cycle_time_details
|
32
|
+
Endpoints::Iteration.new(client).get_analytics_cycle_time_details(project_id, number)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns per day information of story points and counts by state for the given iteration.
|
36
|
+
#
|
37
|
+
# @return [DailyHistoryContainer]
|
38
|
+
def get_history
|
39
|
+
Endpoints::Iteration.new(client).get_history(project_id, number)
|
40
|
+
end
|
27
41
|
end
|
28
42
|
end
|
29
43
|
end
|
@@ -131,6 +131,19 @@ module TrackerApi
|
|
131
131
|
Endpoints::Stories.new(client).get(id, params)
|
132
132
|
end
|
133
133
|
|
134
|
+
# Provides a list of all the releases in the project.
|
135
|
+
#
|
136
|
+
# @param [Hash] params
|
137
|
+
# @option params [String] :with_state A release's current_state which all returned releases must match.
|
138
|
+
# Valid enumeration values: accepted, delivered, finished, started, rejected, unstarted, unscheduled
|
139
|
+
# @option params [Integer] :offset With the first release in your priority list as 0,
|
140
|
+
# the index of the first release you want returned.
|
141
|
+
# @option params [Integer] :limit The number of releases you want returned.
|
142
|
+
# @return [Array[Release]] releases associated with this project
|
143
|
+
def releases(params={})
|
144
|
+
Endpoints::Releases.new(client).get(id, params)
|
145
|
+
end
|
146
|
+
|
134
147
|
# Provides a list of all the memberships in the project.
|
135
148
|
#
|
136
149
|
# @param [Hash] params
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module TrackerApi
|
2
|
+
module Resources
|
3
|
+
class Release
|
4
|
+
include Shared::Base
|
5
|
+
|
6
|
+
attribute :client
|
7
|
+
|
8
|
+
attribute :project_id, Integer
|
9
|
+
attribute :name, String
|
10
|
+
attribute :description, String
|
11
|
+
attribute :current_state, String # (accepted, delivered, finished, started, rejected, planned, unstarted, unscheduled)
|
12
|
+
attribute :accepted_at, DateTime
|
13
|
+
attribute :deadline, DateTime
|
14
|
+
attribute :labels, [Label]
|
15
|
+
attribute :created_at, DateTime
|
16
|
+
attribute :updated_at, DateTime
|
17
|
+
attribute :url, String
|
18
|
+
attribute :kind, String
|
19
|
+
|
20
|
+
# Provides a list of all the stories in the release.
|
21
|
+
#
|
22
|
+
# @param [Hash] params
|
23
|
+
# @return [Array[Story]] stories of this release
|
24
|
+
def stories(params={})
|
25
|
+
Endpoints::Stories.new(client).get_release(project_id, id, params)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|