forked from instructure/canvas-lms
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlint_commit_message
executable file
·131 lines (104 loc) · 4.66 KB
/
lint_commit_message
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/usr/bin/env ruby
require 'shellwords'
require 'json'
require 'jira_ref_parser'
require 'yaml'
GERGICH_GIT_PATH=ENV.fetch("GERGICH_GIT_PATH", ".")
def git(command)
Dir.chdir(GERGICH_GIT_PATH) do
`git #{command}`
end
end
def comment(severity, line, message, link_to_guidelines = false)
$stderr.puts "line #{line}: [#{severity}]: #{message}"
if ENV['GERRIT_REFSPEC']
message += "\n\nHere are some guidelines to keep our git log pretty and useful: http://chris.beams.io/posts/git-commit/" if link_to_guidelines
# NOTE: add 6 to all line numbers, cuz parent/author/commit/dates/etc
payload = {path: "/COMMIT_MSG", position: line + 6, severity: severity, message: message}
`gergich comment #{Shellwords.escape(payload.to_json)}`
end
end
commit_message = ARGV[0] == "--stdin" ? STDIN.read : git("show --pretty=format:%B -s")
exit if commit_message =~ /\A\[?wip($|[\] :-])/i
lines = commit_message.split(/\n/)
subject = lines.shift
if lines.shift != ""
comment "error", 2, "add a blank line after the subject line", true
end
SUBJECT_MAX_LINE_LEN = 75
SUBJECT_IDEAL_LINE_LEN = 65
length_exemption_regex = /^Revert/
if subject.size > SUBJECT_MAX_LINE_LEN && subject !~ length_exemption_regex
comment "error", 1, "subject line can't exceed #{SUBJECT_MAX_LINE_LEN} chars (ideally keep it well under #{SUBJECT_IDEAL_LINE_LEN})", true
elsif subject.size > SUBJECT_IDEAL_LINE_LEN && subject !~ length_exemption_regex
comment "warn", 1, "subject line shouldn't exceed #{SUBJECT_IDEAL_LINE_LEN} chars", true
end
# not perfect (won't get irregular verbs, only checks first word), but
# close enough... does the right thing on most existing commits
maybe_wrong_tense_regex = /\A(spec: )?[a-z]+([^e]ed|[^aijoqsu]s|ing) /i
actually_ok_regex = /\A
(spec:\s+)?
(
# *ing words
(brand|br|[^ ]*learn|masquerad|upcom|shard|word|grad)ing |
# *ed words
(brand|fail|batch|emb|persist|enrich|(un)?publish|moderat|mut|grad)ed |
# *s words
(.*(ion|ment)|observer|alway|outcome|rail|user|spec|student|quizze|alert|plugin|term)s
)
/xi
maybe_start_with_wrong_tense = subject =~ maybe_wrong_tense_regex &&
subject !~ actually_ok_regex
if maybe_start_with_wrong_tense
comment "warn", 1, "make sure your commit message has an imperative verb (e.g. \"add\" instead of \"adds\", \"added\", or \"adding\")", true
end
has_the_word_i = subject =~ /(\A| )i('m)? /i
if has_the_word_i
comment "warn", 1, "just say what the commit does, and not in the first person :P", true
end
BODY_IDEAL_LINE_LENGTH = 75
long_lines = lines.each_with_index.select do |line, i|
line.size > BODY_IDEAL_LINE_LENGTH
end
if long_lines.size > 0
comment "warn", long_lines.first[1] + 3,
"try to keep all lines under #{BODY_IDEAL_LINE_LENGTH} characters" +
(long_lines.size > 1 ? " (note that #{long_lines.size - 1} other long lines follow this one)" : ""), true
end
is_a_selinimum_test = commit_message.split("[selinimum:ignore_intermediate_commits]")
if is_a_selinimum_test.size > 1
line = is_a_selinimum_test[0].count("\n") + 1
comment "error", line, "since you're telling selinimum to ignore intermediate commits, this commit may not be safe to merge"
end
starts_with_spec = subject =~ /\Aspec: /i
exit if starts_with_spec # we're trusting you here, don't be evil
commit_files = git("show --pretty=format:"" --name-only").split("\n")
only_affects_specs = commit_files.all? { |f| f =~ %r{\Aspec/} }
if only_affects_specs
comment "warn", 1, "since your commit only affects specs, please prefix your commit message with \"spec: \""
exit
end
user_config_file = File.expand_path("../../gems/dr_diff/config/gergich_user_config.yml", __FILE__)
if File.exists?(user_config_file)
config = YAML.load_file(user_config_file) || {}
user_list = config['only_report_errors'] || []
exit if user_list.include?(ENV['GERRIT_EVENT_ACCOUNT_EMAIL'])
end
gh_issue = (commit_message =~ /(?:refs|fixes|closes|resolves|references) gh-\d+/i)
SAFE_PARTS_REGEX = /UTF\-8/
TICKET_REGEX = /([A-Z]+\-[0-9]+)/
issue_ids = JiraRefParser.scan_message_for_issue_ids(commit_message)
if issue_ids.empty? && !gh_issue
parts = commit_message.gsub(SAFE_PARTS_REGEX, "")
.split(TICKET_REGEX)
if parts.size > 1
jira_hook_words = JiraRefParser::RefKeywords + JiraRefParser::FixKeywords
comment "warn", parts.first.count("\n") + 1, "the jira hooks won't link this commit to #{parts[1]} unless you use one of the following keywords: #{jira_hook_words.join(", ")}"
else
comment "warn", 3, "you should really reference a ticket ლ(ٱ٥ٱლ)"
end
end
has_a_test_plan = commit_message =~ /test[ -]plan/i
unless has_a_test_plan
comment "warn", 3, "y u no add test plan? ლ(ಠ益ಠლ)"
end