TicGit-ng 1.0.2.14 → 1.0.2.15

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.
@@ -0,0 +1,56 @@
1
+ module TicGitNG
2
+ class Attachment
3
+ attr_reader :user, :added, :filename, :sha, :attachment_name
4
+ attr_reader :original_filename
5
+ alias :read :initialize
6
+
7
+ def initialize( fname )
8
+ #FIXME expect fname to be a raw filename that needs to be converted
9
+ # into a properly formatted ticket name
10
+ @filename=fname
11
+ trailing_underscore= File.basename(fname)[/_$/] ? true : false
12
+ trailing_underscore=false
13
+ temp=File.basename(fname).split('_').reverse
14
+ @added=Time.at(temp.pop.to_i)
15
+ @user= temp.pop
16
+ @attachment_name= temp.reverse.join('_')
17
+ if trailing_underscore
18
+ @attachment_name << '_'
19
+ end
20
+ end
21
+
22
+ #Called when attaching a new attachment and when reading/opening attachments
23
+ #FIXME Make a 'read' and 'create' function to differentiate between
24
+ # between creation of a ticket and reading an existing ticket.
25
+ def self.create raw_fname, ticket, time
26
+ #Attachment naming format:
27
+ #ticket_name/ATTACHMENTS/123456_jeff.welling@gmail.com_fubar.jpg
28
+ #raw_fname "/home/guy/Desktop/fubar.jpg"
29
+
30
+ #create attachment dir if first run
31
+ a_name= File.expand_path( File.join(
32
+ File.join( ticket.ticket_name, 'ATTACHMENTS' ),
33
+ ticket.create_attachment_name(raw_fname, time)
34
+ ))
35
+ #create new filename from ticket
36
+ if File.exist?( File.dirname( a_name ) ) &&
37
+ !File.directory?( File.dirname(a_name) )
38
+
39
+ puts "Could not create ATTACHMENTS directory"
40
+ exit 1
41
+ elsif !File.exist?( File.dirname( a_name ) )
42
+ Dir.mkdir File.dirname( a_name )
43
+ end
44
+ #copy/link the raw_filename
45
+ Dir.chdir( File.dirname(a_name) ) do
46
+ FileUtils.cp( raw_fname, a_name )
47
+ end
48
+ #call init on the new file to properly populate the variables
49
+ a_name= File.join(
50
+ File.basename( File.dirname( a_name ) ),
51
+ File.basename( a_name )
52
+ )
53
+ return Attachment.new( a_name )
54
+ end
55
+ end
56
+ end
@@ -10,6 +10,14 @@ module TicGitNG
10
10
 
11
11
  def initialize(git_dir, opts = {})
12
12
  @git = Git.open(find_repo(git_dir))
13
+
14
+ begin
15
+ git.lib.full_log_commits 1
16
+ rescue
17
+ puts "Git error: please check your git repository, you must have at least one commit in git"
18
+ exit 1
19
+ end
20
+
13
21
  @logger = opts[:logger] || Logger.new(STDOUT)
14
22
 
15
23
  #This is to accomodate for edge-cases where @logger.puts
@@ -65,6 +73,22 @@ module TicGitNG
65
73
 
66
74
  @state = File.expand_path(File.join(@tic_dir, proj, 'state'))
67
75
 
76
+ branches=git.lib.branches_all.map{|b|b.first}
77
+ unless branches.include?(which_branch?) && File.directory?(@tic_working)
78
+ if branches.include?(which_branch?) and !File.exist?(@tic_working)
79
+ #branch exists but tic_working doesn't
80
+ #this could be because the dir was deleted or the repo itself
81
+ #was moved, so recreate the dir.
82
+ reset_ticgitng
83
+ elsif @init
84
+ puts "Initializing TicGit-ng"
85
+ init_ticgitng_branch( branches.include?(which_branch?) )
86
+ else
87
+ puts "Please run `ti init` to initialize TicGit-ng for this repository before running other ti commands."
88
+ exit
89
+ end
90
+ end
91
+
68
92
  if File.file?(@state)
69
93
  load_state
70
94
  else
@@ -84,6 +108,9 @@ module TicGitNG
84
108
  # save config file
85
109
  def save_state
86
110
  state_list = [@last_tickets, @current_ticket]
111
+ unless File.exist? @state
112
+ FileUtils.mkdir_p( File.dirname(@state) )
113
+ end
87
114
  File.open(@state, 'w+'){|io| Marshal.dump(state_list, io) }
