pivotal_tracker 0.2.1 → 0.3.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.
- data/README.rdoc +15 -5
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/pivotal_tracker.rb +46 -10
- data/lib/pivotal_tracker/error.rb +2 -1
- data/pivotal_tracker.gemspec +4 -3
- data/spec/fixtures/activities.xml +28 -8
- data/spec/fixtures/note.xml +7 -0
- data/spec/fixtures/project.xml +23 -3
- data/spec/pivotal_tracker_spec.rb +57 -7
- data/spec/spec_helper.rb +3 -3
- metadata +4 -3
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= pivotal_tracker
|
2
2
|
|
3
|
-
This is a simple ruby wrapper for the Pivotal Tracker
|
3
|
+
This is a simple ruby wrapper for the Pivotal Tracker V3 API utilizing HTTParty and Crack::XML.
|
4
4
|
|
5
5
|
== Setup
|
6
6
|
|
@@ -27,8 +27,8 @@ Notice that all data returned is parsed and built into Mash objects/arrays for y
|
|
27
27
|
|
28
28
|
== Currently implemented methods (More to come!)
|
29
29
|
|
30
|
-
* get_all_activities
|
31
|
-
* get_all_project_activities(project_id)
|
30
|
+
* get_all_activities(options = {})
|
31
|
+
* get_all_project_activities(project_id, options = {})
|
32
32
|
* get_all_projects
|
33
33
|
* get_project(project_id)
|
34
34
|
* create_project(name, options = {})
|
@@ -36,8 +36,18 @@ Notice that all data returned is parsed and built into Mash objects/arrays for y
|
|
36
36
|
* get_project_membership(project_id, membership_id)
|
37
37
|
* add_project_membership(project_id, role, email, options = {})
|
38
38
|
* remove_project_membership(project_id, membership_id)
|
39
|
-
* get_all_project_iterations(project_id)
|
40
|
-
* get_all_project_stories(project_id)
|
39
|
+
* get_all_project_iterations(project_id, options = {})
|
40
|
+
* get_all_project_stories(project_id, options = {})
|
41
|
+
* Filter by passing in a filter hash:
|
42
|
+
{:filter => {:type => "bug", :id => "1,2,5"}}
|
43
|
+
* Read more on filtering here: http://www.pivotaltracker.com/help#howcanasearchberefined
|
44
|
+
* add_project_story(project_id, story)
|
45
|
+
* update_project_story(project_id, story_id, story)
|
46
|
+
* delete_project_story(project_id, story_id)
|
47
|
+
* add_project_story_note(project_id, story_id, text)
|
48
|
+
* move_project_story(project_id, story_id, direction, target_story_id)
|
49
|
+
* direction can be either "before" or "after"
|
50
|
+
|
41
51
|
|
42
52
|
== Note on Patches/Pull Requests
|
43
53
|
|
data/Rakefile
CHANGED
@@ -5,7 +5,7 @@ begin
|
|
5
5
|
require 'jeweler'
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "pivotal_tracker"
|
8
|
-
gem.summary = %Q{Ruby wrapper for the Pivotal Tracker
|
8
|
+
gem.summary = %Q{Ruby wrapper for the Pivotal Tracker V3 API}
|
9
9
|
gem.email = "joslyn.esser@gmail.com"
|
10
10
|
gem.homepage = "http://github.com/joslynesser/pivotal_tracker"
|
11
11
|
gem.authors = ["Joslyn Esser"]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/lib/pivotal_tracker.rb
CHANGED
@@ -10,17 +10,17 @@ class PivotalTracker
|
|
10
10
|
def initialize(api_token, options = {})
|
11
11
|
self.class.headers 'X-TrackerToken' => api_token
|
12
12
|
use_ssl = options.delete(:ssl)
|
13
|
-
self.class.base_uri "http#{'s' if use_ssl}://www.pivotaltracker.com/services/
|
13
|
+
self.class.base_uri "http#{'s' if use_ssl}://www.pivotaltracker.com/services/v3"
|
14
14
|
end
|
15
15
|
|
16
|
-
def get_all_activities
|
17
|
-
response = self.class.get("/activities")
|
16
|
+
def get_all_activities(options = {})
|
17
|
+
response = self.class.get("/activities", :query => options)
|
18
18
|
raise_errors(response)
|
19
19
|
parse_response(response, 'activities')
|
20
20
|
end
|
21
21
|
|
22
|
-
def get_all_project_activities(project_id)
|
23
|
-
response = self.class.get("/projects/#{project_id}/activities")
|
22
|
+
def get_all_project_activities(project_id, options = {})
|
23
|
+
response = self.class.get("/projects/#{project_id}/activities", :query => options)
|
24
24
|
raise_errors(response)
|
25
25
|
parse_response(response, 'activities')
|
26
26
|
end
|
@@ -67,17 +67,51 @@ class PivotalTracker
|
|
67
67
|
parse_response(response, 'membership')
|
68
68
|
end
|
69
69
|
|
70
|
-
def get_all_project_iterations(project_id)
|
71
|
-
response = self.class.get("/projects/#{project_id}/iterations")
|
70
|
+
def get_all_project_iterations(project_id, options = {})
|
71
|
+
response = self.class.get("/projects/#{project_id}/iterations", :query => options)
|
72
72
|
raise_errors(response)
|
73
73
|
parse_response(response, 'iterations')
|
74
74
|
end
|
75
75
|
|
76
|
-
def get_all_project_stories(project_id)
|
77
|
-
|
76
|
+
def get_all_project_stories(project_id, options = {})
|
77
|
+
if options[:filter]
|
78
|
+
options[:filter] = options[:filter].inject([]) {|f,(key,value)| f << "#{key}:#{value}"}.join(' ')
|
79
|
+
end
|
80
|
+
|
81
|
+
response = self.class.get("/projects/#{project_id}/stories", :query => options)
|
78
82
|
raise_errors(response)
|
79
83
|
parse_response(response, 'stories')
|
80
84
|
end
|
85
|
+
|
86
|
+
def add_project_story(project_id, story)
|
87
|
+
response = self.class.post("/projects/#{project_id}/stories", :body => {:story => story})
|
88
|
+
raise_errors(response)
|
89
|
+
parse_response(response, 'story')
|
90
|
+
end
|
91
|
+
|
92
|
+
def update_project_story(project_id, story_id, story)
|
93
|
+
response = self.class.put("/projects/#{project_id}/stories/#{story_id}", :body => {:story => story})
|
94
|
+
raise_errors(response)
|
95
|
+
parse_response(response, 'story')
|
96
|
+
end
|
97
|
+
|
98
|
+
def delete_project_story(project_id, story_id)
|
99
|
+
response = self.class.delete("/projects/#{project_id}/stories/#{story_id}")
|
100
|
+
raise_errors(response)
|
101
|
+
parse_response(response, 'story')
|
102
|
+
end
|
103
|
+
|
104
|
+
def add_project_story_note(project_id, story_id, text)
|
105
|
+
response = self.class.post("/projects/#{project_id}/stories/#{story_id}/notes", :body => {:note => {:text => text}})
|
106
|
+
raise_errors(response)
|
107
|
+
parse_response(response, 'note')
|
108
|
+
end
|
109
|
+
|
110
|
+
def move_project_story(project_id, story_id, direction, target_story_id)
|
111
|
+
response = self.class.post("/projects/#{project_id}/stories/#{story_id}/moves", :body => {:move => {:move => direction, :target => target_story_id}})
|
112
|
+
raise_errors(response)
|
113
|
+
parse_response(response, 'story')
|
114
|
+
end
|
81
115
|
|
82
116
|
private
|
83
117
|
|
@@ -91,8 +125,10 @@ class PivotalTracker
|
|
91
125
|
raise PivotalTracker::General, "(#{response.code}): #{response.message}"
|
92
126
|
when 404
|
93
127
|
raise PivotalTracker::ResourceNotFound, "(#{response.code}): #{response.message}"
|
128
|
+
when 422
|
129
|
+
raise PivotalTracker::ResourceInvalid, "(#{response.code}): #{response['errors'].inspect if response['errors']}"
|
94
130
|
when 500
|
95
|
-
raise PivotalTracker::InformPivotal, "Pivotal Tracker had an internal error. Please let them know. (#{response.code}): #{response.message}"
|
131
|
+
raise PivotalTracker::InformPivotal, "Pivotal Tracker had an internal error. Please let them know. (#{response.code}): #{response.message} - #{response['message'] if response}"
|
96
132
|
when 502..503
|
97
133
|
raise PivotalTracker::Unavailable, "(#{response.code}): #{response.message}"
|
98
134
|
end
|
@@ -13,4 +13,5 @@ class PivotalTracker::Unauthorized < PivotalTracker::Error; end
|
|
13
13
|
class PivotalTracker::General < StandardError; end
|
14
14
|
class PivotalTracker::Unavailable < StandardError; end
|
15
15
|
class PivotalTracker::InformPivotal < StandardError; end
|
16
|
-
class PivotalTracker::ResourceNotFound < StandardError; end
|
16
|
+
class PivotalTracker::ResourceNotFound < StandardError; end
|
17
|
+
class PivotalTracker::ResourceInvalid < StandardError; end
|
data/pivotal_tracker.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{pivotal_tracker}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Joslyn Esser"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2010-02-05}
|
13
13
|
s.email = %q{joslyn.esser@gmail.com}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"LICENSE",
|
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
|
|
29
29
|
"spec/fixtures/iterations.xml",
|
30
30
|
"spec/fixtures/membership.xml",
|
31
31
|
"spec/fixtures/memberships.xml",
|
32
|
+
"spec/fixtures/note.xml",
|
32
33
|
"spec/fixtures/project.xml",
|
33
34
|
"spec/fixtures/projects.xml",
|
34
35
|
"spec/fixtures/stories.xml",
|
@@ -41,7 +42,7 @@ Gem::Specification.new do |s|
|
|
41
42
|
s.rdoc_options = ["--charset=UTF-8"]
|
42
43
|
s.require_paths = ["lib"]
|
43
44
|
s.rubygems_version = %q{1.3.5}
|
44
|
-
s.summary = %q{Ruby wrapper for the Pivotal Tracker
|
45
|
+
s.summary = %q{Ruby wrapper for the Pivotal Tracker V3 API}
|
45
46
|
s.test_files = [
|
46
47
|
"spec/pivotal_tracker_spec.rb",
|
47
48
|
"spec/spec_helper.rb"
|
@@ -2,18 +2,38 @@
|
|
2
2
|
<activities type="array">
|
3
3
|
<activity>
|
4
4
|
<id type="integer">1031</id>
|
5
|
-
<
|
6
|
-
<
|
5
|
+
<version type="integer">175</version>
|
6
|
+
<event_type>story_update</event_type>
|
7
|
+
<occurred_at type="datetime">2009/12/14 14:12:09 PST</occurred_at>
|
8
|
+
<author>James Kirk</author>
|
9
|
+
<project_id type="integer">26</project_id>
|
7
10
|
<description>James Kirk accepted "More power to shields"</description>
|
8
|
-
<
|
9
|
-
|
11
|
+
<stories>
|
12
|
+
<story>
|
13
|
+
<id type="integer">109</id>
|
14
|
+
<url>https://www.pivotaltracker.com/services/v3/projects/26/stories/109</url>
|
15
|
+
<lighthouse_id>43</lighthouse_id>
|
16
|
+
<lighthouse_url>http://mylighthouseapp.com/projects/100/tickets/43</lighthouse_url>
|
17
|
+
<accepted_at type="datetime">2009/12/14 22:12:09 UTC</accepted_at>
|
18
|
+
<current_state>accepted</current_state>
|
19
|
+
</story>
|
20
|
+
</stories>
|
10
21
|
</activity>
|
11
22
|
<activity>
|
12
23
|
<id type="integer">1030</id>
|
13
|
-
<
|
14
|
-
<
|
15
|
-
<
|
24
|
+
<version type="integer">175</version>
|
25
|
+
<event_type>story_update</event_type>
|
26
|
+
<occurred_at type="datetime">2009/12/14 14:12:09 PST</occurred_at>
|
16
27
|
<author>Montgomery Scott</author>
|
17
|
-
<
|
28
|
+
<project_id type="integer">28</project_id>
|
29
|
+
<description>Montgomery Scott rejected "Warp speed" with comments: "Warp speed isn't working"</description>
|
30
|
+
<stories>
|
31
|
+
<story>
|
32
|
+
<id type="integer">119</id>
|
33
|
+
<url>https://www.pivotaltracker.com/services/v3/projects/28/stories/119</url>
|
34
|
+
<accepted_at type="datetime">2009/12/14 22:12:09 UTC</accepted_at>
|
35
|
+
<current_state>rejected</current_state>
|
36
|
+
</story>
|
37
|
+
</stories>
|
18
38
|
</activity>
|
19
39
|
</activities>
|
data/spec/fixtures/project.xml
CHANGED
@@ -1,18 +1,38 @@
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
2
2
|
<project>
|
3
|
-
<id>
|
4
|
-
<name>
|
3
|
+
<id>1</id>
|
4
|
+
<name>Sample Project</name>
|
5
5
|
<iteration_length type="integer">2</iteration_length>
|
6
6
|
<week_start_day>Monday</week_start_day>
|
7
7
|
<point_scale>0,1,2,3</point_scale>
|
8
|
+
<account>James Kirks Account</account>
|
8
9
|
<velocity_scheme>Average of 4 iterations</velocity_scheme>
|
10
|
+
<current_velocity>10</current_velocity>
|
9
11
|
<initial_velocity>10</initial_velocity>
|
10
12
|
<number_of_done_iterations_to_show>12</number_of_done_iterations_to_show>
|
13
|
+
<labels>shields,transporter</labels>
|
11
14
|
<allow_attachments>true</allow_attachments>
|
12
15
|
<public>false</public>
|
13
16
|
<use_https>true</use_https>
|
14
17
|
<bugs_and_chores_are_estimatable>false</bugs_and_chores_are_estimatable>
|
15
18
|
<commit_mode>false</commit_mode>
|
19
|
+
<last_activity_at type="datetime">2010/01/16 17:39:10 CST</last_activity_at>
|
16
20
|
<memberships>
|
21
|
+
<membership>
|
22
|
+
<id>1006</id>
|
23
|
+
<person>
|
24
|
+
<email>kirkybaby@earth.ufp</email>
|
25
|
+
<name>James T. Kirk</name>
|
26
|
+
<initials>JTK</initials>
|
27
|
+
</person>
|
28
|
+
<role>Owner</role>
|
29
|
+
</membership>
|
17
30
|
</memberships>
|
18
|
-
|
31
|
+
<integrations>
|
32
|
+
<integration>
|
33
|
+
<id>4532</id>
|
34
|
+
<title>Lighthouse Sample Integration</title>
|
35
|
+
<active type="boolean">true</active>
|
36
|
+
</integration>
|
37
|
+
</integrations>
|
38
|
+
</project>
|
@@ -35,11 +35,23 @@ describe PivotalTracker do
|
|
35
35
|
activities.first.description.should == "James Kirk accepted \"More power to shields\""
|
36
36
|
end
|
37
37
|
|
38
|
+
it "should filter recent activities" do
|
39
|
+
stub_get('/activities?newer_than_version=170', 'activities.xml')
|
40
|
+
activities = @tracker.get_all_activities(:newer_than_version => 170)
|
41
|
+
activities.first.description.should == "James Kirk accepted \"More power to shields\""
|
42
|
+
end
|
43
|
+
|
38
44
|
it "should get all recent activities for a given project" do
|
39
45
|
stub_get('/projects/1/activities', 'activities.xml')
|
40
46
|
activities = @tracker.get_all_project_activities(1)
|
41
47
|
activities.first.description.should == "James Kirk accepted \"More power to shields\""
|
42
48
|
end
|
49
|
+
|
50
|
+
it "should filter recent activities for a given project" do
|
51
|
+
stub_get('/projects/1/activities?limit=50', 'activities.xml')
|
52
|
+
activities = @tracker.get_all_project_activities(1, :limit => 50)
|
53
|
+
activities.first.description.should == "James Kirk accepted \"More power to shields\""
|
54
|
+
end
|
43
55
|
end
|
44
56
|
|
45
57
|
describe "Projects" do
|
@@ -53,13 +65,19 @@ describe PivotalTracker do
|
|
53
65
|
it "should get a project" do
|
54
66
|
stub_get("/projects/27", 'project.xml')
|
55
67
|
project = @tracker.get_project(27)
|
56
|
-
project.name.should == '
|
68
|
+
project.name.should == 'Sample Project'
|
57
69
|
end
|
58
70
|
|
59
71
|
it "should create a project" do
|
60
72
|
stub_post('/projects', 'project.xml')
|
61
73
|
project = @tracker.create_project('Cardassian War Plans')
|
62
|
-
project.name.should == '
|
74
|
+
project.name.should == 'Sample Project'
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should create a project with options" do
|
78
|
+
stub_post('/projects', 'project.xml')
|
79
|
+
project = @tracker.create_project('Cardassian War Plans', :no_owner => true)
|
80
|
+
project.name.should == 'Sample Project'
|
63
81
|
end
|
64
82
|
end
|
65
83
|
|
@@ -101,7 +119,9 @@ describe PivotalTracker do
|
|
101
119
|
end
|
102
120
|
|
103
121
|
it "should get iterations by limit and offset" do
|
104
|
-
|
122
|
+
stub_get('/projects/1/iterations?offset=1&limit=2', 'iterations.xml')
|
123
|
+
iterations = @tracker.get_all_project_iterations(1, :offset => 1, :limit => 2)
|
124
|
+
iterations.first.stories.first.story_type.should == 'feature'
|
105
125
|
end
|
106
126
|
end
|
107
127
|
|
@@ -112,16 +132,46 @@ describe PivotalTracker do
|
|
112
132
|
stories.first.owned_by.should == 'Montgomery Scott'
|
113
133
|
end
|
114
134
|
|
115
|
-
it "should get all stories for a project based on a given filter" do
|
116
|
-
|
135
|
+
it "should get all stories for a project based on a given filter hash" do
|
136
|
+
stub_get("/projects/1/stories\?filter=type%3Afeature", 'stories.xml')
|
137
|
+
stories = @tracker.get_all_project_stories(1, :filter => {:type => 'feature'})
|
138
|
+
stories.first.owned_by.should == 'Montgomery Scott'
|
117
139
|
end
|
118
140
|
|
119
141
|
it "should get all stories for a project paginated by a limit and offset" do
|
120
|
-
|
142
|
+
stub_get("/projects/1/stories\?limit=10&offset=20", 'stories.xml')
|
143
|
+
stories = @tracker.get_all_project_stories(1, :limit => 10, :offset => 20)
|
144
|
+
stories.first.owned_by.should == 'Montgomery Scott'
|
121
145
|
end
|
122
146
|
|
123
147
|
it "should create a new story for a given project" do
|
124
|
-
|
148
|
+
stub_post('/projects/1/stories', 'story.xml')
|
149
|
+
story = @tracker.add_project_story(1, {})
|
150
|
+
story.name.should == 'Fire torpedoes'
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should update an existing story for a given project and story" do
|
154
|
+
stub_put('/projects/1/stories/12', 'story.xml')
|
155
|
+
story = @tracker.update_project_story(1, 12, :name => "Fire torpedoes")
|
156
|
+
story.name.should == 'Fire torpedoes'
|
157
|
+
end
|
158
|
+
|
159
|
+
it "removes an existing story for a given project" do
|
160
|
+
stub_delete('/projects/1/stories/12', 'story.xml')
|
161
|
+
story = @tracker.delete_project_story(1, 12)
|
162
|
+
story.name.should == 'Fire torpedoes'
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should create a new note for a given project and story" do
|
166
|
+
stub_post('/projects/1234/stories/5678/notes', 'note.xml')
|
167
|
+
note = @tracker.add_project_story_note(1234, 5678, 'new note via API')
|
168
|
+
note.text.should == 'new note via API'
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should move a story before or after another story" do
|
172
|
+
stub_post('/projects/1/stories/1234/moves', 'story.xml')
|
173
|
+
story = @tracker.move_project_story(1, 1234, "after", 5678)
|
174
|
+
story.name.should == 'Fire torpedoes'
|
125
175
|
end
|
126
176
|
end
|
127
177
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -9,7 +9,7 @@ require 'fakeweb'
|
|
9
9
|
require 'ruby-debug'
|
10
10
|
|
11
11
|
Spec::Runner.configure do |config|
|
12
|
-
|
12
|
+
config.before(:each) { FakeWeb.clean_registry }
|
13
13
|
end
|
14
14
|
|
15
15
|
FakeWeb.allow_net_connect = false
|
@@ -21,7 +21,7 @@ def fixture_file(filename)
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def pivotal_tracker_url(url)
|
24
|
-
url =~ /^http/ ? url : "http://www.pivotaltracker.com/services/
|
24
|
+
url =~ /^http/ ? url : "http://www.pivotaltracker.com/services/v3#{url}"
|
25
25
|
end
|
26
26
|
|
27
27
|
def stub_get(url, filename, status=nil)
|
@@ -41,4 +41,4 @@ end
|
|
41
41
|
|
42
42
|
def stub_delete(url, filename)
|
43
43
|
FakeWeb.register_uri(:delete, pivotal_tracker_url(url), :body => fixture_file(filename))
|
44
|
-
end
|
44
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pivotal_tracker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joslyn Esser
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-02-05 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -75,6 +75,7 @@ files:
|
|
75
75
|
- spec/fixtures/iterations.xml
|
76
76
|
- spec/fixtures/membership.xml
|
77
77
|
- spec/fixtures/memberships.xml
|
78
|
+
- spec/fixtures/note.xml
|
78
79
|
- spec/fixtures/project.xml
|
79
80
|
- spec/fixtures/projects.xml
|
80
81
|
- spec/fixtures/stories.xml
|
@@ -109,7 +110,7 @@ rubyforge_project:
|
|
109
110
|
rubygems_version: 1.3.5
|
110
111
|
signing_key:
|
111
112
|
specification_version: 3
|
112
|
-
summary: Ruby wrapper for the Pivotal Tracker
|
113
|
+
summary: Ruby wrapper for the Pivotal Tracker V3 API
|
113
114
|
test_files:
|
114
115
|
- spec/pivotal_tracker_spec.rb
|
115
116
|
- spec/spec_helper.rb
|