napcs-pivotalrecord 0.0.1
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 +31 -0
- data/Rakefile +121 -0
- data/lib/pivotal.rb +10 -0
- data/lib/pivotal/base.rb +155 -0
- data/lib/pivotal/configuration.rb +11 -0
- data/lib/pivotal/iteration.rb +21 -0
- data/lib/pivotal/project.rb +19 -0
- data/lib/pivotal/story.rb +30 -0
- data/spec/pivotal/iteration_spec.rb +357 -0
- data/spec/pivotal/project_spec.rb +317 -0
- data/spec/pivotal/story_spec.rb +243 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +17 -0
- metadata +108 -0
data/README.rdoc
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
=PivotalRecord
|
2
|
+
|
3
|
+
Provides a simple interface to PivotalTracker using syntax similar to ActiveRecord.
|
4
|
+
|
5
|
+
@projects = Pivotal::Project.find(246)
|
6
|
+
@stories = @projects.first.stories
|
7
|
+
|
8
|
+
== Configuring
|
9
|
+
|
10
|
+
Require the library in your project and then configure it with your API key.
|
11
|
+
|
12
|
+
require 'pivotal'
|
13
|
+
Pivotal::Configuration.options[:api_key] = "asdfagjasd"
|
14
|
+
|
15
|
+
|
16
|
+
==Known Issues
|
17
|
+
|
18
|
+
This is extremely rudimentary and not meant for any sort of production use.
|
19
|
+
There is no write support yet, nor are there any search filters.
|
20
|
+
|
21
|
+
|
22
|
+
== Changelog
|
23
|
+
|
24
|
+
===0.0.1
|
25
|
+
* Basic record retrieval from PivotalTracker.
|
26
|
+
|
27
|
+
|
28
|
+
==License
|
29
|
+
Copyright 2009 Brian Hogan
|
30
|
+
Licensed under the MIT license.
|
31
|
+
Use of this library must be in accordance with Pivotal Tracker's terms of service and requires an API key.
|
data/Rakefile
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "rake/gempackagetask"
|
5
|
+
require "rake/rdoctask"
|
6
|
+
|
7
|
+
task :default => :spec
|
8
|
+
|
9
|
+
require "spec"
|
10
|
+
require "spec/rake/spectask"
|
11
|
+
Spec::Rake::SpecTask.new do |t|
|
12
|
+
t.spec_opts = %w(--format specdoc --colour)
|
13
|
+
t.libs = ["spec"]
|
14
|
+
end
|
15
|
+
|
16
|
+
# This builds the actual gem. For details of what all these options
|
17
|
+
# mean, and other ones you can add, check the documentation here:
|
18
|
+
#
|
19
|
+
# http://rubygems.org/read/chapter/20
|
20
|
+
#
|
21
|
+
spec = Gem::Specification.new do |s|
|
22
|
+
|
23
|
+
# Change these as appropriate
|
24
|
+
s.name = "pivotalrecord"
|
25
|
+
s.version = "0.0.1"
|
26
|
+
s.summary = "Simple ActiveRecord-style interface for PivotalTracker"
|
27
|
+
s.author = "Brian Hogan"
|
28
|
+
s.email = "brianhogan@naopcs.com"
|
29
|
+
s.homepage = "http://www.napcs.com"
|
30
|
+
|
31
|
+
s.has_rdoc = true
|
32
|
+
|
33
|
+
# You should probably have a README of some kind. Change the filename
|
34
|
+
# as appropriate
|
35
|
+
s.extra_rdoc_files = %w(README.rdoc)
|
36
|
+
s.rdoc_options = %w(--main README.rdoc)
|
37
|
+
|
38
|
+
# Add any extra files to include in the gem (like your README)
|
39
|
+
s.files = %w(Rakefile) + Dir.glob("{spec,lib}/**/*")
|
40
|
+
|
41
|
+
s.require_paths = ["lib"]
|
42
|
+
|
43
|
+
# If you want to depend on other gems, add them here, along with any
|
44
|
+
# relevant versions
|
45
|
+
s.add_dependency("rest-client", "~> 1.0.3")
|
46
|
+
s.add_dependency("xml-simple", "~> 1.0.12")
|
47
|
+
s.add_dependency("activesupport", "~> 2.0.2")
|
48
|
+
|
49
|
+
s.add_development_dependency("rspec") # add any other gems for testing/development
|
50
|
+
|
51
|
+
# If you want to publish automatically to rubyforge, you'll may need
|
52
|
+
# to tweak this, and the publishing task below too.
|
53
|
+
s.rubyforge_project = "pivotalrecord"
|
54
|
+
end
|
55
|
+
|
56
|
+
# This task actually builds the gem. We also regenerate a static
|
57
|
+
# .gemspec file, which is useful if something (i.e. GitHub) will
|
58
|
+
# be automatically building a gem for this project. If you're not
|
59
|
+
# using GitHub, edit as appropriate.
|
60
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
61
|
+
pkg.gem_spec = spec
|
62
|
+
|
63
|
+
# Generate the gemspec file for github.
|
64
|
+
file = File.dirname(__FILE__) + "/#{spec.name}.gemspec"
|
65
|
+
File.open(file, "w") {|f| f << spec.to_ruby }
|
66
|
+
end
|
67
|
+
|
68
|
+
# Generate documentation
|
69
|
+
Rake::RDocTask.new do |rd|
|
70
|
+
|
71
|
+
rd.rdoc_files.include("lib/**/*.rb")
|
72
|
+
rd.rdoc_dir = "rdoc"
|
73
|
+
end
|
74
|
+
|
75
|
+
desc 'Clear out RDoc and generated packages'
|
76
|
+
task :clean => [:clobber_rdoc, :clobber_package] do
|
77
|
+
rm "#{spec.name}.gemspec"
|
78
|
+
end
|
79
|
+
|
80
|
+
# If you want to publish to RubyForge automatically, here's a simple
|
81
|
+
# task to help do that. If you don't, just get rid of this.
|
82
|
+
# Be sure to set up your Rubyforge account details with the Rubyforge
|
83
|
+
# gem; you'll need to run `rubyforge setup` and `rubyforge config` at
|
84
|
+
# the very least.
|
85
|
+
begin
|
86
|
+
require "rake/contrib/sshpublisher"
|
87
|
+
namespace :rubyforge do
|
88
|
+
|
89
|
+
desc "Release gem and RDoc documentation to RubyForge"
|
90
|
+
task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
|
91
|
+
|
92
|
+
namespace :release do
|
93
|
+
desc "Release a new version of this gem"
|
94
|
+
task :gem => [:package] do
|
95
|
+
require 'rubyforge'
|
96
|
+
rubyforge = RubyForge.new
|
97
|
+
rubyforge.configure
|
98
|
+
rubyforge.login
|
99
|
+
rubyforge.userconfig['release_notes'] = spec.summary
|
100
|
+
path_to_gem = File.join(File.dirname(__FILE__), "pkg", "#{spec.name}-#{spec.version}.gem")
|
101
|
+
puts "Publishing #{spec.name}-#{spec.version.to_s} to Rubyforge..."
|
102
|
+
rubyforge.add_release(spec.rubyforge_project, spec.name, spec.version.to_s, path_to_gem)
|
103
|
+
end
|
104
|
+
|
105
|
+
desc "Publish RDoc to RubyForge."
|
106
|
+
task :docs => [:rdoc] do
|
107
|
+
config = YAML.load(
|
108
|
+
File.read(File.expand_path('~/.rubyforge/user-config.yml'))
|
109
|
+
)
|
110
|
+
|
111
|
+
host = "#{config['username']}@rubyforge.org"
|
112
|
+
remote_dir = "/var/www/gforge-projects/pivotalrecord/" # Should be the same as the rubyforge project name
|
113
|
+
local_dir = 'rdoc'
|
114
|
+
|
115
|
+
Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
rescue LoadError
|
120
|
+
puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
|
121
|
+
end
|
data/lib/pivotal.rb
ADDED
data/lib/pivotal/base.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
module Pivotal
|
2
|
+
class Base
|
3
|
+
|
4
|
+
def initialize(args = {})
|
5
|
+
args.each do |key, value|
|
6
|
+
self.send("#{key}=", value) if self.respond_to?("#{key}=")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
# parses the collection from Pivotal. Invokes the class's parse_result method
|
13
|
+
# which the class should implement.
|
14
|
+
def parse_results(results)
|
15
|
+
return [] if results[self.resource].nil?
|
16
|
+
results[self.resource].collect do |item|
|
17
|
+
klass = self.name.constantize
|
18
|
+
klass.parse_result(item)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
# get_content_for is used to convert the strings in the xml fil
|
24
|
+
# into actual Ruby types.
|
25
|
+
# The element can come in as a string, an array with a string inside
|
26
|
+
# or a hash, so I'm covering all bases here.
|
27
|
+
# Don't change without using the specs!
|
28
|
+
def get_content_for(element)
|
29
|
+
result = if element.is_a? String
|
30
|
+
element.to_s
|
31
|
+
elsif element.nil?
|
32
|
+
nil #doesn't exist
|
33
|
+
else
|
34
|
+
if element[0].is_a? Hash
|
35
|
+
type = element[0]["type"]
|
36
|
+
content = element[0]["content"]
|
37
|
+
cast_value(content, type)
|
38
|
+
else
|
39
|
+
element[0].to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def cast_value(content, type)
|
46
|
+
value = case type
|
47
|
+
when "integer"
|
48
|
+
content.to_i
|
49
|
+
when "datetime"
|
50
|
+
content.to_time
|
51
|
+
else
|
52
|
+
content
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def resource
|
57
|
+
name.split('::').last.downcase
|
58
|
+
end
|
59
|
+
|
60
|
+
# Declares the relationship between the models.
|
61
|
+
#
|
62
|
+
# has_many :stories
|
63
|
+
#
|
64
|
+
# Creates a <tt>stories</tt> method to retrive the related records.
|
65
|
+
def has_many(things)
|
66
|
+
parent_resource = resource
|
67
|
+
object = things.to_s.classify
|
68
|
+
class_eval <<-EOF
|
69
|
+
|
70
|
+
def #{things}
|
71
|
+
Pivotal::#{object}.find_all_by_parent_id("#{parent_resource.pluralize}", self.id)
|
72
|
+
end
|
73
|
+
|
74
|
+
EOF
|
75
|
+
end
|
76
|
+
|
77
|
+
# Creates a reverse association, making it easy to grab
|
78
|
+
# the parent object.
|
79
|
+
def belongs_to(parent)
|
80
|
+
object = parent.to_s.classify
|
81
|
+
parent_id = "#{parent.to_s.downcase}_id"
|
82
|
+
class_eval <<-EOF
|
83
|
+
|
84
|
+
def #{parent.to_s}
|
85
|
+
Pivotal::#{object}.find_by_id(#{parent_id})
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.find_all_by_#{parent.to_s}_id(id)
|
89
|
+
find_all_by_parent_id("#{parent.to_s.pluralize}", id)
|
90
|
+
end
|
91
|
+
|
92
|
+
EOF
|
93
|
+
end
|
94
|
+
|
95
|
+
# Retrives the token from the configuration
|
96
|
+
def token
|
97
|
+
@@token = Pivotal::Configuration.options[:api_key]
|
98
|
+
end
|
99
|
+
|
100
|
+
def debugging?
|
101
|
+
@@debugging = Pivotal::Configuration.options[:debug] == true
|
102
|
+
end
|
103
|
+
|
104
|
+
# retrieves the service url
|
105
|
+
# If not set in the configuration, the default
|
106
|
+
# value is used.
|
107
|
+
def url
|
108
|
+
@@url = Pivotal::Configuration.options[:url] || "http://www.pivotaltracker.com/services/v2"
|
109
|
+
end
|
110
|
+
|
111
|
+
# Base find method
|
112
|
+
def find(type)
|
113
|
+
if type == :all
|
114
|
+
find_all
|
115
|
+
else
|
116
|
+
find_by_id(type)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# find a specific record by id
|
121
|
+
def find_by_id(id)
|
122
|
+
query = "#{self.url}/#{self.resource.pluralize}/#{id}?token=#{self.token}"
|
123
|
+
puts "query : #{query}" if self.debugging?
|
124
|
+
results = RestClient.get query
|
125
|
+
result = XmlSimple.xml_in(results.to_s)
|
126
|
+
parse_result(result)
|
127
|
+
end
|
128
|
+
|
129
|
+
# generic finder, used by associations
|
130
|
+
def find_all_by_parent_id(parent, id)
|
131
|
+
return [] if id.nil?
|
132
|
+
query = "#{self.url}/#{parent}/#{id}/#{self.resource.pluralize}?token=#{self.token}"
|
133
|
+
puts "query : #{query}" if self.debugging?
|
134
|
+
results = RestClient.get query
|
135
|
+
results = XmlSimple.xml_in(results.to_s)
|
136
|
+
parse_results(results)
|
137
|
+
end
|
138
|
+
|
139
|
+
# find all records for the given object.
|
140
|
+
def find_all
|
141
|
+
query ="#{self.url}/#{self.resource.pluralize}?token=#{self.token}"
|
142
|
+
puts "query : #{query}" if self.debugging?
|
143
|
+
results = RestClient.get query
|
144
|
+
puts results.inspect if self.debugging?
|
145
|
+
results = XmlSimple.xml_in(results.to_s)
|
146
|
+
parse_results(results)
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Pivotal
|
2
|
+
# The class that keeps track of the global options for Haml within Rails.
|
3
|
+
module Configuration
|
4
|
+
extend self
|
5
|
+
|
6
|
+
@options = {}
|
7
|
+
# The options hash for the Pivotal library.
|
8
|
+
# Pivotal::Configuration.options[:api_key] = "something"
|
9
|
+
attr_accessor :options
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Pivotal
|
2
|
+
|
3
|
+
#==Iteration
|
4
|
+
# An iteration maps to a Pivotal Project and represents the sprint.
|
5
|
+
class Iteration < Pivotal::Base
|
6
|
+
|
7
|
+
belongs_to :project
|
8
|
+
|
9
|
+
attr_accessor :start, :finish, :id, :stories, :number
|
10
|
+
|
11
|
+
def self.parse_result(iteration)
|
12
|
+
Pivotal::Iteration.new( :id => get_content_for(iteration["id"]),
|
13
|
+
:number => get_content_for(iteration["number"]),
|
14
|
+
:start => get_content_for(iteration["start"]),
|
15
|
+
:finish => get_content_for(iteration["finish"]),
|
16
|
+
:stories => Pivotal::Story.parse_results(iteration["stories"].first)
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Pivotal
|
2
|
+
#==Project
|
3
|
+
# Your project in PivotalTracker. Use the project to get basic info
|
4
|
+
# and to get its stories.
|
5
|
+
class Project < Pivotal::Base
|
6
|
+
|
7
|
+
attr_accessor :id, :name
|
8
|
+
|
9
|
+
has_many :stories
|
10
|
+
|
11
|
+
|
12
|
+
def self.parse_result(project)
|
13
|
+
Pivotal::Project.new( :id => get_content_for(project["id"]),
|
14
|
+
:name => get_content_for(project["name"]) )
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Pivotal
|
2
|
+
class Story < Pivotal::Base
|
3
|
+
|
4
|
+
attr_accessor :id, :project_id, :name, :description, :url, :estimate, :story_type, :accepted_at
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
belongs_to :project
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
|
13
|
+
def self.parse_result(story)
|
14
|
+
Pivotal::Story.new(
|
15
|
+
:id => get_content_for(story["id"]),
|
16
|
+
:name => get_content_for(story["name"]),
|
17
|
+
:description => get_content_for(story["description"]),
|
18
|
+
:url => get_content_for(story["url"]),
|
19
|
+
:estimate => get_content_for(story["estimate"]),
|
20
|
+
:story_type => get_content_for(story["story_type"]),
|
21
|
+
:accepted_at => get_content_for(story["accepted_at"]),
|
22
|
+
:current_state => get_content_for(story["current_state"])
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,357 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "/../spec_helper")
|
2
|
+
|
3
|
+
describe Pivotal::Iteration do
|
4
|
+
before(:each) do
|
5
|
+
@service = "http://www.pivotaltracker.com/services/v2"
|
6
|
+
@token = "abcd"
|
7
|
+
Pivotal::Configuration.options[:api_key] = @token
|
8
|
+
FakeWeb.clean_registry
|
9
|
+
FakeWeb.allow_net_connect = false
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
after(:each) do
|
14
|
+
FakeWeb.clean_registry
|
15
|
+
FakeWeb.allow_net_connect = true
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
describe "with many iterations" do
|
20
|
+
before(:each) do
|
21
|
+
xml = %Q{<?xml version="1.0" encoding="UTF-8"?>
|
22
|
+
<iterations type="array">
|
23
|
+
<iteration>
|
24
|
+
<id type="integer">1</id>
|
25
|
+
<number type="integer">1</number>
|
26
|
+
<start type="datetime">2009/01/12 00:00:00 UTC</start>
|
27
|
+
<finish type="datetime">2009/01/19 00:00:00 UTC</finish>
|
28
|
+
<stories type="array">
|
29
|
+
<story>
|
30
|
+
<id type="integer">300970</id>
|
31
|
+
<story_type>release</story_type>
|
32
|
+
<url>http://www.pivotaltracker.com/story/show/300970</url>
|
33
|
+
<current_state>accepted</current_state>
|
34
|
+
<description></description>
|
35
|
+
<name>rel_1-1-5</name>
|
36
|
+
<requested_by>Brian Hogan</requested_by>
|
37
|
+
<created_at type="datetime">2008/12/04 03:00:57 UTC</created_at>
|
38
|
+
<accepted_at type="datetime">2009/01/14 06:32:15 UTC</accepted_at>
|
39
|
+
<deadline type="datetime">2008/12/12 20:00:00 UTC</deadline>
|
40
|
+
</story>
|
41
|
+
</stories>
|
42
|
+
</iteration>
|
43
|
+
<iteration>
|
44
|
+
<id type="integer">2</id>
|
45
|
+
<number type="integer">2</number>
|
46
|
+
<start type="datetime">2009/01/19 00:00:00 UTC</start>
|
47
|
+
<finish type="datetime">2009/01/26 00:00:00 UTC</finish>
|
48
|
+
<stories type="array">
|
49
|
+
<story>
|
50
|
+
<id type="integer">302045</id>
|
51
|
+
<story_type>bug</story_type>
|
52
|
+
<url>http://www.pivotaltracker.com/story/show/302045</url>
|
53
|
+
<current_state>accepted</current_state>
|
54
|
+
<description>CSS stylesheets for greybox are still referenced in templates causing errors in the logs</description>
|
55
|
+
<name>Remove references to Greybox</name>
|
56
|
+
<requested_by>Brian Hogan</requested_by>
|
57
|
+
<owned_by>Brian Hogan</owned_by>
|
58
|
+
<created_at type="datetime">2008/12/04 18:46:43 UTC</created_at>
|
59
|
+
<accepted_at type="datetime">2009/01/19 17:22:53 UTC</accepted_at>
|
60
|
+
</story>
|
61
|
+
<story>
|
62
|
+
<id type="integer">300931</id>
|
63
|
+
<story_type>bug</story_type>
|
64
|
+
<url>http://www.pivotaltracker.com/story/show/300931</url>
|
65
|
+
<current_state>accepted</current_state>
|
66
|
+
<description>The home page has no title set.</description>
|
67
|
+
<name>Get a title on the home page</name>
|
68
|
+
<requested_by>Brian Hogan</requested_by>
|
69
|
+
<owned_by>Brian Hogan</owned_by>
|
70
|
+
<created_at type="datetime">2008/12/04 02:22:00 UTC</created_at>
|
71
|
+
<accepted_at type="datetime">2009/01/19 17:23:11 UTC</accepted_at>
|
72
|
+
</story>
|
73
|
+
</stories>
|
74
|
+
</iteration>
|
75
|
+
<iteration>
|
76
|
+
<id type="integer">3</id>
|
77
|
+
<number type="integer">3</number>
|
78
|
+
<start type="datetime">2009/01/26 00:00:00 UTC</start>
|
79
|
+
<finish type="datetime">2009/02/02 00:00:00 UTC</finish>
|
80
|
+
<stories type="array">
|
81
|
+
</stories>
|
82
|
+
</iteration>
|
83
|
+
<iteration>
|
84
|
+
<id type="integer">4</id>
|
85
|
+
<number type="integer">4</number>
|
86
|
+
<start type="datetime">2009/02/02 00:00:00 UTC</start>
|
87
|
+
<finish type="datetime">2009/02/09 00:00:00 UTC</finish>
|
88
|
+
<stories type="array">
|
89
|
+
</stories>
|
90
|
+
</iteration>
|
91
|
+
<iteration>
|
92
|
+
<id type="integer">5</id>
|
93
|
+
<number type="integer">5</number>
|
94
|
+
<start type="datetime">2009/02/09 00:00:00 UTC</start>
|
95
|
+
<finish type="datetime">2009/02/16 00:00:00 UTC</finish>
|
96
|
+
<stories type="array">
|
97
|
+
</stories>
|
98
|
+
</iteration>
|
99
|
+
<iteration>
|
100
|
+
<id type="integer">6</id>
|
101
|
+
<number type="integer">6</number>
|
102
|
+
<start type="datetime">2009/02/16 00:00:00 UTC</start>
|
103
|
+
<finish type="datetime">2009/02/23 00:00:00 UTC</finish>
|
104
|
+
<stories type="array">
|
105
|
+
</stories>
|
106
|
+
</iteration>
|
107
|
+
<iteration>
|
108
|
+
<id type="integer">7</id>
|
109
|
+
<number type="integer">7</number>
|
110
|
+
<start type="datetime">2009/02/23 00:00:00 UTC</start>
|
111
|
+
<finish type="datetime">2009/03/02 00:00:00 UTC</finish>
|
112
|
+
<stories type="array">
|
113
|
+
</stories>
|
114
|
+
</iteration>
|
115
|
+
<iteration>
|
116
|
+
<id type="integer">8</id>
|
117
|
+
<number type="integer">8</number>
|
118
|
+
<start type="datetime">2009/03/02 00:00:00 UTC</start>
|
119
|
+
<finish type="datetime">2009/03/09 00:00:00 UTC</finish>
|
120
|
+
<stories type="array">
|
121
|
+
</stories>
|
122
|
+
</iteration>
|
123
|
+
<iteration>
|
124
|
+
<id type="integer">9</id>
|
125
|
+
<number type="integer">9</number>
|
126
|
+
<start type="datetime">2009/03/09 00:00:00 UTC</start>
|
127
|
+
<finish type="datetime">2009/03/16 00:00:00 UTC</finish>
|
128
|
+
<stories type="array">
|
129
|
+
</stories>
|
130
|
+
</iteration>
|
131
|
+
<iteration>
|
132
|
+
<id type="integer">10</id>
|
133
|
+
<number type="integer">10</number>
|
134
|
+
<start type="datetime">2009/03/16 00:00:00 UTC</start>
|
135
|
+
<finish type="datetime">2009/03/23 00:00:00 UTC</finish>
|
136
|
+
<stories type="array">
|
137
|
+
</stories>
|
138
|
+
</iteration>
|
139
|
+
<iteration>
|
140
|
+
<id type="integer">11</id>
|
141
|
+
<number type="integer">11</number>
|
142
|
+
<start type="datetime">2009/03/23 00:00:00 UTC</start>
|
143
|
+
<finish type="datetime">2009/03/30 00:00:00 UTC</finish>
|
144
|
+
<stories type="array">
|
145
|
+
</stories>
|
146
|
+
</iteration>
|
147
|
+
<iteration>
|
148
|
+
<id type="integer">12</id>
|
149
|
+
<number type="integer">12</number>
|
150
|
+
<start type="datetime">2009/03/30 00:00:00 UTC</start>
|
151
|
+
<finish type="datetime">2009/04/06 00:00:00 UTC</finish>
|
152
|
+
<stories type="array">
|
153
|
+
</stories>
|
154
|
+
</iteration>
|
155
|
+
<iteration>
|
156
|
+
<id type="integer">13</id>
|
157
|
+
<number type="integer">13</number>
|
158
|
+
<start type="datetime">2009/04/06 00:00:00 UTC</start>
|
159
|
+
<finish type="datetime">2009/04/13 00:00:00 UTC</finish>
|
160
|
+
<stories type="array">
|
161
|
+
</stories>
|
162
|
+
</iteration>
|
163
|
+
<iteration>
|
164
|
+
<id type="integer">14</id>
|
165
|
+
<number type="integer">14</number>
|
166
|
+
<start type="datetime">2009/04/13 00:00:00 UTC</start>
|
167
|
+
<finish type="datetime">2009/04/20 00:00:00 UTC</finish>
|
168
|
+
<stories type="array">
|
169
|
+
</stories>
|
170
|
+
</iteration>
|
171
|
+
<iteration>
|
172
|
+
<id type="integer">15</id>
|
173
|
+
<number type="integer">15</number>
|
174
|
+
<start type="datetime">2009/04/20 00:00:00 UTC</start>
|
175
|
+
<finish type="datetime">2009/04/27 00:00:00 UTC</finish>
|
176
|
+
<stories type="array">
|
177
|
+
</stories>
|
178
|
+
</iteration>
|
179
|
+
<iteration>
|
180
|
+
<id type="integer">16</id>
|
181
|
+
<number type="integer">16</number>
|
182
|
+
<start type="datetime">2009/04/27 00:00:00 UTC</start>
|
183
|
+
<finish type="datetime">2009/05/04 00:00:00 UTC</finish>
|
184
|
+
<stories type="array">
|
185
|
+
</stories>
|
186
|
+
</iteration>
|
187
|
+
<iteration>
|
188
|
+
<id type="integer">17</id>
|
189
|
+
<number type="integer">17</number>
|
190
|
+
<start type="datetime">2009/05/04 00:00:00 UTC</start>
|
191
|
+
<finish type="datetime">2009/05/11 00:00:00 UTC</finish>
|
192
|
+
<stories type="array">
|
193
|
+
</stories>
|
194
|
+
</iteration>
|
195
|
+
<iteration>
|
196
|
+
<id type="integer">18</id>
|
197
|
+
<number type="integer">18</number>
|
198
|
+
<start type="datetime">2009/05/11 00:00:00 UTC</start>
|
199
|
+
<finish type="datetime">2009/05/18 00:00:00 UTC</finish>
|
200
|
+
<stories type="array">
|
201
|
+
</stories>
|
202
|
+
</iteration>
|
203
|
+
<iteration>
|
204
|
+
<id type="integer">19</id>
|
205
|
+
<number type="integer">19</number>
|
206
|
+
<start type="datetime">2009/05/18 00:00:00 UTC</start>
|
207
|
+
<finish type="datetime">2009/05/25 00:00:00 UTC</finish>
|
208
|
+
<stories type="array">
|
209
|
+
</stories>
|
210
|
+
</iteration>
|
211
|
+
<iteration>
|
212
|
+
<id type="integer">20</id>
|
213
|
+
<number type="integer">20</number>
|
214
|
+
<start type="datetime">2009/05/25 00:00:00 UTC</start>
|
215
|
+
<finish type="datetime">2009/06/01 00:00:00 UTC</finish>
|
216
|
+
<stories type="array">
|
217
|
+
</stories>
|
218
|
+
</iteration>
|
219
|
+
<iteration>
|
220
|
+
<id type="integer">21</id>
|
221
|
+
<number type="integer">21</number>
|
222
|
+
<start type="datetime">2009/06/01 00:00:00 UTC</start>
|
223
|
+
<finish type="datetime">2009/06/08 00:00:00 UTC</finish>
|
224
|
+
<stories type="array">
|
225
|
+
</stories>
|
226
|
+
</iteration>
|
227
|
+
<iteration>
|
228
|
+
<id type="integer">22</id>
|
229
|
+
<number type="integer">22</number>
|
230
|
+
<start type="datetime">2009/06/08 00:00:00 UTC</start>
|
231
|
+
<finish type="datetime">2009/06/15 00:00:00 UTC</finish>
|
232
|
+
<stories type="array">
|
233
|
+
</stories>
|
234
|
+
</iteration>
|
235
|
+
<iteration>
|
236
|
+
<id type="integer">23</id>
|
237
|
+
<number type="integer">23</number>
|
238
|
+
<start type="datetime">2009/06/15 00:00:00 UTC</start>
|
239
|
+
<finish type="datetime">2009/06/22 00:00:00 UTC</finish>
|
240
|
+
<stories type="array">
|
241
|
+
</stories>
|
242
|
+
</iteration>
|
243
|
+
<iteration>
|
244
|
+
<id type="integer">24</id>
|
245
|
+
<number type="integer">24</number>
|
246
|
+
<start type="datetime">2009/06/22 00:00:00 UTC</start>
|
247
|
+
<finish type="datetime">2009/06/29 00:00:00 UTC</finish>
|
248
|
+
<stories type="array">
|
249
|
+
</stories>
|
250
|
+
</iteration>
|
251
|
+
<iteration>
|
252
|
+
<id type="integer">25</id>
|
253
|
+
<number type="integer">25</number>
|
254
|
+
<start type="datetime">2009/06/29 00:00:00 UTC</start>
|
255
|
+
<finish type="datetime">2009/07/06 00:00:00 UTC</finish>
|
256
|
+
<stories type="array">
|
257
|
+
</stories>
|
258
|
+
</iteration>
|
259
|
+
<iteration>
|
260
|
+
<id type="integer">26</id>
|
261
|
+
<number type="integer">26</number>
|
262
|
+
<start type="datetime">2009/07/06 00:00:00 UTC</start>
|
263
|
+
<finish type="datetime">2009/07/13 00:00:00 UTC</finish>
|
264
|
+
<stories type="array">
|
265
|
+
</stories>
|
266
|
+
</iteration>
|
267
|
+
<iteration>
|
268
|
+
<id type="integer">27</id>
|
269
|
+
<number type="integer">27</number>
|
270
|
+
<start type="datetime">2009/07/13 00:00:00 UTC</start>
|
271
|
+
<finish type="datetime">2009/07/20 00:00:00 UTC</finish>
|
272
|
+
<stories type="array">
|
273
|
+
</stories>
|
274
|
+
</iteration>
|
275
|
+
<iteration>
|
276
|
+
<id type="integer">28</id>
|
277
|
+
<number type="integer">28</number>
|
278
|
+
<start type="datetime">2009/07/20 00:00:00 UTC</start>
|
279
|
+
<finish type="datetime">2009/07/27 00:00:00 UTC</finish>
|
280
|
+
<stories type="array">
|
281
|
+
<story>
|
282
|
+
<id type="integer">300939</id>
|
283
|
+
<story_type>feature</story_type>
|
284
|
+
<url>http://www.pivotaltracker.com/story/show/300939</url>
|
285
|
+
<estimate type="integer">1</estimate>
|
286
|
+
<current_state>started</current_state>
|
287
|
+
<description>Images need to be linked and modalbox needs testing in other browsers besides FF and Safari.</description>
|
288
|
+
<name>Finish modalbox implementation</name>
|
289
|
+
<requested_by>Brian Hogan</requested_by>
|
290
|
+
<owned_by>Brian Hogan</owned_by>
|
291
|
+
<created_at type="datetime">2008/12/04 02:33:33 UTC</created_at>
|
292
|
+
</story>
|
293
|
+
<story>
|
294
|
+
<id type="integer">300495</id>
|
295
|
+
<story_type>feature</story_type>
|
296
|
+
<url>http://www.pivotaltracker.com/story/show/300495</url>
|
297
|
+
<estimate type="integer">3</estimate>
|
298
|
+
<current_state>started</current_state>
|
299
|
+
<description>Choose an item, edit it, and notice that the dropdown for file / url is not selected on load, causing the file or url field to not display.</description>
|
300
|
+
<name>Editing an item does not select the correct type</name>
|
301
|
+
<requested_by>Brian Hogan</requested_by>
|
302
|
+
<owned_by>Brian Hogan</owned_by>
|
303
|
+
<created_at type="datetime">2008/12/04 01:55:39 UTC</created_at>
|
304
|
+
</story>
|
305
|
+
<story>
|
306
|
+
<id type="integer">300423</id>
|
307
|
+
<story_type>feature</story_type>
|
308
|
+
<url>http://www.pivotaltracker.com/story/show/300423</url>
|
309
|
+
<estimate type="integer">3</estimate>
|
310
|
+
<current_state>started</current_state>
|
311
|
+
<description>A profile should be viewable using the iPhone or Touch.
|
312
|
+
The profile page should link to the portfolios.
|
313
|
+
items should display within the portfolios.</description>
|
314
|
+
<name>iPhone interface for viewing profiles</name>
|
315
|
+
<requested_by>Brian Hogan</requested_by>
|
316
|
+
<owned_by>Brian Hogan</owned_by>
|
317
|
+
<created_at type="datetime">2008/12/04 01:48:53 UTC</created_at>
|
318
|
+
</story>
|
319
|
+
<story>
|
320
|
+
<id type="integer">300923</id>
|
321
|
+
<story_type>feature</story_type>
|
322
|
+
<url>http://www.pivotaltracker.com/story/show/300923</url>
|
323
|
+
<estimate type="integer">1</estimate>
|
324
|
+
<current_state>unstarted</current_state>
|
325
|
+
<description>Add a "contact us" form that sends an email</description>
|
326
|
+
<name>Contact Us form</name>
|
327
|
+
<requested_by>Brian Hogan</requested_by>
|
328
|
+
<created_at type="datetime">2008/12/04 02:14:51 UTC</created_at>
|
329
|
+
</story>
|
330
|
+
<story>
|
331
|
+
<id type="integer">300518</id>
|
332
|
+
<story_type>feature</story_type>
|
333
|
+
<url>http://www.pivotaltracker.com/story/show/300518</url>
|
334
|
+
<estimate type="integer">1</estimate>
|
335
|
+
<current_state>unstarted</current_state>
|
336
|
+
<description>Add a send to friend link on portfolios</description>
|
337
|
+
<name>Send To Friend linke</name>
|
338
|
+
<requested_by>Brian Hogan</requested_by>
|
339
|
+
<created_at type="datetime">2008/12/04 01:57:22 UTC</created_at>
|
340
|
+
</story>
|
341
|
+
</stories>
|
342
|
+
</iteration>
|
343
|
+
</iterations>}
|
344
|
+
url = "#{@service}/projects/4860/iterations?token=#{@token}"
|
345
|
+
FakeWeb.register_uri(:get, url, :string => xml, :content_type => "application/xml", :status => ["200", "OK"])
|
346
|
+
@project = Pivotal::Iteration.new("id" => "4860", :name => "FeelMySkills")
|
347
|
+
end
|
348
|
+
it "should get iterations" do
|
349
|
+
iterations = Pivotal::Iteration.find_all_by_project_id(@project.id)
|
350
|
+
iterations.each{|i| i.should be_a(Pivotal::Iteration)}
|
351
|
+
iterations.detect{|i| i.number == 28}.should be_true
|
352
|
+
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
|
357
|
+
end
|