rallytastic 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,102 @@
1
+ class RallyAPI
2
+ class Configure
3
+ attr_accessor :user, :password
4
+ end
5
+
6
+ class CredentialsError < RestClient::Unauthorized; end
7
+
8
+ class << self
9
+ @configuration = nil
10
+
11
+ def configure(&block)
12
+ @configuration = @configuration || Configure.new
13
+ yield @configuration
14
+ end
15
+
16
+ def configuration
17
+ @configuration
18
+ end
19
+
20
+ def all resource, options ={}
21
+ check_configuration
22
+ do_get(resource.rally_uri, parsed_options(options))
23
+ end
24
+
25
+ def get resource
26
+ check_configuration
27
+ json = JSON.parse(do_get(resource.rally_uri))
28
+ json[resource.class.node_name]
29
+ end
30
+
31
+ def parsed_options options
32
+ option_string = {}
33
+ if options.has_key? :conditions
34
+ option_string = option_string.merge(parsed_query(options[:conditions]))
35
+ end
36
+
37
+ if options.has_key? :start
38
+ option_string = option_string.merge(parsed_start(options[:start]))
39
+ end
40
+
41
+ if options.has_key? :pagesize
42
+ option_string = option_string.merge(parsed_pagesize(options[:pagesize]))
43
+ end
44
+
45
+ if options.has_key? :fetch
46
+ option_string = option_string.merge(parsed_fetch(options[:fetch]))
47
+ end
48
+ option_string
49
+ end
50
+
51
+ def parsed_fetch(fetch)
52
+ {"fetch" => fetch}
53
+ end
54
+
55
+ def parsed_start(start)
56
+ {"start" => start.to_i}
57
+ end
58
+
59
+ def parsed_pagesize(pagesize)
60
+ {"pagesize" => pagesize.to_i}
61
+ end
62
+
63
+ def parsed_query conditions
64
+ tokens = conditions.collect{|k,v| query_token(k,v)}
65
+ {"query" => tokens.join(" and ")}
66
+ end
67
+
68
+ def query_token k,v
69
+ operators ={
70
+ "gt" => ">",
71
+ "gte" => ">=",
72
+ "lt" => "<",
73
+ "lte" => "<=",
74
+ "ne" => "!="}
75
+ field = k.respond_to?("key") ? k.key : k
76
+ field = field.downcase == field ? field.capitalize : field
77
+ operator = k.respond_to?("operator") ? operators[k.operator] : "="
78
+ "(#{field.to_s} #{operator} \"#{v}\")"
79
+ end
80
+
81
+ def do_get endpoint, options = nil
82
+ if endpoint.match(/https:\/\/.*/)
83
+ rally_resource(endpoint).get(:params => options)
84
+ else
85
+ rally_resource[endpoint].get(:params => options)
86
+ end
87
+ end
88
+
89
+ def rally_resource uri = nil
90
+ uri ||= "https://rally1.rallydev.com/slm/webservice/1.19"
91
+ RestClient::Resource.new(uri,
92
+ :user => self.configuration.user,
93
+ :password => self.configuration.password)
94
+ end
95
+
96
+ def check_configuration
97
+ if self.configuration.user.nil? || self.configuration.password.nil?
98
+ raise CredentialsError.new
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,30 @@
1
+ # Set up gems listed in the Gemfile.
2
+ gemfile = File.expand_path('../Gemfile', __FILE__)
3
+
4
+ begin
5
+ ENV['BUNDLE_GEMFILE'] = gemfile
6
+ require 'bundler'
7
+ Bundler.setup
8
+ rescue Bundler::GemNotFound => e
9
+ STDERR.puts e.message
10
+ STDERR.puts "Try running `bundle install`."
11
+ exit!
12
+ end if File.exist?(gemfile)
13
+
14
+
15
+ lib = File.dirname(__FILE__)
16
+ require 'mongoid'
17
+ require 'rest_client'
18
+ require File.join(lib, 'rally/parsing_helpers.rb')
19
+ require File.join(lib, 'story.rb')
20
+ require File.join(lib, 'project.rb')
21
+ require File.join(lib, 'iteration.rb')
22
+ require File.join(lib, 'revision_history.rb')
23
+ require File.join(lib, 'revision.rb')
24
+ require File.join(lib, 'rally/rally_api.rb')
25
+ require File.join(lib, 'parsers/base.rb')
26
+ require File.join(lib, 'parsers/madison.rb')
27
+
28
+
29
+ #temp for rally and mongoid setup
30
+ require '~/rally_config'
data/lib/revision.rb ADDED
@@ -0,0 +1,18 @@
1
+ class Revision
2
+ include Mongoid::Document
3
+ include Rally::ParsingHelpers
4
+ extend Rally::ParsingHelperClassMethods
5
+
6
+ field :description
7
+ field :revision_number
8
+ field :created_on
9
+
10
+ embedded_in :story, :inverse_of => :revisions
11
+
12
+ def refresh hash_values=nil
13
+ @rally_hash = hash_values if hash_values
14
+ from_rally :description
15
+ from_rally :revision_number
16
+ from_rally :created_on, :CreationDate
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ class RevisionHistory
2
+ include Mongoid::Document
3
+ include Rally::ParsingHelpers
4
+ extend Rally::ParsingHelperClassMethods
5
+
6
+ field :revisions, :type => Array
7
+
8
+ class << self
9
+ def rally_uri
10
+ "/revisionhistory.js"
11
+ end
12
+ end
13
+
14
+ def refresh
15
+ parse_refs :revisions, raw_json["Revisions"]
16
+ self.save
17
+ end
18
+
19
+ end
data/lib/story.rb ADDED
@@ -0,0 +1,101 @@
1
+ class Story
2
+ include Mongoid::Document
3
+ include Rally::ParsingHelpers
4
+ extend Rally::ParsingHelperClassMethods
5
+
6
+ class << self
7
+ def rally_uri
8
+ "/hierarchicalrequirement.js"
9
+ end
10
+ end
11
+
12
+ field :name
13
+ field :rally_uri
14
+ field :created_on, :type => Date
15
+ field :updated_on, :type => Date
16
+ field :description
17
+ field :notes
18
+ field :formatted_id
19
+ field :accepted_on, :type => Date
20
+ field :blocked, :type => Boolean
21
+ field :plan_estimate, :type => Integer
22
+ field :predicessor_uris, :type => Array
23
+ field :rank
24
+ field :schedule_state
25
+ field :requested_due_date, :type => Date
26
+ field :theme
27
+ field :revision_history_uri
28
+ field :rally_hash, :type => Hash
29
+
30
+ field :sized_on, :type => DateTime
31
+ field :prioritized_on, :type => DateTime
32
+ field :started_on, :type => DateTime
33
+ field :completed_on, :type => DateTime
34
+ field :accepted_on, :type => DateTime
35
+
36
+ embeds_many :revisions, :inverse_of => :story
37
+ referenced_in :iteration
38
+ referenced_in :parent, :class_name => "Story", :inverse_of => :children
39
+ references_many :children, :class_name => "Story", :inverse_of => :parent
40
+
41
+ def set_revision_history
42
+ revision_fields.each do |field|
43
+ self.send("#{field}=", revision_parser.send(field))
44
+ end
45
+ end
46
+
47
+ def revision_history
48
+ set_revision_history
49
+ revision_fields.inject({}){|h,field| h[field] = self.send(field.to_s); h}
50
+ end
51
+
52
+ def revision_fields
53
+ [:sized_on, :prioritized_on, :started_on, :completed_on, :accepted_on]
54
+ end
55
+
56
+ def revision_parser
57
+ if self.iteration && self.iteration.project
58
+ eval("Parser::#{self.iteration.project.revision_parser}").new(self)
59
+ end
60
+ end
61
+
62
+ def refresh hash_values=nil
63
+ @rally_hash = hash_values
64
+ from_rally :rally_uri, :_ref
65
+ from_rally :name
66
+ from_rally :notes
67
+ from_rally :created_on, :_CreatedAt
68
+ from_rally :description
69
+ from_rally :formatted_id, :FormattedID
70
+ from_rally :updated_on, :LastUpdateDate
71
+ from_rally :accepted_on, :AcceptedDate
72
+ from_rally :blocked
73
+ from_rally :plan_estimate, :PlanEstimate
74
+ from_rally :rank
75
+ from_rally :schedule_state, :ScheduleState
76
+ from_rally :requested_due_date, :RequestedDueDate
77
+ from_rally :theme
78
+
79
+ parse_ref :revision_history_uri, @rally_hash["RevisionHistory"]
80
+
81
+ self.save
82
+ rescue ArgumentError #getting some bad created_on dates
83
+ puts "Errored on #{self.name}"
84
+ self.save # save what you can
85
+ end
86
+
87
+ def associate hash_values=nil
88
+ @rally_hash = hash_values if hash_values
89
+ if @rally_hash["Iteration"]
90
+ iteration = Iteration.find_or_create_by(:rally_uri => @rally_hash["Iteration"]["_ref"])
91
+ self.iteration = iteration
92
+ end
93
+
94
+ if @rally_hash["Parent"]
95
+ story = Story.find_or_create_by(:rally_uri => @rally_hash["Parent"]["_ref"])
96
+ self.parent = story
97
+ end
98
+
99
+ self.save
100
+ end
101
+ end
@@ -0,0 +1,31 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'rallytastic')
2
+
3
+ class Docs < Thor
4
+ desc "update_readme", "Updates README.doc with thor task descriptions for project"
5
+ def update_readme
6
+ tasks = Scraper.printable_tasks
7
+ file_path = File.join(File.dirname(__FILE__), '..', '..', 'README.rdoc')
8
+
9
+ #indexes of thor section
10
+ f = File.open(file_path)
11
+ lines = f.readlines
12
+ start = lines.index("=== Thor Tasks\n")
13
+ finish = lines.index("<End of Thor Tasks>\n")
14
+ f.close
15
+
16
+ #write new README
17
+ f = File.open(file_path, "w+")
18
+ lines[0..start].each{|l| f << l}
19
+ tasks.each{|l| write_thor_task f, l}
20
+ lines[finish..-1].each{|l| f << l}
21
+ f.close
22
+
23
+ end
24
+
25
+ private
26
+ def write_thor_task file, task
27
+ command_parts = task[0].split(" ")
28
+ file << "==== #{command_parts[1..-1].join(" ")}\n"
29
+ file << "#{task[1]}\n"
30
+ end
31
+ end
@@ -0,0 +1,94 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'rallytastic')
2
+ require File.join("~", 'rally_config.rb')
3
+
4
+ class Scraper < Thor
5
+ desc "refresh", "Pulls down Rally stories since the last run, and creates Iterations and Projects as needed. This is the task you want to put in your job scheduler."
6
+ def refresh
7
+ stories
8
+ update_non_stories
9
+ end
10
+
11
+ desc "stories", "Walk Rally stories updated since last run"
12
+ def stories
13
+ most_recent = Story.desc(:updated_on).limit(1).first
14
+ if most_recent
15
+ pull_all_from_rally_of_object Story, :conditions => {:LastUpdateDate.gt => most_recent.updated_on.to_s}
16
+ else
17
+ pull_all_from_rally_of_object Story
18
+ end
19
+
20
+ end
21
+
22
+ desc "update_non_stories", "The scrape:stroies task creates shell iterations and projects for any that it doesn't know about yet. This task looks for those, and pull their information down from Rally"
23
+ def update_non_stories
24
+ Iteration.all(:conditions => {:name => nil, :rally_uri.ne => nil}).each{|i| i.refresh; i.associate}
25
+ Project.all(:conditions => {:name => nil, :rally_uri.ne => nil}).each{|s| s.refresh; i.associate}
26
+ end
27
+
28
+ desc "revisions iteration_name", "Get the revisions for stories hanging off an iteration"
29
+ def revisions iteration_name
30
+ iteration = Iteration.find(:conditions => {:name => iteration_name}).first
31
+ iteration.stories.each{|story| revisions_for_story(story)}
32
+ end
33
+
34
+ desc "projects", "Bootstrapping method that is primarily useful when you are setting up Rallytastic for the first time. It will walk Rally and pull down all projects. Technically, you don't need to run this because using the scrape:stories; scrape:update_non_stories; will fill this information in for you. It may be a bit quicker though to run this first if you have a lot of projects because it does batch queries"
35
+ def projects
36
+ pull_all_from_rally_of_object Project
37
+ end
38
+
39
+ desc "iterations", "Bootstrapping method that is primarily useful when you are setting up Rallytastic for the first time. It will walk Rally and pull down all Iterations. Technically, you don't need to run this because using the scrape:stories; scrape:update_non_stories; will fill this information in for you. It may be a bit quicker though to run this first if you have a lot of iterations because it does batch queries"
40
+ def iterations
41
+ pull_all_from_rally_of_object Iteration
42
+ end
43
+
44
+ private
45
+ def revisions_for_story(story)
46
+ story_in_rally = RallyAPI.get(story)
47
+ revision_list = RevisionHistory.new(:rally_uri => story_in_rally["RevisionHistory"]["_ref"])
48
+ revision_list.refresh
49
+ revision_uris = story.revisions.collect{|r| r.rally_uri}
50
+ if revision_list.revisions
51
+ revision_list.revisions.each do |uri|
52
+ unless revision_uris.include?(uri)
53
+ r = Revision.new(:rally_uri => uri)
54
+ r.refresh
55
+ story.revisions << r
56
+ end
57
+ end
58
+ end
59
+ story.save
60
+ end
61
+
62
+ def pull_all_from_rally_of_object klass, options={}
63
+ total, page_size, start_index = nil, 100, 1
64
+ while start_index = offset(total, page_size, start_index) do
65
+ query = {:fetch => true, :start => start_index, :pagesize => page_size}.merge(options)
66
+ response = klass.rally_query(query)
67
+ response_hash = JSON.parse(response)["QueryResult"]
68
+ process_results klass, response_hash["Results"]
69
+ total, page_size, start_index = response_hash["TotalResultCount"], response_hash["PageSize"], response_hash["StartIndex"]
70
+ end
71
+ end
72
+
73
+ def process_results klass, results
74
+ results.each do |result|
75
+ local = klass.find_or_create_by(:rally_uri => result["_ref"])
76
+ local.refresh(result)
77
+ local.associate(result)
78
+ end
79
+ end
80
+
81
+ def offset total, page_size, start_index
82
+ if total.nil? #first pass
83
+ return start_index
84
+ elsif start_index >= total
85
+ return nil # we are at th end
86
+ else
87
+ return start_index + page_size
88
+ end
89
+ end
90
+
91
+ def updated_since
92
+ DateTime.parse("1-1-2008")
93
+ end
94
+ end
@@ -0,0 +1 @@
1
+ {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/440861167.js", "_objectVersion"=>"1", "_refObjectName"=>"Customer Experience", "CreationDate"=>"2009-07-01T22:50:23.000Z", "_CreatedAt"=>"Jul 1, 2009", "ObjectID"=>440861167, "Subscription"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/subscription/411778556.js", "_refObjectName"=>"King Arthur's Court", "_type"=>"Subscription"}, "Workspace"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/workspace/411780799.js", "_refObjectName"=>"King Arthurs Court", "_type"=>"Workspace"}, "BuildDefinitions"=>[{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/builddefinition/440861173.js", "_refObjectName"=>"Default Build Definition", "_type"=>"BuildDefinition"}], "Children"=>[{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/43434343.js", "_refObjectName"=>"L&P", "_type"=>"Project"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/2325452.js", "_refObjectName"=>"Kool and the Gang", "_type"=>"Project"}], "Description"=>"A nice description", "Iterations"=>[{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/iteration/4342242.js", "_refObjectName"=>"Week 5 -- July 13 - July 17 2009", "_type"=>"Iteration"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/iteration/4545454.js", "_refObjectName"=>"Week 6 -- July 20 - July 24 2009", "_type"=>"Iteration"}], "Name"=>"Flounder", "Notes"=>"some notes", "Owner"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/user/43434343.js", "_refObjectName"=>"Peter Pan", "_type"=>"User"}, "Parent"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/440864397.js", "_refObjectName"=>"King Arthur's court", "_type"=>"Project"}, "Releases"=>[], "State"=>"Open", "Users"=>[{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/user/342424242.js", "_refObjectName"=>"Bart Simpson", "_type"=>"User"}], "Errors"=>[], "Warnings"=>[]}
@@ -0,0 +1 @@
1
+ {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/iteration/4623232.js", "_objectVersion"=>"1", "_refObjectName"=>"iteration0", "CreationDate"=>"2009-07-13T15:46:05.000Z", "_CreatedAt"=>"Jul 13, 2009", "ObjectID"=>462353428, "Subscription"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/subscription/3434343.js", "_refObjectName"=>"King Arthur's Court", "_type"=>"Subscription"}, "Workspace"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/workspace/454545454.js", "_refObjectName"=>"Wonderful workspace", "_type"=>"Workspace"}, "EndDate"=>"2009-07-18T23:59:59.000Z", "Name"=>"Iteration1", "Notes"=>"", "Project"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/440864397.js", "_refObjectName"=>"Are You Experienced", "_type"=>"Project"}, "Resources"=>"2.0", "RevisionHistory"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/revisionhistory/434344.js", "_type"=>"RevisionHistory"}, "StartDate"=>"2009-07-13T00:00:00.000Z", "State"=>"Planning", "Theme"=>"This is the theme", "UserIterationCapacities"=>[], "Errors"=>[], "Warnings"=>[]}
@@ -0,0 +1 @@
1
+ {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/440864397.js", "_objectVersion"=>"1", "_refObjectName"=>"Customer Experience", "CreationDate"=>"2009-07-01T22:50:23.000Z", "_CreatedAt"=>"Jul 1, 2009", "ObjectID"=>3243423237, "Subscription"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/subscription/411772322.js", "_refObjectName"=>"super subscription", "_type"=>"Subscription"}, "Workspace"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/workspace/4117802322.js", "_refObjectName"=>"Wonderful Workspace", "_type"=>"Workspace"}, "BuildDefinitions"=>[{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/builddefinition/4408632232.js", "_refObjectName"=>"Default Build Definition", "_type"=>"BuildDefinition"}], "Children"=>[{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/4409124343.js", "_refObjectName"=>"L&P", "_type"=>"Project"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/423687232.js", "_refObjectName"=>"Moon Landing", "_type"=>"Project"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/4409452323.js", "_refObjectName"=>"Crater landing", "_type"=>"Project"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/440905343.js", "_refObjectName"=>"Modern Architecture", "_type"=>"Project"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/423682323.js", "_refObjectName"=>"Hugenis", "_type"=>"Project"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/4236834343.js", "_refObjectName"=>"Jupiter", "_type"=>"Project"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/4236854534.js", "_refObjectName"=>"ESA", "_type"=>"Project"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/6006813233.js", "_refObjectName"=>"Ion Propulsion", "_type"=>"Project"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/119393323232.js", "_refObjectName"=>"Martian Rover"}], "Description"=>"A nice description", "Iterations"=>[{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/iteration/46235334434.js", "_refObjectName"=>"for launch", "_type"=>"Iteration"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/iteration/4623534344.js", "_refObjectName"=>"post launch", "_type"=>"Iteration"}], "Name"=>"Down the hatch", "Notes"=>"some notes", "Owner"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/user/411781343443.js", "_refObjectName"=>"Kin Lear", "_type"=>"User"}, "Parent"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/411780344343.js", "_refObjectName"=>"King Aurthr's Court", "_type"=>"Project"}, "Releases"=>[{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/release/46233443434.js", "_refObjectName"=>"September Release", "_type"=>"Release"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/release/46234143434.js", "_refObjectName"=>"October Release", "_type"=>"Release"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/release/462344434343.js", "_refObjectName"=>"December Release", "_type"=>"Release"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/release/1289875344343.js", "_refObjectName"=>"May Major Release - May 13", "_type"=>"Release"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/release/183277434344.js", "_refObjectName"=>"Phase 8", "_type"=>"Release"}], "State"=>"Open", "Users"=>[{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/user/23234444.js", "_refObjectName"=>"Homer Simpson", "_type"=>"User"}], "Errors"=>[], "Warnings"=>[]}
@@ -0,0 +1 @@
1
+ {"HierarchicalRequirement"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/hierarchicalrequirement/413668210.js", "_objectVersion"=>"12", "_refObjectName"=>"Run the Marathon", "CreationDate"=>"2009-06-11T16:12:46.000Z", "_CreatedAt"=>"Jun 11, 2009", "ObjectID"=>413668210, "Subscription"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/subscription/413242424.js", "_refObjectName"=>"Getty Images", "_type"=>"Subscription"}, "Workspace"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/workspace/4324242.js", "_refObjectName"=>"Athens", "_type"=>"Workspace"}, "Description"=>"You've trained for it, now do it. Done when, you run 26.2 miles.", "Discussion"=>[], "FormattedID"=>"US26", "LastUpdateDate"=>"2009-09-10T18:57:55.000Z", "Name"=>"Run the marathon", "Notes"=>"some notes", "Owner"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/user/412332424.js", "_refObjectName"=>"Forest Gump", "_type"=>"User"}, "Project"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/project/342424242.js", "_refObjectName"=>"Getting fit", "_type"=>"Project"}, "RevisionHistory"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/revisionhistory/413668211.js", "_type"=>"RevisionHistory"}, "Tags"=>[], "Attachments"=>[], "Package"=>nil, "AcceptedDate"=>"2009-09-10T18:57:55.000Z", "Blocked"=>false, "Blocker"=>nil, "Children"=>[], "Defects"=>[], "Iteration"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/iteration/234242424.js", "_refObjectName"=>"Week 1 -- August 3 - August 7 2009", "_type"=>"Iteration"}, "Parent"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/hierarchicalrequirement/413668210.js", "_refObjectName"=>"Multi-site: Create Jupiter EZA portfolio in SCI", "_type"=>"HierarchicalRequirement"}, "PlanEstimate"=>3.0, "Predecessors"=>[], "Rank"=>"86292398717311774535928819836502410.432", "Release"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/release/3424242.js", "_refObjectName"=>"Release name", "_type"=>"Release"}, "ScheduleState"=>"Accepted", "Successors"=>[], "TaskActualTotal"=>0.0, "TaskEstimateTotal"=>6.0, "TaskRemainingTotal"=>0.0, "Tasks"=>[{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/task/3424243242.js", "_refObjectName"=>"Put down left foot", "_type"=>"Task"}], "TestCases"=>[], "KanbanState"=>nil, "KanbanStateGITest"=>nil, "KanbanStateUnix"=>nil, "RequestedDueDate"=>"2009-06-11T16:12:46.000Z", "Requestor"=>nil, "Theme"=>"this is the theme", "Errors"=>[], "Warnings"=>[]}}
@@ -0,0 +1 @@
1
+ {"QueryResult"=>{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "Errors"=>[], "Warnings"=>[], "TotalResultCount"=>10, "StartIndex"=>1, "PageSize"=>20, "Results"=>[{"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/hierarchicalrequirement/413668210.js", "_refObjectName"=>"Multi-site: Create Jupiter EZA portfolio in SCI", "_type"=>"HierarchicalRequirement"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/hierarchicalrequirement/451159598.js", "_refObjectName"=>"Multi-site: A time/date stamp is needed on the EM fields for each site", "_type"=>"HierarchicalRequirement"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/hierarchicalrequirement/458369669.js", "_refObjectName"=>"Rights Portal: change text on RightsPortal button and remove old SCI buttons", "_type"=>"HierarchicalRequirement"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/hierarchicalrequirement/458941309.js", "_refObjectName"=>"UU: NOC ticket 1564534 - Send to Finisher failure", "_type"=>"HierarchicalRequirement"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/hierarchicalrequirement/466045791.js", "_refObjectName"=>"Multi-site: Update SCI order confirmation email for JI", "_type"=>"HierarchicalRequirement"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/hierarchicalrequirement/470734293.js", "_refObjectName"=>"Analysis: Cognos: Build queries to populate Cognos with Scorecard metrics", "_type"=>"HierarchicalRequirement"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/hierarchicalrequirement/486810765.js", "_refObjectName"=>"Bug: On GYI, when you check/uncheck your email preference only from Myprofile, the record does not publish out", "_type"=>"HierarchicalRequirement"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/hierarchicalrequirement/517412658.js", "_refObjectName"=>"Oracle Event Project Regression Testing", "_type"=>"HierarchicalRequirement"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/hierarchicalrequirement/519567381.js", "_refObjectName"=>"Request update: CRM request form called \"Contract Billing\"", "_type"=>"HierarchicalRequirement"}, {"_rallyAPIMajor"=>"1", "_rallyAPIMinor"=>"19", "_ref"=>"https://rally1.rallydev.com/slm/webservice/1.19/hierarchicalrequirement/519679148.js", "_refObjectName"=>"Quick Search update: Email query does not work if a hyphen is in the email address", "_type"=>"HierarchicalRequirement"}]}}
@@ -0,0 +1,76 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Iteration do
4
+ before do
5
+ Iteration.collection.remove
6
+ @hash_vals = File.read(File.join(File.dirname(__FILE__), 'fixtures', 'iteration.txt'))
7
+ RallyAPI.stub!(:get).and_return(eval(@hash_vals))
8
+ end
9
+
10
+
11
+ it "should be a iteration" do
12
+ Iteration.new.class.should == Iteration
13
+ end
14
+
15
+ describe "#associate" do
16
+ before do
17
+ @iteration = Iteration.new(:rally_uri => "http://testuri.com")
18
+ end
19
+
20
+ it "should associate project" do
21
+ @iteration.associate(eval(@hash_vals))
22
+ @iteration.project.should_not be_nil
23
+ end
24
+ end
25
+
26
+ describe "refreshing" do
27
+ before do
28
+ @iteration = Iteration.new(:rally_uri => "http://testuri.com")
29
+ end
30
+ it "should assign name" do
31
+ @iteration.refresh
32
+ @iteration.name.should == "Iteration1"
33
+ end
34
+
35
+ it "should assign created_on" do
36
+ @iteration.refresh
37
+ @iteration.created_on.should == Date.parse("Jul 13, 2009")
38
+ end
39
+
40
+ it "should assign end_date" do
41
+ @iteration.refresh
42
+ @iteration.end_date.should == Date.parse("2009-07-18T23:59:59.000Z")
43
+ end
44
+
45
+ it "should assign notes" do
46
+ @iteration.refresh
47
+ @iteration.name.should == "Iteration1"
48
+ end
49
+
50
+ it "should assign resources" do
51
+ @iteration.refresh
52
+ @iteration.resources.should == "2.0"
53
+ end
54
+
55
+ it "should assign start_date" do
56
+ @iteration.refresh
57
+ @iteration.start_date.should == Date.parse("2009-07-13T00:00:00.000Z")
58
+ end
59
+
60
+ it "should assign state" do
61
+ @iteration.refresh
62
+ @iteration.state.should == "Planning"
63
+ end
64
+
65
+ it "should assign theme" do
66
+ @iteration.refresh
67
+ @iteration.theme.should == "This is the theme"
68
+ end
69
+
70
+ #it "should assign user_iteration_capacities" do
71
+ # @iteration.refresh
72
+ # @iteration.user_iteration_capacities.should == "Iteration1"
73
+ #end
74
+ end
75
+
76
+ end