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.
@@ -1,6 +1,6 @@
1
1
  = pivotal_tracker
2
2
 
3
- This is a simple ruby wrapper for the Pivotal Tracker V2 API utilizing HTTParty and Crack::XML.
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 V2 API}
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.2.1
1
+ 0.3.0
@@ -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/v2"
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
- response = self.class.get("/projects/#{project_id}/stories")
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
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{pivotal_tracker}
8
- s.version = "0.2.1"
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{2009-12-04}
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 V2 API}
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
- <project>Sample Project</project>
6
- <story>More power to shields</story>
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 &quot;More power to shields&quot;</description>
8
- <author>James Kirk </author>
9
- <when>06/01/2009 08:22 AM</when>
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
- <project>Another Sample Project</project>
14
- <story>Warp speed</story>
15
- <description>Montgomery Scott rejected &quot;Warp speend&quot; with comments: &quot;Warp speed isn't working&quot;</description>
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
- <when>06/01/2009 12:22 AM</when>
28
+ <project_id type="integer">28</project_id>
29
+ <description>Montgomery Scott rejected &quot;Warp speed&quot; with comments: &quot;Warp speed isn't working&quot;</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>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <note>
3
+ <id type="integer">42</id>
4
+ <text>new note via API</text>
5
+ <author>Spock (young)</author>
6
+ <noted_at type="datetime">2009/01/16 18:53:51 UTC</noted_at>
7
+ </note>
@@ -1,18 +1,38 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <project>
3
- <id>27</id>
4
- <name>Cardassian War Plans</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
- </project>
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 == 'Cardassian War Plans'
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 == 'Cardassian War Plans'
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
- pending
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
- pending
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
- pending
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
- pending
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
@@ -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/v2#{url}"
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.2.1
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: 2009-12-04 00:00:00 -08:00
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 V2 API
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