Skip to content

Commit

Permalink
made default WSAPI_VERSION 2.0, fixed reread to use start instead of …
Browse files Browse the repository at this point in the history
…startindex, upped version to 1.2.0, noodled some tests to get them to pass, got rid of the .js on the end of urls for v2.0 usage, can now accommodate use of DisplayName for custom fields (internally prefix with the c_ sequence for create and update operations)
  • Loading branch information
klehman-rally committed Apr 27, 2015
1 parent ad1f8d7 commit c2902e0
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 c2902e0

Please sign in to comment.