tracker_api 0.2.10 → 0.2.11
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/README.md +3 -1
- data/lib/tracker_api/client.rb +4 -1
- data/lib/tracker_api/endpoints/activity.rb +3 -3
- data/lib/tracker_api/endpoints/comments.rb +1 -1
- data/lib/tracker_api/endpoints/epic.rb +15 -1
- data/lib/tracker_api/endpoints/epics.rb +1 -1
- data/lib/tracker_api/endpoints/iterations.rb +1 -1
- data/lib/tracker_api/endpoints/labels.rb +1 -1
- data/lib/tracker_api/endpoints/memberships.rb +1 -1
- data/lib/tracker_api/endpoints/notifications.rb +1 -1
- data/lib/tracker_api/endpoints/projects.rb +1 -1
- data/lib/tracker_api/endpoints/stories.rb +1 -1
- data/lib/tracker_api/endpoints/story_owners.rb +20 -0
- data/lib/tracker_api/endpoints/tasks.rb +1 -1
- data/lib/tracker_api/resources/account.rb +1 -1
- data/lib/tracker_api/resources/activity.rb +4 -5
- data/lib/tracker_api/resources/change.rb +1 -1
- data/lib/tracker_api/resources/comment.rb +1 -1
- data/lib/tracker_api/resources/epic.rb +24 -2
- data/lib/tracker_api/resources/iteration.rb +1 -2
- data/lib/tracker_api/resources/label.rb +1 -1
- data/lib/tracker_api/resources/me.rb +3 -3
- data/lib/tracker_api/resources/membership_summary.rb +1 -1
- data/lib/tracker_api/resources/notification.rb +4 -4
- data/lib/tracker_api/resources/person.rb +1 -1
- data/lib/tracker_api/resources/primary_resource.rb +1 -1
- data/lib/tracker_api/resources/project.rb +21 -5
- data/lib/tracker_api/resources/project_membership.rb +2 -2
- data/lib/tracker_api/resources/shared/has_id.rb +18 -0
- data/lib/tracker_api/resources/story.rb +22 -8
- data/lib/tracker_api/resources/task.rb +1 -1
- data/lib/tracker_api/version.rb +1 -1
- data/lib/tracker_api.rb +9 -2
- data/test/minitest_helper.rb +1 -0
- data/test/story_test.rb +88 -47
- data/test/vcr/cassettes/get_owners_for_story.json +1 -0
- data/test/vcr/cassettes/get_story_owners.json +1 -0
- data/test/vcr/cassettes/get_story_with_owners.json +1 -0
- metadata +10 -3
- data/lib/tracker_api/resources/base.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4cba526663ee9306a7f26b12aa8f9f0c574b935
|
4
|
+
data.tar.gz: d91cb8b54927afb96dfb2ffd266a21fe9e4732fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a7784c955bea7296f2f92903c5722d114d46895935acb4d8f83519b1fd885803cf4be195cfc0835966a57ea745b4b8fbe295dd0d72bb985e66bd8c17f4bc9b72
|
7
|
+
data.tar.gz: 3fc7c32d7be48c0eaec816b99698ffb7f9ca7d12290dc68aca563ae90bc1a2f1b36702a77fb4be687beaf38ffa1a01fbbbde44f6ef6ebe5585861b1d3897d53f
|
data/README.md
CHANGED
@@ -53,7 +53,7 @@ story.activity # Get
|
|
53
53
|
|
54
54
|
story.name = 'Save the Ewoks' # Update a single story attribute
|
55
55
|
story.attributes = { name: 'Save the Ewoks', description: '...' } # Update multiple story attributes
|
56
|
-
story.labels << Label.new(name: 'Endor')
|
56
|
+
story.labels << TrackerApi::Resources::Label.new(name: 'Endor') # Add a new label to an existing story
|
57
57
|
story.save # Save changes made to a story
|
58
58
|
|
59
59
|
epics = project.epics # Get all epics for a project
|
@@ -71,6 +71,8 @@ client = TrackerApi::Client.new(token: 'my-api-token') # Crea
|
|
71
71
|
client.project(project_id, fields: ':default,labels(name)') # Eagerly get labels with a project
|
72
72
|
client.project(project_id, fields: ':default,epics') # Eagerly get epics with a project
|
73
73
|
client.project(project_id).stories(fields: ':default,tasks') # Eagerly get stories with tasks
|
74
|
+
client.project.stories(fields: ':default,comments(:default,person)') # Eagerly get stories with comments and the person that made the comment
|
75
|
+
story.comments(fields: ':default,person') # Eagerly get comments and the person that made the comment for a story
|
74
76
|
```
|
75
77
|
|
76
78
|
## TODO
|
data/lib/tracker_api/client.rb
CHANGED
@@ -20,7 +20,7 @@ module TrackerApi
|
|
20
20
|
#
|
21
21
|
# @example Creating a Client
|
22
22
|
# Client.new token: 'my-super-special-token'
|
23
|
-
def initialize(options={})
|
23
|
+
def initialize(options={}, &block)
|
24
24
|
url = options.fetch(:url, 'https://www.pivotaltracker.com')
|
25
25
|
@url = Addressable::URI.parse(url).to_s
|
26
26
|
@api_version = options.fetch(:api_version, '/services/v5')
|
@@ -31,6 +31,8 @@ module TrackerApi
|
|
31
31
|
@token = options[:token]
|
32
32
|
raise 'Missing required options: :token' unless @token
|
33
33
|
|
34
|
+
@faraday_block = block if block_given?
|
35
|
+
|
34
36
|
@connection = Faraday.new({ url: @url }.merge(connection_options)) do |builder|
|
35
37
|
# response
|
36
38
|
builder.use Faraday::Response::RaiseError
|
@@ -41,6 +43,7 @@ module TrackerApi
|
|
41
43
|
builder.request :json
|
42
44
|
|
43
45
|
builder.use TrackerApi::Logger, @logger
|
46
|
+
@faraday_block.call(builder) if @faraday_block
|
44
47
|
builder.adapter adapter
|
45
48
|
end
|
46
49
|
end
|
@@ -9,7 +9,7 @@ module TrackerApi
|
|
9
9
|
|
10
10
|
def get(params={})
|
11
11
|
data = client.paginate("/my/activity", params: params)
|
12
|
-
raise
|
12
|
+
raise Errors::UnexpectedData, 'Array of activities expected' unless data.is_a? Array
|
13
13
|
|
14
14
|
data.map do |activity|
|
15
15
|
Resources::Activity.new({ client: client }.merge(activity))
|
@@ -18,7 +18,7 @@ module TrackerApi
|
|
18
18
|
|
19
19
|
def get_project(project_id, params={})
|
20
20
|
data = client.paginate("/projects/#{project_id}/activity", params: params)
|
21
|
-
raise
|
21
|
+
raise Errors::UnexpectedData, 'Array of activities expected' unless data.is_a? Array
|
22
22
|
|
23
23
|
data.map do |activity|
|
24
24
|
Resources::Activity.new({ client: client }.merge(activity))
|
@@ -27,7 +27,7 @@ module TrackerApi
|
|
27
27
|
|
28
28
|
def get_story(project_id, story_id, params={})
|
29
29
|
data = client.paginate("/projects/#{project_id}/stories/#{story_id}/activity", params: params)
|
30
|
-
raise
|
30
|
+
raise Errors::UnexpectedData, 'Array of activities expected' unless data.is_a? Array
|
31
31
|
|
32
32
|
data.map do |activity|
|
33
33
|
Resources::Activity.new({ client: client }.merge(activity))
|
@@ -9,7 +9,7 @@ module TrackerApi
|
|
9
9
|
|
10
10
|
def get(project_id, story_id, params={})
|
11
11
|
data = client.paginate("/projects/#{project_id}/stories/#{story_id}/comments", params: params)
|
12
|
-
raise
|
12
|
+
raise Errors::UnexpectedData, 'Array of comments expected' unless data.is_a? Array
|
13
13
|
|
14
14
|
data.map do |comment|
|
15
15
|
Resources::Comment.new({ story_id: story_id }.merge(comment))
|
@@ -10,7 +10,21 @@ module TrackerApi
|
|
10
10
|
def get(project_id, id, params={})
|
11
11
|
data = client.get("/projects/#{project_id}/epics/#{id}", params: params).body
|
12
12
|
|
13
|
-
Resources::Epic.new({ project_id: project_id }.merge(data))
|
13
|
+
Resources::Epic.new({ client: client, project_id: project_id }.merge(data))
|
14
|
+
end
|
15
|
+
|
16
|
+
def create(project_id, params={})
|
17
|
+
data = client.post("/projects/#{project_id}/epics", params: params).body
|
18
|
+
|
19
|
+
Resources::Epic.new({ client: client }.merge(data))
|
20
|
+
end
|
21
|
+
|
22
|
+
def update(epic, params={})
|
23
|
+
raise ArgumentError, 'Valid epic required to update.' unless epic.instance_of?(Resources::Epic)
|
24
|
+
|
25
|
+
data = client.put("/projects/#{epic.project_id}/epics/#{epic.id}", params: params).body
|
26
|
+
|
27
|
+
epic.attributes = data
|
14
28
|
end
|
15
29
|
end
|
16
30
|
end
|
@@ -9,7 +9,7 @@ module TrackerApi
|
|
9
9
|
|
10
10
|
def get(project_id, params={})
|
11
11
|
data = client.paginate("/projects/#{project_id}/epics", params: params)
|
12
|
-
raise
|
12
|
+
raise Errors::UnexpectedData, 'Array of epics expected' unless data.is_a? Array
|
13
13
|
|
14
14
|
data.map do |epic|
|
15
15
|
Resources::Epic.new({ project_id: project_id }.merge(epic))
|
@@ -9,7 +9,7 @@ module TrackerApi
|
|
9
9
|
|
10
10
|
def get(project_id, params={})
|
11
11
|
data = client.paginate("/projects/#{project_id}/iterations", params: params)
|
12
|
-
raise
|
12
|
+
raise Errors::UnexpectedData, 'Array of iterations expected' unless data.is_a? Array
|
13
13
|
|
14
14
|
data.map do |iteration|
|
15
15
|
Resources::Iteration.new({ client: client, project_id: project_id }.merge(iteration))
|
@@ -9,7 +9,7 @@ module TrackerApi
|
|
9
9
|
|
10
10
|
def get(project_id, params={})
|
11
11
|
data = client.paginate("/projects/#{project_id}/labels", params: params)
|
12
|
-
raise
|
12
|
+
raise Errors::UnexpectedData, 'Array of labels expected' unless data.is_a? Array
|
13
13
|
|
14
14
|
data.map do |label|
|
15
15
|
Resources::Label.new({ project_id: project_id }.merge(label))
|
@@ -9,7 +9,7 @@ module TrackerApi
|
|
9
9
|
|
10
10
|
def get(project_id, params={})
|
11
11
|
data = client.paginate("/projects/#{project_id}/memberships", params: params)
|
12
|
-
raise
|
12
|
+
raise Errors::UnexpectedData, 'Array of memberships expected' unless data.is_a? Array
|
13
13
|
|
14
14
|
data.map do |membership|
|
15
15
|
Resources::ProjectMembership.new({ project_id: project_id }.merge(membership))
|
@@ -9,7 +9,7 @@ module TrackerApi
|
|
9
9
|
|
10
10
|
def get(params={})
|
11
11
|
data = client.paginate('/my/notifications', params: params)
|
12
|
-
raise
|
12
|
+
raise Errors::UnexpectedData, 'Array of notifications expected' unless data.is_a? Array
|
13
13
|
|
14
14
|
data.map do |notification|
|
15
15
|
Resources::Notification.new({ client: client }.merge(notification))
|
@@ -9,7 +9,7 @@ module TrackerApi
|
|
9
9
|
|
10
10
|
def get(params={})
|
11
11
|
data = client.paginate('/projects', params: params)
|
12
|
-
raise
|
12
|
+
raise Errors::UnexpectedData, 'Array of projects expected' unless data.is_a? Array
|
13
13
|
|
14
14
|
data.map { |project| Resources::Project.new({ client: client }.merge(project)) }
|
15
15
|
end
|
@@ -9,7 +9,7 @@ module TrackerApi
|
|
9
9
|
|
10
10
|
def get(project_id, params={})
|
11
11
|
data = client.paginate("/projects/#{project_id}/stories", params: params)
|
12
|
-
raise
|
12
|
+
raise Errors::UnexpectedData, 'Array of stories expected' unless data.is_a? Array
|
13
13
|
|
14
14
|
data.map do |story|
|
15
15
|
Resources::Story.new({ client: client, project_id: project_id }.merge(story))
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module TrackerApi
|
2
|
+
module Endpoints
|
3
|
+
class StoryOwners
|
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.paginate("/projects/#{project_id}/stories/#{story_id}/owners", params: params)
|
12
|
+
raise Errors::UnexpectedData, 'Array of comments expected' unless data.is_a? Array
|
13
|
+
|
14
|
+
data.map do |owner|
|
15
|
+
Resources::Person.new({ story_id: story_id }.merge(owner))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -9,7 +9,7 @@ module TrackerApi
|
|
9
9
|
|
10
10
|
def get(project_id, story_id, params={})
|
11
11
|
data = client.paginate("/projects/#{project_id}/stories/#{story_id}/tasks", params: params)
|
12
|
-
raise
|
12
|
+
raise Errors::UnexpectedData, 'Array of tasks expected' unless data.is_a? Array
|
13
13
|
|
14
14
|
data.map do |task|
|
15
15
|
Resources::Task.new({ story_id: story_id }.merge(task))
|
@@ -2,7 +2,6 @@ module TrackerApi
|
|
2
2
|
module Resources
|
3
3
|
class Activity
|
4
4
|
include Virtus.model
|
5
|
-
|
6
5
|
include Equalizer.new(:guid)
|
7
6
|
|
8
7
|
attribute :client
|
@@ -12,10 +11,10 @@ module TrackerApi
|
|
12
11
|
attribute :project_version, Integer
|
13
12
|
attribute :message, String
|
14
13
|
attribute :highlight, String
|
15
|
-
attribute :changes, Array[
|
16
|
-
attribute :primary_resources, Array[
|
17
|
-
attribute :project,
|
18
|
-
attribute :performed_by,
|
14
|
+
attribute :changes, Array[Change]
|
15
|
+
attribute :primary_resources, Array[PrimaryResource]
|
16
|
+
attribute :project, Project
|
17
|
+
attribute :performed_by, Person
|
19
18
|
attribute :occurred_at, DateTime
|
20
19
|
|
21
20
|
def project=(data)
|
@@ -1,16 +1,38 @@
|
|
1
1
|
module TrackerApi
|
2
2
|
module Resources
|
3
3
|
class Epic
|
4
|
-
include
|
4
|
+
include Shared::HasId
|
5
5
|
|
6
|
+
attribute :client
|
7
|
+
|
8
|
+
attribute :comment_ids, Array[Integer]
|
9
|
+
attribute :comments, Array[Comment]
|
6
10
|
attribute :created_at, DateTime
|
7
11
|
attribute :description, String
|
12
|
+
attribute :follower_ids, Array[Integer]
|
13
|
+
attribute :followers, Array[Person]
|
8
14
|
attribute :kind, String
|
9
|
-
attribute :label,
|
15
|
+
attribute :label, Label
|
16
|
+
attribute :label_id, Integer
|
10
17
|
attribute :name, String
|
11
18
|
attribute :project_id, Integer
|
12
19
|
attribute :updated_at, DateTime
|
13
20
|
attribute :url, String
|
21
|
+
|
22
|
+
class UpdateRepresenter < Representable::Decorator
|
23
|
+
include Representable::JSON
|
24
|
+
|
25
|
+
property :name
|
26
|
+
property :description
|
27
|
+
property :label, class: Label, decorator: Label::UpdateRepresenter, render_empty: true
|
28
|
+
end
|
29
|
+
|
30
|
+
# Save changes to an existing Epic.
|
31
|
+
def save
|
32
|
+
raise ArgumentError, 'Can not update an epic with an unknown project_id.' if project_id.nil?
|
33
|
+
|
34
|
+
Endpoints::Epic.new(client).update(self, UpdateRepresenter.new(self))
|
35
|
+
end
|
14
36
|
end
|
15
37
|
end
|
16
38
|
end
|
@@ -2,7 +2,6 @@ module TrackerApi
|
|
2
2
|
module Resources
|
3
3
|
class Iteration
|
4
4
|
include Virtus.model
|
5
|
-
|
6
5
|
include Equalizer.new(:number, :project_id)
|
7
6
|
|
8
7
|
attribute :client
|
@@ -14,7 +13,7 @@ module TrackerApi
|
|
14
13
|
attribute :planned, Boolean
|
15
14
|
attribute :project_id, Integer
|
16
15
|
attribute :start, DateTime
|
17
|
-
attribute :stories, [
|
16
|
+
attribute :stories, [Story]
|
18
17
|
attribute :story_ids, [Integer]
|
19
18
|
attribute :team_strength, Float
|
20
19
|
|
@@ -1,16 +1,16 @@
|
|
1
1
|
module TrackerApi
|
2
2
|
module Resources
|
3
3
|
class Me
|
4
|
-
include
|
4
|
+
include Shared::HasId
|
5
5
|
|
6
6
|
attribute :name, String
|
7
7
|
attribute :initials, String
|
8
8
|
attribute :username, String
|
9
|
-
attribute :time_zone,
|
9
|
+
attribute :time_zone, TimeZone
|
10
10
|
attribute :api_token, String
|
11
11
|
attribute :has_google_identity, Boolean
|
12
12
|
attribute :project_ids, Array[Integer]
|
13
|
-
attribute :projects, [
|
13
|
+
attribute :projects, [MembershipSummary]
|
14
14
|
attribute :workspace_ids, Array[Integer]
|
15
15
|
attribute :email, String
|
16
16
|
attribute :receives_in_app_notifications, Boolean
|
@@ -1,15 +1,15 @@
|
|
1
1
|
module TrackerApi
|
2
2
|
module Resources
|
3
3
|
class Notification
|
4
|
-
include
|
4
|
+
include Shared::HasId
|
5
5
|
|
6
6
|
attribute :client
|
7
7
|
|
8
8
|
attribute :message, String
|
9
9
|
attribute :kind, String
|
10
|
-
attribute :project,
|
11
|
-
attribute :story,
|
12
|
-
attribute :performer,
|
10
|
+
attribute :project, Project
|
11
|
+
attribute :story, Story
|
12
|
+
attribute :performer, Person
|
13
13
|
attribute :created_at, DateTime
|
14
14
|
attribute :updated_at, DateTime
|
15
15
|
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module TrackerApi
|
2
2
|
module Resources
|
3
3
|
class Project
|
4
|
-
include
|
4
|
+
include Shared::HasId
|
5
5
|
|
6
6
|
attribute :client
|
7
7
|
|
8
|
-
attribute :account,
|
8
|
+
attribute :account, Account
|
9
9
|
attribute :account_id, Integer
|
10
10
|
attribute :atom_enabled, Boolean
|
11
11
|
attribute :bugs_and_chores_are_estimatable, Boolean
|
@@ -18,13 +18,13 @@ module TrackerApi
|
|
18
18
|
attribute :enable_planned_mode, Boolean
|
19
19
|
attribute :enable_tasks, Boolean
|
20
20
|
attribute :epic_ids, Array[Integer]
|
21
|
-
attribute :epics, Array[
|
21
|
+
attribute :epics, Array[Epic]
|
22
22
|
attribute :has_google_domain, Boolean
|
23
23
|
attribute :initial_velocity, Integer
|
24
24
|
attribute :iteration_length, Integer
|
25
25
|
attribute :kind, String
|
26
26
|
attribute :label_ids, Array[Integer]
|
27
|
-
attribute :labels, Array[
|
27
|
+
attribute :labels, Array[Label]
|
28
28
|
attribute :name, String
|
29
29
|
attribute :number_of_done_iterations_to_show, Integer
|
30
30
|
attribute :point_scale, String
|
@@ -33,7 +33,7 @@ module TrackerApi
|
|
33
33
|
attribute :public, Boolean
|
34
34
|
attribute :start_date, DateTime
|
35
35
|
attribute :start_time, DateTime
|
36
|
-
attribute :time_zone,
|
36
|
+
attribute :time_zone, TimeZone
|
37
37
|
attribute :updated_at, DateTime
|
38
38
|
attribute :velocity_averaged_over, Integer
|
39
39
|
attribute :version, Integer
|
@@ -149,6 +149,22 @@ module TrackerApi
|
|
149
149
|
Endpoints::Story.new(client).create(id, params)
|
150
150
|
end
|
151
151
|
|
152
|
+
# Find a epic by id for the project.
|
153
|
+
#
|
154
|
+
# @param [Fixnum] epic_id id of epic to get
|
155
|
+
# @return [Epic] epic with given id
|
156
|
+
def epic(epic_id, params={})
|
157
|
+
Endpoints::Epic.new(client).get(id, epic_id, params)
|
158
|
+
end
|
159
|
+
|
160
|
+
# Create a new epic in the project.
|
161
|
+
#
|
162
|
+
# @param [Hash] params attributes to create the epic with
|
163
|
+
# @return [epic] newly created Epic
|
164
|
+
def create_epic(params)
|
165
|
+
Endpoints::Epic.new(client).create(id, params)
|
166
|
+
end
|
167
|
+
|
152
168
|
# Add a new membership for the project.
|
153
169
|
#
|
154
170
|
# @param [Hash] params attributes to add a member; must have at least email or user_id
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module TrackerApi
|
2
2
|
module Resources
|
3
3
|
class ProjectMembership
|
4
|
-
include
|
4
|
+
include Shared::HasId
|
5
5
|
|
6
6
|
attribute :person_id, Integer
|
7
7
|
attribute :project_id, Integer
|
@@ -9,7 +9,7 @@ module TrackerApi
|
|
9
9
|
attribute :project_color, String
|
10
10
|
attribute :wants_comment_notification_emails, Boolean
|
11
11
|
attribute :kind, String
|
12
|
-
attribute :person,
|
12
|
+
attribute :person, Person
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'virtus'
|
2
|
+
|
3
|
+
module TrackerApi
|
4
|
+
module Resources
|
5
|
+
module Shared
|
6
|
+
module HasId
|
7
|
+
def self.included(base)
|
8
|
+
base.class_eval do
|
9
|
+
include Virtus.model
|
10
|
+
include Equalizer.new(:id)
|
11
|
+
|
12
|
+
attribute :id, Integer
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
module TrackerApi
|
2
2
|
module Resources
|
3
3
|
class Story
|
4
|
-
include
|
4
|
+
include Shared::HasId
|
5
5
|
|
6
6
|
attribute :client
|
7
7
|
|
8
8
|
attribute :accepted_at, DateTime
|
9
9
|
attribute :comment_ids, Array[Integer]
|
10
|
-
attribute :comments, Array[
|
10
|
+
attribute :comments, Array[Comment], :default => []
|
11
11
|
attribute :created_at, DateTime
|
12
12
|
attribute :current_state, String # (accepted, delivered, finished, started, rejected, planned, unstarted, unscheduled)
|
13
13
|
attribute :deadline, DateTime
|
@@ -15,21 +15,23 @@ module TrackerApi
|
|
15
15
|
attribute :estimate, Float
|
16
16
|
attribute :external_id, String
|
17
17
|
attribute :follower_ids, Array[Integer]
|
18
|
+
attribute :followers, Array[Person]
|
18
19
|
attribute :integration_id, Integer
|
19
20
|
attribute :kind, String
|
20
21
|
attribute :label_ids, Array[Integer]
|
21
|
-
attribute :labels, Array[
|
22
|
+
attribute :labels, Array[Label], :default => []
|
22
23
|
attribute :name, String
|
23
24
|
attribute :owned_by_id, Integer # deprecated!
|
25
|
+
attribute :owned_by, Person
|
24
26
|
attribute :owner_ids, Array[Integer]
|
25
|
-
attribute :owners, Array[
|
27
|
+
attribute :owners, Array[Person], :default => []
|
26
28
|
attribute :planned_iteration_number, Integer
|
27
29
|
attribute :project_id, Integer
|
28
30
|
attribute :requested_by, Person
|
29
31
|
attribute :requested_by_id, Integer
|
30
32
|
attribute :story_type, String # (feature, bug, chore, release)
|
31
33
|
attribute :task_ids, Array[Integer]
|
32
|
-
attribute :tasks, Array[
|
34
|
+
attribute :tasks, Array[Task], :default => []
|
33
35
|
attribute :updated_at, DateTime
|
34
36
|
attribute :url, String
|
35
37
|
|
@@ -47,7 +49,7 @@ module TrackerApi
|
|
47
49
|
property :deadline
|
48
50
|
property :requested_by_id
|
49
51
|
property :owner_ids
|
50
|
-
collection :labels, class:
|
52
|
+
collection :labels, class: Label, decorator: Label::UpdateRepresenter, render_empty: true
|
51
53
|
property :integration_id
|
52
54
|
property :external_id
|
53
55
|
end
|
@@ -70,7 +72,7 @@ module TrackerApi
|
|
70
72
|
# @param [Hash] params
|
71
73
|
# @return [Array[Comment]]
|
72
74
|
def comments(params = {})
|
73
|
-
if
|
75
|
+
if params.blank? && @comments.any?
|
74
76
|
@comments
|
75
77
|
else
|
76
78
|
@comments = Endpoints::Comments.new(client).get(project_id, id, params)
|
@@ -82,13 +84,25 @@ module TrackerApi
|
|
82
84
|
# @param [Hash] params
|
83
85
|
# @return [Array[Task]]
|
84
86
|
def tasks(params = {})
|
85
|
-
if
|
87
|
+
if params.blank? && @tasks.any?
|
86
88
|
@tasks
|
87
89
|
else
|
88
90
|
@tasks = Endpoints::Tasks.new(client).get(project_id, id, params)
|
89
91
|
end
|
90
92
|
end
|
91
93
|
|
94
|
+
# Provides a list of all the owners of the story.
|
95
|
+
#
|
96
|
+
# @param [Hash] params
|
97
|
+
# @return [Array[Person]]
|
98
|
+
def owners(params = {})
|
99
|
+
if params.blank? && @owners.any?
|
100
|
+
@owners
|
101
|
+
else
|
102
|
+
@owners = Endpoints::StoryOwners.new(client).get(project_id, id, params)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
92
106
|
# @param [Hash] params attributes to create the task with
|
93
107
|
# @return [Task] newly created Task
|
94
108
|
def create_task(params)
|
data/lib/tracker_api/version.rb
CHANGED
data/lib/tracker_api.rb
CHANGED
@@ -4,7 +4,11 @@ require 'tracker_api/version'
|
|
4
4
|
require 'virtus'
|
5
5
|
require 'faraday'
|
6
6
|
require 'faraday_middleware'
|
7
|
-
|
7
|
+
if defined?(ActiveSupport)
|
8
|
+
require 'active_support/core_ext/object/blank'
|
9
|
+
else
|
10
|
+
require 'core_ext/object/blank'
|
11
|
+
end
|
8
12
|
require 'equalizer'
|
9
13
|
require 'representable/json'
|
10
14
|
require 'oj'
|
@@ -38,13 +42,16 @@ module TrackerApi
|
|
38
42
|
autoload :Projects, 'tracker_api/endpoints/projects'
|
39
43
|
autoload :Stories, 'tracker_api/endpoints/stories'
|
40
44
|
autoload :Story, 'tracker_api/endpoints/story'
|
45
|
+
autoload :StoryOwners, 'tracker_api/endpoints/story_owners'
|
41
46
|
autoload :Task, 'tracker_api/endpoints/task'
|
42
47
|
autoload :Tasks, 'tracker_api/endpoints/tasks'
|
43
48
|
autoload :Comments, 'tracker_api/endpoints/comments'
|
44
49
|
end
|
45
50
|
|
46
51
|
module Resources
|
47
|
-
|
52
|
+
module Shared
|
53
|
+
autoload :HasId, 'tracker_api/resources/shared/has_id'
|
54
|
+
end
|
48
55
|
autoload :Activity, 'tracker_api/resources/activity'
|
49
56
|
autoload :Account, 'tracker_api/resources/account'
|
50
57
|
autoload :Change, 'tracker_api/resources/change'
|
data/test/minitest_helper.rb
CHANGED
data/test/story_test.rb
CHANGED
@@ -67,71 +67,112 @@ describe TrackerApi::Resources::Story do
|
|
67
67
|
story_a.equal?(story_c).must_equal false
|
68
68
|
end
|
69
69
|
|
70
|
-
describe '.
|
71
|
-
it 'gets all
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
task = tasks.first
|
77
|
-
task.must_be_instance_of TrackerApi::Resources::Task
|
70
|
+
describe '.owners' do
|
71
|
+
it 'gets all owners for this story with eager loading' do
|
72
|
+
skip('Until this is resolved: https://pivotaltracker.zendesk.com/requests/35823')
|
73
|
+
|
74
|
+
story = VCR.use_cassette('get story with owners', record: :new_episodes) do
|
75
|
+
project.story(story_id, fields: ':default,owners')
|
78
76
|
end
|
77
|
+
|
78
|
+
# this should not raise VCR::Errors::UnhandledHTTPRequestError since
|
79
|
+
# it should not be making another HTTP request.
|
80
|
+
owners = story.owners
|
81
|
+
|
82
|
+
owners.wont_be_empty
|
83
|
+
owner = owners.first
|
84
|
+
owner.must_be_instance_of TrackerApi::Resources::Person
|
79
85
|
end
|
80
86
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
87
|
+
it 'gets all owners for this story' do
|
88
|
+
VCR.use_cassette('get story', record: :new_episodes) do
|
89
|
+
story = project.story(story_id)
|
90
|
+
owners = VCR.use_cassette('get owners for story') { story.owners }
|
85
91
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
92
|
+
owners.wont_be_empty
|
93
|
+
owner = owners.first
|
94
|
+
owner.must_be_instance_of TrackerApi::Resources::Person
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '.tasks' do
|
100
|
+
it 'gets all tasks for this story with eager loading' do
|
101
|
+
VCR.use_cassette('get story with tasks', record: :new_episodes) do
|
102
|
+
tasks = project.story(story_id, fields: ':default,tasks').tasks
|
103
|
+
|
104
|
+
tasks.wont_be_empty
|
105
|
+
task = tasks.first
|
106
|
+
task.must_be_instance_of TrackerApi::Resources::Task
|
90
107
|
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'gets all tasks for this story' do
|
111
|
+
VCR.use_cassette('get tasks', record: :new_episodes) do
|
112
|
+
story = project.story(story_id)
|
113
|
+
tasks = VCR.use_cassette('get tasks for story') { story.tasks }
|
114
|
+
|
115
|
+
tasks.wont_be_empty
|
116
|
+
task = tasks.first
|
117
|
+
task.must_be_instance_of TrackerApi::Resources::Task
|
118
|
+
end
|
119
|
+
end
|
91
120
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
end
|
121
|
+
it 'gets all tasks even when the project_id is excluded from the story fields' do
|
122
|
+
VCR.use_cassette('get tasks when stories filtered', record: :new_episodes) do
|
123
|
+
stories = project.stories(with_state: 'unstarted', fields: 'name,story_type')
|
124
|
+
stories.each do |story|
|
125
|
+
tasks = story.tasks
|
126
|
+
unless tasks.empty?
|
127
|
+
task = tasks.first
|
128
|
+
task.must_be_instance_of TrackerApi::Resources::Task
|
101
129
|
end
|
102
130
|
end
|
103
131
|
end
|
132
|
+
end
|
104
133
|
|
105
|
-
|
106
|
-
|
107
|
-
|
134
|
+
it 'can create task' do
|
135
|
+
VCR.use_cassette('create task') do
|
136
|
+
task = project.story(story_id).create_task(description: 'Test task')
|
108
137
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
end
|
138
|
+
task.must_be_instance_of TrackerApi::Resources::Task
|
139
|
+
task.id.wont_be_nil
|
140
|
+
task.id.must_be :>, 0
|
141
|
+
task.description.must_equal 'Test task'
|
114
142
|
end
|
115
143
|
end
|
144
|
+
end
|
116
145
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
146
|
+
describe '.activity' do
|
147
|
+
before do
|
148
|
+
# create some activity
|
149
|
+
story.name = "#{story.name}+"
|
121
150
|
|
122
|
-
|
123
|
-
|
124
|
-
end
|
151
|
+
VCR.use_cassette('update story to create activity', record: :new_episodes) do
|
152
|
+
story.save
|
125
153
|
end
|
154
|
+
end
|
126
155
|
|
127
|
-
|
128
|
-
|
129
|
-
|
156
|
+
it 'gets all the activity for this story' do
|
157
|
+
VCR.use_cassette('get story activity', record: :new_episodes) do
|
158
|
+
activity = story.activity
|
130
159
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
end
|
160
|
+
activity.wont_be_empty
|
161
|
+
event = activity.first
|
162
|
+
event.must_be_instance_of TrackerApi::Resources::Activity
|
135
163
|
end
|
136
164
|
end
|
137
165
|
end
|
166
|
+
|
167
|
+
describe '.owners' do
|
168
|
+
it 'gets all owners of this story' do
|
169
|
+
VCR.use_cassette('get story owners', record: :new_episodes) do
|
170
|
+
owners = story.owners
|
171
|
+
|
172
|
+
owners.wont_be_empty
|
173
|
+
owner = owners.first
|
174
|
+
owner.must_be_instance_of TrackerApi::Resources::Person
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
{"http_interactions":[{"request":{"method":"get","uri":"https://www.pivotaltracker.com/services/v5/projects/1027488/stories/66728004/owners","body":{"encoding":"US-ASCII","string":""},"headers":{"User-Agent":["Ruby/2.1.5 (x86_64-darwin14.0; ruby) TrackerApi/0.2.10 Faraday/0.9.1"],"X-TrackerToken":["d55c3bc1f74346b843ca84ba340b29bf"]}},"response":{"status":{"code":200,"message":null},"headers":{"Content-Type":["application/json; charset=utf-8"],"Status":["200 OK"],"X-Tracker-Project-Version":["78"],"X-UA-Compatible":["IE=Edge,chrome=1"],"ETag":["\"1b3412c670febaa8cc831588a4b38288\""],"Cache-Control":["max-age=0, private, must-revalidate"],"X-Request-Id":["468eec53ea706a1fdf0b69be835c09f4"],"X-Runtime":["0.057243"],"Date":["Mon, 20 Jul 2015 20:16:28 GMT"],"X-Rack-Cache":["miss"],"X-Powered-By":["Phusion Passenger 4.0.41"],"Server":["nginx/1.6.0 + Phusion Passenger 4.0.41"],"Access-Control-Allow-Origin":["*"],"Access-Control-Allow-Credentials":["false"],"Access-Control-Allow-Methods":["GET, POST, PUT, DELETE, OPTIONS"],"Access-Control-Allow-Headers":["X-TrackerToken,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Tracker-Warn-Unless-Project-Version-Is"],"X-Tracker-Client-Pinger-Interval":["12"]},"body":{"encoding":"UTF-8","string":"[{\"kind\":\"person\",\"id\":1266314,\"name\":\"Tracker API User1\",\"email\":\"forestcarlisle+trackerapi1@gmail.com\",\"initials\":\"TU1\",\"username\":\"trackerapi1\"},{\"kind\":\"person\",\"id\":1266316,\"name\":\"Tracker API User2\",\"email\":\"forestcarlisle+trackerapi2@gmail.com\",\"initials\":\"TU2\",\"username\":\"trackerapi2\"}]"},"http_version":null},"recorded_at":"Mon, 20 Jul 2015 20:16:49 GMT"}],"recorded_with":"VCR 2.9.3"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"http_interactions":[{"request":{"method":"get","uri":"https://www.pivotaltracker.com/services/v5/projects/1027488/stories/66728004/owners","body":{"encoding":"US-ASCII","string":""},"headers":{"User-Agent":["Ruby/2.1.5 (x86_64-darwin14.0; ruby) TrackerApi/0.2.9 Faraday/0.9.1"],"X-TrackerToken":["d55c3bc1f74346b843ca84ba340b29bf"]}},"response":{"status":{"code":200,"message":null},"headers":{"Content-Type":["application/json; charset=utf-8"],"Status":["200 OK"],"X-Tracker-Project-Version":["66"],"X-UA-Compatible":["IE=Edge,chrome=1"],"ETag":["\"2694c3642376e2adeda5f9cea6310da6\""],"Cache-Control":["max-age=0, private, must-revalidate"],"X-Request-Id":["0d0edc87fef723a07ac224c1b7e4ba9f"],"X-Runtime":["0.051762"],"Date":["Wed, 24 Jun 2015 21:06:02 GMT"],"X-Rack-Cache":["miss"],"X-Powered-By":["Phusion Passenger 4.0.41"],"Server":["nginx/1.6.0 + Phusion Passenger 4.0.41"],"Access-Control-Allow-Origin":["*"],"Access-Control-Allow-Credentials":["false"],"Access-Control-Allow-Methods":["GET, POST, PUT, DELETE, OPTIONS"],"Access-Control-Allow-Headers":["X-TrackerToken,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Tracker-Warn-Unless-Project-Version-Is"],"X-Tracker-Client-Pinger-Interval":["12"]},"body":{"encoding":"UTF-8","string":"[{\"kind\":\"person\",\"id\":22778038,\"name\":\"John Smith\",\"email\":\"john.smith@example.org\",\"initials\":\"JS\",\"username\":\"john.smith\"},{\"kind\":\"person\",\"id\":32873326,\"name\":\"Jane Smith\",\"email\":\"jane.smith@example.org\",\"initials\":\"JaS\",\"username\":\"jane.smith\"}]"},"http_version":null},"recorded_at":"Wed, 24 Jun 2015 21:06:11 GMT"}],"recorded_with":"VCR 2.9.3"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"http_interactions":[{"request":{"method":"get","uri":"https://www.pivotaltracker.com/services/v5/projects/1027488/stories/66728004?fields=%3Adefault%2Cowners","body":{"encoding":"US-ASCII","string":""},"headers":{"User-Agent":["Ruby/2.1.5 (x86_64-darwin14.0; ruby) TrackerApi/0.2.10 Faraday/0.9.1"],"X-TrackerToken":["d55c3bc1f74346b843ca84ba340b29bf"]}},"response":{"status":{"code":200,"message":null},"headers":{"Content-Type":["application/json; charset=utf-8"],"Status":["200 OK"],"X-Tracker-Project-Version":["78"],"X-UA-Compatible":["IE=Edge,chrome=1"],"ETag":["\"1f26a282513ccf8b2f5b0e873938e95b\""],"Cache-Control":["max-age=0, private, must-revalidate"],"X-Request-Id":["a4c140d6a71860108446763556b27a88"],"X-Runtime":["0.074538"],"Date":["Mon, 20 Jul 2015 20:12:29 GMT"],"X-Rack-Cache":["miss"],"X-Powered-By":["Phusion Passenger 4.0.41"],"Server":["nginx/1.6.0 + Phusion Passenger 4.0.41"],"Access-Control-Allow-Origin":["*"],"Access-Control-Allow-Credentials":["false"],"Access-Control-Allow-Methods":["GET, POST, PUT, DELETE, OPTIONS"],"Access-Control-Allow-Headers":["X-TrackerToken,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Tracker-Warn-Unless-Project-Version-Is"],"X-Tracker-Client-Pinger-Interval":["12"]},"body":{"encoding":"UTF-8","string":"{\"kind\":\"story\",\"id\":66728004,\"created_at\":\"2014-02-17T00:00:00Z\",\"updated_at\":\"2015-07-02T16:57:53Z\",\"story_type\":\"bug\",\"name\":\"Some product photos not scaled properly when browsing products++\",\"description\":\"+\",\"current_state\":\"started\",\"requested_by_id\":1266314,\"project_id\":1027488,\"url\":\"https://www.pivotaltracker.com/story/show/66728004\",\"owner_ids\":[1266314,1266316],\"owners\":[],\"labels\":[{\"id\":11049868,\"project_id\":1027488,\"kind\":\"label\",\"name\":\"label1\",\"created_at\":\"2015-03-07T12:51:39Z\",\"updated_at\":\"2015-03-07T12:51:39Z\"},{\"id\":11049870,\"project_id\":1027488,\"kind\":\"label\",\"name\":\"label2\",\"created_at\":\"2015-03-07T12:51:39Z\",\"updated_at\":\"2015-03-07T12:51:39Z\"},{\"id\":12049778,\"project_id\":1027488,\"kind\":\"label\",\"name\":\"super-special-label\",\"created_at\":\"2015-06-24T22:46:12Z\",\"updated_at\":\"2015-06-24T22:46:12Z\"}],\"owned_by_id\":1266314}"},"http_version":null},"recorded_at":"Mon, 20 Jul 2015 20:12:49 GMT"}],"recorded_with":"VCR 2.9.3"}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tracker_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Forest Carlisle
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-10-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -236,13 +236,13 @@ files:
|
|
236
236
|
- lib/tracker_api/endpoints/projects.rb
|
237
237
|
- lib/tracker_api/endpoints/stories.rb
|
238
238
|
- lib/tracker_api/endpoints/story.rb
|
239
|
+
- lib/tracker_api/endpoints/story_owners.rb
|
239
240
|
- lib/tracker_api/endpoints/task.rb
|
240
241
|
- lib/tracker_api/endpoints/tasks.rb
|
241
242
|
- lib/tracker_api/error.rb
|
242
243
|
- lib/tracker_api/logger.rb
|
243
244
|
- lib/tracker_api/resources/account.rb
|
244
245
|
- lib/tracker_api/resources/activity.rb
|
245
|
-
- lib/tracker_api/resources/base.rb
|
246
246
|
- lib/tracker_api/resources/change.rb
|
247
247
|
- lib/tracker_api/resources/comment.rb
|
248
248
|
- lib/tracker_api/resources/epic.rb
|
@@ -255,6 +255,7 @@ files:
|
|
255
255
|
- lib/tracker_api/resources/primary_resource.rb
|
256
256
|
- lib/tracker_api/resources/project.rb
|
257
257
|
- lib/tracker_api/resources/project_membership.rb
|
258
|
+
- lib/tracker_api/resources/shared/has_id.rb
|
258
259
|
- lib/tracker_api/resources/story.rb
|
259
260
|
- lib/tracker_api/resources/task.rb
|
260
261
|
- lib/tracker_api/resources/time_zone.rb
|
@@ -280,12 +281,15 @@ files:
|
|
280
281
|
- test/vcr/cassettes/get_labels.json
|
281
282
|
- test/vcr/cassettes/get_me.json
|
282
283
|
- test/vcr/cassettes/get_my_activities.json
|
284
|
+
- test/vcr/cassettes/get_owners_for_story.json
|
283
285
|
- test/vcr/cassettes/get_project.json
|
284
286
|
- test/vcr/cassettes/get_project_activity.json
|
285
287
|
- test/vcr/cassettes/get_project_with_epics.json
|
286
288
|
- test/vcr/cassettes/get_project_with_labels.json
|
287
289
|
- test/vcr/cassettes/get_story.json
|
288
290
|
- test/vcr/cassettes/get_story_activity.json
|
291
|
+
- test/vcr/cassettes/get_story_owners.json
|
292
|
+
- test/vcr/cassettes/get_story_with_owners.json
|
289
293
|
- test/vcr/cassettes/get_story_with_tasks.json
|
290
294
|
- test/vcr/cassettes/get_tasks.json
|
291
295
|
- test/vcr/cassettes/get_tasks_for_story.json
|
@@ -343,12 +347,15 @@ test_files:
|
|
343
347
|
- test/vcr/cassettes/get_labels.json
|
344
348
|
- test/vcr/cassettes/get_me.json
|
345
349
|
- test/vcr/cassettes/get_my_activities.json
|
350
|
+
- test/vcr/cassettes/get_owners_for_story.json
|
346
351
|
- test/vcr/cassettes/get_project.json
|
347
352
|
- test/vcr/cassettes/get_project_activity.json
|
348
353
|
- test/vcr/cassettes/get_project_with_epics.json
|
349
354
|
- test/vcr/cassettes/get_project_with_labels.json
|
350
355
|
- test/vcr/cassettes/get_story.json
|
351
356
|
- test/vcr/cassettes/get_story_activity.json
|
357
|
+
- test/vcr/cassettes/get_story_owners.json
|
358
|
+
- test/vcr/cassettes/get_story_with_owners.json
|
352
359
|
- test/vcr/cassettes/get_story_with_tasks.json
|
353
360
|
- test/vcr/cassettes/get_tasks.json
|
354
361
|
- test/vcr/cassettes/get_tasks_for_story.json
|