TicGit-ng 1.0.2.14 → 1.0.2.15

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