rally_api 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,102 +1,113 @@
1
- RallyAPI (rally_api)
1
+ = RallyAPI (rally_api) -- a faster Rally REST api wrapper
2
2
 
3
- ==Description
3
+ == Description
4
4
 
5
- RallyAPI is a wrapper of Rally's Web Service API Json endpoints
5
+ RallyAPI is a wrapper of Rally's Web Service API Json endpoints using rest-client and native json parsing
6
6
 
7
7
  == Installation
8
-
9
- gem install rest-client
10
- gem install json
11
- gem install rally_api
12
-
13
- ** Note if you are on Windows - you will need DevKit from http://rubyinstaller.org to properly install the json gem
14
- ** - that native compiled parsing gives us some speed.
15
- ** - Follow the instructions here to install DevKit: https://github.com/oneclick/rubyinstaller/wiki/Development-Kit
8
+ gem install rally_api
16
9
 
17
10
  == Usage
18
11
 
19
- require 'rally_api'
20
-
21
- #Setting custom headers
22
- headers = RallyAPI::CustomHttpHeader.new()
23
- headers.name = "My Utility"
24
- headers.vendor = "MyCompany"
25
- headers.version = "1.0"
26
-
27
- #==================== Making a connection to Rally ====================
28
- config = {:base_url => "https://rally1.rallydev.com/slm"}
29
- config[:username] = "user@company.com"
30
- config[:password] = "password"
31
- config[:workspace] = "Workspace Name"
32
- config[:project] = "Project Name"
33
- config[:headers] = headers #from RallyAPI::CustomHttpHeader.new()
34
-
35
- @rally = RallyAPI::RallyRestJson.new(config)
36
-
37
- #==================== Querying Rally ==========================
38
- test_query = RallyAPI::RallyQuery.new()
39
- test_query.type = :defect
40
- test_query.fetch = "Name"
41
- test_query.workspace = {"_ref" => "https://rally1.rallydev.com/slm/webservice/1.25/workspace/12345.js" } #optional
42
- test_query.project = {"_ref" => "https://rally1.rallydev.com/slm/webservice/1.25/project/12345.js" } #optional
43
- test_query.page_size = 200 #optional - default is 200
44
- test_query.limit = 1000 #optional - default is 99999
45
- test_query.project_scope_up = false
46
- test_query.project_scope_down = true
47
- test_query.order = "Name Asc"
48
- test_query.query_string = "(Severity = \"High\")"
49
-
50
- results = @rally.find(test_query)
51
-
52
- #tip - set the fetch string of the query to the fields you need -
53
- #only resort to the read method if you want your code to be slow
54
- results.each do |defect|
55
- puts defect.Name
56
- defect.read #read the whole defect from Rally to get all fields (eg Severity)
57
- puts defect.Severity
58
- end
59
-
60
- #==================== Reading an Artifact ====================
61
- defect = @rally.read(:defect, 12345) #by ObjectID
62
- #or
63
- defect = @rally.read(:defect, "FormattedID|DE42") #by FormattedID
64
- #or if you already have an object like from a query
65
- results = @rally.find(RallyAPI::RallyQuery.new({:type => :defect, :query_string => "(FormattedID = DE42)"}))
66
- defect = results.first
67
- defect.read
68
-
69
- puts defect["Name"]
70
- #or - fields can be read by bracket artifact["FieldDisplayName"] or artifact.FieldDisplayName
71
- puts defect.Name
72
-
73
- #An Important note about reading fields and fetching:
74
- #If you query with a specific fetch string, for example query defect and fetch Name,Severity,Description
75
- #You will *only* get back those fields defect.Priority will be nil, but may not be null in Rally
76
- #Use object.read or @rally.read to make sure you read the whole object if you want what is in Rally
77
- # This is done for speed - lazy loading (going back to get a value from Rally) can be unneccessarily slow
78
- # *Pick you fetch strings wisely* fetch everything you need and don't rely on read if you don't need it the speed is worth it.
79
-
80
- #==================== Creating an Artifact ====================
81
- obj = {}
82
- obj["Name"] = "Test Defect created #{DateTime.now()}"
83
- new_de = @rally.create(:defect, obj)
84
- puts new_de["FormattedID"]
85
-
86
- #==================== Updating an Artifact ====================
87
- fields = {}
88
- fields["Severity"] = "Critical"
89
- fields["Description"] = "Description for the issue"
90
- updated_defect = @rally.update(:defect, 12345, fields) #by ObjectID
91
- #or
92
- updated_defect = @rally.update(:defect, "FormattedID|DE42", fields) #by FormattedID
93
- # or
94
- defect = @rally.read(:defect, 12345) #by lookup then udpating via the object
95
- field_updates = {"Description" => "Changed Description"}
96
- defect.update(field_updates)
97
-
98
-
99
- #== License
12
+ === Making a connection to Rally
13
+ require 'rally_api'
14
+
15
+ #Setting custom headers
16
+ headers = RallyAPI::CustomHttpHeader.new()
17
+ headers.name = "My Utility"
18
+ headers.vendor = "MyCompany"
19
+ headers.version = "1.0"
20
+
21
+ config = {:base_url => "https://rally1.rallydev.com/slm"}
22
+ config[:username] = "user@company.com"
23
+ config[:password] = "password"
24
+ config[:workspace] = "Workspace Name"
25
+ config[:project] = "Project Name"
26
+ config[:headers] = headers #from RallyAPI::CustomHttpHeader.new()
27
+
28
+ @rally = RallyAPI::RallyRestJson.new(config)
29
+
30
+
31
+ === Querying Rally
32
+ test_query = RallyAPI::RallyQuery.new()
33
+ test_query.type = :defect
34
+ test_query.fetch = "Name"
35
+ test_query.workspace = {"_ref" => "https://rally1.rallydev.com/slm/webservice/1.25/workspace/12345.js" } #optional
36
+ test_query.project = {"_ref" => "https://rally1.rallydev.com/slm/webservice/1.25/project/12345.js" } #optional
37
+ test_query.page_size = 200 #optional - default is 200
38
+ test_query.limit = 1000 #optional - default is 99999
39
+ test_query.project_scope_up = false
40
+ test_query.project_scope_down = true
41
+ test_query.order = "Name Asc"
42
+ test_query.query_string = "(Severity = \"High\")"
43
+
44
+ results = @rally.find(test_query)
45
+
46
+ #tip - set the fetch string of the query to the fields you need -
47
+ #only resort to the read method if you want your code to be slow
48
+ results.each do |defect|
49
+ puts defect.Name # or defect["Name"]
50
+ defect.read #read the whole defect from Rally to get all fields (eg Severity)
51
+ puts defect.Severity
52
+ end
53
+
54
+ #for people comfortable passing around blocks:
55
+ results = @rally.find do |q|
56
+ q.type = :defect
57
+ q.fetch = "Name,FormattedID"
58
+ q.query_string = "(Priority = \"Low\")"
59
+ end
60
+
61
+
62
+ === Reading an Artifact
63
+ defect = @rally.read(:defect, 12345) #by ObjectID
64
+ #or
65
+ defect = @rally.read(:defect, "FormattedID|DE42") #by FormattedID
66
+ #or if you already have an object like from a query
67
+ results = @rally.find(RallyAPI::RallyQuery.new({:type => :defect, :query_string => "(FormattedID = DE42)"}))
68
+ defect = results.first
69
+ defect.read
70
+
71
+ puts defect["Name"]
72
+ #or - fields can be read by bracket artifact["FieldDisplayName"] or artifact.FieldDisplayName
73
+ puts defect.Name
74
+
75
+ #An Important note about reading fields and fetching:
76
+ #If you query with a specific fetch string, for example query defect and fetch Name,Severity,Description
77
+ #You will *only* get back those fields defect.Priority will be nil, but may not be null in Rally
78
+ #Use object.read or @rally.read to make sure you read the whole object if you want what is in Rally
79
+ # This is done for speed - lazy loading (going back to get a value from Rally) can be unneccessarily slow
80
+ # *Pick you fetch strings wisely* fetch everything you need and don't rely on read if you don't need it the speed is worth it.
81
+
82
+ === Creating an Artifact
83
+ obj = {}
84
+ obj["Name"] = "Test Defect created #{DateTime.now()}"
85
+ new_de = @rally.create(:defect, obj)
86
+ puts new_de["FormattedID"]
87
+
88
+ === Updating an Artifact
89
+ fields = {}
90
+ fields["Severity"] = "Critical"
91
+ fields["Description"] = "Description for the issue"
92
+ updated_defect = @rally.update(:defect, 12345, fields) #by ObjectID
93
+ #or
94
+ updated_defect = @rally.update(:defect, "FormattedID|DE42", fields) #by FormattedID
95
+ # or
96
+ defect = @rally.read(:defect, 12345) #by lookup then udpating via the object
97
+ field_updates = {"Description" => "Changed Description"}
98
+ defect.update(field_updates)
99
+
100
+ === Utils
101
+ #allowed values: pass the Artifact type string or downcased symbol and the Display Name of the field
102
+ @rally.allowed_values("Defect", "Severity")
103
+ @rally.allowed_values(:story, "ScheduleState")
104
+
105
+ #re-ranking: rank_above and rank_below
106
+ story1.rank_above(story2) #in a drag and drop workspace move story1 relative to story2
107
+ story1.rank_below(story2)
108
+
109
+ #== License/Meta
110
+ #Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
100
111
  #Copyright (c) 2002-2011 Rally Software Development Corp. All Rights Reserved.
