trail_marker 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,350 @@
1
+ require_relative "response"
2
+
3
+ # TODO: CLEAN UP or DRY testruns and testplans methods since can be combined.
4
+ # Implement other API calls
5
+ #
6
+ class ApiTestRail
7
+ attr_accessor :project_id
8
+ attr_accessor :suite_id
9
+ attr_accessor :run_id
10
+ attr_accessor :test_case_id
11
+ attr_accessor :section_id
12
+
13
+
14
+ def initialize(client)
15
+ @client = client
16
+ @projects = get_projects()
17
+ @project = nil
18
+ @suites = nil
19
+ @suite = nil
20
+ @plans = nil
21
+ @plan = nil
22
+ @runs = nil
23
+ @run = nil
24
+ @test_cases = nil
25
+ @test_case = nil
26
+ @milestones = nil
27
+ @milestone = nil
28
+ @statuses = get_statuses()
29
+
30
+ end
31
+
32
+ # Returns the project ID of the project name passed.
33
+ #
34
+ def get_project_id(project_name)
35
+ if @projects.nil?
36
+ get_projects()
37
+ end
38
+ @project_id = search_array_kv(@projects, 'name', project_name, 'id')
39
+ if @project_id.nil?
40
+ puts "\nProject '#{project_name}' WAS NOT FOUND, select from available projects."
41
+ resp_projects = Response.new(@projects)
42
+ project_name = resp_projects.picker("name")
43
+ @project_id = search_array_kv(@projects, 'name', project_name, 'id')
44
+ end
45
+ return @project_id
46
+ end
47
+
48
+ def get_milestone_id(milestone_name)
49
+ ms_id = nil
50
+ if ! milestone_exists?(milestone_name)
51
+ puts "\nMilestone '#{milestone_name}' WAS NOT FOUND, select from available milestones."
52
+ resp_ms = Response.new(@milestones)
53
+ milestone_name = resp_ms.picker("name")
54
+ #ms_id = search_array_kv(@milestones, 'name', milestone_name, 'id')
55
+ end
56
+ ms_id = search_array_kv(@milestones, 'name', milestone_name, 'id')
57
+ return ms_id
58
+ end
59
+
60
+ def get_test_runplan_id(runplan_name)
61
+ if @runs.nil?
62
+ get_runs(@project_id)
63
+ end
64
+ run_id = search_array_kv(@runs, 'name', runplan_name, 'id')
65
+ if run_id.nil?
66
+ puts "\nTest Run WAS NOT FOUND, select from available."
67
+ resp_runs = Response.new(@runs)
68
+ runplan_name = resp_runs.picker("name")
69
+ run_id = search_array_kv(@runs, 'name', runplan_name, 'id')
70
+ end
71
+ return run_id
72
+ end
73
+
74
+ def get_testplan_id(testplan_name)
75
+ if @plans.nil?
76
+ get_plans(@project_id)
77
+ end
78
+ plan_id = search_array_kv(@plans, 'name', testplan_name, 'id')
79
+ if plan_id.nil?
80
+ puts "\nTestPlan #{testplan_name} WAS NOT FOUND, select from available."
81
+ resp_plans = Response.new(@plans)
82
+ plan_name = resp_plans.picker("name")
83
+ plan_id = search_array_kv(@plans, 'name', plan_name, 'id')
84
+ end
85
+ return plan_id
86
+ end
87
+
88
+ def get_suite_id(proj_id, suite_name)
89
+ suite_id = nil
90
+ if suite_exists?(proj_id, suite_name)
91
+ suite_id = search_array_kv(@suites, 'name', suite_name, 'id')
92
+ end
93
+ return suite_id
94
+ end
95
+
96
+ def get_projects()
97
+ @projects = request_get('get_projects')
98
+ return @projects
99
+ end
100
+
101
+ def get_milestones(proj_id)
102
+ ms_req = "get_milestones/" + proj_id.to_s
103
+ @milestones = request_get(ms_req)
104
+ end
105
+
106
+ def get_runs(proj_id)
107
+ runs_req = "get_runs/" + proj_id.to_s
108
+ @runs = request_get(runs_req)
109
+ end
110
+
111
+ def get_plans(proj_id)
112
+ plans_req = "get_plans/" + proj_id.to_s
113
+ @plans = request_get(plans_req)
114
+ end
115
+
116
+ def get_plan(plan_id)
117
+ plan_req = "get_plan/" + plan_id.to_s
118
+ @plan = request_get(plan_req)
119
+ end
120
+
121
+ def get_suites(proj_id)
122
+ suite_req = "get_suites/" + proj_id.to_s
123
+ @suites = request_get(suite_req)
124
+ end
125
+
126
+ ######################## VERIFY
127
+
128
+ def milestone_exists?(milestone_name)
129
+ it_exists = false
130
+ if @milestones.nil?
131
+ get_milestones(@project_id)
132
+ end
133
+ puts "ALL MILES: #{@milestones}"
134
+ ms_id = search_array_kv(@milestones, 'name', milestone_name, 'id')
135
+ if ! ms_id.nil?
136
+ it_exists = true
137
+ end
138
+ return it_exists
139
+ end
140
+
141
+ def run_exists?(proj_id, run_name)
142
+ it_exists = false
143
+ if @runs.nil?
144
+ @runs = get_runs(proj_id)
145
+ end
146
+ run_id = search_array_kv(@runs, 'name', run_name, 'id')
147
+ if ! run_id.nil?
148
+ it_exists = true
149
+ end
150
+ return it_exists
151
+ end
152
+
153
+ def suite_exists?(proj_id, suite_name)
154
+ it_exists = false
155
+ if @suites.nil?
156
+ @suites = get_suites(proj_id)
157
+ end
158
+ suite_id = search_array_kv(@suites, 'name', suite_name, 'id')
159
+ if ! suite_id.nil?
160
+ it_exists = true
161
+ end
162
+ return it_exists
163
+ end
164
+
165
+ #############
166
+
167
+ # Makes an API call to get all possible results status. Currently has 5
168
+ # passed, blocked, untested, retest, failed.
169
+ # Puts the name and status in @statuses array.
170
+ #
171
+ def get_statuses()
172
+ @statuses = []
173
+ status_req = request_get('get_statuses')
174
+ status_req.each do |status|
175
+ status_hash ={}
176
+ status_hash['id'] = status['id']
177
+ status_hash['name'] = status['name']
178
+ @statuses.push(status_hash)
179
+ end
180
+ return @statuses
181
+ end
182
+
183
+
184
+
185
+ ######################## TEST PLANS #########################
186
+
187
+ # Returns an array of testrun IDs that is inside a testplan.
188
+ #
189
+ def get_testplan_testruns(testplan_id)
190
+ run_ids = []
191
+ plan_resp = get_plan(testplan_id)
192
+ tp_entries = plan_resp['entries']
193
+ tp_entries.each do |entry|
194
+ entry_runs = entry['runs']
195
+ entry_runs.each do |erun|
196
+ run_ids.push(erun['id'])
197
+ end
198
+ end
199
+ return run_ids
200
+ end
201
+
202
+ # Returns array of id for testruns inside a testplan
203
+ def get_testplan_run_ids(testplan_name)
204
+ testplan_id = get_testplan_id(testplan_name)
205
+ get_testplan_testruns(testplan_id)
206
+ end
207
+
208
+ # NOTE - NOT USED RIGHT NOW.
209
+ # Marks a test case inside a testplan. Testplans adds extra API calls
210
+ # because testruns are inside the testplans and are not named.
211
+ # See note below MARK_TESTPLAN
212
+ def markoff_testplan(case_id, testplan_id, pass_status)
213
+ status_id = search_array_kv(@statuses, 'name', 'failed', 'id')
214
+ defect_txt = ""
215
+ if pass_status
216
+ status_id = search_array_kv(@statuses, 'name', 'passed', 'id')
217
+ defect_txt = ""
218
+ end
219
+ equiv_json = {:status_id => status_id, :comment => 'Auto marker.', :defects => defect_txt}
220
+ add_result_req = "add_result_for_case/" + run_id.to_s + "/" + case_id.to_s
221
+ request_post(add_result_req, equiv_json)
222
+ end
223
+
224
+ def get_testid(run_id, case_id)
225
+ puts "SEARCH FOR TESTID: #{run_id} :: #{case_id}"
226
+ tests_req = 'get_tests/' + run_id.to_s
227
+ tests_resp = request_get(tests_req)
228
+ puts "GET_TESTS: #{tests_resp}"
229
+ id_equiv = search_array_kv(tests_resp, 'case_id', case_id.to_i, 'id')
230
+ return id_equiv
231
+ end
232
+
233
+
234
+
235
+ # TODO: Parse XML for failed reason and add to comment(?)
236
+ #
237
+ def markoff_test(case_id, run_id, pass_status, comment_txt)
238
+ status_id = search_array_kv(@statuses, 'name', 'failed', 'id')
239
+ defect_txt = ""
240
+ if pass_status
241
+ status_id = search_array_kv(@statuses, 'name', 'passed', 'id')
242
+ defect_txt = ""
243
+ end
244
+ equiv_json = {:status_id => status_id, :comment => comment_txt, :defects => defect_txt}
245
+ add_result_req = "add_result_for_case/" + run_id.to_s + "/" + case_id.to_s
246
+ request_post(add_result_req, equiv_json)
247
+ end
248
+
249
+ # Makes a post call to create a new milestone
250
+ def create_milestone(proj_name, msname)
251
+ proj_id = get_project_id(proj_name)
252
+ if ! milestone_exists?(msname)
253
+ puts "Create Milestones #{msname} in Project #{proj_name} "
254
+ unix_timestamp = Time.now.to_i
255
+ req_field = {:name => msname, :due_on => unix_timestamp}
256
+ create_milestone_req = "add_milestone/" + proj_id.to_s
257
+ request_post(create_milestone_req, req_field)
258
+ sleep(2)
259
+ get_milestones(proj_id)
260
+ end
261
+ end
262
+
263
+ def delete_milestone(proj_name, msname)
264
+ proj_id = get_project_id(proj_name)
265
+ ms_id = get_milestone_id(msname)
266
+ del_ms_req = "delete_milestone/" + ms_id.to_s
267
+ request_post(del_ms_req, nil)
268
+ exit
269
+ end
270
+
271
+ def create_testrun(proj_name, msname, trname, tsname)
272
+ proj_id = get_project_id(proj_name)
273
+ if ! run_exists?(proj_id, trname)
274
+ if suite_exists?(proj_id, tsname)
275
+ ms_id = nil
276
+ if ! msname.nil? && msname != ""
277
+ ms_id = get_milestone_id(msname)
278
+ end
279
+ puts "MSID: #{msname} #{ms_id}"
280
+ ts_id = get_suite_id(proj_id, tsname)
281
+ req_field = {:name => trname, :suite_id => ts_id, :description => "AutoCreated"}
282
+ if ! ms_id.nil? && ms_id != ""
283
+ req_field[:milestone_id] = ms_id
284
+ end
285
+ add_run_req = "add_run/" + proj_id.to_s
286
+ request_post(add_run_req, req_field)
287
+ puts "CREATING RUN under #{proj_name} #{req_field}"
288
+ sleep(2)
289
+ get_runs(proj_id)
290
+ else
291
+ puts "CANNOT Create New TestRun, (-s) test suite name needed."
292
+ end
293
+ else
294
+ puts "CANNOT Create RUN #{trname}, already exists."
295
+ end
296
+ end
297
+
298
+ private
299
+
300
+ def request_get(api_cmd)
301
+ req = Request.new(@client)
302
+ resp = req.exec_get(api_cmd)
303
+ return resp
304
+ end
305
+
306
+ def request_post(api_cmd, data)
307
+ req = Request.new(@client)
308
+ resp = req.exec_post(api_cmd, data)
309
+ return resp
310
+ end
311
+
312
+ # Searched an array of hashes for a key and value to match
313
+ # and returns a field of that hash.
314
+ # * *Args* :
315
+ # - +rdata+ -> Array of hash data (e.g)
316
+ # - +k+ -> key (e.g. "name")
317
+ # - +v+ -> value to find (e.g. "Test Project")
318
+ # - +key_return+ -> name of another field to return (e.g. "id")
319
+ # * *Returns* :
320
+ # - Value of a field in the hash
321
+ # - nil if none found
322
+ #
323
+ # Example: rdata: [{'id' => 12, 'name' => 'Project-Files, 'owner' => 'Serban', 'run_name' => 'Sprint 2'},
324
+ # {'id' => 22, 'name' => 'Faspex, 'owner' => 'Ajanta', 'run_name' => 'Marathon 10'}]
325
+ #
326
+ # search_array_kv(rdata, "name", "Faspex", "owner")
327
+ # => Calling this find the hash that has 'Faspex' for name,
328
+ # then return the value of 'owner' in that hash 'Ajanta'
329
+ #
330
+ def search_array_kv(rdata, k, v, key_return)
331
+ retval = nil
332
+ fnd = rdata.detect {|unhash| unhash[k] == v}
333
+ if ! fnd.nil?
334
+ retval = fnd[key_return]
335
+ end
336
+ return retval
337
+ end
338
+
339
+
340
+ # NOTE: MARK_TEST_PLAN
341
+ # User Input: Project Name, TestRun Name
342
+ # Project Name > Get project_id
343
+ # Call API get_plans/project_id to get all test plans for the project
344
+ # Get testplan_id of testplan with the given name
345
+ # Call API get_plan/testplan_id to get testruns inside this testplan
346
+ #
347
+
348
+
349
+
350
+ end
@@ -0,0 +1,229 @@
1
+
2
+ # Parses command line argument.
3
+ # Avoids requiring a dependent gem, easy to add any parameters and tags
4
+ # To Add New Parameter:
5
+ # => Add new tag in @valid_parameters
6
+ # => Change HELP message to describe new parameter added
7
+ #
8
+ class Argument
9
+
10
+ USAGE = "Usage: \n testrail_marker -r run_plan_name -p project_name -x /home/path_to/results_xml/dir \n"
11
+ HELP = " -h, Show HELP
12
+ -p *, name of project (e.g. TestRail API Gem) (required parameter)
13
+ -r or -t *, name of test run (-r) or test plan (-t) (required parameter)
14
+ -m, milestone name (can be used when creating a test run)
15
+ -s, test suite name (* required when creating a test run)
16
+ -u, user (e.g. ibarra@apitestrail.com)
17
+ -pw, password or token (recommended)
18
+ -url, URL of TestRail (e.g. https://yourcompany.testrail.io)
19
+ -cf, create a configuration file
20
+ -d, debug mode (set to false to suppresses most messages)
21
+ -x or -f *, path (-x, Directory) or specific file (-f) for results to parse
22
+ -com, comment to put on each test
23
+
24
+
25
+ NOTES: Results must have TestRail test case numbers to match. See README file for
26
+ more details.
27
+ Create options are available by adding \'c\' to some arguments, ex. -cr would create a new test run."
28
+
29
+ REQUIRED = "\nMissing required parameter/s (until config file implemented):
30
+ Ex: testrail_marker -p TestRail API Gem -r Regression Suite -x ./results/path
31
+ -p, name of project (e.g. -p TestRail API Gem)
32
+ -r or -t, name of test run or test plan (e.g. -r Regression Suite)
33
+ -x or -f, path (Directory) or a specific file of results to parse (e.g. -f /home/path/results/rspec_results.xml)\n"
34
+
35
+ # Constructor. Requires passing the parameters from the command line argument.
36
+ #
37
+ def initialize(passed_arguments)
38
+ @arg_passed = passed_arguments
39
+ @valid_parameters = ['-p', '-m', '-r', '-h', '-u', '-pw', '-url', '-d', '-x', '-t', '-s', '-com', '-f']
40
+ @create_parameters = ['-cm', '-cr', '-ct']
41
+ @delete_parameters = ['-dm', '-dr', '-dt']
42
+ @runner_parameters = ['-cf']
43
+ @valid_parameters += @create_parameters
44
+ @valid_parameters += @delete_parameters
45
+ @valid_parameters += @runner_parameters
46
+ @required_parameters = ['-p']
47
+ @requires_atleast_one = ['-r', '-t', '-cr', '-ct']
48
+ @requires_only_one = ['-x', '-f']
49
+
50
+ check_help(passed_arguments)
51
+ initialize_holder()
52
+ parse_args(passed_arguments)
53
+ check_required_parameters(passed_arguments)
54
+ print_arguments
55
+ end
56
+
57
+ def print_arguments()
58
+ puts "\nPassed Arguments:"
59
+ @holder.each do |hold|
60
+ if hold[:value] != ""
61
+ puts " #{hold[:tag]} #{hold[:value]}"
62
+ end
63
+ end
64
+ end
65
+
66
+ def parse_args(arguments)
67
+ par_index = []
68
+ puts "ARG: #{arguments}"
69
+ @valid_parameters.each do |tag|
70
+ arg_index = arguments.index(tag).nil? ? -1 : arguments.index(tag)
71
+ par_index.push(arg_index)
72
+ end
73
+ @valid_parameters.each_with_index do |tag, x|
74
+ tag_index = par_index[x]
75
+ end_index = get_next_highest(tag_index, par_index)
76
+ save_arg_to_holder(arguments, tag_index, end_index)
77
+ end
78
+ end
79
+
80
+ # Returns the argument parameter passed with the specified tag
81
+ #
82
+ def get_arg_value(tag)
83
+ tag_value = nil
84
+ if @valid_parameters.include?(tag)
85
+ tag_hash = @holder.detect{|tag_data| tag_data[:tag] == tag}
86
+ tag_value = tag_hash[:value]
87
+ else
88
+ puts "ERROR: Parameter #{tag} not recognized."
89
+ end
90
+ return tag_value
91
+ end
92
+
93
+ def get_optional_arg(tag_arr)
94
+ tag_value = nil
95
+ tag_arr.each do |tag|
96
+ if @valid_parameters.include?(tag)
97
+ tag_hash = @holder.detect{|tag_data| tag_data[:tag] == tag}
98
+ tag_value = tag_hash[:value]
99
+ else
100
+ puts "ERROR: Parameter #{tag} not recognized."
101
+ end
102
+ if tag_value == ""
103
+ tag_value = nil
104
+ end
105
+ if ! tag_value.nil?
106
+ break
107
+ end
108
+ end
109
+ return tag_value
110
+ end
111
+
112
+ def arg_exists?(tag)
113
+ it_exists = false
114
+ tagv = get_arg_value(tag)
115
+ if ! tagv.nil? && tagv != ""
116
+ it_exists = true
117
+ end
118
+ return it_exists
119
+ end
120
+
121
+ def has_argument?(tag)
122
+ if @arg_passed.include?(tag)
123
+ return true
124
+ end
125
+ return false
126
+ end
127
+
128
+ private
129
+
130
+ # Creates an array to hold values of possible parameter tags.
131
+ #
132
+ def initialize_holder()
133
+ @holder = []
134
+ @valid_parameters.each do |tag|
135
+ param_hash = {:tag => tag, :value => ""}
136
+ @holder.push(param_hash)
137
+ end
138
+ end
139
+
140
+ # Returns the next highest value in the array
141
+ # If num is the highest, then returns 100
142
+ def get_next_highest(num, array_num)
143
+ retval = nil
144
+ if ! num.nil? && num != -1
145
+ arr_size = array_num.size
146
+ sorted_nums = array_num.sort
147
+ num_index = sorted_nums.index(num)
148
+ if num_index == arr_size - 1
149
+ retval = 100
150
+ else
151
+ retval = sorted_nums[num_index + 1]
152
+ end
153
+ end
154
+ return retval
155
+ end
156
+
157
+ def save_arg_to_holder(arguments, startx, endx)
158
+ if startx >= 0
159
+ which_tag = arguments[startx]
160
+ tag_hash = @holder.detect{|tag_data| tag_data[:tag] == which_tag}
161
+ tag_hash[:value] = arguments[startx+1..endx-1].join(" ")
162
+ end
163
+ end
164
+
165
+ def check_help(arguments)
166
+ if arguments.include?('-h')
167
+ puts "#{USAGE}"
168
+ puts "#{HELP} \n\n"
169
+ exit(0)
170
+ end
171
+ end
172
+
173
+ private
174
+
175
+ # Verifies that all required parameters are passed in the argument.
176
+ # Two types of required. First, parameters that are absolutely needed.
177
+ # Second, parameters that are not all required but at least one must
178
+ # be passed.
179
+ # Exits the script if parameter requirements are not satisfied.
180
+ #
181
+ def check_required_parameters(arguments)
182
+ params_good = true
183
+
184
+ @runner_parameters.each do |run_par|
185
+ if arguments.include?(run_par)
186
+ return true
187
+ end
188
+ end
189
+ @required_parameters.each do |req_par|
190
+ passed_reqpar = get_arg_value(req_par)
191
+ if passed_reqpar.nil? || passed_reqpar == ''
192
+ params_good = false
193
+ end
194
+ end
195
+
196
+ has_atleast_one = true
197
+ if @requires_atleast_one.size > 0
198
+ has_atleast_one = false
199
+ @requires_atleast_one.each do |least_one|
200
+ luno = get_arg_value(least_one)
201
+ if ! luno.nil? && luno != ""
202
+ has_atleast_one = true
203
+ end
204
+ end
205
+ end
206
+
207
+ has_only_one = true
208
+ if @requires_only_one.size > 0
209
+ has_only_one = false
210
+ num_detected = 0
211
+ @requires_only_one.each do |only_one|
212
+ if arg_exists?(only_one)
213
+ num_detected += 1
214
+ end
215
+ end
216
+ if num_detected == 1
217
+ has_only_one = true
218
+ end
219
+ end
220
+
221
+ if !params_good || ! has_atleast_one || ! has_only_one
222
+ puts "#{REQUIRED}"
223
+ exit(1)
224
+ end
225
+
226
+ end
227
+
228
+
229
+ end
@@ -0,0 +1,107 @@
1
+ require 'yaml'
2
+
3
+ # History:
4
+ # 2/19/2018 Created ibarra.alfonso@gmail.com
5
+ #
6
+ #
7
+ class ConfigFile
8
+
9
+ attr_accessor :username, :token, :testrail_url, :filename, :default_comment
10
+
11
+ def initialize(cfile)
12
+ @filename = cfile
13
+ read_config_file
14
+ end
15
+
16
+ def prompt_user(user_msg, default_val)
17
+ retval = default_val
18
+ newval = ''
19
+ atmps = 0
20
+ while newval.strip == '' && atmps < 3
21
+ atmps += 1
22
+ print "#{user_msg}"
23
+ newval = STDIN.gets
24
+ retval = newval.strip == '' ? default_val : newval.strip
25
+ newval = retval
26
+ end
27
+ if atmps >= 3
28
+ puts "\nERROR: Value cannot be empty... exiting."
29
+ exit(1)
30
+ end
31
+ return retval
32
+ end
33
+
34
+ def user_continue?(user_msg, default_val=false)
35
+ retval = default_val
36
+ reply = prompt_user(user_msg, 'N')
37
+ if reply.upcase == "Y"
38
+ retval = true
39
+ end
40
+ return retval
41
+ end
42
+
43
+ def read_config_file
44
+ if File.exist?(@filename)
45
+ @trail_info = YAML.load_file(@filename)
46
+ @username = @trail_info["username"]
47
+ @token = @trail_info["token"]
48
+ @testrail_url = @trail_info["testrail_url"]
49
+ @default_comment = @trail_info['default_comment']
50
+ else
51
+ @trail_info = Hash.new
52
+ @username = ''
53
+ @token = ''
54
+ @testrail_url = ''
55
+ @default_comment = 'Marked by Automation'
56
+ end
57
+ end
58
+
59
+ def check_create_configfile
60
+ if ! File.exist?(@filename)
61
+ puts "\nWARNING: Configuration File does not exist."
62
+ if user_continue?("Create a new config file (Y/N)? : ", 'N')
63
+ create_configfile
64
+ end
65
+ end
66
+ end
67
+
68
+ def create_configfile
69
+ @username = prompt_user("Enter testrail email (#{@username}): ", @username)
70
+ @token = prompt_user("Enter testrail token (#{@token}): ", @token)
71
+ @testrail_url = prompt_user("TestRail URL (#{@testrail_url}): ", @testrail_url)
72
+ @default_comment = prompt_user("Test comment (Default - Marked by Automation): ", "Marked by Automation")
73
+ @trail_info = Hash.new
74
+ @trail_info["username"] = @username
75
+ @trail_info["token"] = @token
76
+ @trail_info["testrail_url"] = @testrail_url
77
+ @trail_info["default_comment"] = @default_comment
78
+ save
79
+ # Comment out until overwrite is finished.
80
+ #if user_continue?("Do you want to save the testrail project info (Y/N)?")
81
+ # config_project
82
+ # thash["project_name"] = @project_name
83
+ # thash["testrun"] = @testrun
84
+ # thash["testplan"] = @testplan
85
+ #end
86
+ end
87
+
88
+ def config_project
89
+ @project_name = prompt_user("Enter testrail project name: ")
90
+ @testrun = prompt_user("Enter name of test run: ", "NA")
91
+ @testplan = prompt_user("Enter name of test plan: ", "NA")
92
+ end
93
+
94
+ def update(varname, varvalue)
95
+ if defined? @trail_info
96
+ @trail_info[varname] = varvalue
97
+ end
98
+ end
99
+
100
+ def save
101
+ File.open(@filename, 'w') { |f|
102
+ f.write @trail_info.to_yaml
103
+ puts "Successfully saved config file: #{@filename}"
104
+ }
105
+ end
106
+
107
+ end