88
115
  File.open(@config_file, 'w+'){|io| io.write(config.to_yaml) }
89
116
  end
@@ -103,8 +130,8 @@ module TicGitNG
103
130
  end
104
131
 
105
132
  # returns new Ticket
106
- def ticket_new(title, options = {})
107
- t = TicGitNG::Ticket.create(self, title, options)
133
+ def ticket_new(title, options = {}, time=nil)
134
+ t = TicGitNG::Ticket.create(self, title, options, time)
108
135
  reset_ticgitng
109
136
  TicGitNG::Ticket.open(self, t.ticket_name, tickets[t.ticket_name])
110
137
  end
@@ -122,6 +149,7 @@ module TicGitNG
122
149
  ticket = TicGitNG::Ticket.open(self, t, tickets[t])
123
150
  ticket.add_comment(comment)
124
151
  reset_ticgitng
152
+ ticket
125
153
  end
126
154
  end
127
155
 
@@ -264,6 +292,7 @@ module TicGitNG
264
292
  ticket.add_tag(tag)
265
293
  end
266
294
  reset_ticgitng
295
+ ticket
267
296
  end
268
297
  end
269
298
 
@@ -273,6 +302,7 @@ module TicGitNG
273
302
  ticket = TicGitNG::Ticket.open(self, t, tickets[t])
274
303
  ticket.change_state(new_state)
275
304
  reset_ticgitng
305
+ ticket
276
306
  end
277
307
  end
278
308
  end
@@ -282,6 +312,7 @@ module TicGitNG
282
312
  ticket = TicGitNG::Ticket.open(self, t, tickets[t])
283
313
  ticket.change_assigned(new_assigned)
284
314
  reset_ticgitng
315
+ ticket
285
316
  end
286
317
  end
287
318
 
@@ -290,6 +321,7 @@ module TicGitNG
290
321
  ticket = TicGitNG::Ticket.open(self, t, tickets[t])
291
322
  ticket.change_points(new_points)
292
323
  reset_ticgitng
324
+ ticket
293
325
  end
294
326
  end
295
327
 
@@ -298,15 +330,10 @@ module TicGitNG
298
330
  ticket = TicGitNG::Ticket.open(self, t, tickets[t])
299
331
  @current_ticket = ticket.ticket_name
300
332
  save_state
333
+ ticket
301
334
  end
302
335
  end
303
336
 
304
- def comment_add(ticket_id, comment, options = {})
305
- end
306
-
307
- def comment_list(ticket_id)
308
- end
309
-
310
337
  def tic_states
311
338
  ['open', 'resolved', 'invalid', 'hold']
312
339
  end
@@ -334,30 +361,22 @@ module TicGitNG
334
361
  def read_tickets
335
362
  tickets = {}
336
363
 
337
- bs = git.lib.branches_all.map{|b| b.first }
338
-
339
- unless (bs.include?(which_branch?) || bs.include?(which_branch?)) &&
340
- File.directory?(@tic_working)
341
- unless @init
342
- puts "Please run `ti init` to initialize TicGit-ng for this repository before running other ti commands."
343
- exit
344
- else
345
- puts "Initializing TicGit-ng"
346
- init_ticgitng_branch(
347
- git.lib.branches_all.map{|b| b.first }.include?(which_branch?)
348
- )
349
- end
350
- end
351
-
352
364
  tree = git.lib.full_tree(which_branch?)
353
365
  tree.each do |t|
354
366
  data, file = t.split("\t")
355
367
  mode, type, sha = data.split(" ")
356
368
  tic = file.split('/')
357
369
  if tic.size == 2 # directory depth
358
- ticket, info = tic
359
- tickets[ticket] ||= { 'files' => [] }
360
- tickets[ticket]['files'] << [info, sha]
370
+ ticket, info = tic
371
+ tickets[ticket] ||= { 'files' => [] }
372
+ tickets[ticket]['files'] << [info, sha]
373
+ elsif tic.size == 3
374
+ ticket, attch_dir, filename = tic
375
+ if filename
376
+ filename = 'ATTACHMENTS_' + filename
377
+ tickets[ticket] ||= { 'files' => [] }
378
+ tickets[ticket]['files'] << [filename, sha]
379
+ end
361
380
  end
362
381
  end
363
382
  tickets