101
112
  #Your use of this Software is governed by the terms and conditions
102
113
  #of the applicable Subscription Agreement between your company and
@@ -1,39 +1,34 @@
1
+ # :stopdoc:
1
2
  #Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
2
3
  #Your use of this Software is governed by the terms and conditions
3
4
  #of the applicable Subscription Agreement between your company and
4
5
  #Rally Software Development Corp.
6
+ # :startdoc:
7
+
5
8
  module RallyAPI
6
9
  # query is like:
7
10
  # query_hash = {}
8
- # query_hash[:type] = Defect, Story, etc
9
- # query_hash[:query_string] = "(State = \"Closed\")"
10
- # query_hash[:fetch] = "Name,State,etc"
11
- # query_hash[:workspace] = workspace json object or ref #defaults to workspace passed in RallyRestJson.new if nil
12
- # query_hash[:project] = project json object or ref #defaults to project passed in RallyRestJson.new if nil
13
- # query_hash[:project_scope_up] = true/false
14
- # query_hash[:project_scope_down] = true/false
15
- # query_hash[:order] = "ObjectID asc"
16
- # query_hash[:page_size]
17
- # query_hash[:stopafter]
18
-
19
- class TimeMachineQuery
20
- attr_accessor :workspace
11
+ # query_hash["find"] = { some json for a query} or true
12
+ # query_hash["fields"] = ["State", "PlanEstimate"]
13
+ # query_hash["pagesize"] = 1000
14
+ # query_hash["sort"] = { _id: 1 }
15
+ # query_hash["workspace"] = workspace oid for query uri
16
+
17
+ #query info is the master hash instead of a bunch of instance variables
18
+ class LookbackAPIQuery
19
+ attr_accessor :query_info
21
20
 
