pivit 0.1.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.
Files changed (42) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +30 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +94 -0
  6. data/Rakefile +1 -0
  7. data/lib/pivit.rb +20 -0
  8. data/lib/pivit/authentication.rb +22 -0
  9. data/lib/pivit/client.rb +40 -0
  10. data/lib/pivit/client/activity.rb +34 -0
  11. data/lib/pivit/client/iteration.rb +88 -0
  12. data/lib/pivit/client/membership.rb +92 -0
  13. data/lib/pivit/client/note.rb +47 -0
  14. data/lib/pivit/client/project.rb +58 -0
  15. data/lib/pivit/client/story.rb +177 -0
  16. data/lib/pivit/client/task.rb +112 -0
  17. data/lib/pivit/configuration.rb +29 -0
  18. data/lib/pivit/connection.rb +24 -0
  19. data/lib/pivit/error.rb +6 -0
  20. data/lib/pivit/request.rb +56 -0
  21. data/lib/pivit/version.rb +3 -0
  22. data/pivit.gemspec +37 -0
  23. data/spec/fixtures/authentications.yml.sample +11 -0
  24. data/spec/fixtures/stubs/iteration.xml +77 -0
  25. data/spec/fixtures/stubs/membership.xml +15 -0
  26. data/spec/fixtures/stubs/note.xml +7 -0
  27. data/spec/fixtures/stubs/project/project.xml +29 -0
  28. data/spec/fixtures/stubs/story/delete_story.xml +13 -0
  29. data/spec/fixtures/stubs/task.xml +8 -0
  30. data/spec/fixtures/stubs/task_update.xml +8 -0
  31. data/spec/fixtures/test.png +0 -0
  32. data/spec/pivit/client/activity_spec.rb +26 -0
  33. data/spec/pivit/client/iteration_spec.rb +104 -0
  34. data/spec/pivit/client/membership_spec.rb +91 -0
  35. data/spec/pivit/client/note_spec.rb +48 -0
  36. data/spec/pivit/client/project_spec.rb +64 -0
  37. data/spec/pivit/client/story_spec.rb +156 -0
  38. data/spec/pivit/client/task_spec.rb +124 -0
  39. data/spec/pivit/client_spec.rb +47 -0
  40. data/spec/pivit/configuration_spec.rb +29 -0
  41. data/spec/spec_helper.rb +54 -0
  42. metadata +314 -0
