pivotal-tracker-api 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cbe2c90c2bba74b1786f6b01037b640aa7bb18cc
4
+ data.tar.gz: 1f8948d45390620446e88181d5fbf88da5747b79
5
+ SHA512:
6
+ metadata.gz: be5c6620c49eede7d9804279c3031ff4636653b4c740cc6613e4f702b5e69db06da77b5cb66a62833adad507978e3955d8954bf00cab521751779b40db5043ee
7
+ data.tar.gz: 4c439b0aad7bf21d998bd770abf2070adfa4041f8a2b5ab60b36e0c35251f4a38bcfbfcf0ba46512437c15f0a783081a093c2242ac79f0488daa67032fdeb5c5
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.idea/.name ADDED
@@ -0,0 +1 @@
1
+ pivotal-tracker-api
data/.idea/.rakeTasks ADDED
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Settings><!--This file was automatically generated by Ruby plugin.
3
+ You are allowed to:
4
+ 1. Remove rake task
5
+ 2. Add existing rake tasks
6
+ To add existing rake tasks automatically delete this file and reload the project.
7
+ --><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Build gem into pkg/" fullCmd="build" taksId="build" /><RakeTask description="Remove any temporary products" fullCmd="clean" taksId="clean" /><RakeTask description="Remove any generated file" fullCmd="clobber" taksId="clobber" /><RakeTask description="Remove RDoc HTML files" fullCmd="clobber_rdoc" taksId="clobber_rdoc" /><RakeTask description="Start IRB with all runtime dependencies loaded" fullCmd="console[script]" taksId="console[script]" /><RakeGroup description="" fullCmd="" taksId="gemcutter"><RakeTask description="Release gem to Gemcutter" fullCmd="gemcutter:release" taksId="release" /></RakeGroup><RakeTask description="Generate and validate gemspec" fullCmd="gemspec" taksId="gemspec" /><RakeGroup description="" fullCmd="" taksId="gemspec"><RakeTask description="Display the gemspec for debugging purposes, as jeweler knows it (not from the filesystem)" fullCmd="gemspec:debug" taksId="debug" /><RakeTask description="Regenerate the gemspec on the filesystem" fullCmd="gemspec:generate" taksId="generate" /><RakeTask description="Regenerate and validate gemspec, and then commits and pushes to git" fullCmd="gemspec:release" taksId="release" /><RakeTask description="Validates the gemspec on the filesystem" fullCmd="gemspec:validate" taksId="validate" /></RakeGroup><RakeGroup description="" fullCmd="" taksId="git"><RakeTask description="Tag and push release to git" fullCmd="git:release" taksId="release" /></RakeGroup><RakeTask description="Build and install gem using `gem install`" fullCmd="install" taksId="install" /><RakeTask description="Build RDoc HTML files" fullCmd="rdoc" taksId="rdoc" /><RakeTask description="Release gem" fullCmd="release" taksId="release" /><RakeTask description="Rebuild RDoc HTML files" fullCmd="rerdoc" taksId="rerdoc" /><RakeTask description="Run tests" fullCmd="test" taksId="test" /><RakeTask description="Displays the current version" fullCmd="version" taksId="version" /><RakeGroup description="" fullCmd="" taksId="version"><RakeGroup description="" fullCmd="" taksId="bump"><RakeTask description="Bump the major version by 1" fullCmd="version:bump:major" taksId="major" /><RakeTask description="Bump the a minor version by 1" fullCmd="version:bump:minor" taksId="minor" /><RakeTask description="Bump the patch version by 1" fullCmd="version:bump:patch" taksId="patch" /></RakeGroup><RakeTask description="Writes out an explicit version" fullCmd="version:write" taksId="write" /></RakeGroup><RakeTask description="" fullCmd="console" taksId="console" /><RakeTask description="" fullCmd="default" taksId="default" /><RakeTask description="" fullCmd="gemspec_required" taksId="gemspec_required" /><RakeTask description="" fullCmd="rdoc/index.html" taksId="rdoc/index.html" /><RakeTask description="" fullCmd="version_required" taksId="version_required" /></RakeGroup></Settings>
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
4
+ </project>
5
+
data/.idea/misc.xml ADDED
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectRootManager" version="2" project-jdk-name="RVM: ruby-2.0.0-p195" project-jdk-type="RUBY_SDK" />
4
+ </project>
5
+
data/.idea/modules.xml ADDED
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/pivotal-tracker-api.iml" filepath="$PROJECT_DIR$/.idea/pivotal-tracker-api.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
9
+
@@ -0,0 +1,53 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="RUBY_MODULE" version="4">
3
+ <component name="FacetManager">
4
+ <facet type="gem" name="Gem">
5
+ <configuration>
6
+ <option name="GEM_APP_ROOT_PATH" value="$MODULE_DIR$" />
7
+ <option name="GEM_APP_TEST_PATH" value="$MODULE_DIR$/test" />
8
+ <option name="GEM_APP_LIB_PATH" value="$MODULE_DIR$/lib" />
9
+ </configuration>
10
+ </facet>
11
+ </component>
12
+ <component name="NewModuleRootManager">
13
+ <content url="file://$MODULE_DIR$">
14
+ <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
15
+ </content>
16
+ <orderEntry type="inheritedJdk" />
17
+ <orderEntry type="sourceFolder" forTests="false" />
18
+ <orderEntry type="library" scope="PROVIDED" name="activesupport (v4.0.0, RVM: ruby-2.0.0-p195) [gem]" level="application" />
19
+ <orderEntry type="library" scope="PROVIDED" name="addressable (v2.3.5, RVM: ruby-2.0.0-p195) [gem]" level="application" />
20
+ <orderEntry type="library" scope="PROVIDED" name="atomic (v1.1.14, RVM: ruby-2.0.0-p195) [gem]" level="application" />
21
+ <orderEntry type="library" scope="PROVIDED" name="builder (v3.2.2, RVM: ruby-2.0.0-p195) [gem]" level="application" />
22
+ <orderEntry type="library" scope="PROVIDED" name="bundler (v1.3.5, RVM: ruby-2.0.0-p195) [gem]" level="application" />
23
+ <orderEntry type="library" scope="PROVIDED" name="faraday (v0.8.8, RVM: ruby-2.0.0-p195) [gem]" level="application" />
24
+ <orderEntry type="library" scope="PROVIDED" name="git (v1.2.6, RVM: ruby-2.0.0-p195) [gem]" level="application" />
25
+ <orderEntry type="library" scope="PROVIDED" name="github_api (v0.10.1, RVM: ruby-2.0.0-p195) [gem]" level="application" />
26
+ <orderEntry type="library" scope="PROVIDED" name="hashie (v2.0.5, RVM: ruby-2.0.0-p195) [gem]" level="application" />
27
+ <orderEntry type="library" scope="PROVIDED" name="highline (v1.6.20, RVM: ruby-2.0.0-p195) [gem]" level="application" />
28
+ <orderEntry type="library" scope="PROVIDED" name="httpauth (v0.2.0, RVM: ruby-2.0.0-p195) [gem]" level="application" />
29
+ <orderEntry type="library" scope="PROVIDED" name="i18n (v0.6.5, RVM: ruby-2.0.0-p195) [gem]" level="application" />
30
+ <orderEntry type="library" scope="PROVIDED" name="jeweler (v1.8.8, RVM: ruby-2.0.0-p195) [gem]" level="application" />
31
+ <orderEntry type="library" scope="PROVIDED" name="json (v1.8.1, RVM: ruby-2.0.0-p195) [gem]" level="application" />
32
+ <orderEntry type="library" scope="PROVIDED" name="jwt (v0.1.8, RVM: ruby-2.0.0-p195) [gem]" level="application" />
33
+ <orderEntry type="library" scope="PROVIDED" name="mime-types (v1.25, RVM: ruby-2.0.0-p195) [gem]" level="application" />
34
+ <orderEntry type="library" scope="PROVIDED" name="minitest (v4.7.5, RVM: ruby-2.0.0-p195) [gem]" level="application" />
35
+ <orderEntry type="library" scope="PROVIDED" name="multi_json (v1.8.2, RVM: ruby-2.0.0-p195) [gem]" level="application" />
36
+ <orderEntry type="library" scope="PROVIDED" name="multi_xml (v0.5.5, RVM: ruby-2.0.0-p195) [gem]" level="application" />
37
+ <orderEntry type="library" scope="PROVIDED" name="multipart-post (v1.2.0, RVM: ruby-2.0.0-p195) [gem]" level="application" />
38
+ <orderEntry type="library" scope="PROVIDED" name="nokogiri (v1.5.10, RVM: ruby-2.0.0-p195) [gem]" level="application" />
39
+ <orderEntry type="library" scope="PROVIDED" name="oauth2 (v0.9.2, RVM: ruby-2.0.0-p195) [gem]" level="application" />
40
+ <orderEntry type="library" scope="PROVIDED" name="rack (v1.5.2, RVM: ruby-2.0.0-p195) [gem]" level="application" />
41
+ <orderEntry type="library" scope="PROVIDED" name="rake (v10.1.0, RVM: ruby-2.0.0-p195) [gem]" level="application" />
42
+ <orderEntry type="library" scope="PROVIDED" name="rdoc (v3.12.2, RVM: ruby-2.0.0-p195) [gem]" level="application" />
43
+ <orderEntry type="library" scope="PROVIDED" name="rest-client (v1.6.7, RVM: ruby-2.0.0-p195) [gem]" level="application" />
44
+ <orderEntry type="library" scope="PROVIDED" name="shoulda (v3.5.0, RVM: ruby-2.0.0-p195) [gem]" level="application" />
45
+ <orderEntry type="library" scope="PROVIDED" name="shoulda-context (v1.1.5, RVM: ruby-2.0.0-p195) [gem]" level="application" />
46
+ <orderEntry type="library" scope="PROVIDED" name="shoulda-matchers (v2.4.0, RVM: ruby-2.0.0-p195) [gem]" level="application" />
47
+ <orderEntry type="library" scope="PROVIDED" name="simplecov (v0.7.1, RVM: ruby-2.0.0-p195) [gem]" level="application" />
48
+ <orderEntry type="library" scope="PROVIDED" name="simplecov-html (v0.7.1, RVM: ruby-2.0.0-p195) [gem]" level="application" />
49
+ <orderEntry type="library" scope="PROVIDED" name="thread_safe (v0.1.3, RVM: ruby-2.0.0-p195) [gem]" level="application" />
50
+ <orderEntry type="library" scope="PROVIDED" name="tzinfo (v0.3.38, RVM: ruby-2.0.0-p195) [gem]" level="application" />
51
+ </component>
52
+ </module>
53
+
@@ -0,0 +1,5 @@
1
+ <component name="DependencyValidationManager">
2
+ <state>
3
+ <option name="SKIP_IMPORT_STATEMENTS" value="false" />
4
+ </state>
5
+ </component>
data/.idea/vcs.xml ADDED
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+ </component>
6
+ </project>
7
+
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'http://rubygems.org'
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem 'activesupport', '>= 2.3.5'
5
+ gem 'rest-client', '~> 1.6.7'
6
+
7
+ # Add dependencies to develop your gem here.
8
+ # Include everything needed to run rake, tests, features, etc.
9
+ group :development do
10
+ gem 'shoulda', '>= 0'
11
+ gem 'rdoc', '~> 3.12'
12
+ gem 'bundler', '~> 1.0'
13
+ gem 'jeweler', '~> 1.8.7'
14
+ gem 'simplecov'
15
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,81 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (4.0.0)
5
+ i18n (~> 0.6, >= 0.6.4)
6
+ minitest (~> 4.2)
7
+ multi_json (~> 1.3)
8
+ thread_safe (~> 0.1)
9
+ tzinfo (~> 0.3.37)
10
+ addressable (2.3.5)
11
+ atomic (1.1.14)
12
+ builder (3.2.2)
13
+ faraday (0.8.8)
14
+ multipart-post (~> 1.2.0)
15
+ git (1.2.6)
16
+ github_api (0.10.1)
17
+ addressable
18
+ faraday (~> 0.8.1)
19
+ hashie (>= 1.2)
20
+ multi_json (~> 1.4)
21
+ nokogiri (~> 1.5.2)
22
+ oauth2
23
+ hashie (2.0.5)
24
+ highline (1.6.20)
25
+ httpauth (0.2.0)
26
+ i18n (0.6.5)
27
+ jeweler (1.8.8)
28
+ builder
29
+ bundler (~> 1.0)
30
+ git (>= 1.2.5)
31
+ github_api (= 0.10.1)
32
+ highline (>= 1.6.15)
33
+ nokogiri (= 1.5.10)
34
+ rake
35
+ rdoc
36
+ json (1.8.1)
37
+ jwt (0.1.8)
38
+ multi_json (>= 1.5)
39
+ mime-types (1.25)
40
+ minitest (4.7.5)
41
+ multi_json (1.8.2)
42
+ multi_xml (0.5.5)
43
+ multipart-post (1.2.0)
44
+ nokogiri (1.5.10)
45
+ oauth2 (0.9.2)
46
+ faraday (~> 0.8)
47
+ httpauth (~> 0.2)
48
+ jwt (~> 0.1.4)
49
+ multi_json (~> 1.0)
50
+ multi_xml (~> 0.5)
51
+ rack (~> 1.2)
52
+ rack (1.5.2)
53
+ rake (10.1.0)
54
+ rdoc (3.12.2)
55
+ json (~> 1.4)
56
+ rest-client (1.6.7)
57
+ mime-types (>= 1.16)
58
+ shoulda (3.5.0)
59
+ shoulda-context (~> 1.0, >= 1.0.1)
60
+ shoulda-matchers (>= 1.4.1, < 3.0)
61
+ shoulda-context (1.1.5)
62
+ shoulda-matchers (2.4.0)
63
+ activesupport (>= 3.0.0)
64
+ simplecov (0.7.1)
65
+ multi_json (~> 1.0)
66
+ simplecov-html (~> 0.7.1)
67
+ simplecov-html (0.7.1)
68
+ thread_safe (0.1.3)
69
+ atomic
70
+ tzinfo (0.3.38)
71
+
72
+ PLATFORMS
73
+ ruby
74
+
75
+ DEPENDENCIES
76
+ bundler (~> 1.0)
77
+ jeweler (~> 1.8.7)
78
+ rdoc (~> 3.12)
79
+ rest-client (~> 1.6.7)
80
+ shoulda
81
+ simplecov
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 jfox
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = pivotal-tracker-api
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to pivotal-tracker-api
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
9
+ * Fork the project.
10
+ * Start a feature/bugfix branch.
11
+ * Commit and push until you are happy with your contribution.
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2013 jfox. See LICENSE.txt for
18
+ further details.
19
+
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "pivotal-tracker-api"
18
+ gem.homepage = "http://github.com/atljeremy/pivotal-tracker-api"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{A ruby gem to communicate with the Picotal Tracker API v5}
21
+ gem.description = %Q{A ruby gem to communicate with the Picotal Tracker API v5}
22
+ gem.email = "atljeremy@me.com"
23
+ gem.authors = ["jfox"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ #require 'rcov/rcovtask'
36
+ #Rcov::RcovTask.new do |test|
37
+ # test.libs << 'test'
38
+ # test.pattern = 'test/**/test_*.rb'
39
+ # test.verbose = true
40
+ # test.rcov_opts << '--exclude "gems/*"'
41
+ #end
42
+
43
+ task :default => :test
44
+
45
+ require 'rdoc/task'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "pivotal-tracker-api #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,42 @@
1
+ module Scorer
2
+ class Activity
3
+
4
+ attr_accessor :project_id, :occurred_at, :highlight, :primary_resources, :changes, :guid, :kind, :performed_by_id,
5
+ :performed_by, :message, :project_version
6
+
7
+ def initialize(attributes={})
8
+ update_attributes(attributes)
9
+ end
10
+
11
+ def self.parse_json_activity(json_activity, project_id)
12
+ json_activity.each do |activity|
13
+ new({
14
+ project_id: project_id,
15
+ occurred_at: activity[:stories],
16
+ highlight: activity[:number],
17
+ primary_resources: activity[:team_strength],
18
+ changes: activity[:finish],
19
+ guid: activity[:kind],
20
+ kind: activity[:start],
21
+ performed_by_id: activity[:performed_by_id],
22
+ performed_by: parse_person(activity[:performed_by]),
23
+ message: activity[:message],
24
+ project_version: activity[:project_version]
25
+ })
26
+ end
27
+ end
28
+
29
+ protected
30
+
31
+ def self.parse_person(json_person)
32
+ Scorer::Person.parse_json_person(json_person)
33
+ end
34
+
35
+ def update_attributes(attrs)
36
+ attrs.each do |key, value|
37
+ self.send("#{key}=", value)
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,19 @@
1
+ module Scorer
2
+ class Attachment
3
+
4
+ attr_accessor :status, :url, :filename, :id, :description, :uploaded_at, :uploaded_by
5
+
6
+ def initialize(attributes={})
7
+ update_attributes(attributes)
8
+ end
9
+
10
+ protected
11
+
12
+ def update_attributes(attrs)
13
+ attrs.each do |key, value|
14
+ self.send("#{key}=", value.is_a?(Array) ? value.join(',') : value )
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,96 @@
1
+ module Scorer
2
+ class Client
3
+
4
+ class NoToken < StandardError; end
5
+
6
+ class << self
7
+
8
+ attr_writer :token, :ssl_enabled
9
+ attr_reader :api_host, :api_projects_path
10
+
11
+ def get(path)
12
+ begin
13
+ set_response_headers(connection["#{api_version}#{path}"].get)
14
+ rescue
15
+ puts "Encountered Error in get: #{$!}"
16
+ clear_connections
17
+ set_response_headers(connection["#{api_version}#{path}"].get)
18
+ end
19
+ end
20
+
21
+ def get_with_caching(path)
22
+ begin
23
+ connection["#{api_version}#{path}"].get
24
+ rescue
25
+ puts "Encountered Error in get_with_caching: #{$!}"
26
+ clear_connections
27
+ connection["#{api_version}#{path}"].get
28
+ end
29
+ end
30
+
31
+ def put(path, updates={})
32
+ set_response_headers(connection["#{api_version}#{path}"].put(updates))
33
+ end
34
+
35
+ def connection
36
+ raise NoToken if @token.to_s.empty?
37
+ @connections ||= {}
38
+ cached_connection? ? cached_connection : new_connection
39
+ end
40
+
41
+ def clear_connections
42
+ @connections = nil
43
+ end
44
+
45
+ def ssl_enabled
46
+ @ssl_enabled || true
47
+ end
48
+
49
+ def token(username, password)
50
+ response = RestClient.get("#{api_ssl_host(username, password)}#{api_version}/me")
51
+ json = JSON.parse(response, {:symbolize_names => true})
52
+ @token = json[:api_token]
53
+ end
54
+
55
+ def api_ssl_host(user=nil, password=nil)
56
+ user_password = (user && password) ? "#{user}:#{password}@" : ''
57
+ "https://#{user_password}www.pivotaltracker.com"
58
+ end
59
+
60
+ def api_host
61
+ @api_host ||= 'http://www.pivotaltracker.com'
62
+ end
63
+
64
+ def api_projects_path
65
+ @api_projects_path ||= "#{ssl_enabled ? api_ssl_host : api_host}#{api_version}/projects"
66
+ end
67
+
68
+ protected
69
+
70
+ def set_response_headers(response)
71
+ response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate' # HTTP 1.1.
72
+ response.headers['Pragma'] = 'no-cache' # HTTP 1.0.
73
+ response.headers['Expires'] = '0' # Proxies.
74
+ response
75
+ end
76
+
77
+ def api_version
78
+ '/services/v5'
79
+ end
80
+
81
+ def cached_connection?
82
+ !@connections[@token].nil?
83
+ end
84
+
85
+ def cached_connection
86
+ @connections[@token]
87
+ end
88
+
89
+ def new_connection
90
+ @connections[@token] = RestClient::Resource.new("#{ssl_enabled ? api_ssl_host : api_host}", :headers => {'X-TrackerToken' => @token, 'Content-Type' => 'application/json'})
91
+ end
92
+
93
+ end
94
+
95
+ end
96
+ end
@@ -0,0 +1,25 @@
1
+ module Scorer
2
+ class Comment
3
+
4
+ attr_accessor :story, :project_id, :story_id, :id, :text, :author, :created_at
5
+
6
+ def initialize(attributes={})
7
+ if attributes[:owner]
8
+ self.story = attributes.delete(:owner)
9
+ self.project_id = self.story.project_id
10
+ self.story_id = self.story.id
11
+ end
12
+
13
+ update_attributes(attributes)
14
+ end
15
+
16
+ protected
17
+
18
+ def update_attributes(attrs)
19
+ attrs.each do |key, value|
20
+ self.send("#{key}=", value.is_a?(Array) ? value.join(',') : value )
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,39 @@
1
+ module Scorer
2
+ class Iteration
3
+
4
+ attr_accessor :project_id, :length, :planned, :stories, :story_ids, :number, :team_strength, :finish, :kind, :start
5
+
6
+ def initialize(attributes={})
7
+ update_attributes(attributes)
8
+ end
9
+
10
+ def self.parse_json_iteration(json_iteration)
11
+ new({
12
+ project_id: json_iteration[:project_id].to_i,
13
+ stories: parse_stories(json_iteration[:stories], json_iteration[:project_id].to_i),
14
+ story_ids: json_iteration[:story_ids],
15
+ number: json_iteration[:number],
16
+ team_strength: json_iteration[:team_strength],
17
+ finish: json_iteration[:finish],
18
+ kind: json_iteration[:kind],
19
+ start: json_iteration[:start]
20
+ })
21
+ end
22
+
23
+ protected
24
+
25
+ def self.parse_stories(stories, project_id)
26
+ story_ids = Array.new
27
+ stories.each { |story| story_ids << story[:id].to_i if !story[:id].nil? }
28
+ project = PivotalService.one_project(project_id)
29
+ PivotalService.stories(project, true, story_ids, Scorer::Story.fields)
30
+ end
31
+
32
+ def update_attributes(attrs)
33
+ attrs.each do |key, value|
34
+ self.send("#{key}=", value )
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,29 @@
1
+ module Scorer
2
+ class Person
3
+
4
+ attr_accessor :name, :id, :initials, :email, :username
5
+
6
+ def initialize(attributes={})
7
+ update_attributes(attributes)
8
+ end
9
+
10
+ def self.parse_json_person(json_person)
11
+ new({
12
+ id: json_person[:id].to_i,
13
+ name: json_person[:name],
14
+ initials: json_person[:initals],
15
+ email: json_person[:email],
16
+ username: json_person[:username]
17
+ })
18
+ end
19
+
20
+ protected
21
+
22
+ def update_attributes(attrs)
23
+ attrs.each do |key, value|
24
+ self.send("#{key}=", value)
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,114 @@
1
+ require 'json'
2
+
3
+ class PivotalService
4
+
5
+ class << self
6
+
7
+ def set_token(token)
8
+ Scorer::Client.token = token
9
+ end
10
+
11
+ def all_projects(fields=[])
12
+ api_url = append_fields('/projects', fields)
13
+ response = Scorer::Client.get(api_url)
14
+ json_projects = JSON.parse(response, {:symbolize_names => true})
15
+ Scorer::Project.parse_json_projects(json_projects)
16
+ end
17
+
18
+ def one_project(id, fields=[])
19
+ return @project if !@project.nil? && @project.id == id
20
+
21
+ api_url = append_fields('/projects' + "/#{id}", fields)
22
+ response = Scorer::Client.get(api_url)
23
+ json_project = JSON.parse(response, {:symbolize_names => true})
24
+ @project = Scorer::Project.parse_json_project(json_project)
25
+ end
26
+
27
+ def activity(project_id, story_id=0, limit=20)
28
+ api_url = "/projects/#{project_id}/"
29
+ api_url = api_url + "stories/#{story_id}/" if story_id > 0
30
+ api_url = api_url + "activity?limit=#{limit}"
31
+ response = Scorer::Client.get(api_url)
32
+ json_activity = JSON.parse(response, {:symbolize_names => true})
33
+ Scorer::Activity.parse_json_activity(json_activity, project_id)
34
+ end
35
+
36
+ def iterations(project_id, scope, fields=[], limit=1, offset=1)
37
+ return @iteration if !@iteration.nil? && @iteration.project_id == project_id
38
+
39
+ api_url = "/projects/#{project_id}/iterations?"
40
+ if scope
41
+ if scope != 'current'
42
+ api_url = api_url + "&offset=#{offset}&limit=#{limit}"
43
+ end
44
+ api_url = api_url + "&scope=#{scope}"
45
+ end
46
+ api_url = append_fields(api_url, fields)
47
+ response = Scorer::Client.get_with_caching(api_url)
48
+ json_iterations = JSON.parse(response, {:symbolize_names => true})
49
+ @iteration = Scorer::Iteration.parse_json_iteration(json_iterations[0])
50
+ end
51
+
52
+ def all_stories(project_label, project, fields=[])
53
+ api_url = append_fields('/projects' + "/#{project.id}/stories", fields)
54
+ api_url = api_url + "&with_label=#{project_label}&with_state=unstarted&limit=100"
55
+ response = Scorer::Client.get(api_url)
56
+ json_stories = JSON.parse(response, {:symbolize_names => true})
57
+ Scorer::Story.parse_json_stories(json_stories, project.id)
58
+ end
59
+
60
+ def one_story(project_label, project, fields=[])
61
+ api_url = append_fields('/projects' + "/#{project.id}/stories", fields)
62
+ api_url = api_url + "&with_label=#{project_label}&with_state=unstarted&limit=100"
63
+ response = Scorer::Client.get(api_url)
64
+ json_story = JSON.parse(response, {:symbolize_names => true})
65
+ Scorer::Story.parse_json_story(json_story, project.id)
66
+ end
67
+
68
+ def stories(project, should_cache, ids=[], fields=[])
69
+ @stories = Array.new
70
+ api_url = append_fields('/projects' + "/#{project.id}/stories", fields)
71
+ api_url = api_url.rindex('?fields=') ? "#{api_url}&filter=id%3A" : "#{api_url}?filter=id%3A"
72
+ if ids.size == 1
73
+ api_url = api_url + ids[0].to_s
74
+ if should_cache
75
+ response = Scorer::Client.get_with_caching(api_url)
76
+ else
77
+ response = Scorer::Client.get(api_url)
78
+ end
79
+ json_story = JSON.parse(response, {:symbolize_names => true})
80
+ @stories << Scorer::Story.parse_json_story(json_story[0], project.id)
81
+ else
82
+ story_ids = ''
83
+ ids.each do |id|
84
+ story_ids = "#{story_ids}#{id}%2C"
85
+ end
86
+ api_url = api_url + story_ids
87
+ if should_cache
88
+ response = Scorer::Client.get_with_caching(api_url)
89
+ else
90
+ response = Scorer::Client.get(api_url)
91
+ end
92
+ json_stories = JSON.parse(response, {:symbolize_names => true})
93
+ @stories = Scorer::Story.parse_json_stories(json_stories, project.id)
94
+ end
95
+ end
96
+
97
+ def update_story(story_id, project_id, updates={})
98
+ project = one_project(project_id, Scorer::Project.fields)
99
+ api_url = '/projects' + "/#{project.id}/stories/#{story_id}"
100
+ Scorer::Client.put(api_url, updates)
101
+ end
102
+
103
+ private
104
+
105
+ def append_fields(api_url, fields)
106
+ url = api_url
107
+ fields.each do |field|
108
+ url = url.rindex('?fields=') ? url + ",#{field}" : url + "?fields=#{field}"
109
+ end
110
+ url
111
+ end
112
+
113
+ end
114
+ end
@@ -0,0 +1,63 @@
1
+ module Scorer
2
+ class Project
3
+
4
+ attr_accessor :updated_at, :bugs_and_chores_are_estimatable, :enable_planned_mode, :public, :story_ids, :name,
5
+ :iteration_length, :start_time, :version, :label_ids, :description, :profile_content,
6
+ :iteration_override_numbers, :velocity_averaged_over, :current_velocity, :point_scale_is_custom,
7
+ :epic_ids, :membership_ids, :integration_ids, :created_at, :week_start_day, :time_zone,
8
+ :shown_iterations_start_time, :has_google_domain, :kind, :id, :point_scale, :current_iteration_number,
9
+ :start_date, :number_of_done_iterations_to_show, :account_id, :labels
10
+
11
+ class << self
12
+
13
+ def fields
14
+ ['description', 'labels', 'name']
15
+ end
16
+
17
+ def parse_json_projects(json_projects)
18
+ projects = Array.new
19
+ json_projects.each do |project|
20
+ projects << parse_json_project(project)
21
+ end
22
+ projects
23
+ end
24
+
25
+ def parse_json_project(project)
26
+ new({
27
+ id: project[:id].to_i,
28
+ name: project[:name],
29
+ week_start_day: project[:week_start_day],
30
+ point_scale: project[:point_scale],
31
+ labels: parse_labels(project[:labels]),
32
+ iteration_length: project[:iteration_length],
33
+ current_velocity: project[:current_velocity]
34
+ })
35
+ end
36
+
37
+ def parse_labels(labels)
38
+ parsed_labels = ''
39
+ labels.each do |label|
40
+ parsed_labels = parsed_labels + "#{label[:name]},"
41
+ end
42
+ parsed_labels
43
+ end
44
+ end
45
+
46
+ def initialize(attributes={})
47
+ update_attributes(attributes)
48
+ end
49
+
50
+ def get_labels
51
+ self.labels.split(',')
52
+ end
53
+
54
+ protected
55
+
56
+ def update_attributes(attrs)
57
+ attrs.each do |key, value|
58
+ self.send("#{key}=", value.is_a?(Array) ? value.join(',') : value )
59
+ end
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,199 @@
1
+ module Scorer
2
+ class Story
3
+
4
+ attr_accessor :project_id, :follower_ids, :updated_at, :current_state, :name, :comment_ids, :url, :story_type,
5
+ :label_ids, :description, :requested_by_id, :planned_iteration_number, :external_id, :deadline,
6
+ :owned_by_id, :owned_by, :created_at, :estimate, :kind, :id, :task_ids, :integration_id, :accepted_at,
7
+ :comments, :tasks, :attachments, :requested_by, :labels, :notes, :started_at, :status
8
+
9
+ def initialize(attributes={})
10
+ update_attributes(attributes)
11
+ end
12
+
13
+ def self.fields
14
+ ['url', 'name', 'description', 'story_type',
15
+ 'estimate', 'current_state', 'requested_by',
16
+ 'owned_by', 'labels', 'integration_id',
17
+ 'deadline', 'comments', 'tasks']
18
+ end
19
+
20
+ def self.parse_json_story(json_story, project_id)
21
+ requested_by = json_story[:requested_by][:name] if !json_story[:requested_by].nil?
22
+ story_id = json_story[:id].to_i
23
+ estimate = json_story[:estimate] ? json_story[:estimate].to_i : -1
24
+ current_state = json_story[:current_state]
25
+ parsed_story = new({
26
+ id: story_id,
27
+ url: json_story[:url],
28
+ project_id: project_id,
29
+ name: json_story[:name],
30
+ description: json_story[:description],
31
+ story_type: json_story[:story_type],
32
+ estimate: estimate,
33
+ current_state: current_state,
34
+ requested_by: requested_by,
35
+ owned_by_id: json_story[:owned_by_id],
36
+ owned_by: json_story[:owned_by],
37
+ labels: parse_labels(json_story[:labels]),
38
+ integration_id: json_story[:integration_id],
39
+ deadline: json_story[:deadline]
40
+ })
41
+
42
+ parsed_story.comments = parse_notes(json_story[:comments], json_story)
43
+ parsed_story.tasks = parse_tasks(json_story[:tasks], json_story)
44
+ parsed_story.attachments = []
45
+ parsed_story
46
+ end
47
+
48
+ def self.parse_json_stories(json_stories, project_id)
49
+ stories = Array.new
50
+ json_stories.each do |story|
51
+ stories << parse_json_story(story, project_id)
52
+ end
53
+ stories
54
+ end
55
+
56
+ def self.parse_notes(notes, story)
57
+ comments = Array.new
58
+ if notes
59
+ notes.each do |note|
60
+ comments << Scorer::Comment.new({
61
+ id: note[:id].to_i,
62
+ text: note[:text],
63
+ author: note[:author],
64
+ created_at: DateTime.parse(note[:created_at].to_s).to_s,
65
+ story: story
66
+ })
67
+ end
68
+ end
69
+ comments
70
+ end
71
+
72
+ def self.parse_tasks(tasks, story)
73
+ parsed_tasks = Array.new
74
+ if tasks
75
+ tasks.each do |task|
76
+ parsed_tasks << Scorer::Task.new({
77
+ id: task[:id].to_i,
78
+ description: task[:description],
79
+ complete: task[:complete],
80
+ created_at: DateTime.parse(task[:created_at].to_s).to_s,
81
+ story: story
82
+ })
83
+ end
84
+ end
85
+ parsed_tasks
86
+ end
87
+
88
+ def self.parse_attachments(attachments)
89
+ parsed_attachments = Array.new
90
+ if attachments
91
+ attachments.each do |file|
92
+ attachment = Scorer::Attachment.new
93
+ attachment.id = file[:id].to_i
94
+ attachment.filename = file[:filename]
95
+ attachment.description = file[:description]
96
+ attachment.uploaded_by = file[:uploaded_by]
97
+ attachment.uploaded_at = file[:uploaded_at]
98
+ attachment.url = file[:url]
99
+ attachment.status = file[:status]
100
+ parsed_attachments << attachment
101
+ end
102
+ end
103
+ parsed_attachments
104
+ end
105
+
106
+ def self.parse_labels(labels)
107
+ parsed_labels = ''
108
+ labels.each do |label|
109
+ parsed_labels = parsed_labels + "#{label[:name]},"
110
+ end
111
+ parsed_labels
112
+ end
113
+
114
+ def self.get_story_started_at(project_id, story_id)
115
+ events = Hash.new
116
+ current_started_at = nil
117
+ current_accepted_at = nil
118
+ activity = PivotalService.activity(project_id, story_id, 40)
119
+ activity.each do |event|
120
+ case event[:highlight]
121
+ when 'started'
122
+ started_at = event[:occurred_at]
123
+ if current_started_at.nil? || current_started_at < started_at || current_accepted_at === started_at
124
+ current_started_at = started_at
125
+ events[:started_at] = current_started_at
126
+ end
127
+ when 'accepted'
128
+ accepted_at = event[:occurred_at]
129
+ if current_accepted_at.nil? || current_accepted_at < accepted_at
130
+ current_accepted_at = accepted_at
131
+ events[:accepted_at] = current_accepted_at
132
+ end
133
+ end
134
+ end
135
+ events
136
+ end
137
+
138
+ def self.get_story_status(event_times, points, current_state)
139
+ status = {status: 'ok', hours: -1}
140
+ if !event_times.nil? && !event_times[:started_at].nil? && points > -1 && current_state != 'unstarted'
141
+
142
+ # Times
143
+ started_at_time = Time.parse(event_times[:started_at])
144
+
145
+ # Due Dates
146
+ due_date = (points.to_i.business_hours.after(started_at_time)).to_datetime
147
+ almost_due_date = ((points - 1).to_i.business_hours.after(started_at_time)).to_datetime
148
+
149
+ if current_state == 'accepted' && !event_times[:accepted_at].nil?
150
+ accepted_at = event_times[:accepted_at]
151
+ hours = get_hours_between_times(started_at_time, Time.parse(accepted_at))
152
+ if accepted_at.to_datetime > due_date || hours >= points
153
+ status = {status: 'overdue', hours: hours}
154
+ elsif accepted_at >= almost_due_date || hours == (points - 1)
155
+ status = {status: 'almost_due', hours: hours}
156
+ else
157
+ status = {status: 'ok', hours: hours}
158
+ end
159
+ else
160
+ now = DateTime.now
161
+ hours = get_hours_between_times(started_at_time, Time.parse(now.to_s))
162
+ if now >= due_date || hours >= points
163
+ status = {status: 'overdue', hours: hours}
164
+ elsif now >= almost_due_date || hours == (points - 1)
165
+ status = {status: 'almost_due', hours: hours}
166
+ else
167
+ status = {status: 'ok', hours: hours}
168
+ end
169
+ end
170
+
171
+ end
172
+ status
173
+ end
174
+
175
+ protected
176
+
177
+ def self.get_hours_between_times(time1, time2)
178
+
179
+ # Check to see if both times occurred outside of business hours.
180
+ # If so, calculate the total time in between each time
181
+ if Time::roll_forward(time1) == Time::roll_forward(time2)
182
+ return (((time2 - time1) / 60) / 60).round
183
+ end
184
+
185
+ ((time1.business_time_until(time2) / 60) / 60).round
186
+ end
187
+
188
+ def self.est_time_zone(time)
189
+ time.in_time_zone("Eastern Time (US & Canada)")
190
+ end
191
+
192
+ def update_attributes(attrs)
193
+ attrs.each do |key, value|
194
+ self.send("#{key}=", value.is_a?(Array) ? value.join(',') : value )
195
+ end
196
+ end
197
+
198
+ end
199
+ end
@@ -0,0 +1,25 @@
1
+ module Scorer
2
+ class Task
3
+
4
+ attr_accessor :project_id, :story_id, :story, :id, :description, :position, :complete, :created_at
5
+
6
+ def initialize(attributes={})
7
+ if attributes[:owner]
8
+ self.story = attributes.delete(:owner)
9
+ self.project_id = self.story.project_id
10
+ self.story_id = self.story.id
11
+ end
12
+
13
+ update_attributes(attributes)
14
+ end
15
+
16
+ protected
17
+
18
+ def update_attributes(attrs)
19
+ attrs.each do |key, value|
20
+ self.send("#{key}=", value.is_a?(Array) ? value.join(',') : value )
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,12 @@
1
+ require 'rest_client'
2
+
3
+ require File.join(File.dirname(__FILE__), 'pivotal-tracker-api', 'client')
4
+ require File.join(File.dirname(__FILE__), 'pivotal-tracker-api', 'project')
5
+ require File.join(File.dirname(__FILE__), 'pivotal-tracker-api', 'attachment')
6
+ require File.join(File.dirname(__FILE__), 'pivotal-tracker-api', 'story')
7
+ require File.join(File.dirname(__FILE__), 'pivotal-tracker-api', 'task')
8
+ require File.join(File.dirname(__FILE__), 'pivotal-tracker-api', 'activity')
9
+ require File.join(File.dirname(__FILE__), 'pivotal-tracker-api', 'iteration')
10
+ require File.join(File.dirname(__FILE__), 'pivotal-tracker-api', 'comment')
11
+ require File.join(File.dirname(__FILE__), 'pivotal-tracker-api', 'person')
12
+ require File.join(File.dirname(__FILE__), 'pivotal-tracker-api', 'pivotal_service')
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'pivotal-tracker-api'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestPivotalTrackerApi < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,157 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pivotal-tracker-api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - jfox
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 1.6.7
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 1.6.7
27
+ - !ruby/object:Gem::Dependency
28
+ name: shoulda
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rdoc
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '3.12'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3.12'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '1.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: jeweler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 1.8.7
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 1.8.7
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: A ruby gem to communicate with the Picotal Tracker API v5
98
+ email: atljeremy@me.com
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files:
102
+ - LICENSE.txt
103
+ - README.rdoc
104
+ files:
105
+ - .document
106
+ - .idea/.name
107
+ - .idea/.rakeTasks
108
+ - .idea/encodings.xml
109
+ - .idea/misc.xml
110
+ - .idea/modules.xml
111
+ - .idea/pivotal-tracker-api.iml
112
+ - .idea/scopes/scope_settings.xml
113
+ - .idea/vcs.xml
114
+ - Gemfile
115
+ - Gemfile.lock
116
+ - LICENSE.txt
117
+ - README.rdoc
118
+ - Rakefile
119
+ - VERSION
120
+ - lib/pivotal-tracker-api.rb
121
+ - lib/pivotal-tracker-api/activity.rb
122
+ - lib/pivotal-tracker-api/attachment.rb
123
+ - lib/pivotal-tracker-api/client.rb
124
+ - lib/pivotal-tracker-api/comment.rb
125
+ - lib/pivotal-tracker-api/iteration.rb
126
+ - lib/pivotal-tracker-api/person.rb
127
+ - lib/pivotal-tracker-api/pivotal_service.rb
128
+ - lib/pivotal-tracker-api/project.rb
129
+ - lib/pivotal-tracker-api/story.rb
130
+ - lib/pivotal-tracker-api/task.rb
131
+ - test/helper.rb
132
+ - test/test_pivotal-tracker-api.rb
133
+ homepage: http://github.com/atljeremy/pivotal-tracker-api
134
+ licenses:
135
+ - MIT
136
+ metadata: {}
137
+ post_install_message:
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - '>='
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubyforge_project:
153
+ rubygems_version: 2.0.8
154
+ signing_key:
155
+ specification_version: 4
156
+ summary: A ruby gem to communicate with the Picotal Tracker API v5
157
+ test_files: []