22
21
  def initialize(query_hash = nil)
22
+ @query_info = nil
23
23
  parse_query_hash(query_hash) if !query_hash.nil?
24
24
  self
25
25
  end
26
26
 
27
27
  def make_query_params
28
28
  query_params = {}
29
- #query_params[:query] = @query_string
30
- #query_params[:fetch] = @fetch
31
- query_params[:workspace] = @workspace["_ref"] if !@workspace.nil?
32
- #query_params[:project] = @project["_ref"] if !@project.nil?
33
- #query_params[:projectScopeUp] = @project_scope_up
34
- #query_params[:projectScopeDown] = @project_scope_down
35
- #query_params[:order] = @order
36
- #query_params[:pagesize] = @page_size
29
+ query_params[:find] = @query_string
30
+ query_params[:workspace] = @workspace["_ref"] if !@workspace.nil?
31
+ query
37
32
 
38
33
  query_params
39
34
  end
@@ -1,10 +1,13 @@
1
1
  require 'rest_client'
2
2
  require 'json'
3
3
 
4
+ # :stopdoc:
4
5
  #Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
5
6
  #Your use of this Software is governed by the terms and conditions
6
7
  #of the applicable Subscription Agreement between your company and
7
8
  #Rally Software Development Corp.
9
+ # :startdoc:
10
+
8
11
  module RallyAPI
