git-commit-mailer 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d41e58adc35fd16bcfca2e295036b47397d548d3
4
- data.tar.gz: 4ed5b675e95ceb15e26a06197cdb45951abd0200
3
+ metadata.gz: 136f22114f43ec2e9948d128a9070084b3af3b0b
4
+ data.tar.gz: 11441281f87e1d875665e935939d5af2eb66c701
5
5
  SHA512:
6
- metadata.gz: 487ef516f9c79d6c1648c0ca2f61d055db5b747214de9fbd1b69e52f70b7f0092eb3bb50dbff02c312ee11a4d28b4d543d3793ec07168fb8e8197db42f937a7d
7
- data.tar.gz: 7fddf6a57b2bcf15842033fff29cff2def697f632c323ce54083b6e42524d64ca7d6032ccd229d730186e0b10de49ec9424903db2b84f20bd97b74b77d528b49
6
+ metadata.gz: 2f6c8edf2e5aebffd8132bdebe699570c2cf0027ce3032f6e1d3d22fc3560b68016312d78ececfd12ff79e5157080c1050e406f1727477123b1b35dc63c2b219
7
+ data.tar.gz: 508e1476fb0050113ccbccde483a0209eb173bbebbb216bb69d2c3bf0b2a30a50cf40566eaf7683511b46e130127b242d530645e016a45c70f29ceb597ab3892
@@ -1,5 +1,30 @@
1
1
  # News
2
2
 
3
+ ## 1.0.4 - 2016-10-07 {#version-1-0-4}
4
+
5
+ ### Improvements
6
+
7
+ * [GitHub] Supported formatting merge message.
8
+
9
+ * [GitHub] Supported `GH-NNN` auto link.
10
+
11
+ * Supported diff in a line.
12
+
13
+ * Improved color schema.
14
+
15
+ * Supported special characters such as "," in author name.
16
+
17
+ * Supported showing diff in merge commit.
18
+
19
+ * [GitLab] Supported GitLab Wiki as a repository browser.
20
+
21
+ ### Fixes
22
+
23
+ * Fixed a bug that `@domain` in email address is handled as mention.
24
+
25
+ * Fixed a bug that commit ID like string in email address is handled
26
+ as commit ID.
27
+
3
28
  ## 1.0.3 - 2015-06-09 {#version-1-0-3}
4
29
 
5
30
  ### Improvements
@@ -19,6 +19,8 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
+ spec.add_runtime_dependency "diff-lcs"
23
+
22
24
  spec.add_development_dependency "bundler"
23
25
  spec.add_development_dependency "rake", "~> 10.0"
24
26
  spec.add_development_dependency "test-unit"
@@ -1,7 +1,5 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
1
  # Copyright (C) 2009 Ryo Onodera <onodera@clear-code.com>
4
- # Copyright (C) 2012-2014 Kouhei Sutou <kou@clear-code.com>
2
+ # Copyright (C) 2012-2016 Kouhei Sutou <kou@clear-code.com>
5
3
  #
6
4
  # This program is free software: you can redistribute it and/or modify
7
5
  # it under the terms of the GNU General Public License as published by
@@ -273,7 +271,7 @@ class GitCommitMailer
273
271
 
274
272
  def make_parser(options)
275
273
  OptionParser.new do |parser|
276
- parser.banner += "TO"
274
+ parser.banner += " TO"
277
275
 
278
276
  add_repository_options(parser, options)
279
277
  add_email_options(parser, options)
@@ -304,7 +302,7 @@ class GitCommitMailer
304
302
  options.reference = reference
305
303
  end
306
304
 
307
- available_software = ["github", "github-wiki", "gitlab"]
305
+ available_software = ["github", "github-wiki", "gitlab", "gitlab-wiki"]
308
306
  label = available_software.join(", ")
