bugzyrb 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|