git-commit-notifier 0.8.0 → 0.8.1

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.
Files changed (38) hide show
  1. data/LICENSE +1 -1
  2. data/README.textile +20 -5
  3. data/Rakefile +40 -20
  4. data/VERSION +1 -1
  5. data/bin/git-commit-notifier +8 -1
  6. data/config/git-notifier-config.yml.sample +41 -15
  7. data/git-commit-notifier.gemspec +50 -24
  8. data/lib/commit_hook.rb +104 -74
  9. data/lib/diff_to_html.rb +120 -52
  10. data/lib/emailer.rb +43 -22
  11. data/lib/git.rb +36 -26
  12. data/lib/logger.rb +48 -0
  13. data/lib/result_processor.rb +9 -5
  14. data/{test → spec}/fixtures/existing_file_one_line.txt +0 -0
  15. data/{test → spec}/fixtures/git-notifier-group-email-by-push.yml +2 -0
  16. data/{test → spec}/fixtures/git-notifier-ignore-merge.yml +0 -0
  17. data/{test → spec}/fixtures/git-notifier-with-merge.yml +0 -0
  18. data/{test → spec}/fixtures/git_log +0 -0
  19. data/{test → spec}/fixtures/git_show_055850e7d925110322b8db4e17c3b840d76e144c +0 -0
  20. data/{test → spec}/fixtures/git_show_51b986619d88f7ba98be7d271188785cbbb541a0 +0 -0
  21. data/{test → spec}/fixtures/git_show_a4629e707d80a5769f7a71ca6ed9471015e14dc9 +0 -0
  22. data/{test → spec}/fixtures/git_show_dce6ade4cdc2833b53bd600ef10f9bce83c7102d +0 -0
  23. data/{test → spec}/fixtures/git_show_e28ad77bba0574241e6eb64dfd0c1291b221effe +0 -0
  24. data/spec/fixtures/git_show_ff037a73fc1094455e7bbf506171a3f3cf873ae6 +18 -0
  25. data/{test → spec}/fixtures/new_file_one_line.txt +0 -0
  26. data/spec/lib/commit_hook_spec.rb +88 -0
  27. data/spec/lib/diff_to_html_spec.rb +168 -0
  28. data/spec/lib/emailer_spec.rb +102 -0
  29. data/spec/lib/git_spec.rb +93 -0
  30. data/spec/lib/logger_spec.rb +63 -0
  31. data/spec/lib/result_processor_spec.rb +102 -0
  32. data/{test/test_helper.rb → spec/spec_helper.rb} +14 -12
  33. data/template/email.html.erb +2 -2
  34. data/template/styles.css +2 -1
  35. metadata +110 -31
  36. data/test/unit/test_commit_hook.rb +0 -43
  37. data/test/unit/test_diff_to_html.rb +0 -160
  38. data/test/unit/test_result_processor.rb +0 -95
data/lib/diff_to_html.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'diff/lcs'
3
+ require 'digest/sha1'
4
+
3
5
  require File.dirname(__FILE__) + '/result_processor'
4
6
 
5
7
  def escape_content(s)
@@ -10,16 +12,23 @@ class DiffToHtml
10
12
  INTEGRATION_MAP = {
11
13
  :mediawiki => { :search_for => /\[\[([^\[\]]+)\]\]/, :replace_with => '#{url}/\1' },
12
14
  :redmine => { :search_for => /\b(?:refs|fixes)\s*\#(\d+)/i, :replace_with => '#{url}/issues/show/\1' },
13
- :bugzilla => { :search_for => /\bBUG\s*(\d+)/i, :replace_with => '#{url}/show_bug.cgi?id=\1' }
15
+ :bugzilla => { :search_for => /\bBUG\s*(\d+)/i, :replace_with => '#{url}/show_bug.cgi?id=\1' },
16
+ :fogbugz => { :search_for => /\bbugzid:\s*(\d+)/i, :replace_with => '#{url}\1' }
14
17
  }.freeze
15
-
18
+ MAX_COMMITS_PER_ACTION = 10000
19
+ HANDLED_COMMITS_FILE = 'previously.txt'.freeze
20
+ NEW_HANDLED_COMMITS_FILE = 'previously_new.txt'.freeze
21
+
16
22
  attr_accessor :file_prefix, :current_file_name
17
- attr_reader :result
23
+ attr_reader :result, :branch
18
24
 
19
25
  def initialize(previous_dir = nil, config = nil)
20
26
  @previous_dir = previous_dir
21
27
  @config = config || {}
22
28
  @lines_added = 0
29
+ @file_added = false
30
+ @file_removed = false
31
+ @binary = false
23
32
  end
24
33
 
25
34
  def range_info(range)
@@ -44,9 +53,17 @@ class DiffToHtml
44
53
  end
45
54
  end
46
55
 
56
+ def lines_per_diff
57
+ @config['lines_per_diff']
58
+ end
59
+
60
+ def add_separator
61
+ return if lines_per_diff && @lines_added >= lines_per_diff
62
+ @diff_result << '<tr class="sep"><td class="sep" colspan="3" title="Unchanged content skipped between diff. blocks">&hellip;</td></tr>'
63
+ end
64
+
47
65
  def add_line_to_result(line, escape)
48
66
  @lines_added += 1
49
- lines_per_diff = @config['lines_per_diff']
50
67
  if lines_per_diff
51
68
  if @lines_added == lines_per_diff
52
69
  @diff_result << '<tr><td colspan="3">Diff too large and stripped&hellip;</td></tr>'
@@ -62,7 +79,7 @@ class DiffToHtml
62
79
  end
63
80
 
64
81
  def extract_block_content(block)
65
- block.collect { |b| b[:content]}.join("\n")
82
+ block.collect { |b| b[:content] }.join("\n")
66
83
  end
67
84
 
68
85
  def lcs_diff(removals, additions)
@@ -96,22 +113,22 @@ class DiffToHtml
96
113
  end
97
114
 
98
115
  def tokenize_string(str)
99
- # tokenize by non-alphanumerical characters
116
+ # tokenize by non-word characters
100
117
  tokens = []
101
118
  token = ''
102
- str = str.split('')
103
- str.each_with_index do |char, i|
104
- alphanumeric = !char.match(/[a-zA-Z0-9]/).nil?
105
- if !alphanumeric || str.size == i+1
106
- token += char if alphanumeric
107
- tokens << token unless token.empty?
108
- tokens << char unless alphanumeric
109
- token = ''
119
+ str.scan(/./mu) do |ch|
120
+ if ch =~ /[^\W_]/u
121
+ token += ch
110
122
  else
111
- token += char
123
+ unless token.empty?
124
+ tokens << token
125
+ token = ''
126
+ end
127
+ tokens << ch
112
128
  end
113
129
  end
114
- return tokens
130
+ tokens << token unless token.empty?
131
+ tokens
115
132
  end
116
133
 
117
134
  def operation_description
@@ -123,19 +140,31 @@ class DiffToHtml
123
140
  else
124
141
  op = "Changed"
125
142
  end
126
-
143
+
127
144
  file_name = @current_file_name
128
-
145
+
129
146
  if (@config["link_files"] && @config["link_files"] == "gitweb" && @config["gitweb"])
130
147
  file_name = "<a href='#{@config['gitweb']['path']}?p=#{@config['gitweb']['project']};f=#{file_name};hb=HEAD'>#{file_name}</a>"
131
148
  elsif (@config["link_files"] && @config["link_files"] == "gitorious" && @config["gitorious"])
132
- file_name = "<a href='#{@config['gitorious']['path']}/#{@config['gitorious']['project']}/#{@config['gitorious']['repository']}/blobs/HEAD/#{file_name}'>#{file_name}</a>"
149
+ file_name = "<a href='#{@config['gitorious']['path']}/#{@config['gitorious']['project']}/#{@config['gitorious']['repository']}/blobs/#{branch}/#{file_name}'>#{file_name}</a>"
150
+ elsif (@config["link_files"] && @config["link_files"] == "cgit" && @config["cgit"])
151
+ file_name = "<a href='#{@config['cgit']['path']}/#{@config['cgit']['project']}/tree/#{file_name}'>#{file_name}</a>"
133
152
  end
134
-
153
+
135
154
  header = "#{op} #{binary}file #{file_name}"
136
155
  "<h2>#{header}</h2>\n"
137
156
  end
138
157
 
158
+ def lines_are_sequential?(first, second)
159
+ result = false
160
+ [:added, :removed].each do |side|
161
+ if !first[side].nil? && !second[side].nil?
162
+ result = true if first[side] == (second[side] - 1)
163
+ end
164
+ end
165
+ result
166
+ end
167
+
139
168
  def add_changes_to_result
140
169
  return if @current_file_name.nil?
141
170
  @diff_result << operation_description
@@ -143,12 +172,10 @@ class DiffToHtml
143
172
  unless @diff_lines.empty?
144
173
  removals = []
145
174
  additions = []
146
- @diff_lines.each do |line|
147
- if [:addition, :removal].include?(line[:op])
148
- removals << line if line[:op] == :removal
149
- additions << line if line[:op] == :addition
150
- end
151
- if line[:op] == :unchanged || line == @diff_lines.last # unchanged line or end of block, add prev lines to result
175
+ @diff_lines.each_with_index do |line, index|
176
+ removals << line if line[:op] == :removal
177
+ additions << line if line[:op] == :addition
178
+ if line[:op] == :unchanged || index == @diff_lines.size - 1 # unchanged line or end of block, add prev lines to result
152
179
  if removals.size > 0 && additions.size > 0 # block of removed and added lines - perform intelligent diff
153
180
  add_block_to_results(lcs_diff(removals, additions), escape = false)
154
181
  else # some lines removed or added - no need to perform intelligent diff
@@ -156,6 +183,10 @@ class DiffToHtml
156
183
  end
157
184
  removals = []
158
185
  additions = []
186
+ if index > 0 && index != @diff_lines.size - 1
187
+ prev_line = @diff_lines[index - 1]
188
+ add_separator unless lines_are_sequential?(prev_line, line)
189
+ end
159
190
  add_line_to_result(line, escape = true) if line[:op] == :unchanged
160
191
  end
161
192
  end
@@ -179,8 +210,7 @@ class DiffToHtml
179
210
  @current_file_name = nil
180
211
 
181
212
  content.split("\n").each do |line|
182
- if line =~ /^diff\s\-\-git/
183
- line.match(/diff --git a\/(.*)\sb\//)
213
+ if line =~ /^diff\s\-\-git\sa\/(.*)\sb\//
184
214
  file_name = $1
185
215
  add_changes_to_result
186
216
  @current_file_name = file_name
@@ -200,7 +230,7 @@ class DiffToHtml
200
230
  elsif op == '+'
201
231
  @diff_lines << { :added => @right_ln, :removed => nil, :op => :addition, :content => line[1..-1] }
202
232
  @right_ln += 1
203
- else @right_ln
233
+ else
204
234
  @diff_lines << { :added => @right_ln, :removed => @left_ln, :op => :unchanged, :content => line }
205
235
  @right_ln += 1
206
236
  @left_ln += 1
@@ -229,7 +259,7 @@ class DiffToHtml
229
259
  diff = []
230
260
  diff_found = false
231
261
  content.split("\n").each do |line|
232
- diff_found = true if line =~ /^diff \-\-git/
262
+ diff_found = true if line =~ /^diff\s\-\-git/
233
263
  next unless diff_found
234
264
  diff << line
235
265
  end
@@ -258,15 +288,14 @@ class DiffToHtml
258
288
  end
259
289
 
260
290
  def message_array_as_html(message)
261
- message_map(message.collect { |m| CGI.escapeHTML(m)}.join("<br />"))
291
+ message_map(message.collect { |m| CGI.escapeHTML(m) }.join('<br />'))
262
292
  end
263
293
 
264
294
  def author_name_and_email(info)
265
295
  # input string format: "autor name <author@email.net>"
266
- result = info.scan(/(.*)\s<(.*)>/)[0]
267
- return result if result.is_a?(Array) && result.size == 2 # normal operation
296
+ return [$1, $2] if info =~ /^([^\<]+)\s+\<\s*(.*)\s*\>\s*$/ # normal operation
268
297
  # incomplete author info - return it as author name
269
- return [info, ''] if result.nil?
298
+ [info, '']
270
299
  end
271
300
 
272
301
  def first_sentence(message_array)
@@ -275,7 +304,48 @@ class DiffToHtml
275
304
  msg
276
305
  end
277
306
 
307
+ def unique_commits_per_branch?
308
+ !!@config['unique_commits_per_branch']
309
+ end
310
+
311
+ def get_previous_commits(previous_file)
312
+ previous_list = []
313
+ if File.exists?(previous_file)
314
+ lines = IO.read(previous_file)
315
+ lines = lines.lines if lines.respond_to?(:lines) # Ruby 1.9 tweak
316
+ previous_list = lines.to_a.map { |s| s.chomp }.compact.uniq
317
+ lines = nil
318
+ end
319
+ previous_list
320
+ end
321
+
322
+ def check_handled_commits(commits, branch)
323
+ previous_dir = (!@previous_dir.nil? && File.exists?(@previous_dir)) ? @previous_dir : '/tmp'
324
+ prefix = unique_commits_per_branch? ? "#{Digest::SHA1.hexdigest(branch)}." : ''
325
+ previous_name = "#{prefix}#{HANDLED_COMMITS_FILE}"
326
+ new_name = "#{prefix}#{NEW_HANDLED_COMMITS_FILE}"
327
+ previous_file = File.join(previous_dir, previous_name)
328
+ new_file = File.join(previous_dir, new_name)
329
+
330
+ previous_list = get_previous_commits(previous_file)
331
+
332
+ commits.reject! {|c| c.find { |sha| previous_list.include?(sha) } }
333
+
334
+ # if commit list empty there is no need to override list of handled commits
335
+ flatten_commits = commits.flatten
336
+ unless flatten_commits.empty?
337
+ current_list = (previous_list + flatten_commits).last(MAX_COMMITS_PER_ACTION)
338
+
339
+ # use new file, unlink and rename to make it more atomic
340
+ File.open(new_file, 'w') { |f| f << current_list.join("\n") }
341
+ File.unlink(previous_file) if File.exists?(previous_file)
342
+ File.rename(new_file, previous_file)
343
+ end
344
+ commits
345
+ end
346
+
278
347
  def diff_between_revisions(rev1, rev2, repo, branch)
348
+ @branch = branch
279
349
  @result = []
280
350
  if rev1 == rev2
281
351
  commits = [rev1]
@@ -287,42 +357,36 @@ class DiffToHtml
287
357
  commits = []
288
358
  else
289
359
  log = Git.log(rev1, rev2)
290
- commits = log.scan(/^commit\s([a-f0-9]+)/).map{|match| match[0]}
360
+ commits = log.scan(/^commit\s([a-f0-9]+)/).map { |a| a.first }
291
361
  end
292
362
 
293
- if defined?(Test::Unit)
294
- previous_list = []
295
- else
296
- previous_file = (!@previous_dir.nil? && File.exists?(@previous_dir)) ? File.join(@previous_dir, "previously.txt") : "/tmp/previously.txt"
297
- previous_list = (File.read(previous_file).to_a.map {|sha| sha.chomp!} if File.exist?(previous_file)) || []
298
- end
299
-
300
- commits.reject!{|c| c.find{|sha| previous_list.include?(sha)} }
301
- current_list = (previous_list + commits.flatten).last(1000)
302
- File.open(previous_file, "w"){|f| f << current_list.join("\n") } unless current_list.empty? || defined?(Test::Unit)
363
+ commits = check_handled_commits(commits, branch)
303
364
 
304
365
  commits.each_with_index do |commit, i|
305
-
366
+
306
367
  raw_diff = Git.show(commit)
307
368
  raise "git show output is empty" if raw_diff.empty?
308
- @last_raw = raw_diff
309
369
 
310
370
  commit_info = extract_commit_info_from_git_show_output(raw_diff)
311
371
 
312
372
  title = "<div class=\"title\">"
313
373
  title += "<strong>Message:</strong> #{message_array_as_html commit_info[:message]}<br />\n"
314
374
  title += "<strong>Commit:</strong> "
315
-
375
+
316
376
  if (@config["link_files"] && @config["link_files"] == "gitweb" && @config["gitweb"])
317
377
  title += "<a href='#{@config['gitweb']['path']}?p=#{@config['gitweb']['project']};a=commitdiff;h=#{commit_info[:commit]}'>#{commit_info[:commit]}</a>"
318
378
  elsif (@config["link_files"] && @config["link_files"] == "gitorious" && @config["gitorious"])
319
379
  title += "<a href='#{@config['gitorious']['path']}/#{@config['gitorious']['project']}/#{@config['gitorious']['repository']}/commit/#{commit_info[:commit]}'>#{commit_info[:commit]}</a>"
380
+ elsif (@config["link_files"] && @config["link_files"] == "trac" && @config["trac"])
381
+ title += "<a href='#{@config['trac']['path']}/#{commit_info[:commit]}'>#{commit_info[:commit]}</a>"
382
+ elsif (@config["link_files"] && @config["link_files"] == "cgit" && @config["cgit"])
383
+ title += "<a href='#{@config['cgit']['path']}/#{@config['cgit']['project']}/commit/?id=#{commit_info[:commit]}'>#{commit_info[:commit]}</a>"
320
384
  else
321
385
  title += " #{commit_info[:commit]}"
322
386
  end
323
-
387
+
324
388
  title += "<br />\n"
325
-
389
+
326
390
  title += "<strong>Branch:</strong> #{branch}\n<br />" unless branch =~ /\/head/
327
391
  title += "<strong>Date:</strong> #{CGI.escapeHTML commit_info[:date]}\n<br />"
328
392
  title += "<strong>Author:</strong> #{CGI.escapeHTML(commit_info[:author])} &lt;#{commit_info[:email]}&gt;\n</div>"
@@ -343,14 +407,14 @@ class DiffToHtml
343
407
  end
344
408
 
345
409
  def message_map(message)
346
- if @config.include?('message_integration')
410
+ if @config['message_integration'].respond_to?(:each_pair)
347
411
  @config['message_integration'].each_pair do |pm, url|
348
412
  pm_def = DiffToHtml::INTEGRATION_MAP[pm.to_sym] or next
349
413
  replace_with = pm_def[:replace_with].gsub('#{url}', url)
350
414
  message_replace!(message, pm_def[:search_for], replace_with)
351
415
  end
352
416
  end
353
- if @config.include?('message_map')
417
+ if @config['message_map'].respond_to?(:each_pair)
354
418
  @config['message_map'].each_pair do |search_for, replace_with|
355
419
  message_replace!(message, Regexp.new(search_for), replace_with)
356
420
  end
@@ -379,3 +443,7 @@ class DiffCallback
379
443
  end
380
444
 
381
445
  end
446
+
447
+ __END__
448
+
449
+ vim: tabstop=2:expandtab:shiftwidth=2
data/lib/emailer.rb CHANGED
@@ -1,23 +1,42 @@
1
- require 'yaml'
2
- require 'erb'
3
1
  require 'tamtam'
4
2
 
5
3
  class Emailer
4
+ DEFAULT_STYLESHEET_PATH = File.join(File.dirname(__FILE__), '/../template/styles.css').freeze
5
+ TEMPLATE = File.join(File.dirname(__FILE__), '/../template/email.html.erb').freeze
6
+ PARAMETERS = %w[project_path recipient from_address from_alias subject text_message html_message ref_name old_rev new_rev].freeze
6
7
 
7
- def initialize(config, project_path, recipient, from_address, from_alias, subject, text_message, html_diff, old_rev, new_rev, ref_name)
8
+ attr_reader :config
9
+
10
+ def initialize(config, options = {})
8
11
  @config = config || {}
9
- @project_path = project_path
10
- @recipient = recipient
11
- @from_address = from_address
12
- @from_alias = from_alias
13
- @subject = subject
14
- @text_message = text_message
15
- @ref_name = ref_name
16
- @old_rev = old_rev
17
- @new_rev = new_rev
18
-
19
- template = File.join(File.dirname(__FILE__), '/../template/email.html.erb')
20
- @html_message = TamTam.inline(:document => ERB.new(File.read(template)).result(binding))
12
+ PARAMETERS.each do |name|
13
+ instance_variable_set("@#{name}".to_sym, options[name.to_sym])
14
+ end
15
+ end
16
+
17
+ class << self
18
+ def reset_template
19
+ @template = nil
20
+ end
21
+
22
+ def template
23
+ unless @template
24
+ source = IO.read(TEMPLATE)
25
+ begin
26
+ require 'erubis'
27
+ @template = Erubis::Eruby.new(source)
28
+ rescue LoadError
29
+ require 'erb'
30
+ @template = ERB.new(source)
31
+ end
32
+ end
33
+ @template
34
+ end
35
+ end
36
+
37
+ def generate_message
38
+ # TODO: do not use @html, simply return value
39
+ @html = TamTam.inline(:document => Emailer.template.result(binding))
21
40
  end
22
41
 
23
42
  def boundary
@@ -28,8 +47,8 @@ class Emailer
28
47
  end
29
48
 
30
49
  def stylesheet_string
31
- stylesheet = File.join(File.dirname(__FILE__), '/../template/styles.css')
32
- File.read(stylesheet)
50
+ stylesheet = config['stylesheet'] || DEFAULT_STYLESHEET_PATH
51
+ IO.read(stylesheet)
33
52
  end
34
53
 
35
54
  def perform_delivery_smtp(content, smtp_settings)
@@ -38,12 +57,12 @@ class Emailer
38
57
  val = smtp_settings[key].to_s.empty? ? nil : smtp_settings[key]
39
58
  settings.merge!({ key => val})
40
59
  end
41
-
60
+
42
61
  Net::SMTP.start(settings['address'], settings['port'], settings['domain'],
43
62
  settings['user_name'], settings['password'], settings['authentication']) do |smtp|
44
63
 
45
64
  smtp.enable_tls if settings['enable_tls']
46
-
65
+
47
66
  smtp.open_message_stream(@from_address, [@recipient]) do |f|
48
67
  content.each do |line|
49
68
  f.puts line
@@ -63,13 +82,15 @@ class Emailer
63
82
  f.flush
64
83
  end
65
84
  end
66
-
85
+
67
86
  def send
87
+ generate_message
68
88
  from = quote_if_necessary(@from_alias.empty? ? @from_address : "#{@from_alias} <#{@from_address}>", 'utf-8')
69
89
  content = ["From: #{from}",
70
90
  "Reply-To: #{from}",
71
91
  "To: #{quote_if_necessary(@recipient, 'utf-8')}",
72
92
  "Subject: #{quote_if_necessary(@subject, 'utf-8')}",
93
+ "X-Mailer: git-commit-notifier",
73
94
  "X-Git-Refname: #{@ref_name}",
74
95
  "X-Git-Oldrev: #{@old_rev}",
75
96
  "X-Git-Newrev: #{@new_rev}",
@@ -84,7 +105,7 @@ class Emailer
84
105
  "Content-Type: text/html; charset=utf-8",
85
106
  "Content-Transfer-Encoding: 8bit",
86
107
  "Content-Disposition: inline\n\n\n",
87
- @html_message,
108
+ @html,
88
109
  "--#{boundary}--"]
89
110
 
90
111
  if @recipient.empty?
@@ -92,7 +113,7 @@ class Emailer
92
113
  return
93
114
  end
94
115
 
95
- if @config['delivery_method'] == 'smtp'
116
+ if config['delivery_method'] == 'smtp'
96
117
  perform_delivery_smtp(content, @config['smtp_server'])
97
118
  else
98
119
  perform_delivery_sendmail(content, @config['sendmail_options'])
data/lib/git.rb CHANGED
@@ -1,35 +1,45 @@
1
1
  class Git
2
- def self.show(rev)
3
- `git show #{rev.strip} -w`
4
- end
2
+ class << self
3
+ def from_shell(cmd)
4
+ `#{cmd}`
5
+ end
5
6
 
6
- def self.log(rev1, rev2)
7
- `git log #{rev1}..#{rev2}`.strip
8
- end
7
+ def show(rev)
8
+ from_shell("git show #{rev.strip} -w")
9
+ end
9
10
 
10
- def self.branch_commits(treeish)
11
- args = Git.branch_heads - [Git.branch_head(treeish)]
12
- args.map! {|tree| "^#{tree}"}
13
- args << treeish
14
- `git rev-list #{args.join(' ')}`.to_a.map{|commit| commit.chomp}
15
- end
11
+ def log(rev1, rev2)
12
+ from_shell("git log #{rev1}..#{rev2}").strip
13
+ end
16
14
 
17
- def self.branch_heads
18
- `git rev-parse --branches`.to_a.map{|head| head.chomp}
19
- end
15
+ def branch_commits(treeish)
16
+ args = Git.branch_heads - [ Git.branch_head(treeish) ]
17
+ args.map! { |tree| "^#{tree}" }
18
+ args << treeish
19
+ lines = from_shell("git rev-list #{args.join(' ')}")
20
+ lines = lines.lines if lines.respond_to?(:lines)
21
+ lines.to_a.map { |commit| commit.chomp }
22
+ end
20
23
 
21
- def self.branch_head(treeish)
22
- `git rev-parse #{treeish}`.strip
23
- end
24
+ def branch_heads
25
+ lines = from_shell("git rev-parse --branches")
26
+ lines = lines.lines if lines.respond_to?(:lines)
27
+ lines.to_a.map { |head| head.chomp }
28
+ end
24
29
 
25
- def self.repo_name
26
- git_prefix = `git config hooks.emailprefix`.strip
27
- return git_prefix unless git_prefix.empty?
28
- dir_name = `pwd`.chomp.split("/").last.gsub(/\.git$/, '')
29
- return "#{dir_name}"
30
- end
30
+ def branch_head(treeish)
31
+ from_shell("git rev-parse #{treeish}").strip
32
+ end
31
33
 
32
- def self.mailing_list_address
33
- `git config hooks.mailinglist`.strip
34
+ def repo_name
35
+ git_prefix = from_shell("git config hooks.emailprefix").strip
36
+ return git_prefix unless git_prefix.empty?
37
+ Dir.pwd.split("/").last.sub(/\.git$/, '')
38
+ end
39
+
40
+ def mailing_list_address
41
+ from_shell("git config hooks.mailinglist").strip
42
+ end
34
43
  end
35
44
  end
45
+