fisheye-crucible 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +15 -0
- data/Manifest.txt +30 -0
- data/PostInstall.txt +6 -0
- data/README.rdoc +75 -0
- data/Rakefile +124 -0
- data/features/authenticate.feature +28 -0
- data/features/client_legacy.feature +73 -0
- data/features/development.feature +13 -0
- data/features/step_definitions/authenticate_steps.rb +35 -0
- data/features/step_definitions/client_legacy_steps.rb +28 -0
- data/features/step_definitions/common_steps.rb +168 -0
- data/features/support/common.rb +39 -0
- data/features/support/config.yaml +3 -0
- data/features/support/env.rb +16 -0
- data/features/support/hooks.rb +9 -0
- data/features/support/matchers.rb +11 -0
- data/lib/fisheye-crucible.rb +10 -0
- data/lib/fisheye-crucible/client.rb +33 -0
- data/lib/fisheye-crucible/client/legacy.rb +315 -0
- data/lib/fisheye-crucible/type_converter.rb +285 -0
- data/lib/fisheye_crucible_exception.rb +5 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/client/legacy_spec.rb +36 -0
- data/spec/client_spec.rb +3 -0
- data/spec/fisheye-crucible_spec.rb +11 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- data/tasks/rspec.rake +21 -0
- metadata +252 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
module CommonHelpers
|
2
|
+
def in_tmp_folder(&block)
|
3
|
+
FileUtils.chdir(@tmp_root, &block)
|
4
|
+
end
|
5
|
+
|
6
|
+
def in_project_folder(&block)
|
7
|
+
project_folder = @active_project_folder || @tmp_root
|
8
|
+
FileUtils.chdir(project_folder, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def in_home_folder(&block)
|
12
|
+
FileUtils.chdir(@home_path, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def force_local_lib_override(project_name = @project_name)
|
16
|
+
rakefile = File.read(File.join(project_name, 'Rakefile'))
|
17
|
+
File.open(File.join(project_name, 'Rakefile'), "w+") do |f|
|
18
|
+
f << "$:.unshift('#{@lib_path}')\n"
|
19
|
+
f << rakefile
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def setup_active_project_folder project_name
|
24
|
+
@active_project_folder = File.join(@tmp_root, project_name)
|
25
|
+
@project_name = project_name
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
World(CommonHelpers)
|
30
|
+
|
31
|
+
# Common steps
|
32
|
+
Given /^I have logged in$/ do
|
33
|
+
@fc.login 'gemtest', 'gemtest'
|
34
|
+
@fc.instance_eval("@token").should_not be_nil
|
35
|
+
end
|
36
|
+
|
37
|
+
Given /^I have not logged in$/ do
|
38
|
+
@fc.instance_eval("@token").should be_nil
|
39
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../lib/fisheye-crucible"
|
2
|
+
require File.dirname(__FILE__) + "/../../lib/fisheye-crucible/client/legacy"
|
3
|
+
|
4
|
+
gem 'cucumber'
|
5
|
+
require 'cucumber'
|
6
|
+
gem 'rspec'
|
7
|
+
require 'spec'
|
8
|
+
|
9
|
+
Before do
|
10
|
+
@tmp_root = File.dirname(__FILE__) + "/../../tmp"
|
11
|
+
@home_path = File.expand_path(File.join(@tmp_root, "home"))
|
12
|
+
@lib_path = File.expand_path(File.dirname(__FILE__) + "/../../lib")
|
13
|
+
FileUtils.rm_rf @tmp_root
|
14
|
+
FileUtils.mkdir_p @home_path
|
15
|
+
ENV['HOME'] = @home_path
|
16
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Matchers
|
2
|
+
def contain(expected)
|
3
|
+
simple_matcher("contain #{expected.inspect}") do |given, matcher|
|
4
|
+
matcher.failure_message = "expected #{given.inspect} to contain #{expected.inspect}"
|
5
|
+
matcher.negative_failure_message = "expected #{given.inspect} not to contain #{expected.inspect}"
|
6
|
+
given.index expected
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
World(Matchers)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) ||
|
3
|
+
$:.include?(File.expand_path(File.dirname(__FILE__)))
|
4
|
+
|
5
|
+
require 'fisheye_crucible_exception'
|
6
|
+
|
7
|
+
module FisheyeCrucible
|
8
|
+
VERSION = '0.0.1'
|
9
|
+
WWW = 'http://github.com/turboladen/fisheye-crucible'
|
10
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'fisheye-crucible'
|
3
|
+
require 'rest-client'
|
4
|
+
|
5
|
+
# This is the parent class for accessing Fisheye/Crucible. This will change
|
6
|
+
# quite a bit once work on the current Fisheye/Crucible gets started. For
|
7
|
+
# now, look at the docs for FisheyeCrucible::Client::Legacy to get started.
|
8
|
+
class FisheyeCrucible::Client
|
9
|
+
|
10
|
+
# @return [Boolean] Turn debug on or off
|
11
|
+
attr_accessor :do_debug
|
12
|
+
|
13
|
+
##
|
14
|
+
# Sets up a Rest object to interact with the server(s).
|
15
|
+
#
|
16
|
+
# @param [String] server The base URL of the server to connect to.
|
17
|
+
def initialize(server)
|
18
|
+
@server = server
|
19
|
+
@fisheye_rest = RestClient::Resource.new(@server)
|
20
|
+
@token = nil
|
21
|
+
@do_debug = false
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Print out string if debug is turned on.
|
26
|
+
#
|
27
|
+
# @param [String] string The debug string to print out.
|
28
|
+
def debug(string)
|
29
|
+
if @do_debug
|
30
|
+
puts string
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,315 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'fisheye-crucible/client'
|
3
|
+
require 'fisheye-crucible/type_converter'
|
4
|
+
require 'rexml/document'
|
5
|
+
|
6
|
+
##
|
7
|
+
# This class provides access to the Fisheye/Crucible REST API that was
|
8
|
+
# used before version 2.0. More info here:
|
9
|
+
# http://confluence.atlassian.com/display/FECRUDEV/FishEye+Legacy+Remote+API
|
10
|
+
#
|
11
|
+
# All methods are named in Ruby style, however aliases are provided that are
|
12
|
+
# named after the Fisheye/Crucible function name (if different).
|
13
|
+
class FisheyeCrucible::Client::Legacy < FisheyeCrucible::Client
|
14
|
+
|
15
|
+
def initialize(server)
|
16
|
+
super(server)
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Logs in with provided credentials and returns a token that can be used for
|
21
|
+
# all other calls.
|
22
|
+
#
|
23
|
+
# @param [String] username The user to login with.
|
24
|
+
# @param [String] password The password of the user to login with.
|
25
|
+
# @return [String] The token to use for other calls.
|
26
|
+
def login(username=nil, password=nil)
|
27
|
+
@token = build_rest_call('api/rest/login',
|
28
|
+
:post,
|
29
|
+
{
|
30
|
+
:username => username,
|
31
|
+
:password => password
|
32
|
+
}
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Logs out of Fisheye/Crucible.
|
38
|
+
#
|
39
|
+
# @return [Boolean] Returns true if logout was successful.
|
40
|
+
def logout
|
41
|
+
unless @token
|
42
|
+
error_message = "Can't log out--it seems you're not logged in."
|
43
|
+
raise FisheyeCrucibleError, error_message
|
44
|
+
end
|
45
|
+
|
46
|
+
result = build_rest_call('api/rest/logout', :post, { :auth => @token })
|
47
|
+
|
48
|
+
@token = '' if result == true
|
49
|
+
|
50
|
+
result
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Gets the version of Fisheye.
|
55
|
+
#
|
56
|
+
# @return [String] The version of Fisheye.
|
57
|
+
# @alias fisheyeVersion
|
58
|
+
def fisheye_version
|
59
|
+
build_rest_call('api/rest/fisheyeVersion', :get)
|
60
|
+
end
|
61
|
+
alias_method :fisheyeVersion, :fisheye_version
|
62
|
+
|
63
|
+
##
|
64
|
+
# Gets the version of Crucible.
|
65
|
+
#
|
66
|
+
# @return [String] The version of Crucible.
|
67
|
+
def crucible_version
|
68
|
+
build_rest_call('api/rest/fisheyeVersion', :get)
|
69
|
+
end
|
70
|
+
alias_method :crucibleVersion, :crucible_version
|
71
|
+
|
72
|
+
##
|
73
|
+
# Gets the list of repositories to an array.
|
74
|
+
#
|
75
|
+
# @return [Array] The list of repositories.
|
76
|
+
def repositories
|
77
|
+
build_rest_call('api/rest/repositories',
|
78
|
+
:post,
|
79
|
+
{ :auth => @token }
|
80
|
+
)
|
81
|
+
end
|
82
|
+
alias_method :listRepositories, :repositories
|
83
|
+
|
84
|
+
##
|
85
|
+
# Gets the file/dir listing from a repository.
|
86
|
+
#
|
87
|
+
# @param [String] repository The repository to get the listing for.
|
88
|
+
# @param [String] path The directory in the repository to get the listing
|
89
|
+
# for. If no path is given, listing is from /.
|
90
|
+
# @return [Hash<String><Hash>] The listing, where the key is the
|
91
|
+
# file/directory and the value is another Hash that contains properties of
|
92
|
+
# the file/directory.
|
93
|
+
def list_paths_from(repository, path='')
|
94
|
+
build_rest_call('api/rest/listPaths',
|
95
|
+
:post,
|
96
|
+
{
|
97
|
+
:auth => @token,
|
98
|
+
:rep => repository,
|
99
|
+
:path => path
|
100
|
+
}
|
101
|
+
)
|
102
|
+
end
|
103
|
+
alias_method :listPaths, :list_paths_from
|
104
|
+
|
105
|
+
##
|
106
|
+
# Gets details about a specific file/directory revision from the given
|
107
|
+
# repository.
|
108
|
+
#
|
109
|
+
# @param [String] repository The repository in which the file resides.
|
110
|
+
# @param [String] path The path, relative to the repository, in which the
|
111
|
+
# file resides.
|
112
|
+
# @param [Fixnum] revision The revision of the file/directory to get the info
|
113
|
+
# about.
|
114
|
+
# @return [Hash] The list of details about the file revision.
|
115
|
+
def revision(repository, path, revision)
|
116
|
+
build_rest_call('api/rest/revision',
|
117
|
+
:post,
|
118
|
+
{
|
119
|
+
:auth => @token,
|
120
|
+
:rep => repository,
|
121
|
+
:path => path,
|
122
|
+
:rev => revision.to_s
|
123
|
+
}
|
124
|
+
)
|
125
|
+
end
|
126
|
+
alias_method :getRevision, :revision
|
127
|
+
|
128
|
+
##
|
129
|
+
# Gets tags associated with a file/directory revision.
|
130
|
+
#
|
131
|
+
# @param [String] repository The repository in which the file resides.
|
132
|
+
# @param [String] path The path, relative to the repository, in which the
|
133
|
+
# file resides.
|
134
|
+
# @param [Fixnum] revision The revision of the file/directory to get the tags
|
135
|
+
# for.
|
136
|
+
# @return [Hash] The list of tags for the file revision.
|
137
|
+
def tags(repository, path, revision)
|
138
|
+
puts "WARNING: This method is untested!"
|
139
|
+
|
140
|
+
tags = build_rest_call('api/rest/tags',
|
141
|
+
:post,
|
142
|
+
{
|
143
|
+
:auth => @token,
|
144
|
+
:rep => repository,
|
145
|
+
:path => path,
|
146
|
+
:rev => revision.to_s
|
147
|
+
}
|
148
|
+
)
|
149
|
+
=begin
|
150
|
+
tags_xml = @fisheye_rest['api/rest/tags'].post :auth => @token,
|
151
|
+
:rep => repository,
|
152
|
+
:path => path,
|
153
|
+
:rev => revision.to_s
|
154
|
+
|
155
|
+
#debug tags_xml
|
156
|
+
return tags_xml.to_ruby
|
157
|
+
doc = REXML::Document.new(tags_xml)
|
158
|
+
|
159
|
+
if doc.root.name.eql? 'error'
|
160
|
+
raise doc.root.text
|
161
|
+
elsif doc.root.name.eql? 'response' and doc.root.has_elements?
|
162
|
+
# TODO: Not sure if this works since I can't find any files
|
163
|
+
# with tags.
|
164
|
+
return doc.root.elements['//tags'].text
|
165
|
+
elsif doc.root.name.eql? 'response' and !doc.root.has_elements?
|
166
|
+
return ""
|
167
|
+
end
|
168
|
+
=end
|
169
|
+
end
|
170
|
+
alias_method :listTagsForRevision, :tags
|
171
|
+
|
172
|
+
##
|
173
|
+
# Gets the history for a file/directory, which is a list of revisions and
|
174
|
+
# their associated info.
|
175
|
+
#
|
176
|
+
# @param [String] repository The repository for which to get the history
|
177
|
+
# info about.
|
178
|
+
# @param [String] path The path, relative to root, for which to get info
|
179
|
+
# about.
|
180
|
+
# @return [Array<Hash>] The list of revisions.
|
181
|
+
def path_history(repository, path='')
|
182
|
+
build_rest_call('api/rest/pathHistory',
|
183
|
+
:post,
|
184
|
+
{
|
185
|
+
:auth => @token,
|
186
|
+
:rep => repository,
|
187
|
+
:path => path
|
188
|
+
}
|
189
|
+
)
|
190
|
+
end
|
191
|
+
alias :pathHistory :path_history
|
192
|
+
|
193
|
+
##
|
194
|
+
# Gets information about a changeset.
|
195
|
+
#
|
196
|
+
# @param [String] repository The repository for which to get the changeset
|
197
|
+
# info about.
|
198
|
+
# @param [Fixnum] csid The changeset ID to get the info about.
|
199
|
+
# @return [Hash] All of the changeset info as defined by the API.
|
200
|
+
def changeset(repository, csid)
|
201
|
+
build_rest_call('api/rest/changeset',
|
202
|
+
:post,
|
203
|
+
{
|
204
|
+
:auth => @token,
|
205
|
+
:rep => repository,
|
206
|
+
:csid => csid.to_s
|
207
|
+
}
|
208
|
+
)
|
209
|
+
end
|
210
|
+
alias_method :getChangeset, :changeset
|
211
|
+
|
212
|
+
##
|
213
|
+
# Gets all changeset IDs (csids) that match the parameters given.
|
214
|
+
#
|
215
|
+
# @param [String] repository The repository for which to get the changesets
|
216
|
+
# for.
|
217
|
+
# @param [String] path Path to the item(s) to get changesets for. Can only
|
218
|
+
# be a directory.
|
219
|
+
# @param [Fixnum] max_return The maximum number of values to return. If not
|
220
|
+
# set, this is limited by the internal Fisheye server. If set, the most
|
221
|
+
# recent results are returned.
|
222
|
+
# @param [DateTime] start_date The DateTime object representing the start
|
223
|
+
# date for which to filter the query.
|
224
|
+
# @param [DateTime] end_date The DateTime object representing the end date
|
225
|
+
# for which to filter the query.
|
226
|
+
# @return [Hash<Array,String>] :csids => the Array of changeset IDs;
|
227
|
+
# :max_return => Max values returned.
|
228
|
+
def changesets(repository, path='/', max_return=nil, start_date=nil,
|
229
|
+
end_date=nil)
|
230
|
+
build_rest_call('api/rest/changesets',
|
231
|
+
:post,
|
232
|
+
{
|
233
|
+
:auth => @token,
|
234
|
+
:rep => repository,
|
235
|
+
:path => path,
|
236
|
+
:start => start_date,
|
237
|
+
:end => end_date,
|
238
|
+
:maxReturn => max_return
|
239
|
+
}
|
240
|
+
)
|
241
|
+
end
|
242
|
+
alias_method :listChangesets, :changesets
|
243
|
+
|
244
|
+
##
|
245
|
+
# Sends an EyeQL query to the server for a given repository. Return types
|
246
|
+
# can differ depending on the 'return-clause' used in the query. For more
|
247
|
+
# info, see http://confluence.atlassian.com/display/FISHEYE/EyeQL+Reference+Guide.
|
248
|
+
#
|
249
|
+
# @param [String] repository The repository to run the EyeQL query on.
|
250
|
+
# @param [String] query The EyeQL query to run.
|
251
|
+
# @return [Object]
|
252
|
+
def query(repository, query)
|
253
|
+
build_rest_call('api/rest/query',
|
254
|
+
:post,
|
255
|
+
{
|
256
|
+
:auth => @token,
|
257
|
+
:rep => repository,
|
258
|
+
:query => query
|
259
|
+
}
|
260
|
+
)
|
261
|
+
end
|
262
|
+
|
263
|
+
##
|
264
|
+
# Privates
|
265
|
+
private
|
266
|
+
|
267
|
+
##
|
268
|
+
# Builds and makes the REST call from the arguments given.
|
269
|
+
#
|
270
|
+
# @param [String] url The API portion of the URL as defined by the API.
|
271
|
+
# @param [String] action 'post' or 'get'.
|
272
|
+
# @param [Hash] options The REST params to pass to the REST call.
|
273
|
+
# @return [Object] The Object that #to_ruby returns.
|
274
|
+
def build_rest_call(url, action, options=nil)
|
275
|
+
rest_call = "@fisheye_rest['#{url}'].#{action}"
|
276
|
+
|
277
|
+
unless options.nil?
|
278
|
+
actual_options = non_nil_options_in options
|
279
|
+
|
280
|
+
option_count = 1
|
281
|
+
actual_options.each_pair do |key,value|
|
282
|
+
unless value.nil?
|
283
|
+
rest_call << " :#{key} => '#{value}'"
|
284
|
+
rest_call << ',' unless option_count == actual_options.length
|
285
|
+
option_count += 1
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
response_xml = eval(rest_call)
|
291
|
+
response = response_xml.to_ruby
|
292
|
+
|
293
|
+
if response.class == FisheyeCrucibleError
|
294
|
+
raise response
|
295
|
+
end
|
296
|
+
|
297
|
+
response
|
298
|
+
end
|
299
|
+
|
300
|
+
##
|
301
|
+
# Removes all key/value pairs from Hash that have a nil value and returns
|
302
|
+
# a Hash with keys that have values.
|
303
|
+
#
|
304
|
+
# @param [Hash] options The Hash to remove nil key/value pairs from.
|
305
|
+
def non_nil_options_in options
|
306
|
+
non_nil_options = {}
|
307
|
+
options.each_pair do |k,v|
|
308
|
+
non_nil_options[k] = v unless v.nil?
|
309
|
+
end
|
310
|
+
|
311
|
+
non_nil_options
|
312
|
+
end
|
313
|
+
rescue FisheyeCrucibleError => e
|
314
|
+
puts e.message
|
315
|
+
end
|
@@ -0,0 +1,285 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'fisheye-crucible'
|
3
|
+
|
4
|
+
# By adding this method to String, the #to_ruby method can be called directly
|
5
|
+
# on the return data from RestClient. This, effectively, accomplishes turning
|
6
|
+
# a String of XML into the Ruby data types that make sense for the return types
|
7
|
+
# that Atlassian defined.
|
8
|
+
class String
|
9
|
+
|
10
|
+
# Takes a String of XML then converts in to a correlating Ruby data type.
|
11
|
+
# Aside from the documentation for each private method below, here is the
|
12
|
+
# conversion table:
|
13
|
+
# | Fisheye/Crucible Type | Ruby Type |
|
14
|
+
# | string | String |
|
15
|
+
# | boolean | TrueClass, FalseClass |
|
16
|
+
# | pathinfo | Hash with child Hashes |
|
17
|
+
# | revision | Hash |
|
18
|
+
# | history | Array of revisions |
|
19
|
+
# | changeset | Hash |
|
20
|
+
# | changesets | Hash of changesets |
|
21
|
+
# | revisionkey | Array with child Hashes |
|
22
|
+
# | row | Array |
|
23
|
+
def to_ruby
|
24
|
+
doc = REXML::Document.new self
|
25
|
+
|
26
|
+
type = doc.root.name
|
27
|
+
doc_text = doc.root.text
|
28
|
+
|
29
|
+
responses = []
|
30
|
+
response_type = ''
|
31
|
+
|
32
|
+
if type == 'error'
|
33
|
+
return FisheyeCrucibleError.new(doc_text)
|
34
|
+
elsif type == 'response'
|
35
|
+
doc.root.each_element do |element|
|
36
|
+
# The data type
|
37
|
+
response_type = element.name
|
38
|
+
|
39
|
+
# Text for the next element
|
40
|
+
responses << element.text
|
41
|
+
end
|
42
|
+
else
|
43
|
+
message = "Not sure what to do with this response:\n#{doc_text}"
|
44
|
+
return FisheyeCrucibleError.new(message)
|
45
|
+
end
|
46
|
+
|
47
|
+
# If we have 0 or 1 actual strings, return the string or ""
|
48
|
+
if response_type.eql? 'string' and responses.length <= 1
|
49
|
+
return string_to_string(doc)
|
50
|
+
# If we have mulitple strings, return the Array of Strings
|
51
|
+
elsif response_type.eql? 'string'
|
52
|
+
return string_to_array(doc)
|
53
|
+
elsif response_type.eql? 'boolean'
|
54
|
+
return boolean_to_true_false(doc)
|
55
|
+
elsif response_type.eql? 'pathinfo'
|
56
|
+
return pathinfo_to_hash(doc)
|
57
|
+
elsif response_type.eql? 'revision'
|
58
|
+
return revision_to_hash(doc)
|
59
|
+
elsif response_type.eql? 'history'
|
60
|
+
return history_to_array(doc)
|
61
|
+
elsif response_type.eql? 'changeset'
|
62
|
+
return changeset_to_hash(doc)
|
63
|
+
elsif response_type.eql? 'changesets'
|
64
|
+
return changesets_to_hash(doc)
|
65
|
+
elsif response_type.eql? 'revisionkey'
|
66
|
+
return revisionkeys_to_array(doc)
|
67
|
+
elsif response_type.eql? 'row'
|
68
|
+
return custom_to_array(doc)
|
69
|
+
end
|
70
|
+
|
71
|
+
message = "Response type unknown: '#{response_type}'"
|
72
|
+
return FisheyeCrucibleError.new(message)
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# PRIVATES!
|
77
|
+
private
|
78
|
+
|
79
|
+
##
|
80
|
+
# Converts a REXML::Document with 1 element of type <string> into a String.
|
81
|
+
#
|
82
|
+
# @param [REXML::Document] xml_doc The XML document to convert.
|
83
|
+
# @return [String] The string from the XML document.
|
84
|
+
def string_to_string(xml_doc)
|
85
|
+
xml_doc.root.elements[1].text
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Converts a String to its related Boolean type. If the string doesn't
|
90
|
+
# contain such a type, nil is returned.
|
91
|
+
#
|
92
|
+
# @param [String] string The String to convert.
|
93
|
+
# @return [Boolean,String] true, false, or the original string.
|
94
|
+
def string_to_true_false(string)
|
95
|
+
return true if string.eql? 'true'
|
96
|
+
return false if string.eql? 'false'
|
97
|
+
return string
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# Converts a REXML::Document with element <boolean> into a true or false
|
102
|
+
# value.
|
103
|
+
#
|
104
|
+
# @param [REXML::Document] xml_doc The XML document to convert.
|
105
|
+
# @return [Boolean] true, false, or nil.
|
106
|
+
def boolean_to_true_false(xml_doc)
|
107
|
+
string_to_true_false(xml_doc.root.elements[1].text)
|
108
|
+
end
|
109
|
+
|
110
|
+
##
|
111
|
+
# Converts a REXML::Document with multiple elements of type <string> into an
|
112
|
+
# Array.
|
113
|
+
#
|
114
|
+
# @param [REXML::Document] xml_doc The XML document to convert.
|
115
|
+
# @return [Array] The list of strings.
|
116
|
+
def string_to_array(xml_doc)
|
117
|
+
responses = []
|
118
|
+
xml_doc.root.each_element do |element|
|
119
|
+
response_type = element.name
|
120
|
+
responses << element.text
|
121
|
+
end
|
122
|
+
|
123
|
+
responses
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# Takes Fisheye/Crucible's <pathinfo> return type and turns it in to
|
128
|
+
# a Hash of Hashes.
|
129
|
+
#
|
130
|
+
# @param [REXML::Document] xml_doc The XML document to convert.
|
131
|
+
# @return [Hash<Hash>] The path info as a Hash. The Hash contains keys
|
132
|
+
# which are the file/directory names in the path; values for those keys
|
133
|
+
# are Hashes which contain the properties of that file/directory.
|
134
|
+
def pathinfo_to_hash(xml_doc)
|
135
|
+
path_name = ''
|
136
|
+
path_names = {}
|
137
|
+
|
138
|
+
xml_doc.root.each_element do |element|
|
139
|
+
path_name = element.attributes["name"]
|
140
|
+
path_names[path_name] = {}
|
141
|
+
|
142
|
+
element.attributes.each_attribute do |attribute|
|
143
|
+
next attribute if attribute.name.eql? 'name'
|
144
|
+
boolean_value = string_to_true_false(attribute.value)
|
145
|
+
path_names[path_name][attribute.name.to_sym] = boolean_value
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
path_names
|
150
|
+
end
|
151
|
+
|
152
|
+
##
|
153
|
+
# Takes Fisheye/Crucible's <revision> return type and turns it in to a single
|
154
|
+
# Hash.
|
155
|
+
#
|
156
|
+
# @param [REXML::Document] xml_doc The XML document to convert.
|
157
|
+
# @return [Hash] The info about the revision.
|
158
|
+
def revision_to_hash(xml_doc)
|
159
|
+
details = {}
|
160
|
+
|
161
|
+
xml_doc.root.elements['//revision'].attributes.each do |attribute|
|
162
|
+
# Convert the value to an Int if the string is just a number
|
163
|
+
if attribute[1] =~ /^\d+$/
|
164
|
+
details[attribute.first.to_sym] = attribute[1].to_i
|
165
|
+
else
|
166
|
+
details[attribute.first.to_sym] = attribute[1]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
details[:log] = xml_doc.root.elements['//log'].text
|
170
|
+
|
171
|
+
details
|
172
|
+
end
|
173
|
+
|
174
|
+
##
|
175
|
+
# Takes Fisheye/Crucible's <history> return type and turns it in to an
|
176
|
+
# Array of revisions, which are Hashes.
|
177
|
+
#
|
178
|
+
# @param [REXML::Document] xml_doc The XML document to convert.
|
179
|
+
# @return [Array<Hash>] The Array of revision Hashes.
|
180
|
+
def history_to_array(xml_doc)
|
181
|
+
revisions = []
|
182
|
+
|
183
|
+
revisions_xml = REXML::XPath.match(xml_doc, "//revisions/revision")
|
184
|
+
revisions_xml.each do |revision_xml|
|
185
|
+
revision = REXML::Document.new(revision_xml.to_s)
|
186
|
+
revisions << revision_to_hash(revision)
|
187
|
+
end
|
188
|
+
|
189
|
+
revisions
|
190
|
+
end
|
191
|
+
|
192
|
+
##
|
193
|
+
# Takes Fisheye/Crucible's <changeset> return type and turns it in to a Hash.
|
194
|
+
#
|
195
|
+
# @param [REXML::Document] xml_doc The XML document to convert.
|
196
|
+
# @return [Hash] Hash containting the changeset history information as
|
197
|
+
# defined by the API.
|
198
|
+
def changeset_to_hash(xml_doc)
|
199
|
+
details = {}
|
200
|
+
|
201
|
+
xml_doc.root.elements['//changeset'].attributes.each do |attribute|
|
202
|
+
# Convert the value to an Int if the string is just a number
|
203
|
+
int_attribute = attribute[1]
|
204
|
+
if int_attribute =~ /^\d+$/
|
205
|
+
details[attribute.first.to_sym] = int_attribute.to_i
|
206
|
+
else
|
207
|
+
details[attribute.first.to_sym] = int_attribute
|
208
|
+
end
|
209
|
+
end
|
210
|
+
details[:log] = xml_doc.root.elements['//log'].text
|
211
|
+
|
212
|
+
# Revisions is an Array of Hashes, where each Hash is a key/value pair that
|
213
|
+
# contains the path and revsion of one of the files/directories that's
|
214
|
+
# part of the changeset.
|
215
|
+
details[:revisions] = []
|
216
|
+
details[:revisions] << revisionkeys_to_array(xml_doc)
|
217
|
+
|
218
|
+
details
|
219
|
+
end
|
220
|
+
|
221
|
+
##
|
222
|
+
# Takes Fisheye/Crucible's <revisionkey> return type and turns it in to an
|
223
|
+
# Array of Hashes.
|
224
|
+
#
|
225
|
+
# @param [REXML::Document] xml_doc The XML document to convert.
|
226
|
+
# @return [Array<Hash>] The Array of path & rev data.
|
227
|
+
def revisionkeys_to_array(xml_doc)
|
228
|
+
revisionkeys = []
|
229
|
+
|
230
|
+
xml_doc.root.elements.each('//revisionkey') do |element|
|
231
|
+
revisionkey = { :path => element.attributes['path'],
|
232
|
+
:rev => element.attributes['rev'].to_i
|
233
|
+
}
|
234
|
+
|
235
|
+
revisionkeys << revisionkey
|
236
|
+
end
|
237
|
+
|
238
|
+
revisionkeys
|
239
|
+
end
|
240
|
+
|
241
|
+
##
|
242
|
+
# Takes Fisheye/Crucible's <changesets> return type and turns it in to a
|
243
|
+
# Hash.
|
244
|
+
#
|
245
|
+
# @param [REXML::Document] xml_doc The XML document to convert.
|
246
|
+
# @return [Hash] Contains the changeset IDs as defined by the query.
|
247
|
+
def changesets_to_hash(xml_doc)
|
248
|
+
changesets = {}
|
249
|
+
changesets[:csids] = []
|
250
|
+
|
251
|
+
changesets[:max_return] = xml_doc.root.elements['//changesets'].
|
252
|
+
attributes['maxReturn']
|
253
|
+
|
254
|
+
xml_doc.root.elements['//csids'].each_element do |element|
|
255
|
+
changesets[:csids] << element.text.to_i
|
256
|
+
end
|
257
|
+
|
258
|
+
changesets
|
259
|
+
end
|
260
|
+
|
261
|
+
##
|
262
|
+
# Takes Fisheye/Crucible's custom <row> return type (from a query) and turns
|
263
|
+
# it in to an Array of Hashes containing the results from the query.
|
264
|
+
#
|
265
|
+
# @param [REXML::Document] xml_doc The XML document to convert.
|
266
|
+
# @return [Array] The result from the query.
|
267
|
+
def custom_to_array(xml_doc)
|
268
|
+
responses = []
|
269
|
+
|
270
|
+
xml_doc.elements.each('//row') do |element|
|
271
|
+
response = {}
|
272
|
+
element.each do |subs|
|
273
|
+
if subs.is_a? REXML::Text
|
274
|
+
else
|
275
|
+
# TODO: If subs.text is a Boolean string, it doesn't get converted
|
276
|
+
# to the actual Boolean. Same if it's an int or empty string.
|
277
|
+
response[subs.name.to_sym] = subs.text
|
278
|
+
end
|
279
|
+
end
|
280
|
+
responses << response
|
281
|
+
end
|
282
|
+
|
283
|
+
responses
|
284
|
+
end
|
285
|
+
end
|