git-commit-notifier 0.10.5 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +3 -1
- data/README.md +2 -2
- data/VERSION +1 -1
- data/config/git-notifier-config.example.yml +49 -4
- data/git-commit-notifier.gemspec +1 -1
- data/lib/git_commit_notifier/commit_hook.rb +59 -15
- data/lib/git_commit_notifier/diff_to_html.rb +100 -34
- data/lib/git_commit_notifier/emailer.rb +72 -15
- data/lib/git_commit_notifier/executor.rb +6 -0
- data/lib/git_commit_notifier/git.rb +27 -2
- data/spec/lib/git_commit_notifier/commit_hook_spec.rb +3 -3
- data/spec/lib/git_commit_notifier/diff_to_html_spec.rb +20 -20
- data/spec/lib/git_commit_notifier/git_spec.rb +3 -3
- metadata +31 -31
data/.yardopts
CHANGED
data/README.md
CHANGED
@@ -102,7 +102,7 @@ old commits in processes of forking, branching etc.
|
|
102
102
|
|
103
103
|
## Note on Patches/Pull Requests
|
104
104
|
|
105
|
-
* Fork the project.
|
105
|
+
* Fork [the project](https://github.com/bitboxer/git-commit-notifier).
|
106
106
|
* Make your feature addition or bug fix.
|
107
107
|
* Add tests for it. This is important so I don't break it in a
|
108
108
|
future version unintentionally.
|
@@ -126,5 +126,5 @@ Thanks for [putpat.tv](http://www.putpat.tv), [Primalgrasp](http://www.primalgra
|
|
126
126
|
|
127
127
|
## License
|
128
128
|
|
129
|
-
MIT License, see the file
|
129
|
+
MIT License, see the {file:LICENSE}.
|
130
130
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.11.0
|
@@ -4,11 +4,40 @@ ignore_merge: false
|
|
4
4
|
# Optional parameter for the subject-line of the mail
|
5
5
|
# emailprefix: GIT
|
6
6
|
|
7
|
-
#
|
8
|
-
|
7
|
+
# Set limit on maximum number of lines per file diff
|
8
|
+
lines_per_diff: 300
|
9
9
|
|
10
10
|
# Show file list only when too many files
|
11
|
-
|
11
|
+
too_many_files: 50
|
12
|
+
|
13
|
+
# Whether to expand css inline. May be compatible with more mail readers
|
14
|
+
# but consumes much more space and more cpu. Defaults to true
|
15
|
+
# expand_css: true
|
16
|
+
|
17
|
+
# Determine whether to add plaintext alternative section to generated email.
|
18
|
+
# This allows text-only readers an option, but greatly increases the size
|
19
|
+
# of generated emails. Defaults to true
|
20
|
+
# add_plaintext: true
|
21
|
+
|
22
|
+
# Subject: the subject may be set by specifying a template.
|
23
|
+
#
|
24
|
+
# Substitution into the template is available for the following
|
25
|
+
# words, via the form ${word}
|
26
|
+
#
|
27
|
+
# prefix - The emailprefix set, defaulting to repo_name
|
28
|
+
# repo_name - Name of the git repo
|
29
|
+
# branch_name - Name of the git branch (master is "" unless show_master_branch_name)
|
30
|
+
# commit_id - The git commit id (hash)
|
31
|
+
# message - The commit message
|
32
|
+
# commit_number - The commit number within the push; 1-based
|
33
|
+
# commit_count - The number of commits within the push
|
34
|
+
# commit_count_phrase - The number of commits, as "1 commit", "2 commits", etc.
|
35
|
+
#
|
36
|
+
# The default subject template varies a little depending on whether
|
37
|
+
# or not group_email_by_push is set.
|
38
|
+
#
|
39
|
+
#subject: "[${prefix}${branch_name}] ${commit_count_phrase}: ${message}"
|
40
|
+
#subject: "[${prefix}${branch_name}][${commit_number}] ${message}"
|
12
41
|
|
13
42
|
# defines what branches to email for (defaults to all)
|
14
43
|
# include_branches: ['master', 'some_other_branch']
|
@@ -68,7 +97,8 @@ nntp_settings:
|
|
68
97
|
address: your.nntp.host.here
|
69
98
|
port: 119
|
70
99
|
|
71
|
-
# Decorate files and commit ids with link to a webview. Possible values: none, gitweb,
|
100
|
+
# Decorate files and commit ids with link to a webview. Possible values: none, gitweb,
|
101
|
+
# gitorious, cgit, trac, gitlabhq, or redmine
|
72
102
|
link_files: none
|
73
103
|
|
74
104
|
# If link_files is set to "gitweb", you need to configure the path to your gitweb
|
@@ -94,6 +124,21 @@ cgit:
|
|
94
124
|
trac:
|
95
125
|
path: http://example.com/changeset
|
96
126
|
|
127
|
+
# If link_files is set to "gitlabhq", you need to configure the path to your gitlabhq
|
128
|
+
# instance
|
129
|
+
gitlabhq:
|
130
|
+
path: http://gitlabhq.example.com
|
131
|
+
version: 1.2
|
132
|
+
|
133
|
+
# If link_files is set to "redmine", you need to configure the path to your redmine
|
134
|
+
# instance
|
135
|
+
redmine:
|
136
|
+
path: http://redmine.example.com
|
137
|
+
# project: project-name
|
138
|
+
# keywords: [refs, fixes]
|
139
|
+
# project defaults to git repository name, keywords defaults to refs, fixes (for use with message_integration)
|
140
|
+
|
141
|
+
|
97
142
|
# commit message URL map
|
98
143
|
message_map:
|
99
144
|
# '\brefs\s*\#(\d+)': 'http://example.com/redmine/issues/show/\1'
|
data/git-commit-notifier.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
20
20
|
|
21
|
-
s.homepage = %q{http://github.com/
|
21
|
+
s.homepage = %q{http://bitboxer.github.com/git-commit-notifier/}
|
22
22
|
s.require_paths = ["lib"]
|
23
23
|
s.rubygems_version = %q{1.3.7}
|
24
24
|
s.summary = %q{Sends git commit messages with diffs}
|
@@ -47,11 +47,9 @@ module GitCommitNotifier
|
|
47
47
|
project_path = Dir.getwd
|
48
48
|
recipient = config["mailinglist"] || Git.mailing_list_address
|
49
49
|
|
50
|
+
# If no recipients specified, bail out gracefully. This is not an error, and might be intentional
|
50
51
|
if recipient.nil? || recipient.length == 0
|
51
|
-
|
52
|
-
"Please add a recipient for the emails. Eg : \n" +
|
53
|
-
" git config hooks.mailinglist developer@example.com"
|
54
|
-
)
|
52
|
+
info("bypassing commit notification; no recipients specified (consider setting git config hooks.mailinglist)")
|
55
53
|
return
|
56
54
|
end
|
57
55
|
|
@@ -62,7 +60,9 @@ module GitCommitNotifier
|
|
62
60
|
logger.debug("rev2: #{rev2}")
|
63
61
|
logger.debug("included branches: #{include_branches.join(', ')}") unless include_branches.nil?
|
64
62
|
|
65
|
-
|
63
|
+
repo_name = Git.repo_name
|
64
|
+
prefix = config["emailprefix"] || repo_name
|
65
|
+
|
66
66
|
branch_name = if ref_name =~ /^refs\/heads\/(.+)$/
|
67
67
|
$1
|
68
68
|
else
|
@@ -76,10 +76,30 @@ module GitCommitNotifier
|
|
76
76
|
info("Supressing mail for branch #{branch_name}...")
|
77
77
|
return
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
branch_name = "/#{branch_name}"
|
81
81
|
branch_name = "" if !config["show_master_branch_name"] && branch_name == '/master'
|
82
|
-
|
82
|
+
|
83
|
+
# Replacements for subject template
|
84
|
+
# prefix
|
85
|
+
# repo_name
|
86
|
+
# branch_name
|
87
|
+
# commit_id (hash)
|
88
|
+
# short_message
|
89
|
+
# commit_number
|
90
|
+
# commit_count
|
91
|
+
# commit_count_phrase (1 commit, 2 commits, etc)
|
92
|
+
subject_words = {
|
93
|
+
:prefix => prefix,
|
94
|
+
:repo_name => repo_name,
|
95
|
+
:branch_name => branch_name,
|
96
|
+
:commit_id => nil,
|
97
|
+
:message => nil,
|
98
|
+
:commit_number => nil,
|
99
|
+
:commit_count => nil,
|
100
|
+
:commit_count_phrase => nil
|
101
|
+
}
|
102
|
+
|
83
103
|
info("Sending mail...")
|
84
104
|
|
85
105
|
diff2html = DiffToHtml.new(Dir.pwd, config)
|
@@ -102,39 +122,63 @@ module GitCommitNotifier
|
|
102
122
|
text << result[:text_content]
|
103
123
|
html << result[:html_content]
|
104
124
|
end
|
125
|
+
|
126
|
+
# Form the subject from template
|
127
|
+
revised_subject_words = subject_words.merge({
|
128
|
+
:commit_id => result[:commit_info][:commit],
|
129
|
+
:message => result[:commit_info][:message],
|
130
|
+
:commit_number => 1,
|
131
|
+
:commit_count => diffresult.size,
|
132
|
+
:commit_count_phrase => diffresult.size == 1 ? "#{diffresult.size} commit" : "#{diffresult.size} commits"
|
133
|
+
})
|
134
|
+
subject_template = config['subject'] || "[${prefix}${branch_name}] ${commit_count_phrase}: ${message}"
|
135
|
+
subject = subject_template.gsub(/\$\{(\w+)\}/) { |m| revised_subject_words[$1.intern] }
|
105
136
|
|
106
137
|
emailer = Emailer.new(config,
|
107
138
|
:project_path => project_path,
|
108
139
|
:recipient => recipient,
|
109
140
|
:from_address => config["from"] || result[:commit_info][:email],
|
110
141
|
:from_alias => result[:commit_info][:author],
|
111
|
-
:subject =>
|
142
|
+
:subject => subject,
|
112
143
|
:text_message => text.join("------------------------------------------\n\n"),
|
113
144
|
:html_message => html.join("<hr /><br />"),
|
114
145
|
:old_rev => rev1,
|
115
146
|
:new_rev => rev2,
|
116
|
-
:ref_name => ref_name
|
147
|
+
:ref_name => ref_name,
|
148
|
+
:repo_name => repo_name
|
117
149
|
)
|
118
150
|
emailer.send
|
119
151
|
else
|
120
|
-
|
152
|
+
commit_number = 1
|
121
153
|
diff2html.diff_between_revisions(rev1, rev2, prefix, ref_name) do |result|
|
122
|
-
next
|
123
|
-
|
154
|
+
next if config["ignore_merge"] && merge_commit?(result)
|
155
|
+
|
156
|
+
# Form the subject from template
|
157
|
+
revised_subject_words = subject_words.merge({
|
158
|
+
:commit_id => result[:commit_info][:commit],
|
159
|
+
:message => result[:commit_info][:message],
|
160
|
+
:commit_number => commit_number,
|
161
|
+
:commit_count => 1,
|
162
|
+
:commit_count_phrase => "1 commit"
|
163
|
+
})
|
164
|
+
subject_template = config['subject'] || "[${prefix}${branch_name}][${commit_number}] ${message}"
|
165
|
+
subject = subject_template.gsub(/\$\{(\w+)\}/) { |m| revised_subject_words[$1.intern] }
|
166
|
+
|
124
167
|
emailer = Emailer.new(config,
|
125
168
|
:project_path => project_path,
|
126
169
|
:recipient => recipient,
|
127
170
|
:from_address => config["from"] || result[:commit_info][:email],
|
128
171
|
:from_alias => result[:commit_info][:author],
|
129
|
-
:subject =>
|
172
|
+
:subject => subject,
|
130
173
|
:text_message => result[:text_content],
|
131
174
|
:html_message => result[:html_content],
|
132
175
|
:old_rev => rev1,
|
133
176
|
:new_rev => rev2,
|
134
|
-
:ref_name => ref_name
|
177
|
+
:ref_name => ref_name,
|
178
|
+
:repo_name => repo_name
|
135
179
|
)
|
136
180
|
emailer.send
|
137
|
-
|
181
|
+
commit_number += 1
|
138
182
|
end
|
139
183
|
end
|
140
184
|
end
|
@@ -10,20 +10,27 @@ module GitCommitNotifier
|
|
10
10
|
|
11
11
|
INTEGRATION_MAP = {
|
12
12
|
:mediawiki => { :search_for => /\[\[([^\[\]]+)\]\]/, :replace_with => '#{url}/\1' },
|
13
|
-
:redmine => {
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
13
|
+
:redmine => {
|
14
|
+
:search_for => lambda do |config|
|
15
|
+
keywords = (config['redmine'] && config['redmine']['keywords']) || ["refs", "fixes"]
|
16
|
+
/\b(?:#{keywords.join('\b|')})([\s&,]+\#\d+)+/i
|
17
|
+
end,
|
18
|
+
:replace_with => lambda do |m, url, config|
|
19
|
+
# we can provide Proc that gets matched string and configuration url.
|
20
|
+
# result should be in form of:
|
21
|
+
# { :phrase => 'phrase started with', :links => [ { :title => 'title of url', :url => 'target url' }, ... ] }
|
22
|
+
keywords = (config['redmine'] && config['redmine']['keywords']) || ["refs", "fixes"]
|
23
|
+
match = m.match(/^(#{keywords.join('\b|')})(.*)$/i)
|
24
|
+
return m unless match
|
25
|
+
r = { :phrase => match[1] }
|
26
|
+
captures = match[2].split(/[\s\&\,]+/).map { |m| (m =~ /(\d+)/) ? $1 : m }.reject { |c| c.empty? }
|
27
|
+
r[:links] = captures.map { |mn| { :title => "##{mn}", :url => "#{url}/issues/show/#{mn}" } }
|
28
|
+
r
|
29
|
+
end },
|
24
30
|
:bugzilla => { :search_for => /\bBUG\s*(\d+)/i, :replace_with => '#{url}/show_bug.cgi?id=\1' },
|
25
31
|
:fogbugz => { :search_for => /\bbugzid:\s*(\d+)/i, :replace_with => '#{url}\1' }
|
26
32
|
}.freeze
|
33
|
+
MAX_LINE_LENGTH = 512
|
27
34
|
MAX_COMMITS_PER_ACTION = 10000
|
28
35
|
HANDLED_COMMITS_FILE = 'previously.txt'.freeze
|
29
36
|
NEW_HANDLED_COMMITS_FILE = 'previously_new.txt'.freeze
|
@@ -64,17 +71,13 @@ module GitCommitNotifier
|
|
64
71
|
end
|
65
72
|
|
66
73
|
def lines_per_diff
|
67
|
-
config['lines_per_diff']
|
74
|
+
@config['lines_per_diff']
|
68
75
|
end
|
69
76
|
|
70
|
-
def
|
77
|
+
def ignore_whitespaces?
|
71
78
|
@config['ignore_whitespace'].nil? || @config['ignore_whitespace']
|
72
79
|
end
|
73
80
|
|
74
|
-
def skip_lines?
|
75
|
-
lines_per_diff && (@lines_added >= lines_per_diff)
|
76
|
-
end
|
77
|
-
|
78
81
|
def add_separator
|
79
82
|
@diff_result << '<tr class="sep"><td class="sep" colspan="3" title="Unchanged content skipped between diff. blocks">…</td></tr>'
|
80
83
|
end
|
@@ -84,7 +87,6 @@ module GitCommitNotifier
|
|
84
87
|
end
|
85
88
|
|
86
89
|
def add_line_to_result(line, escape)
|
87
|
-
@lines_added += 1
|
88
90
|
klass = line_class(line)
|
89
91
|
content = (escape == :escape) ? escape_content(line[:content]) : line[:content]
|
90
92
|
padding = ' ' if klass != ''
|
@@ -155,7 +157,8 @@ module GitCommitNotifier
|
|
155
157
|
end
|
156
158
|
|
157
159
|
file_name = @current_file_name
|
158
|
-
|
160
|
+
|
161
|
+
# TODO: these filenames, etc, should likely be properly html escaped
|
159
162
|
if config['link_files']
|
160
163
|
file_name = if config["link_files"] == "gitweb" && config["gitweb"]
|
161
164
|
"<a href='#{config['gitweb']['path']}?p=#{Git.repo_name}.git;f=#{file_name};h=#{@current_sha};hb=#{@current_commit}'>#{file_name}</a>"
|
@@ -163,10 +166,18 @@ module GitCommitNotifier
|
|
163
166
|
"<a href='#{config['gitorious']['path']}/#{config['gitorious']['project']}/#{config['gitorious']['repository']}/blobs/#{branch_name}/#{file_name}'>#{file_name}</a>"
|
164
167
|
elsif config["link_files"] == "cgit" && config["cgit"]
|
165
168
|
"<a href='#{config['cgit']['path']}/#{config['cgit']['project']}/tree/#{file_name}'>#{file_name}</a>"
|
169
|
+
elsif config["link_files"] == "gitlabhq" && config["gitlabhq"]
|
170
|
+
if config["gitlabhq"]["version"] && config["gitlabhq"]["version"] < 1.2
|
171
|
+
"<a href='#{config['gitlabhq']['path']}/#{Git.repo_name.gsub(".", "_")}/tree/#{@current_commit}/#{file_name}'>#{file_name}</a>"
|
172
|
+
else
|
173
|
+
"<a href='#{config['gitlabhq']['path']}/#{Git.repo_name.gsub(".", "_")}/#{@current_commit}/tree/#{file_name}'>#{file_name}</a>"
|
174
|
+
end
|
175
|
+
elsif config["link_files"] == "redmine" && config["redmine"]
|
176
|
+
"<a href='#{config['redmine']['path']}/projects/#{config['redmine']['project'] || Git.repo_name}/repository/revisions/#{@current_commit}/entry/#{file_name}'>#{file_name}</a>"
|
166
177
|
else
|
167
178
|
file_name
|
168
179
|
end
|
169
|
-
|
180
|
+
end
|
170
181
|
|
171
182
|
header = "#{op} #{binary}file #{file_name}"
|
172
183
|
"<h2>#{header}</h2>\n"
|
@@ -184,19 +195,26 @@ module GitCommitNotifier
|
|
184
195
|
|
185
196
|
def add_changes_to_result
|
186
197
|
return if @current_file_name.nil?
|
198
|
+
|
199
|
+
@lines_added = 0
|
187
200
|
@diff_result << operation_description
|
188
201
|
if !@diff_lines.empty? && !@too_many_files
|
189
202
|
@diff_result << '<table>'
|
190
203
|
removals = []
|
191
204
|
additions = []
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
205
|
+
|
206
|
+
lines = if lines_per_diff.nil?
|
207
|
+
line_budget = nil
|
208
|
+
@diff_lines
|
209
|
+
else
|
210
|
+
line_budget = lines_per_diff - @lines_added
|
211
|
+
@diff_lines.slice(0, line_budget)
|
212
|
+
end
|
213
|
+
|
214
|
+
lines.each_with_index do |line, index|
|
197
215
|
removals << line if line[:op] == :removal
|
198
216
|
additions << line if line[:op] == :addition
|
199
|
-
if line[:op] == :unchanged || index ==
|
217
|
+
if line[:op] == :unchanged || index == lines.size - 1 # unchanged line or end of block, add prev lines to result
|
200
218
|
if removals.size > 0 && additions.size > 0 # block of removed and added lines - perform intelligent diff
|
201
219
|
add_block_to_results(lcs_diff(removals, additions), :dont_escape)
|
202
220
|
else # some lines removed or added - no need to perform intelligent diff
|
@@ -204,14 +222,17 @@ module GitCommitNotifier
|
|
204
222
|
end
|
205
223
|
removals = []
|
206
224
|
additions = []
|
207
|
-
if index > 0 && index !=
|
208
|
-
prev_line =
|
225
|
+
if index > 0 && index != lines.size - 1
|
226
|
+
prev_line = lines[index - 1]
|
209
227
|
add_separator unless lines_are_sequential?(prev_line, line)
|
210
228
|
end
|
211
229
|
add_line_to_result(line, :escape) if line[:op] == :unchanged
|
212
230
|
end
|
213
|
-
|
231
|
+
@lines_added += 1
|
214
232
|
end
|
233
|
+
|
234
|
+
add_skip_notification if !line_budget.nil? && line_budget < @diff_lines.size
|
235
|
+
|
215
236
|
@diff_result << '</table>'
|
216
237
|
@diff_lines = []
|
217
238
|
end
|
@@ -424,10 +445,50 @@ module GitCommitNotifier
|
|
424
445
|
def merge_commit?(commit_info)
|
425
446
|
! commit_info[:merge].nil?
|
426
447
|
end
|
448
|
+
|
449
|
+
def truncate_long_lines(text)
|
450
|
+
StringIO.open("", "w") do |output|
|
451
|
+
# Match encoding of output string to that of input string
|
452
|
+
output.string.force_encoding(text.encoding) if output.string.respond_to?(:force_encoding)
|
453
|
+
|
454
|
+
input = StringIO.new(text, "r")
|
455
|
+
input.each_line "\n" do |line|
|
456
|
+
if line.length > MAX_LINE_LENGTH && MAX_LINE_LENGTH >= 9
|
457
|
+
# Truncate the line
|
458
|
+
line.slice!(MAX_LINE_LENGTH-3..-1)
|
459
|
+
|
460
|
+
# Ruby < 1.9 doesn't know how to slice between
|
461
|
+
# characters, so deal specially with that case
|
462
|
+
# so that we don't truncate in the middle of a UTF8 sequence,
|
463
|
+
# which would be invalid.
|
464
|
+
if !line.respond_to?(:force_encoding)
|
465
|
+
# If the last remaining character is part of a UTF8 multibyte character,
|
466
|
+
# keep truncating until we go past the start of a UTF8 character.
|
467
|
+
# This assumes that this is a UTF8 string, which may be a false assumption
|
468
|
+
# unless somebody has taken care to check the encoding of the source file.
|
469
|
+
# We truncate at most 6 additional bytes, which is the length of the longest
|
470
|
+
# UTF8 sequence
|
471
|
+
6.times do
|
472
|
+
c = line[-1, 1].to_i
|
473
|
+
break if (c & 0x80) == 0 # Last character is plain ASCII: don't truncate
|
474
|
+
line.slice!(-1, 1) # Truncate character
|
475
|
+
break if (c & 0xc0) == 0xc0 # Last character was the start of a UTF8 sequence, so we can stop now
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
# Append three dots to the end of line to indicate it's been truncated
|
480
|
+
# (avoiding ellipsis character so as not to introduce more encoding issues)
|
481
|
+
line << "...\n"
|
482
|
+
end
|
483
|
+
output << line
|
484
|
+
end
|
485
|
+
output.string
|
486
|
+
end
|
487
|
+
end
|
427
488
|
|
428
489
|
def diff_for_commit(commit)
|
429
490
|
@current_commit = commit
|
430
|
-
raw_diff = Git.show(commit,
|
491
|
+
raw_diff = truncate_long_lines(Git.show(commit, :ignore_whitespaces => ignore_whitespaces?))
|
431
492
|
raise "git show output is empty" if raw_diff.empty?
|
432
493
|
|
433
494
|
commit_info = extract_commit_info_from_git_show_output(raw_diff)
|
@@ -457,6 +518,10 @@ module GitCommitNotifier
|
|
457
518
|
"<a href='#{config['trac']['path']}/#{commit_info[:commit]}'>#{commit_info[:commit]}</a>"
|
458
519
|
elsif config["link_files"] == "cgit" && config["cgit"]
|
459
520
|
"<a href='#{config['cgit']['path']}/#{config['cgit']['project']}/commit/?id=#{commit_info[:commit]}'>#{commit_info[:commit]}</a>"
|
521
|
+
elsif config["link_files"] == "gitlabhq" && config["gitlabhq"]
|
522
|
+
"<a href='#{config['gitlabhq']['path']}/#{Git.repo_name.gsub(".", "_")}/commits/#{commit_info[:commit]}'>#{commit_info[:commit]}</a>"
|
523
|
+
elsif config["link_files"] == "redmine" && config["redmine"]
|
524
|
+
"<a href='#{config['redmine']['path']}/projects/#{config['redmine']['project'] || Git.repo_name}/repository/revisions/#{commit_info[:commit]}'>#{commit_info[:commit]}</a>"
|
460
525
|
else
|
461
526
|
" #{commit_info[:commit]}"
|
462
527
|
end
|
@@ -504,13 +569,12 @@ module GitCommitNotifier
|
|
504
569
|
[]
|
505
570
|
else
|
506
571
|
log = Git.log(rev1, rev2)
|
507
|
-
log.scan(/^commit\s([a-f0-9]+)/).map { |a| a.first }
|
572
|
+
log.scan(/^commit\s([a-f0-9]+)/).map { |a| a.first }.reverse
|
508
573
|
end
|
509
574
|
|
510
575
|
commits = check_handled_commits(commits)
|
511
576
|
|
512
577
|
commits.each do |commit|
|
513
|
-
@lines_added = 0 unless config["group_email_by_push"]
|
514
578
|
begin
|
515
579
|
commit_result = diff_for_commit(commit)
|
516
580
|
next if commit_result.nil?
|
@@ -539,9 +603,11 @@ module GitCommitNotifier
|
|
539
603
|
return message unless config['message_integration'].respond_to?(:each_pair)
|
540
604
|
config['message_integration'].each_pair do |pm, url|
|
541
605
|
pm_def = DiffToHtml::INTEGRATION_MAP[pm.to_sym] or next
|
606
|
+
search_for = pm_def[:search_for]
|
607
|
+
search_for = search_for.kind_of?(Proc) ? search_for.call(@config) : search_for
|
542
608
|
replace_with = pm_def[:replace_with]
|
543
|
-
replace_with = replace_with.kind_of?(Proc) ? lambda { |m| pm_def[:replace_with].call(m, url) } : replace_with.gsub('#{url}', url)
|
544
|
-
message_replace!(message,
|
609
|
+
replace_with = replace_with.kind_of?(Proc) ? lambda { |m| pm_def[:replace_with].call(m, url, @config) } : replace_with.gsub('#{url}', url)
|
610
|
+
message_replace!(message, search_for, replace_with)
|
545
611
|
end
|
546
612
|
message
|
547
613
|
end
|
@@ -3,7 +3,7 @@ require 'premailer'
|
|
3
3
|
class GitCommitNotifier::Emailer
|
4
4
|
DEFAULT_STYLESHEET_PATH = File.join(File.dirname(__FILE__), '/../../template/styles.css').freeze
|
5
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
|
+
PARAMETERS = %w[project_path recipient from_address from_alias subject text_message html_message repo_name ref_name old_rev new_rev].freeze
|
7
7
|
|
8
8
|
def config
|
9
9
|
@@config
|
@@ -43,8 +43,11 @@ class GitCommitNotifier::Emailer
|
|
43
43
|
|
44
44
|
def mail_html_message
|
45
45
|
html = GitCommitNotifier::Emailer.template.result(binding)
|
46
|
-
|
47
|
-
|
46
|
+
if config['expand_css'].nil? || config['expand_css']
|
47
|
+
premailer = Premailer.new(html, :with_html_string => true, :adapter => :nokogiri)
|
48
|
+
html = premailer.to_inline_css
|
49
|
+
end
|
50
|
+
html
|
48
51
|
end
|
49
52
|
|
50
53
|
def boundary
|
@@ -78,10 +81,13 @@ class GitCommitNotifier::Emailer
|
|
78
81
|
main_smtp.start( settings['domain'],
|
79
82
|
settings['user_name'], settings['password'], settings['authentication']) do |smtp|
|
80
83
|
|
81
|
-
|
82
|
-
|
84
|
+
recipients = @recipient.dup
|
85
|
+
recipients.force_encoding('ASCII-8BIT') if recipients.respond_to?(:force_encoding)
|
86
|
+
recipients = recipients.split(",")
|
87
|
+
smtp.open_message_stream(@from_address, recipients) do |f|
|
83
88
|
content.each do |line|
|
84
|
-
|
89
|
+
line.force_encoding('ASCII-8BIT') if line.respond_to?(:force_encoding)
|
90
|
+
f.print(line, "\r\n")
|
85
91
|
end
|
86
92
|
end
|
87
93
|
end
|
@@ -94,7 +100,9 @@ class GitCommitNotifier::Emailer
|
|
94
100
|
}.merge(options || {})
|
95
101
|
command = "#{sendmail_settings['location']} #{sendmail_settings['arguments']}"
|
96
102
|
IO.popen(command, "w+") do |f|
|
97
|
-
|
103
|
+
content.each do |line|
|
104
|
+
f.print(line, "\r\n")
|
105
|
+
end
|
98
106
|
f.flush
|
99
107
|
end
|
100
108
|
end
|
@@ -110,27 +118,37 @@ class GitCommitNotifier::Emailer
|
|
110
118
|
to_tag = config['delivery_method'] == 'nntp' ? 'Newsgroups' : 'To'
|
111
119
|
quoted_from_alias = quote_if_necessary("#{@from_alias}",'utf-8')
|
112
120
|
from = @from_alias.empty? ? @from_address : "#{quoted_from_alias} <#{@from_address}>"
|
121
|
+
|
122
|
+
plaintext = if config['add_plaintext'].nil? || config['add_plaintext']
|
123
|
+
@text_message
|
124
|
+
else
|
125
|
+
"Plain text part omitted. Consider setting add_plaintext in configuration."
|
126
|
+
end
|
113
127
|
|
114
128
|
content = [
|
115
129
|
"From: #{from}",
|
116
130
|
"#{to_tag}: #{quote_if_necessary(@recipient, 'utf-8')}",
|
117
131
|
"Subject: #{quote_if_necessary(@subject, 'utf-8')}",
|
118
132
|
"X-Mailer: git-commit-notifier",
|
133
|
+
"X-Git-Repository: #{@repo_name}",
|
119
134
|
"X-Git-Refname: #{@ref_name}",
|
120
135
|
"X-Git-Oldrev: #{@old_rev}",
|
121
136
|
"X-Git-Newrev: #{@new_rev}",
|
122
137
|
"Mime-Version: 1.0",
|
123
|
-
"Content-Type: multipart/alternative; boundary=#{boundary}
|
138
|
+
"Content-Type: multipart/alternative; boundary=#{boundary}",
|
139
|
+
"",
|
124
140
|
"--#{boundary}",
|
125
141
|
"Content-Type: text/plain; charset=utf-8",
|
126
|
-
"Content-Transfer-Encoding:
|
127
|
-
"Content-Disposition: inline
|
128
|
-
|
129
|
-
|
142
|
+
"Content-Transfer-Encoding: quoted-printable",
|
143
|
+
"Content-Disposition: inline",
|
144
|
+
"",
|
145
|
+
encode_quoted_printable_message(plaintext),
|
146
|
+
"--#{boundary}",
|
130
147
|
"Content-Type: text/html; charset=utf-8",
|
131
|
-
"Content-Transfer-Encoding:
|
132
|
-
"Content-Disposition: inline
|
133
|
-
|
148
|
+
"Content-Transfer-Encoding: quoted-printable",
|
149
|
+
"Content-Disposition: inline",
|
150
|
+
"",
|
151
|
+
encode_quoted_printable_message(mail_html_message),
|
134
152
|
"--#{boundary}--"]
|
135
153
|
|
136
154
|
if @recipient.empty?
|
@@ -147,6 +165,45 @@ class GitCommitNotifier::Emailer
|
|
147
165
|
end
|
148
166
|
end
|
149
167
|
|
168
|
+
# Convert a message into quoted printable encoding,
|
169
|
+
# limiting line length to 76 characters per spec
|
170
|
+
# Encoding messages in this way ensures that they
|
171
|
+
# won't violate rules for maximum line length, which
|
172
|
+
# can result in the MTA breaking lines at inconvenient points,
|
173
|
+
# such as in the middle of UTF8 characters.
|
174
|
+
def encode_quoted_printable_message(text)
|
175
|
+
StringIO.open("", "w") do |output|
|
176
|
+
# Character encoding of output string can be plain US-ASCII since quoted-printable is plain ASCII
|
177
|
+
output.string.force_encoding("US-ASCII") if output.string.respond_to?(:force_encoding)
|
178
|
+
|
179
|
+
line_max = 76
|
180
|
+
line_len = 0
|
181
|
+
|
182
|
+
input = StringIO.new(text, "r")
|
183
|
+
input.each_byte do |b|
|
184
|
+
case (b)
|
185
|
+
when 9, 32..60, 62..126
|
186
|
+
if line_len >= line_max - 1
|
187
|
+
output << "=\r\n"
|
188
|
+
line_len = 0
|
189
|
+
end
|
190
|
+
output << b.chr
|
191
|
+
line_len += 1
|
192
|
+
else
|
193
|
+
if line_len >= line_max - 3
|
194
|
+
output << "=\r\n"
|
195
|
+
line_len = 0
|
196
|
+
end
|
197
|
+
output << "=%02X" % b
|
198
|
+
line_len += 3
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
output << "=\r\n" if line_len > 0
|
203
|
+
output.string
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
150
207
|
# Convert the given text into quoted printable format, with an instruction
|
151
208
|
# that the text be eventually interpreted in the given charset.
|
152
209
|
def quoted_printable(text, charset)
|
@@ -2,8 +2,13 @@
|
|
2
2
|
|
3
3
|
require 'git_commit_notifier'
|
4
4
|
|
5
|
+
# Git commit notifier namespace
|
5
6
|
module GitCommitNotifier
|
7
|
+
# binaries code
|
6
8
|
class Executor
|
9
|
+
# runs git commit notifier life
|
10
|
+
# @param [Array(String)] args Command line arguments
|
11
|
+
# @return [nil] Nothing
|
7
12
|
def self.run!(args)
|
8
13
|
case args.length
|
9
14
|
when 0
|
@@ -24,6 +29,7 @@ module GitCommitNotifier
|
|
24
29
|
else
|
25
30
|
GitCommitNotifier::CommitHook.run args.first, args[1], args[2], args[3]
|
26
31
|
end
|
32
|
+
nil
|
27
33
|
end
|
28
34
|
end
|
29
35
|
end
|
@@ -1,5 +1,9 @@
|
|
1
|
+
# Git methods
|
1
2
|
class GitCommitNotifier::Git
|
2
3
|
class << self
|
4
|
+
# Runs specified command.
|
5
|
+
# @return (String) Shell command STDOUT (forced to UTF-8)
|
6
|
+
# @raise [ArgumentError] when command exits with nonzero status.
|
3
7
|
def from_shell(cmd)
|
4
8
|
r = `#{cmd}`
|
5
9
|
raise ArgumentError.new("#{cmd} failed") unless $?.exitstatus.zero?
|
@@ -7,19 +11,38 @@ class GitCommitNotifier::Git
|
|
7
11
|
r
|
8
12
|
end
|
9
13
|
|
10
|
-
|
14
|
+
# runs `git show`
|
15
|
+
# @note uses "--pretty=fuller" option.
|
16
|
+
# @return [String] Its output
|
17
|
+
# @see from_shell
|
18
|
+
# @param [String] rev Revision
|
19
|
+
# @param [Hash] opts Options
|
20
|
+
# @option opts [Boolean] :ignore_whitespaces Ignore whitespaces or not
|
21
|
+
def show(rev, opts = {})
|
11
22
|
gitopt = ""
|
12
23
|
gitopt += " --pretty=fuller"
|
13
|
-
gitopt += " -w" if
|
24
|
+
gitopt += " -w" if opts[:ignore_whitespaces]
|
14
25
|
data = from_shell("git show #{rev.strip}#{gitopt}")
|
15
26
|
data
|
16
27
|
end
|
17
28
|
|
29
|
+
# runs `git log`
|
30
|
+
# @note uses "--pretty=fuller" option.
|
31
|
+
# @return [String] Its output
|
32
|
+
# @see from_shell
|
33
|
+
# @param [String] rev1 First revision
|
34
|
+
# @param [String] rev2 Second revision
|
18
35
|
def log(rev1, rev2)
|
19
36
|
data = from_shell("git log --pretty=fuller #{rev1}..#{rev2}").strip
|
20
37
|
data
|
21
38
|
end
|
22
39
|
|
40
|
+
# runs `git log` and extract filenames only
|
41
|
+
# @note uses "--pretty=fuller" and "--name-status" options.
|
42
|
+
# @return [Array(String)] File names
|
43
|
+
# @see from_shell
|
44
|
+
# @param [String] rev1 First revision
|
45
|
+
# @param [String] rev2 Second revision
|
23
46
|
def changed_files(rev1, rev2)
|
24
47
|
output = ""
|
25
48
|
lines = from_shell("git log #{rev1}..#{rev2} --name-status --pretty=oneline")
|
@@ -59,6 +82,8 @@ class GitCommitNotifier::Git
|
|
59
82
|
|
60
83
|
def mailing_list_address
|
61
84
|
from_shell("git config hooks.mailinglist").strip
|
85
|
+
rescue ArgumentError
|
86
|
+
nil
|
62
87
|
end
|
63
88
|
end
|
64
89
|
end
|
@@ -75,7 +75,7 @@ describe GitCommitNotifier::CommitHook do
|
|
75
75
|
mock(GitCommitNotifier::Git).repo_name { 'testproject' }
|
76
76
|
mock(GitCommitNotifier::Git).changed_files('7e4f6b4', '4f13525') { [] }
|
77
77
|
REVISIONS.each do |rev|
|
78
|
-
mock(GitCommitNotifier::Git).show(rev, true) { IO.read(FIXTURES_PATH + "git_show_#{rev}") }
|
78
|
+
mock(GitCommitNotifier::Git).show(rev, :ignore_whitespaces => true) { IO.read(FIXTURES_PATH + "git_show_#{rev}") }
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
@@ -104,10 +104,10 @@ describe GitCommitNotifier::CommitHook do
|
|
104
104
|
end
|
105
105
|
|
106
106
|
describe :run do
|
107
|
-
it "should report
|
107
|
+
it "should report informational message when no recipients specified" do
|
108
108
|
mock(File).exists?(:noconfig) { false }
|
109
109
|
mock(GitCommitNotifier::Git).mailing_list_address { nil }
|
110
|
-
mock(GitCommitNotifier::CommitHook).
|
110
|
+
mock(GitCommitNotifier::CommitHook).info(/recipient/)
|
111
111
|
GitCommitNotifier::CommitHook.run(:noconfig, :rev1, :rev2, 'master')
|
112
112
|
end
|
113
113
|
end
|
@@ -129,9 +129,9 @@ describe GitCommitNotifier::DiffToHtml do
|
|
129
129
|
mock(GitCommitNotifier::Git).changed_files('7e4f6b4', '4f13525') { [] }
|
130
130
|
mock(GitCommitNotifier::Git).log(REVISIONS.first, REVISIONS.last) { IO.read(FIXTURES_PATH + 'git_log') }
|
131
131
|
REVISIONS.each do |rev|
|
132
|
-
mock(GitCommitNotifier::Git).show(rev, true) { IO.read(FIXTURES_PATH + 'git_show_' + rev) }
|
132
|
+
mock(GitCommitNotifier::Git).show(rev, :ignore_whitespaces => true) { IO.read(FIXTURES_PATH + 'git_show_' + rev) }
|
133
133
|
end
|
134
|
-
|
134
|
+
|
135
135
|
diff = GitCommitNotifier::DiffToHtml.new
|
136
136
|
mock(diff).check_handled_commits(anything) { |commits| commits }
|
137
137
|
diff.diff_between_revisions REVISIONS.first, REVISIONS.last, 'testproject', 'master'
|
@@ -142,22 +142,16 @@ describe GitCommitNotifier::DiffToHtml do
|
|
142
142
|
html.should_not be_include('@@') # diff correctly processed
|
143
143
|
end
|
144
144
|
|
145
|
-
#
|
146
|
-
hp = Nokogiri::HTML diff.result
|
147
|
-
(hp/"table").should have(
|
145
|
+
# second commit - 51b986619d88f7ba98be7d271188785cbbb541a0
|
146
|
+
hp = Nokogiri::HTML diff.result[1][:html_content]
|
147
|
+
(hp/"table").should have(3).tables # 3 files updated
|
148
148
|
(hp/"table"/"tr"/"td").each do |td|
|
149
|
-
if td.inner_html
|
150
|
-
|
151
|
-
|
152
|
-
td.parent.search('td')[1].inner_text.should == '2' # right
|
153
|
-
td.parent.search('td')[2].inner_html.should == "require 'iconv'" # change
|
149
|
+
if td.inner_html =~ /create_btn/
|
150
|
+
cols = td.parent.search('td')
|
151
|
+
['405', '408', ''].should be_include(cols[0].inner_text) # line 405 changed
|
154
152
|
end
|
155
153
|
end
|
156
154
|
|
157
|
-
# second commit
|
158
|
-
hp = Nokogiri::HTML diff.result[1][:html_content]
|
159
|
-
(hp/"table").should have(1).table # 1 file updated
|
160
|
-
|
161
155
|
# third commit - dce6ade4cdc2833b53bd600ef10f9bce83c7102d
|
162
156
|
hp = Nokogiri::HTML diff.result[2][:html_content]
|
163
157
|
(hp/"h2").should have(6).headers # 6 files in commit
|
@@ -167,13 +161,19 @@ describe GitCommitNotifier::DiffToHtml do
|
|
167
161
|
(hp/"h2")[3].inner_text.should == 'Deleted file railties/doc/guides/source/icons/README'
|
168
162
|
(hp/"h2")[4].inner_text.should == 'Added file railties/doc/guides/source/images/icons/README'
|
169
163
|
|
170
|
-
# fourth commit
|
164
|
+
# fourth commit
|
171
165
|
hp = Nokogiri::HTML diff.result[3][:html_content]
|
172
|
-
(hp/"table").should have(
|
166
|
+
(hp/"table").should have(1).table # 1 file updated
|
167
|
+
|
168
|
+
# fifth commit
|
169
|
+
hp = Nokogiri::HTML diff.result[4][:html_content]
|
170
|
+
(hp/"table").should have(2).tables # 2 files updated - one table for each of the files
|
173
171
|
(hp/"table"/"tr"/"td").each do |td|
|
174
|
-
if td.inner_html
|
175
|
-
|
176
|
-
|
172
|
+
if td.inner_html == "require 'iconv'"
|
173
|
+
# first added line in changeset a4629e707d80a5769f7a71ca6ed9471015e14dc9
|
174
|
+
td.parent.search('td')[0].inner_text.should == '' # left
|
175
|
+
td.parent.search('td')[1].inner_text.should == '2' # right
|
176
|
+
td.parent.search('td')[2].inner_html.should == "require 'iconv'" # change
|
177
177
|
end
|
178
178
|
end
|
179
179
|
end
|
@@ -182,7 +182,7 @@ describe GitCommitNotifier::DiffToHtml do
|
|
182
182
|
first_rev, last_rev = %w[ 0000000000000000000000000000000000000000 9b15cebcc5434e27c00a4a2acea43509f9faea21 ]
|
183
183
|
mock(GitCommitNotifier::Git).branch_commits('rvm') { %w[ ff037a73fc1094455e7bbf506171a3f3cf873ae6 ] }
|
184
184
|
%w[ ff037a73fc1094455e7bbf506171a3f3cf873ae6 ].each do |rev|
|
185
|
-
mock(GitCommitNotifier::Git).show(rev, true) { IO.read(FIXTURES_PATH + 'git_show_' + rev) }
|
185
|
+
mock(GitCommitNotifier::Git).show(rev, :ignore_whitespaces => true) { IO.read(FIXTURES_PATH + 'git_show_' + rev) }
|
186
186
|
end
|
187
187
|
diff = GitCommitNotifier::DiffToHtml.new
|
188
188
|
mock(diff).check_handled_commits(anything) { |commits| commits }
|
@@ -15,18 +15,18 @@ describe GitCommitNotifier::Git do
|
|
15
15
|
it "should get data from shell: git show without whitespaces" do
|
16
16
|
expected = 'some data from git show'
|
17
17
|
mock(GitCommitNotifier::Git).from_shell("git show #{SAMPLE_REV} --pretty=fuller -w") { expected }
|
18
|
-
GitCommitNotifier::Git.show(SAMPLE_REV, true).should == expected
|
18
|
+
GitCommitNotifier::Git.show(SAMPLE_REV, :ignore_whitespaces => true).should == expected
|
19
19
|
end
|
20
20
|
|
21
21
|
it "should get data from shell: git show with whitespaces" do
|
22
22
|
expected = 'some data from git show'
|
23
23
|
mock(GitCommitNotifier::Git).from_shell("git show #{SAMPLE_REV} --pretty=fuller") { expected }
|
24
|
-
GitCommitNotifier::Git.show(SAMPLE_REV, false).should == expected
|
24
|
+
GitCommitNotifier::Git.show(SAMPLE_REV, :ignore_whitespaces => false).should == expected
|
25
25
|
end
|
26
26
|
|
27
27
|
it "should strip given revision" do
|
28
28
|
mock(GitCommitNotifier::Git).from_shell("git show #{SAMPLE_REV} --pretty=fuller -w")
|
29
|
-
GitCommitNotifier::Git.show("#{SAMPLE_REV}\n", true)
|
29
|
+
GitCommitNotifier::Git.show("#{SAMPLE_REV}\n", :ignore_whitespaces => true)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git-commit-notifier
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-12-09 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: diff-lcs
|
17
|
-
requirement: &
|
17
|
+
requirement: &70202081729720 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ~>
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: 1.1.2
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70202081729720
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: nntp
|
28
|
-
requirement: &
|
28
|
+
requirement: &70202081729240 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ~>
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: '1.0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70202081729240
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: premailer
|
39
|
-
requirement: &
|
39
|
+
requirement: &70202081728720 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ~>
|
@@ -50,10 +50,10 @@ dependencies:
|
|
50
50
|
version: 1.7.2
|
51
51
|
type: :runtime
|
52
52
|
prerelease: false
|
53
|
-
version_requirements: *
|
53
|
+
version_requirements: *70202081728720
|
54
54
|
- !ruby/object:Gem::Dependency
|
55
55
|
name: nokogiri
|
56
|
-
requirement: &
|
56
|
+
requirement: &70202081727760 !ruby/object:Gem::Requirement
|
57
57
|
none: false
|
58
58
|
requirements:
|
59
59
|
- - ~>
|
@@ -61,10 +61,10 @@ dependencies:
|
|
61
61
|
version: '1.4'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
|
-
version_requirements: *
|
64
|
+
version_requirements: *70202081727760
|
65
65
|
- !ruby/object:Gem::Dependency
|
66
66
|
name: rake
|
67
|
-
requirement: &
|
67
|
+
requirement: &70202081727220 !ruby/object:Gem::Requirement
|
68
68
|
none: false
|
69
69
|
requirements:
|
70
70
|
- - ~>
|
@@ -75,10 +75,10 @@ dependencies:
|
|
75
75
|
version: 0.9.0
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
|
-
version_requirements: *
|
78
|
+
version_requirements: *70202081727220
|
79
79
|
- !ruby/object:Gem::Dependency
|
80
80
|
name: bundler
|
81
|
-
requirement: &
|
81
|
+
requirement: &70202081726400 !ruby/object:Gem::Requirement
|
82
82
|
none: false
|
83
83
|
requirements:
|
84
84
|
- - ~>
|
@@ -89,10 +89,10 @@ dependencies:
|
|
89
89
|
version: 1.0.10
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
|
-
version_requirements: *
|
92
|
+
version_requirements: *70202081726400
|
93
93
|
- !ruby/object:Gem::Dependency
|
94
94
|
name: code-cleaner
|
95
|
-
requirement: &
|
95
|
+
requirement: &70202081725280 !ruby/object:Gem::Requirement
|
96
96
|
none: false
|
97
97
|
requirements:
|
98
98
|
- - ! '>='
|
@@ -100,10 +100,10 @@ dependencies:
|
|
100
100
|
version: '0'
|
101
101
|
type: :development
|
102
102
|
prerelease: false
|
103
|
-
version_requirements: *
|
103
|
+
version_requirements: *70202081725280
|
104
104
|
- !ruby/object:Gem::Dependency
|
105
105
|
name: rspec-core
|
106
|
-
requirement: &
|
106
|
+
requirement: &70202081724720 !ruby/object:Gem::Requirement
|
107
107
|
none: false
|
108
108
|
requirements:
|
109
109
|
- - ! '>='
|
@@ -111,10 +111,10 @@ dependencies:
|
|
111
111
|
version: '0'
|
112
112
|
type: :development
|
113
113
|
prerelease: false
|
114
|
-
version_requirements: *
|
114
|
+
version_requirements: *70202081724720
|
115
115
|
- !ruby/object:Gem::Dependency
|
116
116
|
name: rspec-expectations
|
117
|
-
requirement: &
|
117
|
+
requirement: &70202081724240 !ruby/object:Gem::Requirement
|
118
118
|
none: false
|
119
119
|
requirements:
|
120
120
|
- - ! '>='
|
@@ -122,10 +122,10 @@ dependencies:
|
|
122
122
|
version: '0'
|
123
123
|
type: :development
|
124
124
|
prerelease: false
|
125
|
-
version_requirements: *
|
125
|
+
version_requirements: *70202081724240
|
126
126
|
- !ruby/object:Gem::Dependency
|
127
127
|
name: rr
|
128
|
-
requirement: &
|
128
|
+
requirement: &70202081723720 !ruby/object:Gem::Requirement
|
129
129
|
none: false
|
130
130
|
requirements:
|
131
131
|
- - ~>
|
@@ -133,10 +133,10 @@ dependencies:
|
|
133
133
|
version: '1.0'
|
134
134
|
type: :development
|
135
135
|
prerelease: false
|
136
|
-
version_requirements: *
|
136
|
+
version_requirements: *70202081723720
|
137
137
|
- !ruby/object:Gem::Dependency
|
138
138
|
name: faker
|
139
|
-
requirement: &
|
139
|
+
requirement: &70202081723240 !ruby/object:Gem::Requirement
|
140
140
|
none: false
|
141
141
|
requirements:
|
142
142
|
- - ~>
|
@@ -144,10 +144,10 @@ dependencies:
|
|
144
144
|
version: 0.9.5
|
145
145
|
type: :development
|
146
146
|
prerelease: false
|
147
|
-
version_requirements: *
|
147
|
+
version_requirements: *70202081723240
|
148
148
|
- !ruby/object:Gem::Dependency
|
149
149
|
name: yard
|
150
|
-
requirement: &
|
150
|
+
requirement: &70202081722760 !ruby/object:Gem::Requirement
|
151
151
|
none: false
|
152
152
|
requirements:
|
153
153
|
- - ~>
|
@@ -155,10 +155,10 @@ dependencies:
|
|
155
155
|
version: 0.7.3
|
156
156
|
type: :development
|
157
157
|
prerelease: false
|
158
|
-
version_requirements: *
|
158
|
+
version_requirements: *70202081722760
|
159
159
|
- !ruby/object:Gem::Dependency
|
160
160
|
name: redcarpet
|
161
|
-
requirement: &
|
161
|
+
requirement: &70202081858160 !ruby/object:Gem::Requirement
|
162
162
|
none: false
|
163
163
|
requirements:
|
164
164
|
- - ~>
|
@@ -166,7 +166,7 @@ dependencies:
|
|
166
166
|
version: 1.17.2
|
167
167
|
type: :development
|
168
168
|
prerelease: false
|
169
|
-
version_requirements: *
|
169
|
+
version_requirements: *70202081858160
|
170
170
|
description: This git commit notifier sends html mails with nice diffs for every changed
|
171
171
|
file.
|
172
172
|
email: bodo@bitboxer.de
|
@@ -223,7 +223,7 @@ files:
|
|
223
223
|
- spec/spec_helper.rb
|
224
224
|
- template/email.html.erb
|
225
225
|
- template/styles.css
|
226
|
-
homepage: http://github.com/
|
226
|
+
homepage: http://bitboxer.github.com/git-commit-notifier/
|
227
227
|
licenses: []
|
228
228
|
post_install_message:
|
229
229
|
rdoc_options: []
|
@@ -237,7 +237,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
237
237
|
version: '0'
|
238
238
|
segments:
|
239
239
|
- 0
|
240
|
-
hash: -
|
240
|
+
hash: -3538399353583787974
|
241
241
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
242
242
|
none: false
|
243
243
|
requirements:
|
@@ -246,7 +246,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
246
246
|
version: '0'
|
247
247
|
requirements: []
|
248
248
|
rubyforge_project:
|
249
|
-
rubygems_version: 1.8.
|
249
|
+
rubygems_version: 1.8.10
|
250
250
|
signing_key:
|
251
251
|
specification_version: 3
|
252
252
|
summary: Sends git commit messages with diffs
|