bugzyrb 0.2.1 → 0.3.0
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/CHANGELOG.rdoc +4 -0
- data/VERSION +1 -1
- data/bugzyrb.gemspec +2 -2
- data/lib/bugzyrb/common/cmdapp.rb +271 -111
- data/lib/bugzyrb.rb +124 -226
- metadata +4 -4
data/CHANGELOG.rdoc
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/bugzyrb.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{bugzyrb}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Rahul Kumar"]
|
12
|
-
s.date = %q{2010-07-
|
12
|
+
s.date = %q{2010-07-12}
|
13
13
|
s.default_executable = %q{bugzyrb}
|
14
14
|
s.description = %q{basic, easy-to-use command-line issue-tracker using sqlite for ruby 1.9}
|
15
15
|
s.email = %q{sentinel1879@gmail.com}
|
@@ -27,6 +27,8 @@ module Cmdapp
|
|
27
27
|
# @param [Array] rest of args on command line
|
28
28
|
# @return [Boolean] whether it is mapped or not.
|
29
29
|
#
|
30
|
+
# NOTE: some of these are relevant only if we are not using subcommand, so we should move out
|
31
|
+
# to another file.
|
30
32
|
def check_aliases action, args
|
31
33
|
return false unless @aliases
|
32
34
|
ret = @aliases[action]
|
@@ -96,10 +98,12 @@ module Cmdapp
|
|
96
98
|
@actions[name.to_s] = desc
|
97
99
|
end
|
98
100
|
|
101
|
+
# TODO: move to serial_number.rb or a file that deals with file_data as against sql data
|
102
|
+
# which should also have backup, load_array and save_array.
|
99
103
|
##
|
100
104
|
# reads serial_number file, returns serialno for this app
|
101
105
|
# and increments the serial number and writes back.
|
102
|
-
def
|
106
|
+
def get_serial_number
|
103
107
|
require 'fileutils'
|
104
108
|
appname = @appname
|
105
109
|
filename = @app_serial_path || "serial_numbers"
|
@@ -125,23 +129,27 @@ module Cmdapp
|
|
125
129
|
end
|
126
130
|
##
|
127
131
|
# After doing a redo of the numbering, we need to reset the numbers for that app
|
128
|
-
def
|
132
|
+
def set_serial_number number
|
129
133
|
appname = @appname
|
130
134
|
pattern = Regexp.new "^#{appname}:.*$"
|
131
135
|
filename = @app_serial_path || "serial_numbers"
|
132
136
|
# during testing redo this file does not exist, so i get errors
|
133
137
|
if !File.exists? filename
|
134
|
-
|
138
|
+
get_serial_number
|
135
139
|
end
|
136
|
-
|
140
|
+
backup filename
|
137
141
|
# from Sed
|
138
142
|
change_row filename, pattern, "#{appname}:#{number}"
|
139
143
|
end
|
140
144
|
|
141
|
-
|
145
|
+
#
|
146
|
+
# backup file to filename.org
|
147
|
+
# use prior to a modification operation that could be dangerous or risky
|
148
|
+
def backup filename=@app_file_path
|
142
149
|
require 'fileutils'
|
143
150
|
FileUtils.cp filename, "#{filename}.org"
|
144
151
|
end
|
152
|
+
# exit after printing an error message
|
145
153
|
def die text
|
146
154
|
$stderr.puts text
|
147
155
|
exit ERRCODE
|
@@ -194,6 +202,7 @@ module Cmdapp
|
|
194
202
|
##
|
195
203
|
# retrieve version info updated by jeweler.
|
196
204
|
# Typically used by --version option of any command.
|
205
|
+
# FIXME: link VERSION to version.rb in lib/buzg.. and read from same dir
|
197
206
|
# @return [String, nil] version as string, or nil if file not found
|
198
207
|
def version_info
|
199
208
|
# thanks to Roger Pack on ruby-forum for how to get to the version
|
@@ -213,7 +222,7 @@ module Cmdapp
|
|
213
222
|
# and returns as a string.
|
214
223
|
# Add newline after each line
|
215
224
|
# @return [String, nil] newline delimited string, or nil
|
216
|
-
def
|
225
|
+
def old_get_lines
|
217
226
|
lines = nil
|
218
227
|
#$stdin.flush
|
219
228
|
$stdin.each_line do |line|
|
@@ -231,118 +240,117 @@ module Cmdapp
|
|
231
240
|
end
|
232
241
|
|
233
242
|
|
234
|
-
# edits given text using EDITOR
|
235
|
-
# @param [String] text to edit
|
236
|
-
# @return [String, nil] edited string, or nil if no change
|
237
|
-
def edit_text text
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
243
|
+
# edits given text using EDITOR
|
244
|
+
# @param [String] text to edit
|
245
|
+
# @return [String, nil] edited string, or nil if no change
|
246
|
+
def edit_text text
|
247
|
+
# 2010-06-29 10:24
|
248
|
+
require 'fileutils'
|
249
|
+
require 'tempfile'
|
250
|
+
ed = ENV['EDITOR'] || "vim"
|
251
|
+
temp = Tempfile.new "tmp"
|
252
|
+
File.open(temp,"w"){ |f| f.write text }
|
253
|
+
mtime = File.mtime(temp.path)
|
254
|
+
#system("#{ed} #{temp.path}")
|
255
|
+
system(ed, temp.path)
|
247
256
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
end
|
257
|
+
newmtime = File.mtime(temp.path)
|
258
|
+
newstr = nil
|
259
|
+
if mtime < newmtime
|
260
|
+
# check timestamp, if updated ..
|
261
|
+
newstr = File.read(temp)
|
262
|
+
else
|
263
|
+
#puts "user quit without saving"
|
264
|
+
return nil
|
265
|
+
end
|
266
|
+
return newstr.chomp if newstr
|
267
|
+
return nil
|
268
|
+
end
|
261
269
|
|
262
|
-
# pipes given string to command
|
263
|
-
# @param [String] command to pipe data to
|
264
|
-
# @param [String] data to pipe to command
|
265
|
-
# @example
|
266
|
-
# cmd = %{mail -s "my title" rahul}
|
267
|
-
# pipe_output(cmd, "some long text")
|
268
|
-
# FIXME: not clear how to return error.
|
269
|
-
# NOTE: this is obviously more portable than using system echo or system cat.
|
270
|
-
def pipe_output (pipeto, str)
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
270
|
+
# pipes given string to command
|
271
|
+
# @param [String] command to pipe data to
|
272
|
+
# @param [String] data to pipe to command
|
273
|
+
# @example
|
274
|
+
# cmd = %{mail -s "my title" rahul}
|
275
|
+
# pipe_output(cmd, "some long text")
|
276
|
+
# FIXME: not clear how to return error.
|
277
|
+
# NOTE: this is obviously more portable than using system echo or system cat.
|
278
|
+
def pipe_output (pipeto, str)
|
279
|
+
#pipeto = '/usr/sbin/sendmail -t'
|
280
|
+
#pipeto = %q{mail -s "my title" rahul}
|
281
|
+
if pipeto != nil # i was taking pipeto from a hash, so checking
|
282
|
+
proc = IO.popen(pipeto, "w+")
|
283
|
+
proc.puts str
|
284
|
+
proc.close_write
|
285
|
+
#puts proc.gets
|
286
|
+
end
|
278
287
|
end
|
279
|
-
|
280
|
-
|
281
|
-
#
|
282
|
-
# @param [
|
283
|
-
# @
|
284
|
-
#
|
285
|
-
|
286
|
-
|
287
|
-
#tmpltext=File::read(template);
|
288
|
+
##
|
289
|
+
# reads up template, and substirutes values from myhash
|
290
|
+
# @param [String] template text
|
291
|
+
# @param [Hash] values to replace in template
|
292
|
+
# @return [String] template output
|
293
|
+
# NOTE: probably better to use rdoc/template which can handle arrays as well.
|
294
|
+
def template_replace template, myhash
|
295
|
+
#tmpltext=File::read(template);
|
288
296
|
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
end
|
296
|
-
#------------------------------------------------------------
|
297
|
-
# these 2 methods deal with with maintaining readline history
|
298
|
-
# for various columns. _read reads up any earlier values
|
299
|
-
# so user can select from them.
|
300
|
-
# _save saves the values for future use.
|
301
|
-
#------------------------------------------------------------
|
302
|
-
# for a given column, check if there's any previous data
|
303
|
-
# in our cache, and put in readlines history so user can
|
304
|
-
# use or edit. Also put default value in history.
|
305
|
-
# @param [String] name of column for maintaining cache
|
306
|
-
# @param [String] default data for user to recall, or edit
|
307
|
-
def history_read column, default=nil
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
297
|
+
t = template.dup
|
298
|
+
t.gsub!( /##(.*?)##/ ) {
|
299
|
+
#raise "Key '#{$1}' found in template but the value has not been set" unless ( myhash.has_key?( $1 ) )
|
300
|
+
myhash[ $1 ].to_s
|
301
|
+
}
|
302
|
+
t
|
303
|
+
end
|
304
|
+
#------------------------------------------------------------
|
305
|
+
# these 2 methods deal with with maintaining readline history
|
306
|
+
# for various columns. _read reads up any earlier values
|
307
|
+
# so user can select from them.
|
308
|
+
# _save saves the values for future use.
|
309
|
+
#------------------------------------------------------------
|
310
|
+
# for a given column, check if there's any previous data
|
311
|
+
# in our cache, and put in readlines history so user can
|
312
|
+
# use or edit. Also put default value in history.
|
313
|
+
# @param [String] name of column for maintaining cache
|
314
|
+
# @param [String] default data for user to recall, or edit
|
315
|
+
def history_read column, default=nil
|
316
|
+
values = []
|
317
|
+
oldstr = ""
|
318
|
+
if !defined? $history_hash
|
319
|
+
require 'readline'
|
320
|
+
require 'yaml'
|
321
|
+
filename = File.expand_path "~/.bugzy_history.yml"
|
322
|
+
$history_filename = filename
|
323
|
+
# if file exists with values push them into history
|
324
|
+
if File.exists? filename
|
325
|
+
$history_hash = YAML::load( File.open( filename ) )
|
326
|
+
else
|
327
|
+
$history_hash = Hash.new
|
328
|
+
end
|
320
329
|
end
|
330
|
+
values.push(*$history_hash[column]) if $history_hash.has_key? column
|
331
|
+
# push existing value into history also, so it can be edited
|
332
|
+
values.push(default) if default
|
333
|
+
values.uniq!
|
334
|
+
Readline::HISTORY.clear # else previous values of other fields also come in
|
335
|
+
Readline::HISTORY.push(*values) unless values.empty?
|
336
|
+
#puts Readline::HISTORY.to_a
|
321
337
|
end
|
322
|
-
|
323
|
-
#
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
if $history_hash.has_key? column
|
338
|
-
return if $history_hash[column].include? str
|
339
|
-
end
|
340
|
-
($history_hash[column] ||= []) << str
|
341
|
-
filename = $history_filename
|
342
|
-
File.open( filename, 'w' ) do |f|
|
343
|
-
f << $history_hash.to_yaml
|
338
|
+
##
|
339
|
+
# update our cache with str if not present in cache already
|
340
|
+
# @param [String] name of column for maintaining cache
|
341
|
+
# @param [String] str : data just entered by user
|
342
|
+
#
|
343
|
+
def history_save column, str
|
344
|
+
return if str.nil? or str == ""
|
345
|
+
if $history_hash.has_key? column
|
346
|
+
return if $history_hash[column].include? str
|
347
|
+
end
|
348
|
+
($history_hash[column] ||= []) << str
|
349
|
+
filename = $history_filename
|
350
|
+
File.open( filename, 'w' ) do |f|
|
351
|
+
f << $history_hash.to_yaml
|
352
|
+
end
|
344
353
|
end
|
345
|
-
end
|
346
354
|
# separates args to list-like operations
|
347
355
|
# +xxx means xxx should match in output
|
348
356
|
# -xxx means xxx should not exist in output
|
@@ -377,7 +385,159 @@ end
|
|
377
385
|
end
|
378
386
|
rows
|
379
387
|
end
|
388
|
+
# ----------- file operations -------------
|
389
|
+
#
|
390
|
+
def file_read filename
|
391
|
+
filename = File.expand_path filename
|
392
|
+
return File.read(filename)
|
393
|
+
#if File.exists? filename
|
394
|
+
end
|
395
|
+
def file_write filename, text
|
396
|
+
filename = File.expand_path filename
|
397
|
+
File.open(filename,"w"){ |f| f.write text }
|
398
|
+
#if File.exists? filename
|
399
|
+
end
|
400
|
+
def file_append filename, text
|
401
|
+
filename = File.expand_path filename
|
402
|
+
File.open(temp,"a"){ |f| f.write text }
|
403
|
+
end
|
404
|
+
def check_file filename=@app_file_path
|
405
|
+
File.exists?(filename) or die "#{filename} does not exist in this dir. "
|
406
|
+
end
|
380
407
|
|
408
|
+
##
|
409
|
+
# separates args into tag or subcommand and items
|
410
|
+
# This allows user to pass e.g. a priority first and then item list
|
411
|
+
# or item list first and then priority.
|
412
|
+
# This can only be used if the tag or pri or status is non-numeric and the item is numeric.
|
413
|
+
def _separate args, pattern=nil #/^[a-zA-Z]/
|
414
|
+
tag = nil
|
415
|
+
items = []
|
416
|
+
args.each do |arg|
|
417
|
+
if arg =~ /^[0-9\.]+$/
|
418
|
+
items << arg
|
419
|
+
else
|
420
|
+
tag = arg
|
421
|
+
if pattern
|
422
|
+
die "#{@action}: #{arg} appears invalid." if arg !~ pattern
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
426
|
+
items = nil if items.empty?
|
427
|
+
return tag, items
|
428
|
+
end
|
381
429
|
|
430
|
+
## prompts user for multiline input
|
431
|
+
# NOTE: we do not take Ctrl-d as EOF then causes an error in next input in 1.9 (not 1.8)
|
432
|
+
# @param [String] text to use as prompt
|
433
|
+
# @return [String, nil] string with newlines or nil (if nothing entered).
|
434
|
+
# FIXME: move to Cmdapp
|
435
|
+
def get_lines prompt=nil
|
436
|
+
#prompt ||= "Enter multiple lines, to quit enter . on empty line"
|
437
|
+
#message prompt
|
438
|
+
str = ""
|
439
|
+
while $stdin.gets # reads from STDIN
|
440
|
+
case $_.chomp
|
441
|
+
when "."
|
442
|
+
break
|
443
|
+
when ".vim"
|
444
|
+
return edit_text str
|
445
|
+
end
|
446
|
+
str << $_
|
447
|
+
#puts "Read: #{$_}" # writes to STDOUT
|
448
|
+
end
|
449
|
+
return nil if str == ""
|
450
|
+
return str.chomp
|
451
|
+
end
|
452
|
+
# get a string from user, using readline or gets
|
453
|
+
# if readline, then manage column specific history
|
454
|
+
# FIXME: move to Cmdapp.
|
455
|
+
def _gets column, prompt, default=nil
|
456
|
+
text = "#{prompt}? "
|
457
|
+
text << "|#{default}|" if default
|
458
|
+
puts text
|
459
|
+
if $use_readline
|
460
|
+
Cmdapp::history_read column, default
|
461
|
+
str = Readline::readline('>', false)
|
462
|
+
Cmdapp::history_save column, str
|
463
|
+
str = default if str.nil? or str == ""
|
464
|
+
return str
|
465
|
+
else
|
466
|
+
str = $stdin.gets.chomp
|
467
|
+
str = default if str.nil? or str == ""
|
468
|
+
return str
|
469
|
+
end
|
470
|
+
end
|
471
|
+
# get choice from user from a list of options
|
472
|
+
# @param [String] prompt text
|
473
|
+
# @param [Array] values to chose from
|
474
|
+
def _choice prompt, choices
|
475
|
+
choose do |menu|
|
476
|
+
menu.prompt = prompt
|
477
|
+
menu.choices(*choices) do |n| return n; end
|
478
|
+
end
|
479
|
+
end
|
480
|
+
#
|
481
|
+
# take user input based on value of flag
|
482
|
+
# @param [String] column name
|
483
|
+
# @param [Boolean, Symbol] true, false, :freeform, :choice
|
484
|
+
# @param [String, nil] text to prompt
|
485
|
+
# @param [Array, nil] choices array or nil
|
486
|
+
# @param [Object] default value
|
487
|
+
# @return [String, nil] users choice
|
488
|
+
#
|
489
|
+
# TODO: should we not check for the ask_x methods and call them if present.
|
490
|
+
# FIXME: move to Cmdapp
|
491
|
+
def user_input column, prompt_flag, prompt_text=nil, choices=nil, default=nil
|
492
|
+
if prompt_flag == true
|
493
|
+
prompt_flag = :freeform
|
494
|
+
prompt_flag = :choice if choices
|
495
|
+
end
|
496
|
+
case prompt_flag
|
497
|
+
when :freeform
|
498
|
+
prompt_text ||= "#{column.capitalize}"
|
499
|
+
#str = ask(prompt_text){ |q| q.default = default if default }
|
500
|
+
str = _gets(column, prompt_text, default)
|
501
|
+
return str
|
502
|
+
when :choice
|
503
|
+
prompt_text ||= "Select #{column}:"
|
504
|
+
str = _choice(prompt_text, choices)
|
505
|
+
return str
|
506
|
+
when :multiline, :ml
|
507
|
+
return Cmdapp::edit_text default
|
508
|
+
when false
|
509
|
+
return default
|
510
|
+
end
|
511
|
+
end
|
512
|
+
# indents given string, n spaces
|
513
|
+
# http://redmine.ruby-lang.org/issues/show/749 Thomas Sawyer
|
514
|
+
def indent(str,n)
|
515
|
+
if n >= 0
|
516
|
+
str.gsub(/^/, ' ' * n)
|
517
|
+
else
|
518
|
+
str.gsub(/^ {0,#{-n}}/, "")
|
519
|
+
end
|
520
|
+
end
|
521
|
+
# indents a string, indenting all but first line.
|
522
|
+
# This allows us to print a string as follows:
|
523
|
+
# Description : The description starts here.
|
524
|
+
# And continues here. The first line was not indented.
|
525
|
+
# http://www.ralfebert.de/blog/ruby/string_helpers/ Ralf Ebert
|
526
|
+
def indent2(str, count)
|
527
|
+
if str
|
528
|
+
char = ' '
|
529
|
+
#(char * count) + gsub(/(\n+)/) { $1 + (char * count) }
|
530
|
+
str.gsub(/(\n+)/) { $1 + (char * count) }
|
531
|
+
end
|
532
|
+
end
|
533
|
+
# for updating in log file
|
534
|
+
# truncates long strings comments, descriptions, fix etc and removed newlines
|
535
|
+
def truncate string, count
|
536
|
+
string = string.to_s
|
537
|
+
string.tr!("\n",' ')
|
538
|
+
return string if string.length <= count
|
539
|
+
(string[0..(count-4)] + " ...")
|
540
|
+
end
|
382
541
|
|
542
|
+
# ADD
|
383
543
|
end
|
data/lib/bugzyrb.rb
CHANGED
@@ -5,7 +5,6 @@
|
|
5
5
|
* Author: rkumar
|
6
6
|
* Date: 2010-06-24
|
7
7
|
* License: Ruby License
|
8
|
-
* Now requires subcommand gem
|
9
8
|
|
10
9
|
=end
|
11
10
|
require 'rubygems'
|
@@ -220,7 +219,7 @@ SQL
|
|
220
219
|
title = body['title']
|
221
220
|
logid = db.sql_logs_insert rowid, "create", "#{rowid} #{type}: #{title}"
|
222
221
|
body["id"] = rowid
|
223
|
-
mail_issue body
|
222
|
+
mail_issue nil, body
|
224
223
|
0
|
225
224
|
end
|
226
225
|
|
@@ -248,8 +247,10 @@ SQL
|
|
248
247
|
title = text
|
249
248
|
desc = nil
|
250
249
|
if $prompt_desc
|
250
|
+
# choice of vim or this XXX also how to store in case of error or abandon
|
251
|
+
# and allow user to edit, so no retyping. This could be for mult fields
|
251
252
|
message "Enter a detailed description (. to exit): "
|
252
|
-
desc = get_lines
|
253
|
+
desc = Cmdapp.get_lines
|
253
254
|
#message "You entered #{desc}"
|
254
255
|
end
|
255
256
|
type = $default_type || "bug"
|
@@ -257,34 +258,34 @@ SQL
|
|
257
258
|
status = $default_status || "open"
|
258
259
|
priority = $default_priority || "P3"
|
259
260
|
if $prompt_type
|
260
|
-
type = _choice("Select type:", %w[bug enhancement feature task] )
|
261
|
+
type = Cmdapp._choice("Select type:", %w[bug enhancement feature task] )
|
261
262
|
#message "You selected #{type}"
|
262
263
|
end
|
263
264
|
if $prompt_severity
|
264
|
-
severity = _choice("Select severity:", %w[normal critical moderate] )
|
265
|
+
severity = Cmdapp._choice("Select severity:", %w[normal critical moderate] )
|
265
266
|
#message "You selected #{severity}"
|
266
267
|
end
|
267
268
|
if $prompt_status
|
268
|
-
status = _choice("Select status:", %w[open started closed stopped canceled] )
|
269
|
+
status = Cmdapp._choice("Select status:", %w[open started closed stopped canceled] )
|
269
270
|
#message "You selected #{status}"
|
270
271
|
end
|
271
272
|
assigned_to = $default_assigned_to
|
272
273
|
if $prompt_assigned_to
|
273
274
|
message "Assign to:"
|
274
275
|
#assigned_to = $stdin.gets.chomp
|
275
|
-
assigned_to = _gets "assigned_to", "assigned_to", $default_assigned_to
|
276
|
+
assigned_to = Cmdapp._gets "assigned_to", "assigned_to", $default_assigned_to
|
276
277
|
#message "You selected #{assigned_to}"
|
277
278
|
end
|
278
279
|
project = component = version = nil
|
279
280
|
# project
|
280
281
|
if $use_project
|
281
|
-
project = user_input('project', $prompt_project, nil, $valid_project, $default_project)
|
282
|
+
project = Cmdapp.user_input('project', $prompt_project, nil, $valid_project, $default_project)
|
282
283
|
end
|
283
284
|
if $use_component
|
284
|
-
component = user_input('component', $prompt_component, nil, $valid_component, $default_component)
|
285
|
+
component = Cmdapp.user_input('component', $prompt_component, nil, $valid_component, $default_component)
|
285
286
|
end
|
286
287
|
if $use_version
|
287
|
-
version = user_input('version', $prompt_version, nil, $valid_version, $default_version)
|
288
|
+
version = Cmdapp.user_input('version', $prompt_version, nil, $valid_version, $default_version)
|
288
289
|
end
|
289
290
|
|
290
291
|
start_date = @now
|
@@ -315,17 +316,18 @@ SQL
|
|
315
316
|
puts "Issue #{rowid} created"
|
316
317
|
logid = db.sql_logs_insert rowid, "create", "#{rowid} #{type}: #{title}"
|
317
318
|
body["id"] = rowid
|
318
|
-
mail_issue body
|
319
|
+
mail_issue nil, body
|
319
320
|
|
320
321
|
0
|
321
322
|
end
|
322
|
-
def mail_issue row, emailid=nil
|
323
|
+
def mail_issue subject, row, emailid=nil
|
323
324
|
emailid ||= $default_user
|
324
325
|
body = <<TEXT
|
325
326
|
Id : #{row['id']}
|
326
327
|
Title : #{row['title']}
|
327
328
|
Description : #{row['description']}
|
328
329
|
Type : #{row['type']}
|
330
|
+
Status : #{row['status']}
|
329
331
|
Start Date : #{row['start_date']}
|
330
332
|
Due Date : #{row['due_date']}
|
331
333
|
Priority : #{row['priority']}
|
@@ -335,9 +337,9 @@ TEXT
|
|
335
337
|
body << " Project : #{row['project']}\n" if $use_project
|
336
338
|
body << " Component : #{row['component']}\n" if $use_component
|
337
339
|
body << " Version : #{row['version']}\n" if $use_version
|
338
|
-
|
340
|
+
subject ||= "#{row['id']}: #{row['title']} "
|
339
341
|
|
340
|
-
cmd = %{ mail -s "#{
|
342
|
+
cmd = %{ mail -s "#{subject}" "#{emailid}" }
|
341
343
|
#puts cmd
|
342
344
|
Cmdapp::pipe_output(cmd, body)
|
343
345
|
end
|
@@ -352,32 +354,40 @@ TEXT
|
|
352
354
|
db, row = validate_id id
|
353
355
|
die "No data found for #{id}" unless row
|
354
356
|
puts "[#{row['type']} \##{row['id']}] #{row['title']}"
|
355
|
-
puts
|
356
|
-
puts
|
357
|
+
puts "Description:"
|
358
|
+
puts Cmdapp.indent(row['description'],3)
|
359
|
+
puts "\nAdded by #{row['created_by']} on #{row['date_created']}. Updated #{row['date_modified']}."
|
357
360
|
comment_count = 0
|
358
361
|
#puts row
|
359
362
|
row.each_pair { |name, val|
|
360
363
|
next if name == "project" && !$use_project
|
361
364
|
next if name == "version" && !$use_version
|
362
365
|
next if name == "component" && !$use_component
|
366
|
+
next if %w{ id title description created_by date_created date_modified }.include? name
|
363
367
|
comment_count = val.to_i if name == "comment_count"
|
368
|
+
val = Cmdapp.indent2(val, 18) if name == "fix"
|
364
369
|
n = sprintf("%-15s", name);
|
365
370
|
puts "#{n} : #{val}"
|
366
371
|
}
|
367
372
|
puts
|
368
373
|
if comment_count > 0
|
369
374
|
puts "Comments :"
|
375
|
+
ctr = 0
|
370
376
|
db.select_where "comments", "id", id do |r|
|
371
|
-
#puts r
|
372
|
-
|
373
|
-
#
|
377
|
+
#puts "(#{r['date_created']}) [ #{r['created_by']} ] #{r['comment']}"
|
378
|
+
ctr += 1
|
379
|
+
puts "------- (#{r['date_created']}) #{r['created_by']} (#{ctr})------"
|
380
|
+
puts r['comment']
|
374
381
|
end
|
382
|
+
puts
|
375
383
|
end
|
376
384
|
puts "Log:"
|
385
|
+
ctr = 0
|
377
386
|
db.select_where "log", "id", id do |r|
|
378
|
-
|
379
|
-
puts "------- (#{r['date_created']}) ------"
|
380
|
-
puts "#{r['
|
387
|
+
ctr += 1
|
388
|
+
#puts "------- (#{r['date_created']}) #{r['created_by']} ------"
|
389
|
+
puts "------- #{r['date_created']} - #{r['created_by']} (#{ctr})------"
|
390
|
+
puts " * [#{r['field']}]: #{r['log']} "
|
381
391
|
#pp r
|
382
392
|
end
|
383
393
|
end
|
@@ -412,7 +422,7 @@ TEXT
|
|
412
422
|
editable << "project" if $use_project
|
413
423
|
editable << "component" if $use_component
|
414
424
|
editable << "version" if $use_version
|
415
|
-
sel = _choice "Select field to edit", editable
|
425
|
+
sel = Cmdapp._choice "Select field to edit", editable
|
416
426
|
print "You chose: #{sel}"
|
417
427
|
old = row[sel]
|
418
428
|
puts " Current value is: #{old}"
|
@@ -434,8 +444,8 @@ TEXT
|
|
434
444
|
message str
|
435
445
|
db.sql_update "bugs", id, sel, str
|
436
446
|
puts "Updated #{id}"
|
437
|
-
|
438
|
-
rowid = db.sql_logs_insert id, sel, "[#{id}] updated [#{sel}] with #{
|
447
|
+
sstr = Cmdapp.truncate(str.to_s,50)
|
448
|
+
rowid = db.sql_logs_insert id, sel, "[#{id}] updated [#{sel}] with #{sstr}"
|
439
449
|
0
|
440
450
|
end
|
441
451
|
# deletes given issue
|
@@ -482,9 +492,11 @@ TEXT
|
|
482
492
|
|
483
493
|
logid = db.sql_logs_insert rowid, "create", "#{rowid} #{type}: #{title}"
|
484
494
|
newrow["id"] = rowid
|
485
|
-
mail_issue newrow
|
495
|
+
mail_issue nil, newrow
|
486
496
|
end
|
487
|
-
|
497
|
+
# view logs for a given id, or highest issue
|
498
|
+
# @param [Array] issue id
|
499
|
+
def viewlogs args=nil
|
488
500
|
db = get_db
|
489
501
|
id = args[0].nil? ? db.max_bug_id : args[0]
|
490
502
|
row = db.sql_select_rowid "bugs", id
|
@@ -591,16 +603,16 @@ TEXT
|
|
591
603
|
puts "GOT:: #{args}"
|
592
604
|
end
|
593
605
|
def ask_type old=nil
|
594
|
-
type = _choice("Select type:", %w[bug enhancement feature task] )
|
606
|
+
type = Cmdapp._choice("Select type:", %w[bug enhancement feature task] )
|
595
607
|
end
|
596
608
|
def ask_severity old=nil
|
597
|
-
severity = _choice("Select severity:", %w[normal critical moderate] )
|
609
|
+
severity = Cmdapp._choice("Select severity:", %w[normal critical moderate] )
|
598
610
|
end
|
599
611
|
def ask_status old=nil
|
600
|
-
status = _choice("Select status:", %w[open started closed stopped canceled] )
|
612
|
+
status = Cmdapp._choice("Select status:", %w[open started closed stopped canceled] )
|
601
613
|
end
|
602
614
|
def ask_priority old=nil
|
603
|
-
priority = _choice("Select priority:", %w[P1 P2 P3 P4 P5] )
|
615
|
+
priority = Cmdapp._choice("Select priority:", %w[P1 P2 P3 P4 P5] )
|
604
616
|
end
|
605
617
|
def ask_fix old=nil
|
606
618
|
Cmdapp::edit_text old
|
@@ -620,22 +632,23 @@ TEXT
|
|
620
632
|
unless id
|
621
633
|
id = ask("Issue Id? ", Integer)
|
622
634
|
end
|
635
|
+
db, row = validate_id id, true
|
636
|
+
die "No issue found for #{id}" unless row
|
623
637
|
if !args.empty?
|
624
638
|
comment = args.join(" ")
|
625
639
|
else
|
626
640
|
message "Enter a comment (. to exit): "
|
627
|
-
comment = get_lines
|
641
|
+
comment = Cmdapp.get_lines
|
628
642
|
end
|
629
643
|
die "Operation cancelled" if comment.nil? or comment.empty?
|
630
644
|
message "Comment is: #{comment}."
|
631
|
-
db, row = validate_id id
|
632
|
-
die "No issue found for #{id}" unless row
|
633
645
|
message "Adding comment to #{id}: #{row['title']}"
|
634
646
|
_comment db, id, comment
|
635
647
|
0
|
636
648
|
end
|
637
649
|
# insert comment into database
|
638
650
|
# called from interactive, as well as "close" or others
|
651
|
+
# Should we send a mail here ? XXX
|
639
652
|
def _comment db, id, text
|
640
653
|
rowid = db.sql_comments_insert id, text
|
641
654
|
puts "Comment #{rowid} created"
|
@@ -644,55 +657,43 @@ TEXT
|
|
644
657
|
commcount = handle.get_first_value( "select count(id) from comments where id = #{id};" )
|
645
658
|
commcount = commcount.to_i
|
646
659
|
db.sql_update "bugs", id, "comment_count", commcount
|
647
|
-
rowid = db.sql_logs_insert id, "comment",text
|
660
|
+
rowid = db.sql_logs_insert id, "comment", Cmdapp.truncate(text, 50)
|
648
661
|
end
|
649
662
|
# prompts user for a fix related to an issue
|
663
|
+
# # XXX what if fix already exists, will we overwrite.
|
650
664
|
def fix args #id, fix
|
651
665
|
id = args.shift
|
652
666
|
unless id
|
653
667
|
id = ask("Issue Id? ", Integer)
|
654
668
|
end
|
669
|
+
db, row = validate_id id
|
655
670
|
if !args.empty?
|
656
671
|
text = args.join(" ")
|
672
|
+
if row['fix']
|
673
|
+
die "Sorry. I already have a fix, pls edit ... #{row['fix']}"
|
674
|
+
end
|
657
675
|
else
|
658
|
-
|
659
|
-
|
676
|
+
# XXX give the choice of using vim
|
677
|
+
if row['fix']
|
678
|
+
text = Cmdapp.edit_text row['fix']
|
679
|
+
else
|
680
|
+
message "Enter a fix (. to exit): "
|
681
|
+
text = Cmdapp.get_lines
|
682
|
+
end
|
660
683
|
end
|
684
|
+
# FIXME: what if user accidentally enters a fix, and wants to nullify ?
|
661
685
|
die "Operation cancelled" if text.nil? or text.empty?
|
662
686
|
message "fix is: #{text}."
|
663
|
-
db, row = validate_id id
|
664
687
|
message "Adding fix to #{id}: #{row['title']}"
|
665
688
|
_fix db, id, text
|
666
689
|
0
|
667
690
|
end
|
691
|
+
# internal method that actually updates the fix. can be called
|
692
|
+
# from fix or from close using --fix
|
693
|
+
# Should we send a mail here ? XXX
|
668
694
|
def _fix db, id, text
|
669
695
|
db.sql_update "bugs", id, "fix", text
|
670
|
-
rowid = db.sql_logs_insert id, "fix", text
|
671
|
-
end
|
672
|
-
## internal method to log an action
|
673
|
-
# @param [Fixnum] id
|
674
|
-
# @param [String] column or create/delete for row
|
675
|
-
# @param [String] details such as content added, or content changed
|
676
|
-
def log id, field, text
|
677
|
-
id = args.shift
|
678
|
-
unless id
|
679
|
-
id = ask("Issue Id? ", Integer)
|
680
|
-
end
|
681
|
-
if !args.empty?
|
682
|
-
comment = args.join(" ")
|
683
|
-
else
|
684
|
-
message "Enter a comment (. to exit): "
|
685
|
-
comment = get_lines
|
686
|
-
end
|
687
|
-
die "Operation cancelled" if comment.nil? or comment.empty?
|
688
|
-
message "Comment is: #{comment}."
|
689
|
-
db = get_db
|
690
|
-
row = db.sql_select_rowid "bugs", id
|
691
|
-
die "No issue found for #{id}" unless row
|
692
|
-
message "Adding comment to #{id}: #{row['title']}"
|
693
|
-
rowid = db.sql_logs_insert id, field, log
|
694
|
-
puts "Comment #{rowid} created"
|
695
|
-
0
|
696
|
+
rowid = db.sql_logs_insert id, "fix", Cmdapp.truncate(text, 50)
|
696
697
|
end
|
697
698
|
|
698
699
|
##
|
@@ -724,6 +725,8 @@ TEXT
|
|
724
725
|
db.sql_update "bugs", id, field, value
|
725
726
|
puts "Updated #{id}"
|
726
727
|
rowid = db.sql_logs_insert id, field, "[#{id}] updated [#{field}] with #{value}"
|
728
|
+
row[field] = value
|
729
|
+
mail_issue "[#{id}] updated [#{field}] with #{value}", row
|
727
730
|
else
|
728
731
|
message "#{id} already #{value}"
|
729
732
|
end
|
@@ -788,173 +791,62 @@ TEXT
|
|
788
791
|
}
|
789
792
|
end
|
790
793
|
|
791
|
-
def check_file filename=@app_file_path
|
792
|
-
File.exists?(filename) or die "#{filename} does not exist in this dir. Use 'add' to create an item first."
|
793
|
-
end
|
794
|
-
##
|
795
|
-
# colorize each line, if required.
|
796
|
-
# However, we should put the colors in some Map, so it can be changed at configuration level.
|
797
|
-
#
|
798
|
-
def colorize # TODO:
|
799
|
-
colorme = @options[:colorize]
|
800
|
-
@data.each do |r|
|
801
|
-
if @options[:hide_numbering]
|
802
|
-
string = "#{r[1]} "
|
803
|
-
else
|
804
|
-
string = " #{r[0]} #{r[1]} "
|
805
|
-
end
|
806
|
-
if colorme
|
807
|
-
m=string.match(/\(([A-Z])\)/)
|
808
|
-
if m
|
809
|
-
case m[1]
|
810
|
-
when "A", "B", "C", "D"
|
811
|
-
pri = self.class.const_get("PRI_#{m[1]}")
|
812
|
-
#string = "#{YELLOW}#{BOLD}#{string}#{CLEAR}"
|
813
|
-
string = "#{pri}#{string}#{CLEAR}"
|
814
|
-
else
|
815
|
-
string = "#{NORMAL}#{GREEN}#{string}#{CLEAR}"
|
816
|
-
#string = "#{BLUE}\e[6m#{string}#{CLEAR}"
|
817
|
-
#string = "#{BLUE}#{string}#{CLEAR}"
|
818
|
-
end
|
819
|
-
else
|
820
|
-
#string = "#{NORMAL}#{string}#{CLEAR}"
|
821
|
-
# no need to put clear, let it be au natural
|
822
|
-
end
|
823
|
-
end # colorme
|
824
|
-
## since we've added notes, we convert C-a to newline with spaces
|
825
|
-
# so it prints in next line with some neat indentation.
|
826
|
-
string.gsub!('', "\n ")
|
827
|
-
#string.tr! '', "\n"
|
828
|
-
puts string
|
829
|
-
end
|
830
|
-
end
|
831
|
-
# internal method for sorting on reverse of line (status, priority)
|
832
|
-
def sort # TODO:
|
833
|
-
fold_subtasks
|
834
|
-
if @options[:reverse]
|
835
|
-
@data.sort! { |a,b| a[1] <=> b[1] }
|
836
|
-
else
|
837
|
-
@data.sort! { |a,b| b[1] <=> a[1] }
|
838
|
-
end
|
839
|
-
unfold_subtasks
|
840
|
-
end
|
841
|
-
def grep # TODO:
|
842
|
-
r = Regexp.new @options[:grep]
|
843
|
-
#@data = @data.grep r
|
844
|
-
@data = @data.find_all {|i| i[1] =~ r }
|
845
|
-
end
|
846
|
-
|
847
|
-
##
|
848
|
-
# separates args into tag or subcommand and items
|
849
|
-
# This allows user to pass e.g. a priority first and then item list
|
850
|
-
# or item list first and then priority.
|
851
|
-
# This can only be used if the tag or pri or status is non-numeric and the item is numeric.
|
852
|
-
def _separate args, pattern=nil #/^[a-zA-Z]/
|
853
|
-
tag = nil
|
854
|
-
items = []
|
855
|
-
args.each do |arg|
|
856
|
-
if arg =~ /^[0-9\.]+$/
|
857
|
-
items << arg
|
858
|
-
else
|
859
|
-
tag = arg
|
860
|
-
if pattern
|
861
|
-
die "#{@action}: #{arg} appears invalid." if arg !~ pattern
|
862
|
-
end
|
863
|
-
end
|
864
|
-
end
|
865
|
-
items = nil if items.empty?
|
866
|
-
return tag, items
|
867
|
-
end
|
868
794
|
|
869
|
-
# get choice from user from a list of options
|
870
|
-
# @param [String] prompt text
|
871
|
-
# @param [Array] values to chose from
|
872
|
-
# FIXME: move to Cmdapp
|
873
|
-
def _choice prompt, choices
|
874
|
-
choose do |menu|
|
875
|
-
menu.prompt = prompt
|
876
|
-
menu.choices(*choices) do |n| return n; end
|
877
|
-
end
|
878
|
-
end
|
879
|
-
#
|
880
|
-
# take user input based on value of flag
|
881
|
-
# @param [String] column name
|
882
|
-
# @param [Boolean, Symbol] true, false, :freeform, :choice
|
883
|
-
# @param [String, nil] text to prompt
|
884
|
-
# @param [Array, nil] choices array or nil
|
885
|
-
# @param [Object] default value
|
886
|
-
# @return [String, nil] users choice
|
887
|
-
#
|
888
|
-
# TODO: should we not check for the ask_x methods and call them if present.
|
889
|
-
# FIXME: move to Cmdapp
|
890
|
-
def user_input column, prompt_flag, prompt_text=nil, choices=nil, default=nil
|
891
|
-
if prompt_flag == true
|
892
|
-
prompt_flag = :freeform
|
893
|
-
prompt_flag = :choice if choices
|
894
|
-
end
|
895
|
-
case prompt_flag
|
896
|
-
when :freeform
|
897
|
-
prompt_text ||= "#{column.capitalize}"
|
898
|
-
#str = ask(prompt_text){ |q| q.default = default if default }
|
899
|
-
str = _gets(column, prompt_text, default)
|
900
|
-
return str
|
901
|
-
when :choice
|
902
|
-
prompt_text ||= "Select #{column}:"
|
903
|
-
str = _choice(prompt_text, choices)
|
904
|
-
return str
|
905
|
-
when :multiline, :ml
|
906
|
-
return Cmdapp::edit_text default
|
907
|
-
when false
|
908
|
-
return default
|
909
|
-
end
|
910
|
-
end
|
911
795
|
def test args=nil
|
912
796
|
puts "This is only for testing things out"
|
913
797
|
if $use_project
|
914
|
-
project = user_input('project', $prompt_project, nil, $valid_project, $default_project)
|
798
|
+
project = Cmdapp.user_input('project', $prompt_project, nil, $valid_project, $default_project)
|
915
799
|
puts project
|
916
800
|
end
|
917
801
|
if $use_component
|
918
|
-
component = user_input('component', $prompt_component, nil, $valid_component, $default_component)
|
802
|
+
component = Cmdapp.user_input('component', $prompt_component, nil, $valid_component, $default_component)
|
919
803
|
puts component
|
920
804
|
end
|
921
805
|
end
|
922
|
-
|
923
|
-
#
|
924
|
-
# @param [
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
806
|
+
#
|
807
|
+
# prints recent log/activity
|
808
|
+
# @param [Array] first index is limit (how many rows to show), default 10
|
809
|
+
def recentlogs args=nil
|
810
|
+
limit = args[0] || 10
|
811
|
+
sql = "select log.id, title, log.created_by, log.date_created, log from log,bugs where bugs.id = log.id order by log.date_created desc limit #{limit}"
|
812
|
+
|
813
|
+
db = get_db
|
814
|
+
db.run sql do |row|
|
815
|
+
log = Cmdapp.indent2( row['log'],20)
|
816
|
+
text = <<-TEXT
|
817
|
+
|
818
|
+
id : [#{row['id']}] #{row['title']}
|
819
|
+
action_by : #{row['created_by']}
|
820
|
+
date : #{row['date_created']}
|
821
|
+
activity : #{log}
|
822
|
+
|
823
|
+
TEXT
|
824
|
+
#puts row.keys
|
825
|
+
puts text
|
826
|
+
|
937
827
|
end
|
938
|
-
return nil if str == ""
|
939
|
-
return str.chomp
|
940
828
|
end
|
941
|
-
#
|
942
|
-
#
|
943
|
-
#
|
944
|
-
def
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
829
|
+
#
|
830
|
+
# prints recent comments
|
831
|
+
# @param [Array] first index is limit (how many rows to show), default 10
|
832
|
+
def recentcomments args=nil
|
833
|
+
limit = args[0] || 10
|
834
|
+
sql = "select comments.id, title, comments.created_by, comments.date_created, comment from comments,bugs where bugs.id = comments.id order by comments.date_created desc limit #{limit}"
|
835
|
+
|
836
|
+
db = get_db
|
837
|
+
db.run sql do |row|
|
838
|
+
comment = Cmdapp.indent2( row['comment'],20)
|
839
|
+
text = <<-TEXT
|
840
|
+
|
841
|
+
id : [#{row['id']}] #{row['title']}
|
842
|
+
author : #{row['created_by']}
|
843
|
+
date : #{row['date_created']}
|
844
|
+
comment : #{comment}
|
845
|
+
|
846
|
+
TEXT
|
847
|
+
#puts row.keys
|
848
|
+
puts text
|
849
|
+
|
958
850
|
end
|
959
851
|
end
|
960
852
|
# ADD here
|
@@ -1111,7 +1003,11 @@ TEXT
|
|
1111
1003
|
end
|
1112
1004
|
Subcommands::command :comment do |opts|
|
1113
1005
|
opts.banner = "Usage: comment [options] ISSUE_NO TEXT"
|
1114
|
-
opts.description = "Add comment a given issue"
|
1006
|
+
opts.description = "Add a comment to a given issue"
|
1007
|
+
end
|
1008
|
+
Subcommands::command :fix do |opts|
|
1009
|
+
opts.banner = "Usage: fix [options] ISSUE_NO TEXT"
|
1010
|
+
opts.description = "Add a fix for a given issue"
|
1115
1011
|
end
|
1116
1012
|
Subcommands::command :test do |opts|
|
1117
1013
|
opts.banner = "Usage: test [options] ISSUE_NO TEXT"
|
@@ -1144,6 +1040,14 @@ TEXT
|
|
1144
1040
|
opts.banner = "Usage: viewlogs [options] ISSUE_NO"
|
1145
1041
|
opts.description = "view logs for an issue"
|
1146
1042
|
end
|
1043
|
+
Subcommands::command :recentlogs do |opts|
|
1044
|
+
opts.banner = "Usage: recentlogs [options] <HOWMANY>"
|
1045
|
+
opts.description = "view recent logs/activity, default last 10 logs "
|
1046
|
+
end
|
1047
|
+
Subcommands::command :recentcomments do |opts|
|
1048
|
+
opts.banner = "Usage: recentcomments [options] <HOWMANY>"
|
1049
|
+
opts.description = "view recent comments, default last 10 logs "
|
1050
|
+
end
|
1147
1051
|
# XXX order of these 2 matters !! reverse and see what happens
|
1148
1052
|
Subcommands::command :close, :clo do |opts|
|
1149
1053
|
opts.banner = "Usage: clo [options] <ISSUENO>"
|
@@ -1178,16 +1082,10 @@ TEXT
|
|
1178
1082
|
opts.on("-f", "--[no-]force", "force - don't prompt") do |v|
|
1179
1083
|
options[:force] = v
|
1180
1084
|
end
|
1181
|
-
#opts.on("--recursive", "operate on subtasks also") { |v|
|
1182
|
-
#options[:recursive] = v
|
1183
|
-
#}
|
1184
1085
|
end
|
1185
1086
|
Subcommands::command :status do |opts|
|
1186
1087
|
opts.banner = "Usage: status [options] <STATUS> <ISSUE>"
|
1187
1088
|
opts.description = "Change the status of an issue. \t<STATUS> are open closed started canceled stopped "
|
1188
|
-
#opts.on("--recursive", "operate on subtasks also") { |v|
|
1189
|
-
#options[:recursive] = v
|
1190
|
-
#}
|
1191
1089
|
end
|
1192
1090
|
# TODO:
|
1193
1091
|
#Subcommands::command :tag do |opts|
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 3
|
8
|
+
- 0
|
9
|
+
version: 0.3.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Rahul Kumar
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-07-
|
17
|
+
date: 2010-07-12 00:00:00 +05:30
|
18
18
|
default_executable: bugzyrb
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|