9
12
 
10
13
 
@@ -169,13 +172,13 @@ module RallyAPI
169
172
  @retry_list[req.url] += 1
170
173
  retry
171
174
  end
172
- raise msg
175
+ raise StandardError, msg
173
176
  end
174
177
  @retry_list.delete(req.url)
175
178
  puts response if @low_debug
176
179
  json_obj = JSON.parse(response.body) #todo handle null post error
177
180
  errs = check_for_errors(json_obj)
178
- raise "\nError on request - #{url} - \n#{errs}" if errs[:errors].length > 0
181
+ raise StandardError, "\nError on request - #{url} - \n#{errs}" if errs[:errors].length > 0
179
182
  json_obj
180
183
  end
181
184
 
@@ -1,9 +1,18 @@
1
+ # :stopdoc:
1
2
  #Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
2
3
  #Your use of this Software is governed by the terms and conditions
3
4
  #of the applicable Subscription Agreement between your company and
4
5
  #Rally Software Development Corp.
6
+ # :startdoc:
7
+
5
8
  module RallyAPI
6
9
 
10
+ #todo add rankTo bottom and top
11
+ #https://trial.rallydev.com/slm/webservice/x/defect/oid.js?rankTo=BOTTOM
12
+ #https://trial.rallydev.com/slm/webservice/x/defect/oid.js?rankTo=TOP
13
+
14
+ # RallyObject is a helper class that wraps the JSON.parsed hash
15
+ #
7
16
  class RallyObject
8
17
 
9
18
  attr_reader :rally_object
@@ -37,6 +46,10 @@ module RallyAPI
37
46
  end
38
47
 
39
48
  def getref
49
+ ref
50
+ end
51
+
52
+ def ref
40
53
  @rally_object["_ref"]
41
54
  end
42
55
 
@@ -54,22 +67,16 @@ module RallyAPI
54
67
 
55
68
  private
56
69
 
70
+ # An attempt to be rally_rest_api user friendly -
71
+ # you can get a field the old way with an underscored field name or the upcase name
57
72
  def method_missing(sym, *args)
58
- get_val(sym.to_s)
73
+ ret_val = get_val(sym.to_s)
74
+ if @rally_rest.rally_rest_api_compat && ret_val.nil?
75
+ ret_val = get_val(camel_case_word(:sym))
76
+ end
77
+ ret_val
59
78
  end
60
79
 
61
- #the magic of lazy loading is gone
62
- #def method_missing(sym, *args)
63
- # return_val = get_val(sym.to_s)
64
- #
65
- # if return_val.nil?
66
- # @rally_object = @rally_rest.reread(@rally_object)
67
- # return_val = get_val(sym.to_s)
68
- # end
69
- #
70
- # return_val
71
- #end
72
-
73
80
  def get_val(field)
74
81
  return_val = @rally_object[field]
75
82
 
@@ -93,6 +100,11 @@ module RallyAPI
93
100
  @rally_object[field] = object_array
94
101
  end
95
102
 