309
307
  parser.on("--repository-browser=SOFTWARE",
310
308
  available_software,
@@ -559,11 +557,22 @@ class GitCommitMailer
559
557
  if /\A[^\s<]+@[^\s>]\z/ =~ @from
560
558
  @from
561
559
  else
562
- "#{info.author_name} <#{@from}>"
560
+ "#{format_name(info.author_name)} <#{@from}>"
561
+ end
562
+ else
563
+ "#{format_name(info.author_name)} <#{info.author_email}>"
564
+ end
565
+ end
566
+
567
+ def format_name(name)
568
+ case name
569
+ when /[,"\\]/
570
+ escaped_name = name.gsub(/["\\]/) do |special_character|
571
+ "\\#{special_character}"
563
572
  end
573
+ "\"#{escaped_name}\""
564
574
  else
565
- # return "#{info.author_name}@#{@from_domain}".sub(/@\z/, '') if @from_domain
566
- "#{info.author_name} <#{info.author_email}>"
575
+ name
567
576
  end
568
577
  end
569
578
 
@@ -1037,8 +1046,8 @@ EOF
1037
1046
  end
1038
1047
 
1039
1048
  merge_message = "Merged #{merge_commit.short_revision}: #{merge_commit.subject}"
1040
- if not is_traversing_first_parent and not commit_info.merge_status.index(merge_message)
1041
- commit_info.merge_status << merge_message
1049
+ if not is_traversing_first_parent and not commit_info.merge_messages.index(merge_message)
1050
+ commit_info.merge_messages << merge_message
1042
1051
  commit_info.merge_commits << merge_commit
1043
1052
  end
1044
1053
 
@@ -44,7 +44,7 @@ class GitCommitMailer
44
44
  attr_reader :added_files, :copied_files, :deleted_files, :updated_files
45
45
  attr_reader :renamed_files, :type_changed_files, :diffs
46
46
  attr_reader :subject, :author_name, :author_email, :date, :summary
47
- attr_accessor :merge_status
47
+ attr_accessor :merge_messages
48
48
  attr_writer :reference
49
49
  attr_reader :merge_commits
50
50
  def initialize(mailer, reference, revision)
@@ -64,7 +64,7 @@ class GitCommitMailer
64
64
  parse_file_status
65
65
  parse_diff
66
66
 
67
- @merge_status = []
67
+ @merge_messages = []
68
68
  @merge_commits = []
69
69
  end
70
70
 
@@ -185,7 +185,7 @@ class GitCommitMailer
185
185
  @diffs = []
186
186
  output = []
187
187
  n_bytes = 0
188
- git("log -n 1 --pretty=format:'' -C -p #{@revision}") do |io|
188
+ git("log -n 1 --pretty=format:'' -C --cc -p #{@revision}") do |io|
189
189
  io.each_line do |line|
190
190
  n_bytes += line.bytesize
191
191
  break if n_bytes > mailer.max_diff_size
@@ -83,9 +83,14 @@ class GitCommitMailer
83
83
 
84
84
  def parse_header(lines)
85
85
  line = lines.shift.strip
86
- if line =~ /\Adiff --git ("?a\/.*) ("?b\/.*)/
86
+ case line
87
+ when /\Adiff --git ("?a\/.*) ("?b\/.*)/
87
88
  @from_file = extract_file_path($1)
88
89
  @to_file = extract_file_path($2)
90
+ when /\Adiff --(?:combined|cc) (.*?)/
91
+ path = CommitInfo.unescape_file_path($1)
92
+ @from_file = path
93
+ @to_file = path
89
94
  else
90
95
  raise "Unexpected diff header format: #{line}"
91
96
  end
@@ -116,6 +121,9 @@ class GitCommitMailer
116
121
  when /\Aindex ([0-9a-f]{7,})\.\.([0-9a-f]{7,})/
117
122
  @old_blob = $1
118
123
  @new_blob = $2
124
+ when /\Aindex ([0-9a-f]{7,}),([0-9a-f]{7,}\.\.[0-9a-f]{7,})/
125
+ @old_blob = $1
126
+ @new_blob = $2
119
127
  else
120
128
  return false
121
129
  end
@@ -18,6 +18,8 @@
18
18
 
19
19
  require "digest/md5"
20
20
 
21
+ require "diff/lcs"
22
+
21
23
  class GitCommitMailer
22
24
  class HTMLMailBodyFormatter < MailBodyFormatter
23
25
  include ERB::Util
@@ -42,18 +44,18 @@ class GitCommitMailer
42
44
  <%= dd(h(@mailer.format_time(@info.date))) %>
43
45
  <%= dt("New Revision") %>
44
46
  <%= dd(format_revision) %>
45
- <% unless @info.merge_status.empty? %>
47
+ <% unless @info.merge_messages.empty? %>
46
48
  <%= dt("Merge") %>
47
49
  <%= dd_start %>
48
50
  <ul>
49
- <% @info.merge_status.each do |status| %>
50
- <li><%= h(status) %></li>
51
+ <% @info.merge_messages.each do |message| %>
52
+ <li><%= format_message(message) %></li>
51
53
  <% end %>
52
54
  </ul>
53
55
  </dd>
54
56
  <% end %>
55
57
  <%= dt("Message") %>
56
- <%= dd(format_summary(@info.summary.strip)) %>
58
+ <%= dd(pre(format_message(@info.summary))) %>
57
59
  <%= format_files("Added", @info.added_files) %>
58
60
  <%= format_files("Copied", @info.copied_files) %>
59
61
  <%= format_files("Removed", @info.deleted_files) %>
@@ -72,7 +74,7 @@ class GitCommitMailer
72
74
  revision = @info.revision
73
75
  url = commit_url
74
76
  if url
75
- formatted_revision = "<a href=\"#{h(url)}\">#{h(revision)}</a>"
77
+ formatted_revision = tag("a", {"href" => url}, h(revision))
76
78
  else
77
79
  formatted_revision = h(revision)
78
80
  end
@@ -170,6 +172,8 @@ class GitCommitMailer
170
172
  from_line_column = ""
171
173
  to_line_column = ""
172
174
  content_column = ""
175
+ content_lines = []
176
+
173
177
  file_path = diff.file_path
174
178
  diff.changes.each do |type, line_number, line|
175
179
  case type
@@ -179,6 +183,8 @@ class GitCommitMailer
179
183
  from_line_number)
180
184
  to_line_column << span_line_number_hunk_header(file_path, :to,
181
185
  to_line_number)
186
+
187
+ flush_content_lines(content_column, content_lines)
182
188
  case line
183
189
  when /\A(@@[\s0-9\-+,]+@@\s*)(.+)(\s*)\z/
184
190
  hunk_info = $1
@@ -187,50 +193,152 @@ class GitCommitMailer
187
193
  else
188
194
  formatted_line = h(line)
189
195
  end
190
- content_column << span_diff_hunk_header(formatted_line)
196
+ content_column << span_diff_hunk_header(formatted_line) << "\n"
191
197
  when :added
192
198
  from_line_column << span_line_number_nothing
193
199
  to_line_column << span_line_number_added(file_path, line_number)
194
- content_column << span_diff_added(h(line))
200
+ content_lines << [:added, line]
195
201
  when :deleted
196
202
  from_line_column << span_line_number_deleted(file_path, line_number)
197
203
  to_line_column << span_line_number_nothing
198
- content_column << span_diff_deleted(h(line))
204
+ content_lines << [:deleted, line]
199
205
  when :not_changed
200
206
  from_line_number, to_line_number = line_number
201
207
  from_line_column << span_line_number_not_changed(file_path, :from,
202
208
  from_line_number)
203
209
  to_line_column << span_line_number_not_changed(file_path, :to,
204
210
  to_line_number)
205
- content_column << span_diff_not_changed(h(line))
211
+ flush_content_lines(content_column, content_lines)
212
+ content_column << span_diff_not_changed(h(line)) << "\n"
206
213
  end
207
214
  from_line_column << "\n"
208
215
  to_line_column << "\n"
209
- content_column << "\n"
210
216
  end
217
+ flush_content_lines(content_column, content_lines)
211
218
  [from_line_column, to_line_column, content_column]
212
219
  end
213
220
 
214
- def format_summary(summary)
221
+ def flush_content_lines(column, lines)
222
+ return if lines.empty?
223
+
224
+ added_lines = []
225
+ deleted_lines = []
226
+ lines.each do |type, line|
227
+ if type == :added
228
+ added_lines << line
229
+ else
230
+ deleted_lines << line
231
+ end
232
+ end
233
+
234
+ if added_lines.size == deleted_lines.size
235
+ nth_added = 0
236
+ nth_deleted = 0
237
+ lines.each do |type, line|
238
+ if type == :added
239
+ deleted_line = deleted_lines[nth_added]
240
+ formatted_added_line = format_added_words(line, deleted_line)
241
+ column << span_diff_added(formatted_added_line) << "\n"
242
+ nth_added += 1
243
+ else
244
+ added_line = added_lines[nth_deleted]
245
+ formatted_deleted_line = format_deleted_words(line, added_line)
246
+ column << span_diff_deleted(formatted_deleted_line) << "\n"
247
+ nth_deleted += 1
248
+ end
249
+ end
250
+ else
251
+ lines.each do |type, line|
252
+ if type == :added
253
+ column << span_diff_added(h(line)) << "\n"
254
+ else
255
+ column << span_diff_deleted(h(line)) << "\n"
256
+ end
257
+ end
258
+ end
259
+ lines.clear
260
+ end
261
+
262
+ def format_changed_words(from_line, to_line, &formatter)
263
+ line = h(from_line[0, 1])
264
+ changed_chars = ""
265
+
266
+ flush_changed_chars = lambda do
267
+ unless changed_chars.empty?
268
+ line << formatter.call(h(changed_chars))
269
+ changed_chars.clear
270
+ end
271
+ end
272
+
273
+ Diff::LCS.sdiff(from_line[1..-1], to_line[1..-1]).each do |diff|
274
+ action, from, _to = *diff
275
+ _from_nth, from_char = from
276
+ next if from_char.nil?
277
+
278
+ case action
279
+ when "="
280
+ flush_changed_chars.call
281
+ line << h(from_char)
282
+ when "!", "-"
283
+ changed_chars << from_char
284
+ when "+"
285
+ flush_changed_chars.call
286
+ end
287
+ end
288
+ flush_changed_chars.call
289
+
290
+ line
291
+ end
292
+
293
+ def format_added_words(added_line, deleted_line)
294
+ format_changed_words(added_line, deleted_line) do |chars|
295
+ span_diff_added_word(chars)
296
+ end
297
+ end
298
+
299
+ def format_deleted_words(deleted_line, added_line)
300
+ format_changed_words(deleted_line, added_line) do |chars|
301
+ span_diff_deleted_word(chars)
302
+ end
303
+ end
304
+
305
+ def format_message(message)
306
+ message = message.strip
215
307
  case @mailer.repository_browser
216
308
  when "github"
217
- format_summary_github(summary)
309
+ format_message_github(message)
218
310
  else
219
- pre(h(summary))
311
+ h(message)
220
312
  end
221
313
  end
222
314
 
315
+ PATTERN_HTML_SPECIAL_CHARACTER = /['&\"<>]/
316
+ PATTERN_EMAIL = /[\da-zA-Z\-_]+@[\da-zA-Z\-_.]+/
317
+ GITHUB_MARKUP_PATTERN_GH_ISSUE = /GH-\d+/
223
318
  GITHUB_MARKUP_PATTERN_ISSUE = /\#\d+/
224
319
  GITHUB_MARKUP_PATTERN_COMMIT = /[\da-fA-F]{7,}/
225
320
  GITHUB_MARKUP_PATTERN_MENTION = /@[\da-zA-Z\-]+/
226
- def format_summary_github(summary)
227
- formatted_summary = summary.gsub(/
228
- ['&\"<>]|
229
- #{GITHUB_MARKUP_PATTERN_ISSUE}|
230
- #{GITHUB_MARKUP_PATTERN_COMMIT}|
231
- #{GITHUB_MARKUP_PATTERN_MENTION}
232
- /x) do |matched|
321
+ def format_message_github(message)
322
+ message.gsub(/
323
+ #{PATTERN_HTML_SPECIAL_CHARACTER}|
324
+ #{PATTERN_EMAIL}|
325
+ #{GITHUB_MARKUP_PATTERN_GH_ISSUE}|
326
+ #{GITHUB_MARKUP_PATTERN_ISSUE}|
327
+ #{GITHUB_MARKUP_PATTERN_COMMIT}|
328
+ #{GITHUB_MARKUP_PATTERN_MENTION}
329
+ /x) do |matched|
233
330
  case matched
331
+ when /\A#{PATTERN_HTML_SPECIAL_CHARACTER}\z/
332
+ h(matched)
333
+ when /\A#{PATTERN_EMAIL}\z/
334
+ h(matched)
335
+ when /\A#{GITHUB_MARKUP_PATTERN_GH_ISSUE}\z/
336
+ issue_number = matched.gsub(/\AGH-/, "")
337
+ tag("a",
338
+ {
339
+ "href" => github_issue_url(issue_number),
340
+ },
341
+ h(matched))
234
342
  when /\A#{GITHUB_MARKUP_PATTERN_ISSUE}\z/
235
343
  issue_number = matched.gsub(/\A\#/, "")
236
344
  tag("a",
@@ -256,7 +364,6 @@ class GitCommitMailer
256
364
  h(matched)
257
365
  end
258
366
  end
259
- pre(formatted_summary)
260
367
  end
261
368
 
262
369
  def github_issue_url(id)
@@ -462,14 +569,28 @@ class GitCommitMailer
462
569
 
463
570
  def span_deleted_styles
464
571
  {
465
- "background-color" => "#ffaaaa",
572
+ "background-color" => "#ffecec",
573
+ "color" => "#000000",
574
+ }
575
+ end
576
+
577
+ def span_deleted_word_styles
578
+ {
579
+ "background-color" => "#f8cbcb",
466
580
  "color" => "#000000",
467
581
  }
468
582
  end
469
583
 
470
584
  def span_added_styles
471
585
  {
472
- "background-color" => "#aaffaa",
586
+ "background-color" => "#eaffea",
587
+ "color" => "#000000",
588
+ }
589
+ end
590
+
591
+ def span_added_word_styles
592
+ {
593
+ "background-color" => "#a6f3a6",
473
594
  "color" => "#000000",
474
595
  }
475
596
  end
@@ -605,6 +726,15 @@ class GitCommitMailer
605
726
  content)
606
727
  end
607
728
 
729
+ def span_diff_deleted_word(content)
730
+ tag("span",
731
+ {
732
+ "class" => "diff-deleted-word",
733
+ "style" => span_deleted_word_styles,
734
+ },
735
+ content)
736
+ end
737
+
608
738
  def span_diff_added(content)
609
739
  tag("span",
610
740
  {
@@ -614,6 +744,15 @@ class GitCommitMailer
614
744
  content)
615
745
  end
616
746
 
747
+ def span_diff_added_word(content)
748
+ tag("span",
749
+ {
750
+ "class" => "diff-added-word",
751
+ "style" => span_added_word_styles,
752
+ },
753
+ content)
754
+ end
755
+
617
756
  def span_diff_not_changed(content)
618
757
  tag("span",
619
758
  {
@@ -632,6 +771,8 @@ class GitCommitMailer
632
771
  "#{base_url}#diff-#{file_md5}"
633
772
  when "github-wiki"
634
773
  commit_file_url_github_wiki(file)
774
+ when "gitlab-wiki"
775
+ commit_file_url_gitlab_wiki(file)
635
776
  else
636
777
  nil
637
778
  end
@@ -40,6 +40,9 @@ class GitCommitMailer
40
40
  return nil if @mailer.gitlab_project_uri.nil?
41
41
  revision = @info.revision
42
42
  "#{@mailer.gitlab_project_uri}/commit/#{revision}"
43
+ when "gitlab-wiki"
44
+ file = (@info.updated_files + @info.added_files).first
45
+ commit_file_url_gitlab_wiki(file)
43
46
  else
44
47
  nil
45
48
  end
@@ -66,5 +69,17 @@ class GitCommitMailer
66
69
  revision = @info.revision
67
70
  "#{base_url}/#{user}/#{repository}/wiki/#{page_name_in_url}/#{revision}"
68
71
  end
72
+
73
+ def commit_file_url_gitlab_wiki(file)
74
+ return nil if file.nil?
75
+
76
+ gitlab_project_uri = @mailer.gitlab_project_uri
77
+ return nil if gitlab_project_uri.nil?
78
+
79
+ page_name = file.gsub(/\.[^.]+\z/, "")
80
+ page_name_in_url = ERB::Util.u(page_name)
81
+ revision = @info.revision
82
+ "#{gitlab_project_uri}/wikis/#{page_name_in_url}?version_id=#{revision}"
83
+ end
69
84
  end
70
85
  end
@@ -31,9 +31,9 @@ class GitCommitMailer
31
31
  New Revision: <%= @info.revision %>
32
32
  <%= format_commit_url %>
33
33
 
34
- <% unless @info.merge_status.empty? %>
35
- <% @info.merge_status.each do |status| %>
36
- <%= status %>
34
+ <% unless @info.merge_messages.empty? %>
35
+ <% @info.merge_messages.each do |message| %>
36
+ <%= message %>
37
37
  <% end %>
38
38
 
39
39
  <% end %>
@@ -1,4 +1,4 @@
1
1
  class GitCommitMailer
2
- VERSION = "1.0.3"
2
+ VERSION = "1.0.4"
3
3
  URL = "https://github.com/clear-code/git-commit-mailer"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git-commit-mailer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryo Onodera
@@ -10,8 +10,22 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-06-09 00:00:00.000000000 Z
13
+ date: 2016-10-07 00:00:00.000000000 Z
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: diff-lcs
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '0'
15
29
  - !ruby/object:Gem::Dependency
16
30
  name: bundler
17
31
  requirement: !ruby/object:Gem::Requirement
@@ -117,9 +131,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
131
  version: '0'
118
132
  requirements: []
119
133
  rubyforge_project:
120
- rubygems_version: 2.2.2
134
+ rubygems_version: 2.5.1
121
135
  signing_key:
122
136
  specification_version: 4
123
137
  summary: A utility to send commit mails for commits pushed to git repositories.
124
138
  test_files: []
125
- has_rdoc: