git-commit-notifier 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/emailer.rb ADDED
@@ -0,0 +1,102 @@
1
+ require 'yaml'
2
+ require 'erb'
3
+
4
+ class Emailer
5
+
6
+ def initialize(config, project_path, recipient, from_address, from_alias, subject, text_message, html_diff, old_rev, new_rev, ref_name)
7
+ @config = config
8
+ @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 = ERB.new(File.read(template)).result(binding)
21
+ end
22
+
23
+ def boundary
24
+ return @boundary if @boundary
25
+ srand
26
+ seed = "#{rand(10000)}#{Time.now}"
27
+ @boundary = Digest::SHA1.hexdigest(seed)
28
+ end
29
+
30
+ def stylesheet_string
31
+ stylesheet = File.join(File.dirname(__FILE__), '/../template/styles.css')
32
+ File.read(stylesheet)
33
+ end
34
+
35
+ def perform_delivery_smtp(content, smtp_settings)
36
+ settings = { }
37
+ %w(address port domain user_name password authentication enable_tls).each do |key|
38
+ val = smtp_settings[key].to_s.empty? ? nil : smtp_settings[key]
39
+ settings.merge!({ key => val})
40
+ end
41
+
42
+ Net::SMTP.start(settings['address'], settings['port'], settings['domain'],
43
+ settings['user_name'], settings['password'], settings['authentication']) do |smtp|
44
+
45
+ smtp.enable_tls if settings['enable_tls']
46
+
47
+ smtp.open_message_stream(@from_address, [@recipient]) do |f|
48
+ content.each do |line|
49
+ f.puts line
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ def perform_delivery_sendmail(content, options = nil)
56
+ sendmail_settings = {
57
+ 'location' => "/usr/sbin/sendmail",
58
+ 'arguments' => "-i -t"
59
+ }.merge(options || {})
60
+ command = "#{sendmail_settings['location']} #{sendmail_settings['arguments']}"
61
+ IO.popen(command, "w+") do |f|
62
+ f.write(content.join("\n"))
63
+ f.flush
64
+ end
65
+ end
66
+
67
+ def send
68
+ from = @from_alias.empty? ? @from_address : "#{@from_alias} <#{@from_address}>"
69
+ content = ["From: #{from}",
70
+ "Reply-To: #{from}",
71
+ "To: #{@recipient}",
72
+ "Subject: #{@subject}",
73
+ "X-Git-Refname: #{@ref_name}",
74
+ "X-Git-Oldrev: #{@old_rev}",
75
+ "X-Git-Newrev: #{@new_rev}",
76
+ "Mime-Version: 1.0",
77
+ "Content-Type: multipart/alternative; boundary=#{boundary}\n\n\n",
78
+ "--#{boundary}",
79
+ "Content-Type: text/plain; charset=utf-8",
80
+ "Content-Transfer-Encoding: 8bit",
81
+ "Content-Disposition: inline\n\n\n",
82
+ @text_message,
83
+ "--#{boundary}",
84
+ "Content-Type: text/html; charset=utf-8",
85
+ "Content-Transfer-Encoding: 8bit",
86
+ "Content-Disposition: inline\n\n\n",
87
+ @html_message,
88
+ "--#{boundary}--"]
89
+
90
+ if @recipient.empty?
91
+ puts content.join("\n")
92
+ return
93
+ end
94
+
95
+ if @config['delivery_method'] == 'smtp'
96
+ perform_delivery_smtp(content, @config['smtp_server'])
97
+ else
98
+ perform_delivery_sendmail(content, @config['sendmail_options'])
99
+ end
100
+ end
101
+
102
+ end
data/lib/git.rb ADDED
@@ -0,0 +1,35 @@
1
+ class Git
2
+ def self.show(rev)
3
+ `git show #{rev.strip} -w`
4
+ end
5
+
6
+ def self.log(rev1, rev2)
7
+ `git log #{rev1}..#{rev2}`.strip
8
+ end
9
+
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
16
+
17
+ def self.branch_heads
18
+ `git rev-parse --branches`.to_a.map{|head| head.chomp}
19
+ end
20
+
21
+ def self.branch_head(treeish)
22
+ `git rev-parse #{treeish}`.strip
23
+ end
24
+
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
31
+
32
+ def self.mailing_list_address
33
+ `git config hooks.mailinglist`.strip
34
+ end
35
+ end
@@ -0,0 +1,122 @@
1
+ require 'cgi'
2
+
3
+ class ResultProcessor
4
+ # input (loaded in @diff) is an array having Hash elements:
5
+ # { :action => action, :token => string }
6
+ # action can be :discard_a, :discard_b or :match
7
+
8
+ # output: two formatted html strings, one for the removals and one for the additions
9
+
10
+ def results
11
+ close_tags # close last tag
12
+ [array_of_lines(@result[:removal]), array_of_lines(@result[:addition])]
13
+ end
14
+
15
+ private
16
+
17
+ def initialize(diff)
18
+ @diff = diff
19
+ init
20
+ filter_replaced_lines
21
+ process
22
+ end
23
+
24
+ def init
25
+ @result = { :addition => [], :removal => [] }
26
+ @tag_open = { :addition => false, :removal => false}
27
+ end
28
+
29
+ def process
30
+ @highlight = !@diff.select { |d| d[:action] == :match}.empty? # highlight only if block contains both matches and differences
31
+ @diff.each do |diff|
32
+ case diff[:action]
33
+ when :match
34
+ match(diff)
35
+ when :discard_a
36
+ discard_a(diff)
37
+ when :discard_b
38
+ discard_b(diff)
39
+ end
40
+ end
41
+ end
42
+
43
+ def discard_match(position, token)
44
+ # replace it with 2 changes
45
+ @diff[position][:action] = :discard_a
46
+ @diff.insert(position, { :action => :discard_b, :token => token} )
47
+ end
48
+
49
+ def length_in_chars(diff)
50
+ diff.inject(0) { |length, s| length + s[:token].size}
51
+ end
52
+
53
+ def filter_replaced_lines
54
+ # if a block is replaced by an other one, lcs-diff will find even the single common word between the old and the new content
55
+ # no need for intelligent diff in this case, simply show the removed and the added block with no highlighting
56
+ # rule: if less than 33% of a block is not a match, we don't need intelligent diff for that block
57
+ match_length = length_in_chars(@diff.select { |d| d[:action] == :match})
58
+ total_length = length_in_chars(@diff)
59
+
60
+ if total_length.to_f / match_length > 3.3
61
+ @diff.each_with_index do |d, i|
62
+ next if d[:action] != :match
63
+ discard_match(i, d[:token])
64
+ end
65
+ end
66
+ end
67
+
68
+ def match(diff)
69
+ close_tags
70
+ all_actions do |action|
71
+ close_last_tag(diff)
72
+ @result[action] << escape_content(diff[:token])
73
+ end
74
+ end
75
+
76
+ def discard_a(diff)
77
+ open_tag(:removal, diff[:token])
78
+ close_last_tag(diff)
79
+ @result[:removal] << escape_content(diff[:token])
80
+ end
81
+
82
+ def discard_b(diff)
83
+ open_tag(:addition, diff[:token])
84
+ close_last_tag(diff)
85
+ @result[:addition] << escape_content(diff[:token])
86
+ end
87
+
88
+ def all_actions
89
+ [:addition, :removal].each do |action|
90
+ yield(action)
91
+ end
92
+ end
93
+
94
+ def open_tag(action, next_token)
95
+ return if !@highlight || next_token.strip.empty? # don't open span tag if no highlighting is needed or the first token is empty
96
+ unless @tag_open[action]
97
+ klass = action == :addition ? 'aa' : 'rr'
98
+ @result[action] << "<span class=\"#{klass}\">"
99
+ @tag_open[action] = true
100
+ end
101
+ end
102
+
103
+ def close_tags
104
+ return unless @highlight
105
+ all_actions do |action|
106
+ if @tag_open[action]
107
+ @result[action] << "</span>"
108
+ @tag_open[action] = false
109
+ end
110
+ end
111
+ end
112
+
113
+ def close_last_tag(diff)
114
+ return unless @highlight
115
+ close_tags if diff[:token] == "\n"
116
+ end
117
+
118
+ def array_of_lines(tokens)
119
+ tokens.join('').split("\n")
120
+ end
121
+
122
+ end
@@ -0,0 +1,9 @@
1
+ <html><head>
2
+ <style>
3
+ <%= stylesheet_string %>
4
+ </style>
5
+ </head>
6
+ <body>
7
+ <%= html_diff %>
8
+ </body>
9
+ </html>
@@ -0,0 +1,10 @@
1
+ * {font-size:11px;}
2
+ h2 {font-family:Verdana;font-size:12px;background-color: #bbb; font-weight: bold; line-height:25px; margin-bottom:2px; padding-left:5px}
3
+ table {width:100%;border-collapse:collapse}
4
+ .r {background-color: #fdd;}
5
+ .rr {background-color: #faa;}
6
+ .a {background-color: #dfd;}
7
+ .aa {background-color: #afa;}
8
+ .title {background-color: #ddd; padding: 10px;font-family:Verdana;font-size:12px;}
9
+ tr {color:#000;font-family: "Bitstream Vera Sans Mono","Monaco","Courier",monospace}
10
+ .ln {background-color: #ccc; width:23px; text-align:right}
@@ -0,0 +1,34 @@
1
+ commit e28ad77bba0574241e6eb64dfd0c1291b221effe
2
+ Author: Tom Stuart <tom@experthuman.com>
3
+ Date: Wed Oct 8 09:31:00 2008 +0100
4
+
5
+ Allow use of :path_prefix and :name_prefix outside of namespaced routes. [#1188 state:resolved]
6
+
7
+ Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
8
+
9
+ commit a4629e707d80a5769f7a71ca6ed9471015e14dc9
10
+ Author: Michael Koziarski <michael@koziarski.com>
11
+ Date: Mon Sep 29 17:36:09 2008 +0200
12
+
13
+ Extract transliteration code to a seperate method.
14
+
15
+ Use iconv by default, but only when the transliteration is well behaved. When it isn't, fallback to mb_chars
16
+
17
+ commit dce6ade4cdc2833b53bd600ef10f9bce83c7102d
18
+ Author: Andrew Kaspick <andrew@redlinesoftware.com>
19
+ Date: Tue Sep 30 14:15:36 2008 -0500
20
+
21
+ Ensure select_tag#name attribute uses [] when :multiple is true. [#1146 state:resolved]
22
+
23
+ Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
24
+
25
+ commit 51b986619d88f7ba98be7d271188785cbbb541a0
26
+ Author: Tarmo Tänav <tarmo@itech.ee>
27
+ Date: Mon Oct 6 17:35:21 2008 +0300
28
+
29
+ Implement submit_to_remote as a wrapper around a more generic button_to_remote
30
+
31
+ Removed the "return false" from submit_to_remote onclick end as
32
+ button input elements have no default behavior to cancel.
33
+
34
+ Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
@@ -0,0 +1,83 @@
1
+ commit 51b986619d88f7ba98be7d271188785cbbb541a0
2
+ Author: Tarmo Tänav <tarmo@itech.ee>
3
+ Date: Mon Oct 6 17:35:21 2008 +0300
4
+
5
+ Implement submit_to_remote as a wrapper around a more generic button_to_remote
6
+
7
+ Removed the "return false" from submit_to_remote onclick end as
8
+ button input elements have no default behavior to cancel.
9
+
10
+ Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
11
+
12
+ diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
13
+ index 54ea93f..4de93a1 100644
14
+ --- a/actionpack/CHANGELOG
15
+ +++ b/actionpack/CHANGELOG
16
+ @@ -1,5 +1,7 @@
17
+ *Edge*
18
+
19
+ +* Make PrototypeHelper#submit_to_remote a wrapper around PrototypeHelper#button_to_remote. [Tarmo Tänav]
20
+ +
21
+ * Set HttpOnly for the cookie session store's cookie. #1046
22
+
23
+ * Added FormTagHelper#image_submit_tag confirm option #784 [Alastair Brunton]
24
+ diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
25
+ index ff41a6d..a3eccc7 100644
26
+ --- a/actionpack/lib/action_view/helpers/prototype_helper.rb
27
+ +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
28
+ @@ -405,7 +405,7 @@ module ActionView
29
+ # # Generates: <input name="create_btn" onclick="new Ajax.Request('/testing/create',
30
+ # # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});
31
+ # # return false;" type="button" value="Create" />
32
+ - # <%= button_to_remote 'create_btn', 'Create', :url => { :action => 'create' } %>
33
+ + # <%= submit_to_remote 'create_btn', 'Create', :url => { :action => 'create' } %>
34
+ #
35
+ # # Submit to the remote action update and update the DIV succeed or fail based
36
+ # # on the success or failure of the request
37
+ @@ -413,24 +413,18 @@ module ActionView
38
+ # # Generates: <input name="update_btn" onclick="new Ajax.Updater({success:'succeed',failure:'fail'},
39
+ # # '/testing/update', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});
40
+ # # return false;" type="button" value="Update" />
41
+ - # <%= button_to_remote 'update_btn', 'Update', :url => { :action => 'update' },
42
+ + # <%= submit_to_remote 'update_btn', 'Update', :url => { :action => 'update' },
43
+ # :update => { :success => "succeed", :failure => "fail" }
44
+ #
45
+ # <tt>options</tt> argument is the same as in form_remote_tag.
46
+ - #
47
+ - # Note: This method used to be called submit_to_remote, but that's now just an alias for button_to_remote
48
+ - def button_to_remote(name, value, options = {})
49
+ + def submit_to_remote(name, value, options = {})
50
+ options[:with] ||= 'Form.serialize(this.form)'
51
+
52
+ - options[:html] ||= {}
53
+ - options[:html][:type] = 'button'
54
+ - options[:html][:onclick] = "#{remote_function(options)}; return false;"
55
+ - options[:html][:name] = name
56
+ - options[:html][:value] = value
57
+ + html_options = options.delete(:html) || {}
58
+ + html_options[:name] = name
59
+
60
+ - tag("input", options[:html], false)
61
+ + button_to_remote(value, options, html_options)
62
+ end
63
+ - alias_method :submit_to_remote, :button_to_remote
64
+
65
+ # Returns '<tt>eval(request.responseText)</tt>' which is the JavaScript function
66
+ # that +form_remote_tag+ can call in <tt>:complete</tt> to evaluate a multiple
67
+ diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb
68
+ index a1f541f..d6b86a3 100644
69
+ --- a/actionpack/test/template/prototype_helper_test.rb
70
+ +++ b/actionpack/test/template/prototype_helper_test.rb
71
+ @@ -218,9 +218,9 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
72
+
73
+ end
74
+
75
+ - def test_button_to_remote
76
+ - assert_dom_equal %(<input name=\"More beer!\" onclick=\"new Ajax.Updater('empty_bottle', 'http://www.example.com/', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)}); return false;\" type=\"button\" value=\"1000000\" />),
77
+ - button_to_remote("More beer!", 1_000_000, :update => "empty_bottle")
78
+ + def test_submit_to_remote
79
+ + assert_dom_equal %(<input name=\"More beer!\" onclick=\"new Ajax.Updater('empty_bottle', 'http://www.example.com/', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});\" type=\"button\" value=\"1000000\" />),
80
+ + submit_to_remote("More beer!", 1_000_000, :update => "empty_bottle")
81
+ end
82
+
83
+ def test_observe_field
@@ -0,0 +1,49 @@
1
+ commit a4629e707d80a5769f7a71ca6ed9471015e14dc9
2
+ Author: Michael Koziarski <michael@koziarski.com>
3
+ Date: Mon Sep 29 17:36:09 2008 +0200
4
+
5
+ Extract transliteration code to a seperate method.
6
+
7
+ Use iconv by default, but only when the transliteration is well behaved. When it isn't, fallback to mb_chars
8
+
9
+ diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb
10
+ index 89a93f4..f1e7abf 100644
11
+ --- a/activesupport/lib/active_support/inflector.rb
12
+ +++ b/activesupport/lib/active_support/inflector.rb
13
+ @@ -1,4 +1,5 @@
14
+ require 'singleton'
15
+ +require 'iconv'
16
+
17
+ module ActiveSupport
18
+ # The Inflector transforms words from singular to plural, class names to table names, modularized class names to ones without,
19
+ @@ -258,14 +259,28 @@ module ActiveSupport
20
+ # # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
21
+ def parameterize(string, sep = '-')
22
+ re_sep = Regexp.escape(sep)
23
+ - string.mb_chars.normalize(:kd). # Decompose accented characters
24
+ - gsub(/[^\x00-\x7F]+/, ''). # Remove anything non-ASCII entirely (e.g. diacritics).
25
+ + transliterate(string).
26
+ gsub(/[^a-z0-9\-_\+]+/i, sep). # Turn unwanted chars into the separator.
27
+ squeeze(sep). # No more than one of the separator in a row.
28
+ gsub(/^#{re_sep}|#{re_sep}$/i, ''). # Remove leading/trailing separator.
29
+ downcase
30
+ end
31
+
32
+ +
33
+ + # Replaces accented characters with their ascii equivalents.
34
+ + def transliterate(string)
35
+ + Iconv.iconv('ascii//translit//IGNORE', 'utf-8', string).to_s
36
+ + end
37
+ +
38
+ + # The iconv transliteration code doesn't function correctly
39
+ + # on some platforms, but it's very fast where it does function.
40
+ + if "foo" != Inflector.transliterate("föö")
41
+ + def transliterate(string)
42
+ + string.mb_chars.normalize(:kd). # Decompose accented characters
43
+ + gsub(/[^\x00-\x7F]+/, '') # Remove anything non-ASCII entirely (e.g. diacritics).
44
+ + end
45
+ + end
46
+ +
47
+ # Create the name of a table like Rails does for models to table names. This method
48
+ # uses the +pluralize+ method on the last word in the string.
49
+ #