103
+ #taken from rally_rest_api - to try to help with backwards compatibility
104
+ def camel_case_word(sym)
105
+ sym.to_s.split("_").map { |word| word.capitalize }.join
106
+ end
107
+
96
108
  end
97
109
 
98
110
  end
@@ -1,20 +1,28 @@
1
+ # :stopdoc:
1
2
  #Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
2
3
  #Your use of this Software is governed by the terms and conditions
3
4
  #of the applicable Subscription Agreement between your company and
4
5
  #Rally Software Development Corp.
6
+ # :startdoc:
5
7
  module RallyAPI
6
- # query is like:
7
- # query_hash = {}
8
- # query_hash[:type] = Defect, Story, etc
9
- # query_hash[:query_string] = "(State = \"Closed\")"
10
- # query_hash[:fetch] = "Name,State,etc"
11
- # query_hash[:workspace] = workspace json object or ref #defaults to workspace passed in RallyRestJson.new if nil
12
- # query_hash[:project] = project json object or ref #defaults to project passed in RallyRestJson.new if nil
13
- # query_hash[:project_scope_up] = true/false
14
- # query_hash[:project_scope_down] = true/false
15
- # query_hash[:order] = "ObjectID asc"
16
- # query_hash[:page_size]
17
- # query_hash[:stopafter]
8
+
9
+ # ===RallyAPI::RallyQuery - A helper class for making queries to Rally's REST API
10
+ # Example:
11
+ # new_query = RallyAPI::RallyQuery.new() and set query properties as needed
12
+ # --- or ---
13
+ # new_query = RallyAPI::RallyQuery.new(query_hash) with a hash of attributes<br>
14
+ # query_hash for example can be:<br>
15
+ # query_hash = {} <br>
16
+ # query_hash[:type] = Defect, Story, etc <br>
17
+ # query_hash[:query_string] = "(State = \"Closed\")" <br>
18
+ # query_hash[:fetch] = "Name,State,etc" <br>
19
+ # query_hash[:workspace] = workspace json object or ref #defaults to workspace passed in RallyRestJson.new if nil <br>
20
+ # query_hash[:project] = project json object or ref #defaults to project passed in RallyRestJson.new if nil <br>
21
+ # query_hash[:project_scope_up] = true/false <br>
22
+ # query_hash[:project_scope_down] = true/false <br>
23
+ # query_hash[:order] = "ObjectID asc" <br>
24
+ # query_hash[:page_size] <br>
25
+ # query_hash[:limit] <br>
18
26
 
19
27
  class RallyQuery
20
28
  attr_accessor :type, :query_string, :fetch, :workspace, :project, :project_scope_up, :project_scope_down
@@ -1,7 +1,9 @@
1
+ # :stopdoc:
1
2
  #Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
2
3
  #Your use of this Software is governed by the terms and conditions
3
4
  #of the applicable Subscription Agreement between your company and
4
5
  #Rally Software Development Corp.
6
+ # :startdoc:
5
7
  module RallyAPI
6
8
  class RallyQueryResult
7
9
  include Enumerable
@@ -4,29 +4,58 @@ require_relative "rally_object"
4
4
  require_relative "rally_query"
5
5
  require_relative "rally_query_result"
6
6
 
7
+ # --
7
8
  #Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
8
9
  #Your use of this Software is governed by the terms and conditions
9
10
  #of the applicable Subscription Agreement between your company and
10
11
  #Rally Software Development Corp.
12
+ # ++
13
+
14
+ #todo - raise exception if ws/project is not set on create?
15
+
16
+ # -----
17
+ # :title:RallyAPI
18
+ #
19
+ # ===Getting Started
20
+ # RallyAPI::RallyRestJson is the starting point for working in Ruby with Rally's REST WSAPI
21
+ #
22
+ # config = {:base_url => "https://rally1.rallydev.com/slm"}
23
+ #
24
+ # config[:username] = "user@company.com"
25
+ #
26
+ # config[:password] = "password"
27
+ #
28
+ # config[:workspace] = "Workspace Name"
29
+ #
30
+ # config[:project] = "Project Name"
31
+ #
32
+ # config[:headers] = headers #from RallyAPI::CustomHttpHeader.new()
33
+ #
34
+ # @rally = RallyAPI::RallyRestJson.new(config)
35
+
36
+
11
37
  module RallyAPI