@@ -410,7 +429,9 @@ module TicGitNG
410
429
  def new_file(name, contents)
411
430
  File.open(name, 'w+'){|f| f.puts(contents) }
412
431
  end
432
+
413
433
  def which_branch?
434
+ #At present use the 'ticgit' branch for backwards compatibility
414
435
  branches=@git.branches.local.map {|b| b.name}
415
436
  if branches.include? 'ticgit-ng'
416
437
  return 'ticgit-ng'
@@ -436,6 +457,24 @@ module TicGitNG
436
457
  def needs_reset? cache_mtime, gitlog_mtime
437
458
  ((cache_mtime.to_i - gitlog_mtime.to_i) > 120) or ((gitlog_mtime.to_i - cache_mtime.to_i) > 120)
438
459
  end
460
+
461
+ def ticket_attach filename, ticket_id=nil, time=nil
462
+ t = ticket_revparse( ticket_id )
463
+ ticket= TicGitNG::Ticket.open( self, t, tickets[t] )
464
+ ticket.add_attach( self, filename, time )
465
+ reset_ticgitng
466
+ ticket
467
+ end
439
468
 
469
+ #ticket_get_attachment()
470
+ #file_id - return the attachment identified by file_id
471
+ #new_filename - save the attachment as new_filename
472
+ #ticket_id - get the attachment from ticket_id instead of current
473
+ def ticket_get_attachment file_id=nil, new_filename=nil, ticket_id=nil
474
+ if t = ticket_revparse(ticket_id)
475
+ ticket = Ticket.open( self, t, tickets[t] )
476
+ ticket.get_attach( file_id, new_filename )
477
+ end
478
+ end
440
479
  end
441
480
  end
data/lib/ticgit-ng/cli.rb CHANGED
@@ -110,44 +110,62 @@ module TicGitNG
110
110
  end
111
111
 
112
112
  def ticket_show(t, more=nil)
113
- days_ago = ((Time.now - t.opened) / (60 * 60 * 24)).round
114
-
115
- data = [
116
- ['Title', t.title],
117
- ['TicId', t.ticket_id],
118
- '',
119
- ['Assigned', t.assigned],
120
- ['Opened', "#{t.opened} (#{days_ago} days)"],
121
- ['State', t.state.upcase],
122
- ['Points', t.points || 'no estimate'],
123
- ['Tags', t.tags.join(', ')],
124
- ''
125
- ]
126
-
127
- data.each do |(key, value)|
128
- puts(value ? "#{key}: #{value}" : key)
129
- end
130
-
131
- unless t.comments.empty?
132
- puts "Comments (#{t.comments.size}):"
133
- t.comments.reverse_each do |c|
134
- puts " * Added #{c.added.strftime('%m/%d %H:%M')} by #{c.user}"
135
-
136
- wrapped = c.comment.split("\n").map{|line|
137
- line.length > 80 ? line.gsub(/(.{1,80})(\s+|$)/, "\\1\n").strip : line
138
- }.join("\n")
139
-
140
- wrapped = wrapped.split("\n").map{|line| "\t#{line}" }
113
+ days_ago = ((Time.now - t.opened) / (60 * 60 * 24)).round
114
+
115
+ data = [
116
+ ['Title', t.title],
117
+ ['TicId', t.ticket_id],
118
+ '',
119
+ ['Assigned', t.assigned],
120
+ ['Opened', "#{t.opened} (#{days_ago} days)"],
121
+ ['State', t.state.upcase],
122
+ ['Points', t.points || 'no estimate'],
123
+ ['Tags', t.tags.join(', ')],
124
+ ''
125
+ ]
126
+
127
+ data.each do |(key, value)|
128
+ puts(value ? "#{key}: #{value}" : key)
129
+ end
141
130
 
