bugzyrb 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ = bugzyrb 0.2.0, 2010-07-08 1
2
+ * added readline support and history for fields being entered
3
+ * optional project, component, version
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
data/bugzy.cfg CHANGED
@@ -3,9 +3,9 @@
3
3
  # this overrides defaults inside main program
4
4
 
5
5
  $prompt_assigned_to = false
6
- $default_assigned_to = ENV['logname']
6
+ $default_assigned_to = ENV['LOGNAME']
7
7
  $send_email = true
8
- $email_to = ENV['logname']
8
+ $email_to = ENV['LOGNAME']
9
9
  #$app_dir =
10
10
 
11
11
  $default_type = "bug"
@@ -13,6 +13,8 @@ $default_severity = "normal"
13
13
  $default_status = "open"
14
14
  $default_priority = "P3"
15
15
 
16
+ # prompt variables indicate whether you wish to be prompted during add operation
17
+ # if false, then default value will be used
16
18
  $prompt_type = true
17
19
  $prompt_severity = false
18
20
  $prompt_status = false
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.1.0"
8
+ s.version = "0.2.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-07}
12
+ s.date = %q{2010-07-08}
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}
@@ -21,6 +21,7 @@ Gem::Specification.new do |s|
21
21
  s.files = [
22
22
  ".document",
23
23
  ".gitignore",
24
+ "CHANGELOG.rdoc",
24
25
  "LICENSE",
25
26
  "README.rdoc",
26
27
  "Rakefile",
data/lib/bugzyrb.rb CHANGED
@@ -101,9 +101,11 @@ class Bugzy
101
101
  $default_severity = "normal"
102
102
  $default_status = "open"
103
103
  $default_priority = "P3"
104
- $default_assigned_to = ""
104
+ $default_assigned_to = "unassigned"
105
105
  $default_due = 5 # how many days in advance due date should be
106
106
  #$bare = @options[:bare]
107
+ $use_readline = true
108
+ $g_row = nil
107
109
  # we need to load the cfg file here, if given # , or else in home dir.
108
110
  if @options[:config]
109
111
  load @options[:config]
@@ -169,11 +171,15 @@ SQL
169
171
  message "#{@file} created." if File.exists? @file
170
172
  text = <<-TEXT
171
173
  If you wish to associate projects and/or components and versions to an issue,
172
- please add the same in the database using:
174
+ please modify bugzyrb.cfg as follows:
175
+
176
+ $use_project = true
177
+ $use_component = true
178
+ $use_version = true
179
+ Also, fill in valid_project=[...], default_project="x" and prompt_project=true.
180
+
181
+ bugzyrb.cfg must be called using -c bugzyrb.cfg if overriding ~/.bugzyrb.cfg
173
182
 
174
- project add <NAME>
175
- component add <PROJECTNAME> <COMPONENT>
176
- version add <PROJECTNAME> <VERSION>
177
183
  TEXT
178
184
  message text
179
185
 
@@ -201,7 +207,7 @@ SQL
201
207
  body['severity'] = @options[:severity] || $default_severity
202
208
  body['status'] = @options[:status] || $default_status
203
209
  body['priority'] = @options[:priority] || $default_priority
204
- body['assigned_to'] = @options[:assigned_to]
210
+ body['assigned_to'] = @options[:assigned_to] || $default_assigned_to
205
211
  #comment_count = 0
206
212
  #body['description = nil
207
213
  #fix = nil
@@ -244,30 +250,30 @@ SQL
244
250
  if $prompt_desc
245
251
  message "Enter a detailed description (. to exit): "
246
252
  desc = get_lines
253
+ #message "You entered #{desc}"
247
254
  end
248
- message "You entered #{desc}"
249
255
  type = $default_type || "bug"
250
256
  severity = $default_severity || "normal"
251
257
  status = $default_status || "open"
252
258
  priority = $default_priority || "P3"
253
259
  if $prompt_type
254
260
  type = _choice("Select type:", %w[bug enhancement feature task] )
255
- message "You selected #{type}"
261
+ #message "You selected #{type}"
256
262
  end
257
263
  if $prompt_severity
258
264
  severity = _choice("Select severity:", %w[normal critical moderate] )
259
- message "You selected #{severity}"
265
+ #message "You selected #{severity}"
260
266
  end
261
267
  if $prompt_status
262
268
  status = _choice("Select status:", %w[open started closed stopped canceled] )
263
- message "You selected #{status}"
269
+ #message "You selected #{status}"
264
270
  end
271
+ assigned_to = $default_assigned_to
265
272
  if $prompt_assigned_to
266
273
  message "Assign to:"
267
- assigned_to = $stdin.gets.chomp
268
- message "You selected #{assigned_to}"
269
- else
270
- assigned_to = $default_assigned_to
274
+ #assigned_to = $stdin.gets.chomp
275
+ assigned_to = _gets "assigned_to", "assigned_to", $default_assigned_to
276
+ #message "You selected #{assigned_to}"
271
277
  end
272
278
  project = component = version = nil
273
279
  # project
@@ -293,6 +299,7 @@ SQL
293
299
  body["title"]=title
294
300
  body["description"]=description
295
301
  body["type"]=type
302
+ body["status"]=status
296
303
  body["start_date"]=start_date.to_s
297
304
  body["due_date"]=due_date.to_s
298
305
  body["priority"]=priority
@@ -308,8 +315,6 @@ SQL
308
315
  rowid = db.table_insert_hash("bugs", body)
309
316
  puts "Issue #{rowid} created"
310
317
  logid = db.sql_logs_insert rowid, "create", "#{rowid} #{type}: #{title}"
311
- # send an email of some sort needs improbement FIXME
312
- #printable = %w[ title description status severity type assigned_to start_date due_date priority fix ]
313
318
  body["id"] = rowid
314
319
  mail_issue body
315
320
 
@@ -328,22 +333,16 @@ SQL
328
333
  Severity : #{row['severity']}
329
334
  Assigned To : #{row['assigned_to']}
330
335
  TEXT
336
+ body << " Project : #{row['project']}\n" if $use_project
337
+ body << " Component : #{row['component']}\n" if $use_component
338
+ body << " Version : #{row['version']}\n" if $use_version
331
339
  title = "#{row['id']}: #{row['title']} "
332
- require 'tempfile'
333
- temp = Tempfile.new "bugzy"
334
- File.open(temp,"w"){ |f| f.write body }
335
-
336
- #cmd = %Q{ echo "#{body}" | mail -s "#{title}" "#{emailid}" }
337
- # cat is not portable please change
338
- cmd = %Q{ cat #{temp.path} | mail -s "#{title}" "#{emailid}" }
339
-
340
- $stderr.puts "executing: #{cmd}"
341
- unless system(cmd)
342
- $stderr.puts "Error executing #{cmd}"
343
- $stderr.puts $?
344
- end
345
340
 
341
+ cmd = %{ mail -s "#{title}" "#{emailid}" }
342
+ #puts cmd
343
+ Cmdapp::pipe_output(cmd, body)
346
344
  end
345
+
347
346
  ##
348
347
  # view details of a single issue/bug
349
348
  # @param [Array] ARGV, first element is issue number
@@ -411,16 +410,21 @@ TEXT
411
410
  row = db.sql_select_rowid "bugs", id
412
411
  die "No data found for #{id}" unless row
413
412
  editable = %w[ status severity type assigned_to start_date due_date priority title description fix ]
413
+ editable << "project" if $use_project
414
+ editable << "component" if $use_component
415
+ editable << "version" if $use_version
414
416
  sel = _choice "Select field to edit", editable
415
417
  print "You chose: #{sel}"
416
418
  old = row[sel]
417
419
  puts " Current value is: #{old}"
420
+ $g_row = row
418
421
  meth = "ask_#{sel}".to_sym
419
422
  if respond_to? "ask_#{sel}".to_sym
420
423
  str = send(meth, old)
421
424
  else
422
- print "Enter value: "
423
- str = $stdin.gets.chomp
425
+ #print "Enter value: "
426
+ #str = $stdin.gets.chomp
427
+ str = _gets sel, sel, old
424
428
  end
425
429
  #str = old if str.nil? or str == ""
426
430
  if str.nil? or str == old
@@ -431,6 +435,7 @@ TEXT
431
435
  message str
432
436
  db.sql_update "bugs", id, sel, str
433
437
  puts "Updated #{id}"
438
+ str = str.to_s
434
439
  rowid = db.sql_logs_insert id, sel, "[#{id}] updated [#{sel}] with #{str[0..50]}"
435
440
  0
436
441
  end
@@ -451,6 +456,25 @@ TEXT
451
456
  end
452
457
  0
453
458
  end
459
+ def copy args
460
+ id = args.shift
461
+ db, row = validate_id id, true
462
+ newrow = row.to_hash
463
+ ret = newrow.delete("id")
464
+ newrow.delete("date_created")
465
+ newrow.delete("date_modified")
466
+ #row.each_pair { |name, val| puts "(#{name}): #{val} " }
467
+ ret = ask_title row['title']
468
+ newrow['title'] = ret.chomp if ret
469
+ rowid = db.table_insert_hash( "bugs", newrow)
470
+
471
+ title = newrow['title']
472
+ type = newrow['type']
473
+
474
+ logid = db.sql_logs_insert rowid, "create", "#{rowid} #{type}: #{title}"
475
+ newrow["id"] = rowid
476
+ mail_issue newrow
477
+ end
454
478
  def viewlogs args
455
479
  db = get_db
456
480
  id = args[0].nil? ? db.max_bug_id : args[0]
@@ -502,7 +526,26 @@ TEXT
502
526
  elsif @options[:long]
503
527
  fields = "id,status,title,severity,priority,due_date,description"
504
528
  end
505
- rows = db.run "select #{fields} from bugs "
529
+ where = nil
530
+ wherestring = ""
531
+ if @options[:overdue]
532
+ #where = %{ where status != 'closed' and due_date <= "#{Date.today}" }
533
+ where ||= []
534
+ where << %{ status != 'closed'}
535
+ where << %{ due_date <= "#{Date.today}" }
536
+ end
537
+ if @options[:unassigned]
538
+ #where = %{ where status != 'closed' and due_date <= "#{Date.today}" }
539
+ where ||= []
540
+ where << %{ (assigned_to = 'unassigned' or assigned_to is null) }
541
+ end
542
+ if where
543
+ wherestring = " where " + where.join(" and ")
544
+ end
545
+ puts wherestring
546
+
547
+ rows = db.run "select #{fields} from bugs #{wherestring} "
548
+ die "No rows" unless rows
506
549
 
507
550
  if incl
508
551
  incl_str = incl.join "|"
@@ -572,6 +615,11 @@ TEXT
572
615
  def ask_description old=nil
573
616
  Cmdapp::edit_text old
574
617
  end
618
+ def ask_title old=nil
619
+ ret = Cmdapp::edit_text old
620
+ return ret.chomp if ret
621
+ ret
622
+ end
575
623
  ##
576
624
  # prompts user for a cooment to be attached to a issue/bug
577
625
  def comment args #id, comment
@@ -711,32 +759,24 @@ TEXT
711
759
  # future_date(1).to_s[0..10]; # => creates a string object with only Date part, no time
712
760
  # Date.parse(future_date(1).to_s[0..10]) # => converts to a Date object
713
761
 
714
- def future_date days=1
715
- Time.now() + (24 * 60 * 60 * days)
716
- #(Time.now() + (24 * 60 * 60) * days).to_s[0..10];
717
- end
718
-
719
- ## prompt user for due date, called from edit
720
- #def ask_due_date
721
- #days = 1
722
- #ask("Enter due date? ", Date) {
723
- #|q| q.default = future_date(days).to_s[0..10];
724
- #q.validate = lambda { |p| Date.parse(p) >= Date.parse(Time.now.to_s) };
725
- #q.responses[:not_valid] = "Enter a date greater than today"
726
- #}
762
+ #def future_date days=1
763
+ #Time.now() + (24 * 60 * 60 * days)
727
764
  #end
765
+
728
766
  # prompt user for due date, called from edit
729
- def ask_due_date
730
- days = 1
767
+ # NOTE: this takes a peek at $g_row to get start_date and validate against that
768
+ def ask_due_date old=nil
769
+ days = $default_due
731
770
  today = Date.today
732
- ask("Enter due date? ", Date) {
733
- |q| q.default = today + days;
734
- q.validate = lambda { |p| Date.parse(p) >= today };
735
- q.responses[:not_valid] = "Enter a date greater than today"
771
+ start = Date.parse($g_row['start_date'].to_s) || today
772
+ ask("Enter due date? (>= #{start}) ", Date) {
773
+ |q| q.default = (today + days).to_s;
774
+ q.validate = lambda { |p| Date.parse(p) >= start };
775
+ q.responses[:not_valid] = "Enter a date >= than #{start}"
736
776
  }
737
777
  end
738
778
 
739
- def ask_start_date
779
+ def ask_start_date old=nil
740
780
  ask("Enter start date? ", Date) {
741
781
  #|q| q.default = Time.now.to_s[0..10];
742
782
  |q| q.default = Date.today
@@ -844,8 +884,9 @@ TEXT
844
884
  end
845
885
  case prompt_flag
846
886
  when :freeform
847
- prompt_text ||= "#{column.capitalize}? "
848
- str = ask(prompt_text){ |q| q.default = default if default }
887
+ prompt_text ||= "#{column.capitalize}"
888
+ #str = ask(prompt_text){ |q| q.default = default if default }
889
+ str = _gets(column, prompt_text, default)
849
890
  return str
850
891
  when :choice
851
892
  prompt_text ||= "Select #{column}:"
@@ -884,8 +925,25 @@ TEXT
884
925
  #puts "Read: #{$_}" # writes to STDOUT
885
926
  end
886
927
  return nil if str == ""
887
- return str
928
+ return str.chomp
929
+ end
930
+ def _gets column, prompt, default=nil
931
+ text = "#{prompt}? "
932
+ text << "|#{default}|" if default
933
+ puts text
934
+ if $use_readline
935
+ Cmdapp::history_read column, default
936
+ str = Readline::readline('>', false)
937
+ Cmdapp::history_save column, str
938
+ str = default if str.nil? or str == ""
939
+ return str
940
+ else
941
+ str = $stdin.gets.chomp
942
+ str = default if str.nil? or str == ""
943
+ return str
944
+ end
888
945
  end
946
+ # ADD here
889
947
 
890
948
  def self.main args
891
949
  ret = nil
@@ -905,6 +963,11 @@ TEXT
905
963
  if plain
906
964
  options[:colorize] = (plain == "0") ? false:true
907
965
  end
966
+ config = File.expand_path "~/.bugzyrb.cfg"
967
+ if File.exists? config
968
+ options[:config] = config
969
+ #puts "found #{config} "
970
+ end
908
971
 
909
972
  Subcommands::global_options do |opts|
910
973
  opts.banner = "Usage: #{APPNAME} [options] [subcommand [options]]"
@@ -1028,6 +1091,10 @@ TEXT
1028
1091
  opts.banner = "Usage: edit [options] ISSUE_NO"
1029
1092
  opts.description = "Edit a given issue"
1030
1093
  end
1094
+ Subcommands::command :copy do |opts|
1095
+ opts.banner = "Usage: copy [options] ISSUE_NO"
1096
+ opts.description = "Copy a given issue"
1097
+ end
1031
1098
  Subcommands::command :comment do |opts|
1032
1099
  opts.banner = "Usage: comment [options] ISSUE_NO TEXT"
1033
1100
  opts.description = "Add comment a given issue"
@@ -1052,6 +1119,12 @@ TEXT
1052
1119
  options[:bare] = v
1053
1120
  $bare = true
1054
1121
  }
1122
+ opts.on("-o","--overdue", "not closed, due date past") { |v|
1123
+ options[:overdue] = v
1124
+ }
1125
+ opts.on("-u","--unassigned", "not assigned") { |v|
1126
+ options[:unassigned] = v
1127
+ }
1055
1128
  end
1056
1129
  Subcommands::command :viewlogs do |opts|
1057
1130
  opts.banner = "Usage: viewlogs [options] ISSUE_NO"
data/lib/common/cmdapp.rb CHANGED
@@ -258,6 +258,24 @@ def edit_text text
258
258
  return newstr
259
259
  end
260
260
 
261
+ # pipes given string to command
262
+ # @param [String] command to pipe data to
263
+ # @param [String] data to pipe to command
264
+ # @example
265
+ # cmd = %{mail -s "my title" rahul}
266
+ # pipe_output(cmd, "some long text")
267
+ # FIXME: not clear how to return error.
268
+ # NOTE: this is obviously more portable than using system echo or system cat.
269
+ def pipe_output (pipeto, str)
270
+ #pipeto = '/usr/sbin/sendmail -t'
271
+ #pipeto = %q{mail -s "my title" rahul}
272
+ if pipeto != nil # i was taking pipeto from a hash, so checking
273
+ proc = IO.popen(pipeto, "w+")
274
+ proc.puts str
275
+ proc.close_write
276
+ #puts proc.gets
277
+ end
278
+ end
261
279
  ##
262
280
  # reads up template, and substirutes values from myhash
263
281
  # @param [String] template text
@@ -274,6 +292,56 @@ def template_replace template, myhash
274
292
  }
275
293
  t
276
294
  end
295
+ #------------------------------------------------------------
296
+ # these 2 methods deal with with maintaining readline history
297
+ # for various columns. _read reads up any earlier values
298
+ # so user can select from them.
299
+ # _save saves the values for future use.
300
+ #------------------------------------------------------------
301
+ # for a given column, check if there's any previous data
302
+ # in our cache, and put in readlines history so user can
303
+ # use or edit. Also put default value in history.
304
+ # @param [String] name of column for maintaining cache
305
+ # @param [String] default data for user to recall, or edit
306
+ def history_read column, default=nil
307
+ values = []
308
+ oldstr = ""
309
+ if !defined? $history_hash
310
+ require 'readline'
311
+ require 'yaml'
312
+ filename = File.expand_path "~/.bugzy_history.yml"
313
+ $history_filename = filename
314
+ # if file exists with values push them into history
315
+ if File.exists? filename
316
+ $history_hash = YAML::load( File.open( filename ) )
317
+ else
318
+ $history_hash = Hash.new
319
+ end
320
+ end
321
+ values.push(*$history_hash[column]) if $history_hash.has_key? column
322
+ # push existing value into history also, so it can be edited
323
+ values.push(default) if default
324
+ values.uniq!
325
+ Readline::HISTORY.clear # else previous values of other fields also come in
326
+ Readline::HISTORY.push(*values) unless values.empty?
327
+ #puts Readline::HISTORY.to_a
328
+ end
329
+ ##
330
+ # update our cache with str if not present in cache already
331
+ # @param [String] name of column for maintaining cache
332
+ # @param [String] str : data just entered by user
333
+ #
334
+ def history_save column, str
335
+ return if str.nil? or str == ""
336
+ if $history_hash.has_key? column
337
+ return if $history_hash[column].include? str
338
+ end
339
+ ($history_hash[column] ||= []) << str
340
+ filename = $history_filename
341
+ File.open( filename, 'w' ) do |f|
342
+ f << $history_hash.to_yaml
343
+ end
344
+ end
277
345
 
278
346
 
279
347
 
data/lib/common/db.rb CHANGED
@@ -118,7 +118,7 @@ module Database
118
118
  str << ") values ("
119
119
  str << qstr.join(",")
120
120
  str << ")"
121
- puts str
121
+ #puts str
122
122
  @db.execute(str, *bind_vars)
123
123
  rowid = @db.get_first_value( "select last_insert_rowid();")
124
124
  return rowid
@@ -150,7 +150,7 @@ module Database
150
150
  # @param [Fixnum] id unique key
151
151
  # @param [String] fieldname
152
152
  # @param [String] value to update
153
- # @example sql_bugs_update 9, :name, "Roger"
153
+ # @example sql_update "bugs", 9, :name, "Roger"
154
154
  def sql_update table, id, field, value
155
155
  @db.execute( "update #{table} set #{field} = ?, date_modified = ? where id = ?", value,$now, id)
156
156
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
7
+ - 2
8
8
  - 0
9
- version: 0.1.0
9
+ version: 0.2.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-07 00:00:00 +05:30
17
+ date: 2010-07-08 00:00:00 +05:30
18
18
  default_executable: bugzyrb
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -112,6 +112,7 @@ extra_rdoc_files:
112
112
  files:
113
113
  - .document
114
114
  - .gitignore
115
+ - CHANGELOG.rdoc
115
116
  - LICENSE
116
117
  - README.rdoc
117
118
  - Rakefile