12
38
 
39
+ #--
13
40
  #this contstant is here - a tradeoff of speed vs completeness- right now speed wins because it is so
14
41
  #expensive to query typedef and read all attributes for "OBJECT" or "COLLECTION" types
42
+ #++
15
43
  RALLY_REF_FIELDS = { "Subscription" => :subscription, "Workspace" => :workspace, "Project" => :project,
16
44
  "Iteration" => :iteration, "Release" => :release, "WorkProduct" => :artifact,
17
45
  "Requirement" => :hierarchicalrequirement, "Owner" => :user, "Tester" => :user,
18
46
  "RevisionHistory" => :revisionhistory, "Revision" => :revision, "Revisions" => :revision,
19
47
  "Blocker" => :artifact, "SubmittedBy" => :user, "TestCaseResult" => :testcaseresult,
20
- "TestSet" => :testset, "Parent" => :hierarchicalrequirement, "TestFolder"=> :testfolder }
21
-
48
+ "TestSet" => :testset, "Parent" => :hierarchicalrequirement, "TestFolder"=> :testfolder,
49
+ "PortfolioItemType" => :type }
22
50
 
23
51
 
24
- #Main Class to create from when using the tool
52
+ #Main Class to instantiate when using the tool
25
53
  class RallyRestJson
26
- DEFAULT_WSAPI_VERSION = "1.25"
54
+ DEFAULT_WSAPI_VERSION = "1.30"
27
55
 
28
56
  attr_accessor :rally_url, :rally_user, :rally_password, :rally_workspace_name, :rally_project_name, :wsapi_version
29
57
  attr_accessor :rally_headers, :rally_default_workspace, :rally_default_project, :low_debug, :proxy_info, :retries
58
+ attr_accessor :rally_rest_api_compat
30
59
 
31
60
  attr_reader :rally_objects
32
61
 
@@ -40,6 +69,7 @@ module RallyAPI
40
69
  @rally_headers = args[:headers] || CustomHttpHeader.new
41
70
  @proxy_info = args[:proxy]
42
71
  @retries = args[:retries] || 0
72
+ @rally_rest_api_compat = args[:rally_rest_api_compat] || false
43
73
 
44
74
  @low_debug = args[:debug] || false
45
75
 
@@ -53,12 +83,12 @@ module RallyAPI
53
83
 
54
84
  if !@rally_workspace_name.nil?
55
85
  @rally_default_workspace = find_workspace(@rally_workspace_name)
56
- raise "unable to find default workspace #{@rally_workspace_name}" if @rally_default_workspace.nil?
86
+ raise StandardError, "unable to find default workspace #{@rally_workspace_name}" if @rally_default_workspace.nil?
57
87
  end
58
88
 
59
89
  if !@rally_project_name.nil?
60
90
  @rally_default_project = find_project(@rally_default_workspace, @rally_project_name)
61
- raise "unable to find default project #{@rally_project_name}" if @rally_default_project.nil?
91
+ raise StandardError, "unable to find default project #{@rally_project_name}" if @rally_default_project.nil?
62
92
  end
63
93
 
64
94
  self
@@ -79,7 +109,7 @@ module RallyAPI
79
109
 
80
110
  def find_project(workspace_object, project_name)
81
111
  if workspace_object.nil?
82
- raise "A workspace must be provided to find a project"
112
+ raise StandardError, "A workspace must be provided to find a project"
83
113
  end
84
114
 
85
115
  query = RallyQuery.new()
@@ -105,8 +135,8 @@ module RallyAPI
105
135
  rally_type = check_type(type)
106
136
 
107
137
  if (fields["Workspace"].nil? && fields["Project"].nil?)