142
- if wrapped.size > 6 and more.nil?
143
- puts wrapped[0, 6].join("\n")
144
- puts "\t** more... **"
145
- else
146
- puts wrapped.join("\n")
147
- end
148
- puts
131
+ #FIXME display attachments inline chronologically with comments
132
+ unless t.comments.empty? and t.attachments.empty?
133
+ comments_and_attachments= Hash.new
134
+ puts "Comments and attachments (#{t.comments.size + t.attachments.size}):"
135
+ t.comments.each do |c|
136
+ comments_and_attachments[c.added]=c
137
+ end
138
+
139
+ t.attachments.each do |a|
140
+ comments_and_attachments[a.added]=a
141
+ end
142
+ comments_and_attachments.sort.each {|item|
143
+ if item[1].class==TicGitNG::Comment
144
+ #print comment
145
+ puts " * Added #{item[1].added.strftime('%m/%d %H:%M')} by #{item[1].user}"
146
+
147
+ wrapped = item[1].comment.split("\n").map{|line|
148
+ line.length > 80 ? line.gsub(/(.{1,80})(\s+|$)/, "\\1\n").strip : line
149
+ }.join("\n")
150
+
151
+ wrapped = wrapped.split("\n").map{|line| "\t#{line}" }
152
+
153
+ if wrapped.size > 6 and more.nil?
154
+ puts wrapped[0, 6].join("\n")
155
+ puts "\t** more... **"
156
+ else
157
+ puts wrapped.join("\n")
158
+ end
159
+ puts
160
+ else
161
+ #print attachment
162
+ puts " * Added #{item[1].added.strftime('%m/%d %H:%M')} by #{item[1].user}"
163
+ puts " Attachment: #{t.attachments.index(item[1]) }"
164
+ puts " Filename: #{item[1].attachment_name}"
165
+ puts
166
+ end
167
+ }
149
168
  end
150
- end
151
169
  end
152
170
 
153
171
  class << self
@@ -254,4 +272,8 @@ module TicGitNG
254
272
  end
255
273
 
256
274
  TicGitNG::CLI.reset_window_width
257
- Signal.trap("SIGWINCH") { TicGitNG::CLI.reset_window_width }
275
+ begin
276
+ Signal.trap("SIGWINCH") { TicGitNG::CLI.reset_window_width }
277
+ rescue
278
+ TicGitNG::CLI.use_fallback
279
+ end
@@ -0,0 +1,48 @@
1
+ module TicGitNG
2
+ module Command
3
+ # Attach a file to a ticket
4
+ #
5
+ # Usage:
6
+ # ti attach
7
+ # (print help for 'ti attach')
8
+ #
9
+ # ti attach {filename}
10
+ # (attach {filename} to current ticket)
11
+ #
12
+ # ti attach -i {ID} {filename}
13
+ # (attach file {filename} to ticket with ID {ID})
14
+ #
15
+ # ti attach -g {f_id}
16
+ # (retrieve attached file {f_id}, place in current dir}
17
+ #
18
+ # ti attach -g {f_id} -n {new_filename}
19
+ # (retrieve attached file {f_id}, place as {new_filename})
20
+ module Attach
21
+ def parser(opts)
22
+ opts.banner = "Usage: ti attach [options] [filename]"
23
+
24
+ opts.on_head(
25
+ "-i TICKET_ID", "--id TICKET_ID", "Attach the file to this ticket"){|v|
26
+ options.ticket_id = v
27
+ }
28
+ opts.on_head(
29
+ "-g FILE_ID", "--get FILE_ID", "Retrieve the file FILE_ID"){|v|
30
+ puts "Warning: ticket ID argument is not valid with the retrieve attachment argument" if options.ticket_id
31
+ options.get_file = v
32
+ }
33
+ opts.on_head(
34
+ "-n N_FILENAME", "--new-filename", "Use this filename for the retrieved attachment"){|v|
35
+ raise ArgumentError, "Error: New filename argument is only valid with the retrieve arrachment argument" unless options.get_file
36
+ options.new_filename = v
37
+ }
38
+ end
39
+ def execute
40
+ if options.get_file
41
+ tic.ticket_get_attachment( options.get_file, options.new_filename )
42
+ else
43
+ tic.ticket_attach( args[0], options.ticket_id )
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,27 @@
1
+ module TicGitNG
2
+ module Command
3
+ # Shows help for ticgit or a particular command
4
+ #
5
+ # Usage:
6
+ # ti help (show help for ticgit)
7
+ # ti help {command} (show help for specified command)
8
+ module Help
9
+ def parser(opts)
10
+ opts.banner = "Usage: ti help [command]\n"
11
+ end
12
+ def execute
13
+ cli = CLI.new([])
14
+ if ARGV.length >= 2 # ti help {command}
15
+ action = ARGV[1]
16
+ if command = Command.get(action)
17
+ cli.extend(command)
18
+ else
19
+ puts "Unknown command #{action}\n\n"
20
+ end
21
+ end
22
+ puts cli.usage
23
+ end
24
+ end
25
+ end
26
+ end
27
+
@@ -6,7 +6,7 @@ module TicGitNG
6
6
  o.banner = "Usage: ti list [options]"
