Skip to content

Commit

Permalink
Merge pull request #50 from RallyTools/collection_read_defect_fix
Browse files Browse the repository at this point in the history
made default WSAPI_VERSION 2.0, fixed reread to use start instead of sta...
  • Loading branch information
klehman-rally committed Apr 27, 2015
2 parents ad1f8d7 + c2902e0 commit cf29337
Show file tree
Hide file tree
Showing 15 changed files with 150 additions and 129 deletions.
26 changes: 15 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## License

Copyright (c) Rally Software Development Corp. 2013 Distributed under the MIT License.
Copyright (c) Rally Software Development Corp. 2015 Distributed under the MIT License.

## Warranty

Expand All @@ -16,7 +16,7 @@ RallyAPI (rally_api) -- a wrapper for Rally's REST Web Services API

[![Stories in Ready](http://badge.waffle.io/RallyTools/RallyRestToolkitForRuby.png)](http://waffle.io/RallyTools/RallyRestToolkitForRuby)

RallyAPI is a wrapper of Rally's Web Service API Json endpoints using rest-client and native json parsing
RallyAPI is a wrapper of Rally's Web Service API JSON endpoints using rest-client and native json parsing
Check the examples directory for more detailed samples.

### Installation
Expand Down Expand Up @@ -70,8 +70,8 @@ A Rally API Key can be used for user authentication. If an API Key is provided,
test_query = RallyAPI::RallyQuery.new()
test_query.type = "defect"
test_query.fetch = "Name"
test_query.workspace = {"_ref" => "https://rally1.rallydev.com/slm/webservice/1.25/workspace/12345.js" } #optional
test_query.project = {"_ref" => "https://rally1.rallydev.com/slm/webservice/1.25/project/12345.js" } #optional
test_query.workspace = {"_ref" => "https://rally1.rallydev.com/slm/webservice/v2.0/workspace/12345" } #optional
test_query.project = {"_ref" => "https://rally1.rallydev.com/slm/webservice/v2.0/project/12345" } #optional
test_query.page_size = 200 #optional - default is 200
test_query.limit = 1000 #optional - default is 99999
test_query.project_scope_up = false
Expand Down Expand Up @@ -114,8 +114,8 @@ A Rally API Key can be used for user authentication. If an API Key is provided,
#If you query with a specific fetch string, for example query defect and fetch Name,Severity,Description
#You will *only* get back those fields defect.Priority will be nil, but may not be null in Rally
#Use object.read or @rally.read to make sure you read the whole object if you want what is in Rally
# This is done for speed - lazy loading (going back to get a value from Rally) can be unneccessarily slow
# *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.
# This is done for speed - lazy loading (going back to get a value from Rally) can be unnecessarily slow
# *Pick your fetch strings wisely* fetch everything you need and don't rely on read if you don't need it, the speed is worth it.

### Creating an Artifact
obj = {}
Expand Down Expand Up @@ -147,12 +147,16 @@ A Rally API Key can be used for user authentication. If an API Key is provided,
story1.rank_to_top

### Revision History

Version 1.2.0 (April 2015) - set default WSAPI version to 2.0, fix paging issue in reread,
can now use DisplayName for custom fields in create and update operations.
Set httpclient gem runtime dependency to '= 2.5.0'.

Version 1.1.2 (October 2014) - Set httpclient gem runtime dependency to '~> 2.4.0'.

Version 1.1.1 (October 2014) - Relax httpclient gem runtime dependency to '>= 2.3.0'.

Version 1.1.0 (September 2014) - Appends workspace to Rally API requests to enable correct retrieval
of allowed values from a user's non-default workspace. Updates gem development dependencies and
test files structure.

Version 1.1.1 (October 2014) - Relax version requirement of httpclient runtime
dependency to '>= 2.3.0'.

Version 1.1.2 (October 2014) - Change version requirement of httpclient runtime
dependency to '~> 2.4.0'.
2 changes: 1 addition & 1 deletion lib/rally_api.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
#Copyright (c) 2002-2015 Rally Software Development Corp. All Rights Reserved.
#Your use of this Software is governed by the terms and conditions
#of the applicable Subscription Agreement between your company and
#Rally Software Development Corp.
Expand Down
2 changes: 1 addition & 1 deletion lib/rally_api/custom_http_header.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
#Copyright (c) 2002-2015 Rally Software Development Corp. All Rights Reserved.
#Your use of this Software is governed by the terms and conditions
#of the applicable Subscription Agreement between your company and
#Rally Software Development Corp.
Expand Down
2 changes: 1 addition & 1 deletion lib/rally_api/lookback_api_query.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# :stopdoc:
#Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
#Copyright (c) 2002-2015 Rally Software Development Corp. All Rights Reserved.
#Your use of this Software is governed by the terms and conditions
#of the applicable Subscription Agreement between your company and
#Rally Software Development Corp.
Expand Down
2 changes: 1 addition & 1 deletion lib/rally_api/rally_collection.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# :stopdoc:
#Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
#Copyright (c) 2002-2015 Rally Software Development Corp. All Rights Reserved.
#Your use of this Software is governed by the terms and conditions
#of the applicable Subscription Agreement between your company and
#Rally Software Development Corp.
Expand Down
2 changes: 1 addition & 1 deletion lib/rally_api/rally_json_connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
require 'json'

# :stopdoc:
#Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
#Copyright (c) 2002-2015 Rally Software Development Corp. All Rights Reserved.
#Your use of this Software is governed by the terms and conditions
#of the applicable Subscription Agreement between your company and
#Rally Software Development Corp.
Expand Down
32 changes: 9 additions & 23 deletions lib/rally_api/rally_object.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# :stopdoc:
#Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
#Copyright (c) 2002-2015 Rally Software Development Corp. All Rights Reserved.
#Your use of this Software is governed by the terms and conditions
#of the applicable Subscription Agreement between your company and
#Rally Software Development Corp.
Expand All @@ -15,14 +15,15 @@ class RallyObject

def initialize(rally_rest, json_hash, warnings = {})
# handle that we might not get a _ref or a _type
if !json_hash["_type"].nil? || !json_hash["_ref"].nil?
@type = json_hash["_type"] || json_hash["_ref"].split("/")[-2]
else
@type = "unknown"
end
@type = "unknown"
if json_hash["_type"] && !json_hash["_type"].empty?
@type = json_hash["_type"]
elsif json_hash["_ref"] && !json_hash["_ref"].empty?
@type = json_hash["_ref"].split("/")[-2]
end
@rally_object = json_hash
@rally_rest = rally_rest
@warnings = warnings[:warnings]
@rally_rest = rally_rest
@warnings = warnings[:warnings]
end

def update(fields, params = {})
Expand Down Expand Up @@ -150,21 +151,6 @@ def method_missing(sym, *args)
ret_val
end

#def get_val(field)
# return_val = rally_object[field]
#
# if return_val.class == Hash
# return RallyObject.new(@rally_rest, return_val)
# end
#
# if return_val.class == Array
# make_object_array(field)
# return_val = rally_object[field]
# end
#
# return_val
#end

def get_val(field)
return_val = @rally_object[field]
return_val = @rally_object["c_#{field}"] if return_val.nil?
Expand Down
2 changes: 1 addition & 1 deletion lib/rally_api/rally_query.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# :stopdoc:
#Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
#Copyright (c) 2002-2015 Rally Software Development Corp. All Rights Reserved.
#Your use of this Software is governed by the terms and conditions
#of the applicable Subscription Agreement between your company and
#Rally Software Development Corp.
Expand Down
2 changes: 1 addition & 1 deletion lib/rally_api/rally_query_result.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# :stopdoc:
#Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
#Copyright (c) 2002-2015 Rally Software Development Corp. All Rights Reserved.
#Your use of this Software is governed by the terms and conditions
#of the applicable Subscription Agreement between your company and
#Rally Software Development Corp.
Expand Down
75 changes: 54 additions & 21 deletions lib/rally_api/rally_rest_json.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#require "rally_query_result"

# --
#Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
#Copyright (c) 2002-2015 Rally Software Development Corp. All Rights Reserved.
#Your use of this Software is governed by the terms and conditions
#of the applicable Subscription Agreement between your company and
#Rally Software Development Corp.
Expand Down Expand Up @@ -44,7 +44,7 @@ module RallyAPI

#Main Class to instantiate when using the tool
class RallyRestJson
DEFAULT_WSAPI_VERSION = "1.43"
DEFAULT_WSAPI_VERSION = "v2.0"

attr_accessor :rally_url, :rally_workspace_name, :rally_project_name, :wsapi_version,
:rally_headers, :rally_default_workspace, :rally_default_project, :low_debug, :proxy_info,
Expand Down Expand Up @@ -96,12 +96,13 @@ def initialize(args)
end

def send_request(url = nil, args = nil, params = {})
url += '.js' if @wsapi_version !~ /^v2/ && url !~ /\.js$/ # append ".js" if it is needed
if params[:workspace].nil? && rally_workspace_object
params[:workspace] = rally_workspace_object['_ref']
end
if params[:workspace]
wksp_id = params[:workspace].match(/workspace\/(\d*)/)[1]
url += "?/workspace=/workspace/#{wksp_id}"
url += "?workspace=workspace/#{wksp_id}"
end
@rally_connection.send_request(url, args, params)
end
Expand Down Expand Up @@ -181,15 +182,15 @@ def create(type, fields, params = {})
params[:workspace] = ws_ref

fields = RallyAPI::RallyRestJson.fix_case(fields) if @rally_rest_api_compat
object2create = { type => check_fields(fields) }
postable_fields = check_fields(fields)
postable_fields = adjust_for_custom(type, postable_fields) if @wsapi_version =~ /^v2/
object2create = { type => postable_fields }
args = { :method => :post, :payload => object2create }
#json_response = @rally_connection.create_object(make_create_url(rally_type), args, object2create)
json_response = send_request(make_create_url(type), args, params)
#todo - check for warnings
RallyObject.new(self, json_response["CreateResult"]["Object"], warnings(json_response)).read()
end


def read(type, obj_id, params = {})
type = check_type(type)
ref = check_id(type.to_s, obj_id)
Expand Down Expand Up @@ -224,7 +225,7 @@ def read_collection(collection_hash, params = {})
pagesize = params[:pagesize] || 200
full_collection = []
start.step(collection_count, pagesize).each do |page_start|
page = reread(collection_hash, {:pagesize => 200, :startindex => page_start})
page = reread(collection_hash, {:pagesize => 200, :start => page_start})
full_collection.concat(page["Results"])
end
{"Results" => full_collection}
Expand All @@ -234,7 +235,9 @@ def update(type, obj_id, fields, params = {})
type = check_type(type)
ref = check_id(type.to_s, obj_id)
fields = RallyAPI::RallyRestJson.fix_case(fields) if @rally_rest_api_compat
json_update = {type.to_s => check_fields(fields)}
update_fields = check_fields(fields)
update_fields = adjust_for_custom(type.to_s, update_fields) if @wsapi_version =~ /^v2/
json_update = {type.to_s => update_fields}
args = {:method => :post, :payload => json_update}
json_response = send_request(ref, args, params)
#todo check for warnings on json_response["OperationResult"]
Expand All @@ -247,8 +250,8 @@ def update(type, obj_id, fields, params = {})
#test_query = RallyAPI::RallyQuery.new()
#test_query.type = :defect
#test_query.fetch = "Name"
#test_query.workspace = {"_ref" => "https://rally1.rallydev.com/slm/webservice/1.25/workspace/12345.js" } #optional
#test_query.project = {"_ref" => "https://rally1.rallydev.com/slm/webservice/1.25/project/12345.js" } #optional
#test_query.workspace = {"_ref" => "https://rally1.rallydev.com/slm/webservice/v2.0/workspace/12345" } #optional
#test_query.project = {"_ref" => "https://rally1.rallydev.com/slm/webservice/v2.0/project/12345" } #optional
#test_query.page_size = 200 #optional - default is 200
#test_query.limit = 1000 #optional - default is 99999
#test_query.project_scope_up = false
Expand Down Expand Up @@ -279,6 +282,7 @@ def find(query_obj = RallyQuery.new)
end

query_url = make_query_url(@rally_url, @wsapi_version, check_type(query_obj.type.to_s))
query_url += '.js' if @wsapi_version !~ /^v2/
query_params = query_obj.make_query_params
args = {:method => :get}
json_response = @rally_connection.get_all_json_results(query_url, args, query_params, query_obj.limit)
Expand All @@ -290,7 +294,7 @@ def adjust_find_threads(num_threads)
end

#rankAbove=%2Fhierarchicalrequirement%2F4624552599
#{"hierarchicalrequirement":{"_ref":"https://rally1.rallydev.com/slm/webservice/1.27/hierarchicalrequirement/4616818613.js"}}
#{"hierarchicalrequirement":{"_ref":"https://rally1.rallydev.com/slm/webservice/v2.0/hierarchicalrequirement/4616818613"}}
def rank_above(ref_to_rank, relative_ref)
ref = ref_to_rank
params = {}
Expand Down Expand Up @@ -389,28 +393,33 @@ def pre_init()
end

def make_get_url(type)
"#{@rally_url}/webservice/#{@wsapi_version}/#{type}.js"
"#{@rally_url}/webservice/#{@wsapi_version}/#{type}"
end

def security_url
"#{@rally_url}/webservice/#{@wsapi_version}/security/authorize.js"
"#{@rally_url}/webservice/#{@wsapi_version}/security/authorize"
end

def make_read_url(type,oid)
"#{@rally_url}/webservice/#{@wsapi_version}/#{type}/#{oid}.js"
"#{@rally_url}/webservice/#{@wsapi_version}/#{type}/#{oid}"
end

def make_create_url(type)
"#{@rally_url}/webservice/#{@wsapi_version}/#{type}/create.js"
"#{@rally_url}/webservice/#{@wsapi_version}/#{type}/create"
end

def make_query_url(rally_url, wsapi_version, type)
"#{rally_url}/webservice/#{wsapi_version}/#{type}.js"
"#{rally_url}/webservice/#{wsapi_version}/#{type}"
end

def short_ref(long_ref)
ref_pieces = long_ref.split("/")
"/#{ref_pieces[-2]}/#{ref_pieces[-1].split(".js")[0]}"
if @wsapi_version =~ /^v2/
path_components = long_ref.split("/")
path_components[-2..-1].join("/")
else
ref_pieces = long_ref.split("/")
"/#{ref_pieces[-2]}/#{ref_pieces[-1].split(".js")[0]}"
end
end

def warnings(json_obj)
Expand All @@ -425,12 +434,16 @@ def check_type(type_name)
return type_name
end

#ref should be like https://rally1.rallydev.com/slm/webservice/1.25/defect/12345.js
#ref should be like https://rally1.rallydev.com/slm/webservice/v2.0/defect/12345
def has_ref?(json_object)
if json_object["_ref"].nil?
return false
end
return true if json_object["_ref"] =~ /^https:\/\/\S*(\/slm\/webservice)\S*.js$/
if @wsapi_version =~ /^v2/
return true if json_object["_ref"] =~ /^https:\/\/\S*(\/slm\/webservice)\S*$/
else
return true if json_object["_ref"] =~ /^https:\/\/\S*(\/slm\/webservice)\S*.js$/
end
false
end

Expand Down Expand Up @@ -460,14 +473,15 @@ def ref_by_formatted_id(type, fid)
nil
end

#eg https://rally1.rallydev.com/slm/webservice/1.25/defect/12345.js
#eg https://rally1.rallydev.com/slm/webservice/v2.0/defect/12345
def get_type_from_ref(ref)
ref.split("/")[-2]
end

def check_fields(fields)
fields.each do |key, val|
fields[key] = make_ref_field(val)

if val.class == Time
fields[key] = val.iso8601
end
Expand All @@ -493,6 +507,25 @@ def make_ref_field(val)
val
end

def adjust_for_custom(type, fields)
# only needed for when using WSAPI v2.x or later, custom fields must be prefixed with 'c_'
begin
type_custom_fields = custom_fields_for(type)
rescue => ex
return fields
end
transform = {}
fields.each do |name, value|
is_custom = type_custom_fields.select {|fn| fn.downcase == name.downcase}
if is_custom.length > 0
transform[is_custom.first.last] = value
else
transform[name] = value
end
end
transform
end

def self.fix_case(values)
values.inject({}) do |new_values, (key, value)|
new_values[camel_case_word(key)] = value.is_a?(Hash) ? fix_case(value) : value
Expand Down
4 changes: 2 additions & 2 deletions lib/rally_api/version.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# :nodoc:
#Copyright (c) 2002-2012 Rally Software Development Corp. All Rights Reserved.
#Copyright (c) 2002-2015 Rally Software Development Corp. All Rights Reserved.
#Your use of this Software is governed by the terms and conditions
#of the applicable Subscription Agreement between your company and
#Rally Software Development Corp.
module RallyAPI
VERSION = "1.1.2"
VERSION = "1.2.0"
end
Loading

0 comments on commit cf29337

Please sign in to comment.