108
- fields["Workspace"] = @rally_default_workspace._ref
109
- fields["Project"] = @rally_default_project._ref
138
+ fields["Workspace"] = @rally_default_workspace._ref unless @rally_default_workspace.nil?
139
+ fields["Project"] = @rally_default_project._ref unless @rally_default_project.nil?
110
140
  end
111
141
 
112
142
  args = {:user => @rally_user, :password => @rally_password }
@@ -144,23 +174,40 @@ module RallyAPI
144
174
  RallyObject.new(self, reread({"_ref" => ref}))
145
175
  end
146
176
 
147
- #query_hash is a has like:
148
- # query_hash = {}
149
- # query_hash[:type] = Defect, Story, etc
150
- # query_hash[:query_string] = "(State = \"Closed\")"
151
- # query_hash[:fetch] = "Name,State,etc"
152
- # query_hash[:workspace] = workspace json object or ref #defaults to workspace passed in RallyRestJson.new if nil
153
- # query_hash[:project] = project json object or ref #defaults to project passed in RallyRestJson.new if nil
154
- # query_hash[:project_scope_up] = true/false
155
- # query_hash[:project_scope_down] = true/false
156
- # query_hash[:order] = "ObjectID asc"
157
- # query_hash[:pagesize]
158
- # query_hash[:stopafter]
159
- #todo default workspace and project if not set?
160
- def find(query_obj)
177
+ ##-----
178
+ #Querying Rally example
179
+ #test_query = RallyAPI::RallyQuery.new()
180
+ #test_query.type = :defect
181
+ #test_query.fetch = "Name"
182
+ #test_query.workspace = {"_ref" => "https://rally1.rallydev.com/slm/webservice/1.25/workspace/12345.js" } #optional
183
+ #test_query.project = {"_ref" => "https://rally1.rallydev.com/slm/webservice/1.25/project/12345.js" } #optional
184
+ #test_query.page_size = 200 #optional - default is 200
185
+ #test_query.limit = 1000 #optional - default is 99999
186
+ #test_query.project_scope_up = false
187
+ #test_query.project_scope_down = true
188
+ #test_query.order = "Name Asc"
189
+ #test_query.query_string = "(Severity = \"High\")"
190
+ #
191
+ #results = @rally.find(test_query)
192
+ #
193
+ ##tip - set the fetch string of the query to the fields you need -
194
+ ##only resort to the read method if you want your code to be slow
195
+ #results.each do |defect|
196
+ # puts defect.Name # or defect["Name"]
197
+ # defect.read #read the whole defect from Rally to get all fields (eg Severity)
198
+ # puts defect.Severity
199
+ #end
200
+ #query_obj is RallyQuery
201
+ def find(query_obj = RallyQuery.new)
202
+ yield query_obj if block_given?
203
+
204
+ if query_obj.workspace.nil?
205
+ query_obj.workspace = @rally_default_workspace unless @rally_default_workspace.nil?
206
+ end
207
+
161
208
  errs = query_obj.validate(@rally_objects)
162
209
  if errs.length > 0
163
- raise "Errors making Rally Query: #{errs.to_s}"
210
+ raise StandardError, "Errors making Rally Query: #{errs.to_s}"
164
211
  end
165
212
 
166
213
  query_url = make_query_url(@rally_url, @wsapi_version, check_type(query_obj.type))
@@ -195,6 +242,30 @@ module RallyAPI
195
242
  RallyObject.new(self, update["Object"])
196
243
  end
197
244
 
245
+ def allowed_values(type, field)
246
+ if type.class == Symbol
247
+ query_type = @rally_objects[type]
248
+ else
249
+ query_type = type
250
+ end
251
+ type_defs_query = RallyQuery.new()
252
+ type_defs_query.type = :typedefinition
253
+ type_defs_query.fetch = true
254
+ type_defs_query.query_string= "(Name = \"#{query_type}\")"
255
+ type_defs = find(type_defs_query)
256
+
257
+ allowed_vals = {}
258
+ type_defs[0]["Attributes"].each do |attr|
259
+ next if attr["ElementName"] != field
260
+ attr["AllowedValues"].each do |val_ref|
261
+ val = val_ref["StringValue"]
262
+ val = "Null" if val.nil? || val.empty?
263
+ allowed_vals[val] = true
264
+ end
265
+ end
266
+ allowed_vals
267
+ end
268
+
198
269
  private