7
7
  o.on_head(
8
8
  "-o ORDER", "--order ORDER",
9
- "Field to order by - one of : assigned,state,date,title"){|v|
9
+ "Field to order by - one of : assigned,state,date,title [.desc for reverse order]"){|v|
10
10
  options.order = v
11
11
  }
12
12
 
@@ -13,17 +13,14 @@ module TicGitNG
13
13
  puts 'remove'
14
14
  end
15
15
 
16
- if ARGV.size > 3
17
- tid = ARGV[1].chomp
18
- tic.ticket_tag(ARGV[3].chomp, tid, options)
19
- elsif ARGV.size > 2 #tag
20
- tic.ticket_tag(ARGV[2], nil, options)
21
- elsif ARGV.size == 2 #tag add 'tag_foobar'
22
- tic.ticket_tag(ARGV[1], nil, options)
16
+ if ARGV.size > 2 # `ti tag 1234abc tagname1`
17
+ tic.ticket_tag(ARGV[2], ARGV[1].chomp, options)
18
+ elsif ARGV.size == 2 # `ti tag tagname1`
19
+ tic.ticket_tag(ARGV[1], nil, options)
23
20
  else
24
21
  puts 'You need to at least specify one tag to add'
25
22
  puts
26
- puts parser
23
+ puts usage
27
24
  end
28
25
  end
29
26
  end
@@ -13,8 +13,9 @@ module TicGitNG
13
13
  register 'Attach', 'Attach file to ticket', 'attach'
14
14
  register 'Checkout', 'Checkout a ticket', 'checkout', 'co'
15
15
  register 'Comment', 'Comment on a ticket', 'comment'
16
+ register 'Help', 'Show help for a ticgit command', 'help'
16
17
  register 'List', 'List tickets', 'list'
17
- register 'Milestone', 'List and modify milestones', 'milestone'
18
+ # register 'Milestone', 'List and modify milestones', 'milestone'
18
19
  register 'New', 'Create a new ticket', 'new'
19
20
  register 'Points', 'Assign points to a ticket', 'points'
20
21
  register 'Recent', 'List recent activities', 'recent'
@@ -1,17 +1,19 @@
1
1
  module TicGitNG
2
2
  class Comment
3
+ attr_accessor :base, :user, :added, :comment
3
4
 
4
- attr_reader :base, :user, :added, :comment
5
-
6
- def initialize(base, file_name, sha)
7
- @base = base
8
- @comment = base.git.gblob(sha).contents rescue nil
5
+ def initialize( c, user, time=nil )
6
+ raise unless c
7
+ @comment= c
8
+ @user=user
9
+ @added= time.nil? ? Time.now : time
10
+ self
11
+ end
9
12
 
13
+ def self.read( base, file_name, sha )
10
14
  type, date, user = file_name.split('_')
11
15
 
12
- @added = Time.at(date.to_i)
13
- @user = user
16
+ new( (base.git.gblob(sha).contents rescue nil), user, Time.at(date.to_i) )
14
17
  end
15
-
16
18
  end
17
19
  end
@@ -25,10 +25,10 @@ module TicGitNG
25
25
  @attachments = []
26
26
  end
27
27
 
28
- def self.create(base, title, options = {})
28
+ def self.create(base, title, options = {}, time=nil)
29
29
  t = Ticket.new(base, options)
30
30
  t.title = title
31
- t.ticket_name = self.create_ticket_name(title)
31
+ t.ticket_name = self.create_ticket_name(title, time)
32
32
  t.save_new
33
33
  t
34
34
  end
@@ -42,39 +42,46 @@ module TicGitNG
42
42
  title, date = self.parse_ticket_name(ticket_name)
43
43
  t.opened = date
44
44
 
45
- ticket_hash['files'].each do |fname, value|
45
+ ticket_hash['files'].each do |fname, sha|
46
46
  if fname == 'TICKET_ID'
47
- tid = value
47
+ tid = sha
48
48
  elsif fname == 'TICKET_TITLE'
49
- t.title = base.git.gblob(value).contents
49
+ t.title = base.git.gblob(sha).contents
50
50
  else
51
51
  # matching
52
52
  data = fname.split('_')
53
53
 