@@ -0,0 +1,6 @@
1
+ module Pivit
2
+ class Error < StandardError
3
+ #Raised when there is an error with authentication
4
+ class AuthenticationError < Error; end
5
+ end
6
+ end
@@ -0,0 +1,56 @@
1
+ module Pivit
2
+ module Request
3
+ def get(path, options = {})
4
+ response = request(:get, path, options)
5
+ response.body
6
+ end
7
+
8
+ def post(path, options = {})
9
+ request(:post, path, options).body
10
+ end
11
+
12
+ def put(path, options={})
13
+ request(:put, path, options).body
14
+ end
15
+
16
+ def delete(path, options={})
17
+ request(:delete, path, options).body
18
+ end
19
+
20
+ # Builds the api endpoint to reach the Pivotal Api
21
+ #the api endpoint to reach the Pivotal Api
22
+ #
23
+ # @return [String] Endpoint
24
+ #
25
+ # @author Jason Truluck
26
+ def build_endpoint
27
+ endpoint = ssl || self.api_token.nil? ? "https://" : "http://"
28
+ endpoint << "#{self.username}:#{self.password}@" unless self.authenticated?
29
+ endpoint << "www.pivotaltracker.com/services/v3/"
30
+ self.api_endpoint = endpoint
31
+ end
32
+
33
+ private
34
+ def request(method, path, options = {})
35
+ url = options.delete(:endpoint) || build_endpoint
36
+ payload = options.delete(:payload) || nil
37
+ payload = Faraday::UploadIO.new(payload, "application/octet-stream") unless payload.nil?
38
+
39
+ connection_options = {}.merge!(:url => url)
40
+
41
+ response = connection(connection_options).send(method) do |request|
42
+ case method
43
+ when :get
44
+ request.url(path, options)
45
+ when :post, :put
46
+ request.url(path, options)
47
+ request.body = { :Filedata => payload } unless payload.nil?
48
+ when :delete
49
+ request.url(path, options)
50
+ end
51
+ end
52
+
53
+ response
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,3 @@
1
+ module Pivit
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pivit/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "pivit"
8
+ spec.version = Pivit::VERSION
9
+ spec.authors = ["Jason Truluck"]
10
+ spec.email = ["jason.truluck@gmail.com"]
11
+ spec.description = %q{Pivit is a wrapper for the Pivotal Tracker API}
12
+ spec.summary = spec.description
13
+ spec.homepage = "https://github.com/jasontruluck/pivit"
14
+ spec.license = "MIT"
15
+
16
+ spec.add_dependency "faraday"
17
+ spec.add_dependency "faraday_middleware"
18
+ spec.add_dependency "hashie"
19
+ spec.add_dependency "multi_xml"
20
+ spec.add_development_dependency "rspec"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "vcr"
23
+ spec.add_development_dependency "mocha"
24
+ spec.add_development_dependency "webmock"
25
+ spec.add_development_dependency "simplecov"
26
+ spec.add_development_dependency "capybara"
27
+ spec.add_development_dependency "yard"
28
+ spec.add_development_dependency "redcarpet"
29
+
30
+ spec.files = `git ls-files`.split($/)
31
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
32
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
33
+ spec.require_paths = ["lib"]
34
+
35
+ spec.add_development_dependency "bundler", "~> 1.3"
36
+ spec.add_development_dependency "rake"
37
+ end
@@ -0,0 +1,11 @@
1
+ #spec/fixtures/authentications.yml
2
+ USERNAME: myusername
3
+ PASSWORD: supersecret
4
+ TOKEN: supersecret
5
+ PROJECT: "12345" # ID of a project
6
+ STORY: "12345" # ID of a story
7
+ STORY_B: "12345" # ID of an alternate story
8
+ MEMBERSHIP: "12345" # a id of a membership of a user in your project
9
+ NOTE: "This some note text" # Some test text
10
+ TASK: "12345" # ID of a task within your pivotal tracker project
11
+ FILE: "../../../fixtures/test.png" # File locatin of the image/doc/text you would like to use to test with
@@ -0,0 +1,77 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <iterations type="array">
3
+ <iteration>
4
+ <id type="integer">2</id>
5
+ <number type="integer">2</number>
6
+ <start type="datetime">2013/05/01 00:00:00 EDT</start>
7
+ <finish type="datetime">2013/05/08 00:00:00 EDT</finish>
8
+ <team_strength type="float">1</team_strength>
9
+ <stories type="array">
10
+ <story>
11
+ <id type="integer">48862635</id>
12
+ <project_id type="integer">795721</project_id>
13
+ <story_type>feature</story_type>
14
+ <url>http://www.pivotaltracker.com/story/show/48862635</url>
15
+ <estimate type="integer">2</estimate>
16
+ <current_state>unstarted</current_state>
17
+ <description></description>
18
+ <name>Awesome Test story</name>
19
+ <requested_by>Jason Truluck</requested_by>
20
+ <created_at type="datetime">2013/04/28 00:24:00 UTC</created_at>
21
+ <updated_at type="datetime">2013/04/30 01:21:40 UTC</updated_at>
22
+ </story>
23
+ <story>
24
+ <id type="integer">48860219</id>
25
+ <project_id type="integer">795721</project_id>
26
+ <story_type>feature</story_type>
27
+ <url>http://www.pivotaltracker.com/story/show/48860219</url>
28
+ <estimate type="integer">2</estimate>
29
+ <current_state>unstarted</current_state>
30
+ <description></description>
31
+ <name>Awesome Test story</name>
32
+ <requested_by>Jason Truluck</requested_by>
33
+ <created_at type="datetime">2013/04/27 20:45:48 UTC</created_at>
34
+ <updated_at type="datetime">2013/04/30 01:21:41 UTC</updated_at>
35
+ </story>
36
+ <story>
37
+ <id type="integer">48962157</id>
38
+ <project_id type="integer">795721</project_id>
39
+ <story_type>feature</story_type>
40
+ <url>http://www.pivotaltracker.com/story/show/48962157</url>
41
+ <estimate type="integer">2</estimate>
42
+ <current_state>unstarted</current_state>
43
+ <description></description>
44
+ <name>Awesome Test story</name>
45
+ <requested_by>Jason Truluck</requested_by>
46
+ <created_at type="datetime">2013/04/30 01:18:10 UTC</created_at>
47
+ <updated_at type="datetime">2013/04/30 01:21:44 UTC</updated_at>
48
+ </story>
49
+ <story>
50
+ <id type="integer">48879093</id>
51
+ <project_id type="integer">795721</project_id>
52
+ <story_type>feature</story_type>
53
+ <url>http://www.pivotaltracker.com/story/show/48879093</url>
54
+ <estimate type="integer">2</estimate>
55
+ <current_state>unstarted</current_state>
56
+ <description></description>
57
+ <name>Awesome Test story</name>
58
+ <requested_by>Jason Truluck</requested_by>
59
+ <created_at type="datetime">2013/04/29 00:53:47 UTC</created_at>
60
+ <updated_at type="datetime">2013/04/30 01:21:46 UTC</updated_at>
61
+ </story>
62
+ <story>
63
+ <id type="integer">48877603</id>
64
+ <project_id type="integer">795721</project_id>
65
+ <story_type>feature</story_type>
66
+ <url>http://www.pivotaltracker.com/story/show/48877603</url>
67
+ <estimate type="integer">-1</estimate>
68
+ <current_state>unstarted</current_state>
69
+ <description></description>
70
+ <name>Awesome Test story</name>
71
+ <requested_by>Jason Truluck</requested_by>
72
+ <created_at type="datetime">2013/04/28 22:44:55 UTC</created_at>
73
+ <updated_at type="datetime">2013/04/30 01:21:38 UTC</updated_at>
74
+ </story>
75
+ </stories>
76
+ </iteration>
77
+ </iterations>
@@ -0,0 +1,15 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <membership>
3
+ <id>15007</id>
4
+ <person>
5
+ <email>jadzia@trill.ufp</email>
6
+ <name>Jadzia Dax</name>
7
+ <initials>JD</initials>
8
+ </person>
9
+ <role>Member</role>
10
+ <project>
11
+ <id>1</id>
12
+ <name>Warp Engine Upgrades</name>
13
+ </project>
14
+ </membership>
15
+
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <note>
3
+ <id type="integer">NOTE_ID</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>
@@ -0,0 +1,29 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project>
3
+ <id>27</id>
4
+ <name>Cardassian War Plans</name>
5
+ <iteration_length type="integer">2</iteration_length>
6
+ <week_start_day>Monday</week_start_day>
7
+ <point_scale>0,1,2,3</point_scale>
8
+ <velocity_scheme>Average of 4 iterations</velocity_scheme>
9
+ <initial_velocity>10</initial_velocity>
10
+ <number_of_done_iterations_to_show>12</number_of_done_iterations_to_show>
11
+ <allow_attachments>true</allow_attachments>
12
+ <public>false</public>
13
+ <use_https>true</use_https>
14
+ <bugs_and_chores_are_estimatable>false</bugs_and_chores_are_estimatable>
15
+ <commit_mode>false</commit_mode>
16
+ <memberships type="array">
17
+ <membership>
18
+ <id>1</id>
19
+ <person>
20
+ <email>picard@earth.ufp</email>
21
+ <name>Jean-Luc Picard</name>
22
+ <initials>jlp</initials>
23
+ </person>
24
+ <role>Owner</role>
25
+ </membership>
26
+ </memberships>
27
+ <integrations type="array">
28
+ </integrations>
29
+ </project>
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <story>
3
+ <id type="integer">48859617</id>
4
+ <project_id type="integer">795721</project_id>
5
+ <story_type>feature</story_type>
6
+ <url>https://www.pivotaltracker.com/story/show/48859617</url>
7
+ <estimate type="integer">2</estimate>
8
+ <current_state>started</current_state>
9
+ <description></description>
10
+ <name>Make it so</name>
11
+ <requested_by>Picard</requested_by>
12
+ <created_at type="datetime">2008/12/10 00:00:00 UTC</created_at>
13
+ </story>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <task>
3
+ <id type="integer">14216257</id>
4
+ <description>find shields</description>
5
+ <position>1</position>
6
+ <complete>false</complete>
7
+ <created_at type="datetime">2008/12/10 00:00:00 UTC</created_at>
8
+ </task>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <task>
3
+ <id type="integer">$TASK_ID</id>
4
+ <description>awesome new description</description>
5
+ <position>1</position>
6
+ <complete>false</complete>
7
+ <created_at type="datetime">2008/12/10 00:00:00 UTC</created_at>
8
+ </task>
Binary file
@@ -0,0 +1,26 @@
1
+ require "spec_helper"
2
+
3
+ # Activity Spec
4
+ describe Pivit::Client do
5
+ before do
6
+ Pivit.reset!
7
+ end
8
+
9
+ let!(:pivit) { Pivit::Client.new(:token => ENV["TOKEN"]) }
10
+
11
+ describe ".activity", :vcr => {:cassette_name => "activity/activities"} do
12
+ let(:current_response) { pivit.activity }
13
+
14
+ it "returns an array of activities" do
15
+ current_response.should be_a(Array)
16
+ end
17
+
18
+ it "returns the version" do
19
+ current_response.each{ |x| x.should respond_to(:version) }
20
+ end
21
+
22
+ it "returns the activities" do
23
+ current_response.should_not be_nil
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,104 @@
1
+ require "spec_helper"
2
+
3
+ # Client Spec
4
+ describe Pivit::Client do
5
+ before do
6
+ Pivit.reset!
7
+ end
8
+ let!(:pivit) { Pivit::Client.new(:token => ENV["TOKEN"]) }
9
+
10
+ describe ".iterations", :vcr => {:cassette_name => "iteration/iterations"} do
11
+ let(:current_response) { pivit.iterations(ENV["PROJECT"]) }
12
+
13
+ it "returns a array of projects" do
14
+ current_response.should be_a(Array)
15
+ end
16
+
17
+ it "responds to iteration" do
18
+ current_response.each{ |x| x.should respond_to(:stories) }
19
+ end
20
+
21
+ it "returns the iterations" do
22
+ current_response.should_not be_nil
23
+ end
24
+ end
25
+
26
+ describe ".done_iterations", :type => :webmock do
27
+ let(:current_response) { pivit.done_iterations(ENV["PROJECT"]) }
28
+
29
+ it "returns a array of projects" do
30
+ stub_request(:get, "https://www.pivotaltracker.com/services/v3/projects/795721/iterations/done").
31
+ to_return(:status => 200,
32
+ :body => File.open(File.expand_path("../../../fixtures/stubs/iteration.xml", __FILE__)),
33
+ :headers => {"Accept" => "application/xml", "Content-type" => "application/xml"})
34
+
35
+ current_response.should be_a(Array)
36
+ end
37
+
38
+ it "responds to iteration" do
39
+ stub_request(:get, "https://www.pivotaltracker.com/services/v3/projects/795721/iterations/done").
40
+ to_return(:status => 200,
41
+ :body => File.open(File.expand_path("../../../fixtures/stubs/iteration.xml", __FILE__)),
42
+ :headers => {"Accept" => "application/xml", "Content-type" => "application/xml"})
43
+
44
+ current_response.each{ |x| x.should respond_to(:stories) }
45
+ end
46
+
47
+ it "returns the iterations" do
48
+ stub_request(:get, "https://www.pivotaltracker.com/services/v3/projects/795721/iterations/done").
49
+ to_return(:status => 200,
50
+ :body => File.open(File.expand_path("../../../fixtures/stubs/iteration.xml", __FILE__)),
51
+ :headers => {"Accept" => "application/xml", "Content-type" => "application/xml"})
52
+
53
+ current_response.should_not be_nil
54
+ end
55
+ end
56
+
57
+ describe ".iteration_backlog", :vcr => {:cassette_name => "iteration/iteration_backlog"} do
58
+ let(:current_response) { pivit.iteration_backlog(ENV["PROJECT"]) }
59
+
60
+ it "returns a array of projects" do
61
+ current_response.should be_a(Array)
62
+ end
63
+
64
+ it "responds to iteration" do
65
+ current_response.each{ |x| x.should respond_to(:stories) }
66
+ end
67
+
68
+ it "returns the iterations" do
69
+ current_response.should_not be_nil
70
+ end
71
+ end
72
+
73
+ describe ".iteration_current", :vcr => {:cassette_name => "iteration/iteration_current"} do
74
+ let(:current_response) { pivit.iteration_current(ENV["PROJECT"]) }
75
+
76
+ it "returns a array of projects" do
77
+ current_response.should be_a(Array)
78
+ end
79
+
80
+ it "responds to iteration" do
81
+ current_response.each{ |x| x.should respond_to(:stories) }
82
+ end
83
+
84
+ it "returns the iterations" do
85
+ current_response.should_not be_nil
86
+ end
87
+ end
88
+
89
+ describe ".iteration_current_and_backlog", :vcr => {:cassette_name => "iteration/iteration_current_and_backlog"} do
90
+ let(:current_response) { pivit.iteration_current_and_backlog(ENV["PROJECT"]) }
91
+
92
+ it "returns a array of projects" do
93
+ current_response.should be_a(Array)
94
+ end
95
+
96
+ it "responds to iteration" do
97
+ current_response.each{ |x| x.should respond_to(:stories) }
98
+ end
99
+
100
+ it "returns the iterations" do
101
+ current_response.should_not be_nil
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,91 @@
1
+ require "spec_helper"
2
+
3
+ # Membership Spec
4
+ describe Pivit::Client::Membership do
5
+ before do
6
+ Pivit.reset!
7
+ end
8
+
9
+ let!(:pivit) { Pivit::Client.new(:token=> ENV["TOKEN"]) }
10
+
11
+ describe ".membership", :vcr => {:cassette_name => "membership/membership"} do
12
+ let(:current_response) { pivit.membership(ENV["PROJECT"], ENV["membership"]) }
13
+
14
+ it "should return the membership response" do
15
+ current_response.should_not be_nil
16
+ end
17
+
18
+ it "should return the person of the membership" do
19
+ current_response.should respond_to(:person)
20
+ end
21
+
22
+ it "should return the role of the membership" do
23
+ current_response.should respond_to(:role)
24
+ end
25
+ end
26
+
27
+ describe ".memberships", :vcr => {:cassette_name => "membership/memberships"} do
28
+ let(:current_response) { pivit.memberships(ENV["PROJECT"]) }
29
+
30
+ it "should return an array of memberships" do
31
+ current_response.should be_a(Array)
32
+ current_response.each{ |x| x.should respond_to(:person) }
33
+ end
34
+
35
+ it "should return the memberships" do
36
+ current_response.should_not be_nil
37
+ end
38
+ end
39
+
40
+ describe ".create_membership", :type => :webmock do
41
+ let(:current_response) {
42
+ pivit.create_membership(ENV["PROJECT"], "jason@woofound.com", "Member")
43
+ }
44
+
45
+ it "returns the person of the membership that was created" do
46
+ stub_request(:post, "https://www.pivotaltracker.com/services/v3/projects/795721/memberships?membership%5Bperson%5D%5Bemail%5D=jason@woofound.com&membership%5Brole%5D=Member").
47
+ to_return(:status => 200,
48
+ :body => File.open(File.expand_path("../../../fixtures/stubs/membership.xml", __FILE__)),
49
+ :headers => {'Accept' => 'application/xml', 'Content-type' => 'application/xml',})
50
+ current_response.should respond_to(:person)
51
+ end
52
+
53
+ it "returns the role of the membership that was created" do
54
+ stub_request(:post, "https://www.pivotaltracker.com/services/v3/projects/795721/memberships?membership%5Bperson%5D%5Bemail%5D=jason@woofound.com&membership%5Brole%5D=Member").
55
+ to_return(:status => 200,
56
+ :body => File.open(File.expand_path("../../../fixtures/stubs/membership.xml", __FILE__)),
57
+ :headers => {'Accept' => 'application/xml', 'Content-type' => 'application/xml',})
58
+ current_response.should respond_to(:role)
59
+ end
60
+
61
+ it "should be a hashie" do
62
+ stub_request(:post, "https://www.pivotaltracker.com/services/v3/projects/795721/memberships?membership%5Bperson%5D%5Bemail%5D=jason@woofound.com&membership%5Brole%5D=Member").
63
+ to_return(:status => 200,
64
+ :body => File.open(File.expand_path("../../../fixtures/stubs/membership.xml", __FILE__)),
65
+ :headers => {'Accept' => 'application/xml', 'Content-type' => 'application/xml',})
66
+ current_response.should be_a(Hashie::Mash)
67
+ end
68
+ end
69
+
70
+ describe ".delete_membership", :type => :webmock do
71
+ let(:current_response) { pivit.delete_membership(ENV["PROJECT"], ENV["MEMBERSHIP"]) }
72
+
73
+ it "returns the membership that was deleted" do
74
+ stub_request(:delete, "https://www.pivotaltracker.com/services/v3/projects/795721/memberships/534713").
75
+ to_return(:status => 200,
76
+ :body => File.open(File.expand_path("../../../fixtures/stubs/membership.xml", __FILE__)),
77
+ :headers => {'Accept' => 'application/xml', 'Content-type' => 'application/xml',})
78
+
79
+ current_response.id.should == 15007.to_s
80
+ end
81
+
82
+ it "should be a hashie" do
83
+ stub_request(:delete, "https://www.pivotaltracker.com/services/v3/projects/795721/memberships/534713").
84
+ to_return(:status => 200,
85
+ :body => File.open(File.expand_path("../../../fixtures/stubs/membership.xml", __FILE__)),
86
+ :headers => {'Accept' => 'application/xml', 'Content-type' => 'application/xml',})
87
+
88
+ current_response.should be_a(Hashie::Mash)
89
+ end
90
+ end
91
+ end