199
270
 
200
271
  def make_get_url(type)
@@ -220,9 +291,9 @@ module RallyAPI
220
291
 
221
292
  def check_type(type_name)
222
293
  if @rally_objects[type_name].nil?
223
- raise "The object type #{type_name} is not valid for the wsapi"
294
+ raise StandardError, "The object type #{type_name} is not valid for the wsapi"
224
295
  end
225
- @rally_objects[type_name]
296
+ @rally_objects[type_name].gsub(" ", "") #for wsapi no space is expected
226
297
  end
227
298
 
228
299
  #ref should be like https://rally1.rallydev.com/slm/webservice/1.25/defect/12345.js
@@ -282,16 +353,16 @@ module RallyAPI
282
353
  type_defs = find(type_defs_query)
283
354
  type_defs.each do |td|
284
355
  type_sym = td.Name.downcase.gsub(" ", "").to_sym
285
- @rally_objects[type_sym] = td.Name.gsub(" ","")
356
+ @rally_objects[type_sym] = td.Name
286
357
  end
287
358
 
288
359
  #some convenience keys to help people - someday we'll fix the api and make HR called story
289
360
  @rally_objects[:artifact] = "Artifact"
290
- @rally_objects[:persistableobject] = "PersistableObject"
291
- @rally_objects[:useriterationcapacity] = "UserIterationCapacity"
292
- @rally_objects[:userpermission] = "UserPermission"
293
- @rally_objects[:story] = "HierarchicalRequirement"
294
- @rally_objects[:userstory] = "HierarchicalRequirement"
361
+ @rally_objects[:persistableobject] = "Persistable Object"
362
+ @rally_objects[:useriterationcapacity] = "User Iteration Capacity"
363
+ @rally_objects[:userpermission] = "User Permission"
364
+ @rally_objects[:story] = "Hierarchical Requirement"
365
+ @rally_objects[:userstory] = "Hierarchical Requirement"
295
366
 
296
367
  end
297
368
 
@@ -1,7 +1,8 @@
1
+ # :nodoc:
1
2
  #Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
2
3
  #Your use of this Software is governed by the terms and conditions
3
4
  #of the applicable Subscription Agreement between your company and
4
5
  #Rally Software Development Corp.
5
6
  module RallyAPI
6
- VERSION = "0.4.1"
7
+ VERSION = "0.5.0"
7
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rally_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-01 00:00:00.000000000Z
12
+ date: 2012-06-28 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rest-client
16
- requirement: &70105132306080 !ruby/object:Gem::Requirement
16
+ requirement: &70134702100760 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: 1.6.7
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70105132306080
24
+ version_requirements: *70134702100760
25
25
  description: API wrapper for Rally's JSON REST web services api
26
26
  email:
27
27
  - dsmith@rallydev.com
@@ -32,12 +32,12 @@ files:
32
32
  - README.rdoc
33
33
  - Rakefile
34
34
  - lib/rally_api/custom_http_header.rb
35
+ - lib/rally_api/lookback_api_query.rb
35
36
  - lib/rally_api/rally_json_connection.rb
36
37
  - lib/rally_api/rally_object.rb
37
38
  - lib/rally_api/rally_query.rb
38
39
  - lib/rally_api/rally_query_result.rb
39
40
  - lib/rally_api/rally_rest_json.rb
40
- - lib/rally_api/time_machine_query.rb
41
41
  - lib/rally_api/version.rb
42
42
  - lib/rally_api.rb
43
43
  homepage: http://developer.rallydev.com/help