54
54
  case data[0]
55
55
  when 'ASSIGNED'
56
- t.assigned = data[1]
57
- when 'ATTACHMENT'
58
- t.attachments << TicGitNG::Attachment.new(base, fname, value)
56
+ t.assigned = data[1..-1].join('_')
57
+ when 'ATTACHMENTS'
58
+ #Attachments dir naming format:
59
+ #ticket_name/ATTACHMENTS/123456_jeff.welling@gmail.com_fubar.jpg
60
+ #data[] format:
61
+ #"ATTACHMENTS_1342116799_jeff.welling@gmail.com_Rakefile".split('_')
62
+ filename=File.join( 'ATTACHMENTS', fname.gsub(/^ATTACHMENTS_/,'') )
63
+ t.attachments << TicGitNG::Attachment.new( filename )
59
64
  when 'COMMENT'
60
- t.comments << TicGitNG::Comment.new(base, fname, value)
65
+ t.comments << TicGitNG::Comment.read(base, fname, sha)
61
66
  when 'POINTS'
62
- t.points = base.git.gblob(value).contents.to_i
67
+ t.points = base.git.gblob(sha).contents.to_i
63
68
  when 'STATE'
64
69
  t.state = data[1]
65
70
  when 'TAG'
66
71
  t.tags << data[1]
67
72
  when 'TITLE'
68
- t.title = base.git.gblob(value).contents
73
+ t.title = base.git.gblob(sha).contents
69
74
  end
70
75
  end
71
76
  end
72
77
 
78
+ if !t.attachments.class==NilClass and t.attachments.size > 1
79
+ t.attachments= t.attachments.sort {|a1, a2| a1.added <=> a2.added }
80
+ end
73
81
  t.ticket_id = tid
74
82
  t
75
83
  end
76
84
 
77
-
78
85
  def self.parse_ticket_name(name)
79
86
  epoch, title, rand = name.split('_')
80
87
  title = title.gsub('-', ' ')
@@ -144,6 +151,89 @@ module TicGitNG
144
151
  base.git.add File.join(ticket_name, t)
145
152
  base.git.commit("added comment to ticket #{ticket_name}")
146
153
  end
154
+ @comments << TicGitNG::Comment.new( comment, email )
155
+ self
156
+ end
157
+
158
+ def add_attach( base, filename, time=nil )
159
+ filename=File.expand_path(filename)
160
+ #FIXME Refactor -- Attachment.new should be called from Ticket.rb
161
+ # -- Attachment filename creation should be handled
162
+ # by the Attachment.rb code
163
+ base.in_branch do |wd|
164
+ attachments << (a=TicGitNG::Attachment.create( filename, self, time))
165
+ base.git.add File.join( ticket_name, a.filename )
166
+ base.git.commit("added attachment #{File.basename(a.filename)} to ticket #{ticket_name}")
167
+ end
168
+ if attachments.class!=NilClass and attachments.size > 1
169
+ @attachments=attachments.sort {|a1,a2| a1.added <=> a2.added }
170
+ end
171
+ self
172
+ end
173
+
174
+ #file_id can be one of:
175
+ # - An index number of the attachment (1,2,3,...)
176
+ # - A filename (fubar.jpg)
177
+ # - nil (nil) means use the last attachment
178
+ #
179
+ #if new_filename is nil, use existing filename
180
+ def get_attach file_id=nil, new_filename=nil
181
+ attachment=nil
182
+ pwd=Dir.pwd
183
+ base.in_branch do |wd|
184
+ if file_id.to_i==0 and (file_id=="0" or file_id.class==Fixnum)
185
+ if !attachments[file_id.to_i].nil?
186
+ attachment= attachments[0]
187
+ else
188
+ puts "No attachments match file id #{file_id}"
189
+ exit 1
190
+ end
191
+ elsif file_id.to_i > 0
192
+ if !attachments[file_id.to_i].nil?
193
+ attachment= attachments[file_id.to_i]
194
+ else
195
+ puts "No attachments match file id #{file_id}"
196
+ exit 1
197
+ end
198
+ else
199
+ #find attachment by filename
200
+ attachments.each {|a|
201
+ attachment=a if a.attachment_name==file_id
202
+ }
203
+ if attachment.nil?
204
+ puts "No attachments match filename #{file_id}"
205
+ exit 1
206
+ end
207
+ end
208
+
209
+ if !new_filename
210
+ #if no filename is specified...
211
+ filename= attachment.attachment_name
212
+ else
213
+ #if there is a new_filename given
214
+ if File.exist?( new_filename ) and File.directory?( new_filename )
215
+ #if it is a directory, not a filename
216
+ filename= File.join(
217
+ new_filename,
218
+ File.basename(attachment.attachment_name)
219
+ )
220
+ else
221
+ #if it is a filename, not a dir
222
+ filename= new_filename
223
+ end
224
+ end
225
+
226
+ unless File.exist?( File.dirname(filename) )
227
+ FileUtils.mkdir_p( File.dirname(filename) )
228
+ end
229
+ #save attachment [as new_filename]
230
+ t=File.join( ticket_name, attachment.filename )
231
+ unless filename[/^\//]
232
+ filename=File.join( pwd, filename )
233
+ end
234
+ FileUtils.cp( t, filename )
235
+ end
236
+ self
147
237
  end
148
238
 
149
239
  def change_state(new_state)
@@ -159,6 +249,8 @@ module TicGitNG
159
249
  base.git.add File.join(ticket_name, t)
160
250
  base.git.commit("added state (#{new_state}) to ticket #{ticket_name}")
161
251
  end
252
+ @state=new_state
253
+ self
162
254
  end
163
255
 
164
256
  def change_assigned(new_assigned)
@@ -175,6 +267,8 @@ module TicGitNG
175
267
  base.git.add File.join(ticket_name,t)
176
268
  base.git.commit("assigned #{new_assigned} to ticket #{ticket_name}")
177
269
  end
270
+ @assigned=new_assigned
271
+ self
178
272
  end
179
273
 
180
274
  def change_points(new_points)
@@ -187,6 +281,8 @@ module TicGitNG
187
281
  base.git.add File.join(ticket_name, 'POINTS')
188
282
  base.git.commit("set points to #{new_points} for ticket #{ticket_name}")
189
283
  end
284
+ @points=new_points
285
+ self
190
286
  end
191
287
 
192
288
  def add_tag(tag)
@@ -214,6 +310,10 @@ module TicGitNG
214
310
  base.git.commit("added tags (#{tag}) to ticket #{ticket_name}")
215
311
  end
216
312
  end
313
+ tags.each {|tag|
314
+ @tags << tag
315
+ }
316
+ self
217
317
  end
218
318
 
219
319
  def remove_tag(tag)
@@ -232,6 +332,8 @@ module TicGitNG
232
332
  base.git.commit("removed tags (#{tag}) from ticket #{ticket_name}")
233
333
  end
234
334
  end
335
+ @tags.delete_if {|t| t==tag }
336
+ self
235
337
  end
236
338
 
237
339
  def path
@@ -250,10 +352,29 @@ module TicGitNG
250
352
  assigned.split('@').first rescue ''
251
353
  end
252
354
 
253
- def self.create_ticket_name(title)
254
- [Time.now.to_i.to_s, Ticket.clean_string(title), rand(999).to_i.to_s].join('_')
355
+ def self.create_ticket_name(title, time=nil)
356
+ [time.nil? ? Time.now.to_i.to_s : time, Ticket.clean_string(title), rand(999).to_i.to_s].join('_')
255
357
  end
256
358
 
257
-
359
+ def create_attachment_name( attachment_name, time=nil )
360
+ raise ArgumentError, "create_attachment_name( ) only takes a string" unless attachment_name.class==String
361
+ if time
362
+ if time.to_i == 0
363
+ raise ArgumentError, "argument 'time' is not valid" unless time.class==Fixnum
364
+ else
365
+ time=time.to_i
366
+ end
367
+ end
368
+ time or time=Time.now.to_i
369
+ time.to_s+'_'+email+'_'+File.basename( attachment_name )
370
+ end
371
+ def ==(ticket2)
372
+ self.instance_variables.each {|instance_var|
373
+ unless send( instance_var.gsub('@','').to_sym ) == ticket2.instance_eval {send(instance_var.gsub('@','').to_sym)}
374
+ return false
375
+ end
376
+ }
377
+ return true
378
+ end
258
379
  end
259
380
  end
@@ -1,3 +1,3 @@
1
1
  module TicGitNG
2
- VERSION = '1.0.2.14'
2
+ VERSION = '1.0.2.15'
3
3
  end
data/lib/ticgit-ng.rb CHANGED
@@ -4,6 +4,7 @@ require 'optparse'
4
4
  require 'ostruct'
5
5
  require 'set'
6
6
  require 'yaml'
7
+ require 'pp'
7
8
 
8
9
  # Add the directory containing this file to the start of the load path if it
9
10
  # isn't there already.
@@ -15,12 +16,12 @@ require 'rubygems'
15
16
  require 'git'
16
17
 
17
18
  #Only redefine if we are not using 1.9
18
- unless Config::CONFIG["ruby_version"][/^\d\.9/]
19
+ unless (defined?(RbConfig) ? RbConfig : Config)::CONFIG["ruby_version"][/^\d\.9/]
19
20
  # FIXME: Monkeypatch git until fixed upstream
20
21
  module Git
21
22
  class Lib
22
23
  def config_get(name)
23
- do_get = lambda do |name|
24
+ do_get = lambda do |x|
24
25
  command('config', ['--get', name])
25
26
  end
26
27
  if @git_dir
@@ -35,6 +36,7 @@ end
35
36
 
36
37
  require 'ticgit-ng/base'
37
38
  require 'ticgit-ng/cli'
39
+ require 'ticgit-ng/attachment'
38
40
  module TicGitNG
39
41
  autoload :VERSION, 'ticgit-ng/version'
40
42
  autoload :Comment, 'ticgit-ng/comment'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: TicGit-ng
3
3
  version: !ruby/object:Gem::Version
4
- hash: 75
4
+ hash: 73
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
9
  - 2
10
- - 14
11
- version: 1.0.2.14
10
+ - 15
11
+ version: 1.0.2.15
12
12
  platform: ruby
13
13
  authors:
14
14
  - Scott Chacon
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2012-03-06 00:00:00 Z
20
+ date: 2012-08-12 00:00:00 Z
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
23
23
  name: git
@@ -58,28 +58,31 @@ extensions: []
58
58
  extra_rdoc_files: []
59
59
 
60
60
  files:
61
- - bin/ti
62
61
  - bin/ticgitweb
62
+ - bin/ti
63
63
  - lib/ticgit-ng.rb
64
- - lib/ticgit-ng/comment.rb
65
64
  - lib/ticgit-ng/cli.rb
66
- - lib/ticgit-ng/command/new.rb
67
- - lib/ticgit-ng/command/comment.rb
68
- - lib/ticgit-ng/command/show.rb
69
- - lib/ticgit-ng/command/init.rb
65
+ - lib/ticgit-ng/attachment.rb
66
+ - lib/ticgit-ng/command/milestone.rb
67
+ - lib/ticgit-ng/command/checkout.rb
70
68
  - lib/ticgit-ng/command/state.rb
71
69
  - lib/ticgit-ng/command/list.rb
70
+ - lib/ticgit-ng/command/assign.rb
72
71
  - lib/ticgit-ng/command/sync.rb
73
- - lib/ticgit-ng/command/recent.rb
72
+ - lib/ticgit-ng/command/comment.rb
74
73
  - lib/ticgit-ng/command/points.rb
75
- - lib/ticgit-ng/command/assign.rb
76
- - lib/ticgit-ng/command/milestone.rb
77
74
  - lib/ticgit-ng/command/tag.rb
78
- - lib/ticgit-ng/command/checkout.rb
75
+ - lib/ticgit-ng/command/show.rb
76
+ - lib/ticgit-ng/command/help.rb
77
+ - lib/ticgit-ng/command/recent.rb
78
+ - lib/ticgit-ng/command/attach.rb
79
+ - lib/ticgit-ng/command/init.rb
80
+ - lib/ticgit-ng/command/new.rb
81
+ - lib/ticgit-ng/comment.rb
79
82
  - lib/ticgit-ng/version.rb
83
+ - lib/ticgit-ng/ticket.rb
80
84
  - lib/ticgit-ng/command.rb
81
85
  - lib/ticgit-ng/base.rb
82
- - lib/ticgit-ng/ticket.rb
83
86
  - LICENSE_MIT
84
87
  - LICENSE_GPL
85
88
  - README.mkd
@@ -112,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
115
  requirements: []
113
116
 
114
117
  rubyforge_project: ticgit-ng
115
- rubygems_version: 1.7.2
118
+ rubygems_version: 1.8.15
116
119
  signing_key:
117
120
  specification_version: 3
118
121
  summary: Git based distributed ticketing system