Commit d8145aa6 authored by Kamil Trzciński's avatar Kamil Trzciński

Refactor commit_messages#lint_commit

This introduces additional method for linting,
to reduce the complexity of `lint_commits`.
parent 9d842c70
...@@ -64,11 +64,12 @@ def too_many_changed_lines?(commit) ...@@ -64,11 +64,12 @@ def too_many_changed_lines?(commit)
lines_changed_in_commit(commit) >= 30 lines_changed_in_commit(commit) >= 30
end end
def lint_commits(commits) def emoji_checker
failures = false @emoji_checker ||= EmojiChecker.new
emoji_checker = EmojiChecker.new end
unicode_emoji_regex = %r(( def unicode_emoji_regex
@unicode_emoji_regex ||= %r((
[\u{1F300}-\u{1F5FF}] | [\u{1F300}-\u{1F5FF}] |
[\u{1F1E6}-\u{1F1FF}] | [\u{1F1E6}-\u{1F1FF}] |
[\u{2700}-\u{27BF}] | [\u{2700}-\u{27BF}] |
...@@ -77,123 +78,132 @@ def lint_commits(commits) ...@@ -77,123 +78,132 @@ def lint_commits(commits)
[\u{1F680}-\u{1F6FF}] | [\u{1F680}-\u{1F6FF}] |
[\u{2600}-\u{26FF}] [\u{2600}-\u{26FF}]
))x ))x
end
def lint_commit(commit)
# For now we'll ignore merge commits, as getting rid of those is a problem
# separate from enforcing good commit messages.
return false if commit.message.start_with?('Merge branch')
# We ignore revert commits as they are well structured by Git already
return false if commit.message.start_with?('Revert "')
failures = false
subject, separator, details = commit.message.split("\n", 3)
if subject.split.length < 3
fail_commit(
commit,
'The commit subject must contain at least three words'
)
failures = true
end
if subject.length > 72
fail_commit(
commit,
'The commit subject may not be longer than 72 characters'
)
failures = true
elsif subject.length > 50
warn_commit(
commit,
"This commit's subject line is acceptable, but please try to [reduce it to 50 characters](#{URL_LIMIT_SUBJECT})."
)
end
unless subject_starts_with_capital?(subject)
fail_commit(commit, 'The commit subject must start with a capital letter')
failures = true
end
if subject.end_with?('.')
fail_commit(commit, 'The commit subject must not end with a period')
failures = true
end
if separator && !separator.empty?
fail_commit(
commit,
'The commit subject and body must be separated by a blank line'
)
failures = true
end
details&.each_line do |line|
line = line.strip
commits.each do |commit| next if line.length <= 72
# For now we'll ignore merge commits, as getting rid of those is a problem
# separate from enforcing good commit messages. url_size = line.scan(%r((https?://\S+))).sum { |(url)| url.length }
next if commit.message.start_with?('Merge branch')
# If the line includes a URL, we'll allow it to exceed 72 characters, but
# We ignore revert commits as they are well structured by Git already # only if the line _without_ the URL does not exceed this limit.
next if commit.message.start_with?('Revert "') next if line.length - url_size <= 72
subject, separator, details = commit.message.split("\n", 3) fail_commit(
commit,
if subject.split.length < 3 'The commit body should not contain more than 72 characters per line'
fail_commit( )
commit,
'The commit subject must contain at least three words' failures = true
) end
failures = true if !details && too_many_changed_lines?(commit)
end fail_commit(
commit,
if subject.length > 72 'Commits that change 30 or more lines across at least three files ' \
fail_commit( 'must describe these changes in the commit body'
commit, )
'The commit subject may not be longer than 72 characters'
) failures = true
end
failures = true
elsif subject.length > 50 if emoji_checker.includes_emoji?(commit.message)
warn_commit( fail_commit(
commit, commit,
"This commit's subject line is acceptable, but please try to [reduce it to 50 characters](#{URL_LIMIT_SUBJECT})." 'Avoid the use of Markdown Emoji such as `:+1:`. ' \
) 'These add no value to the commit message, ' \
end 'and are displayed as plain text outside of GitLab'
)
unless subject_starts_with_capital?(subject)
fail_commit(commit, 'The commit subject must start with a capital letter') failures = true
failures = true end
end
if commit.message.match?(unicode_emoji_regex)
if subject.end_with?('.') fail_commit(
fail_commit(commit, 'The commit subject must not end with a period') commit,
failures = true 'Avoid the use of Unicode Emoji. ' \
end 'These add no value to the commit message, ' \
'and may not be displayed properly everywhere'
if separator && !separator.empty? )
fail_commit(
commit, failures = true
'The commit subject and body must be separated by a blank line' end
)
if commit.message.match?(%r(([\w\-\/]+)?(#|!|&|%)\d+\b))
failures = true fail_commit(
end commit,
'Use full URLs instead of short references ' \
details&.each_line do |line| '(`gitlab-org/gitlab-ce#123` or `!123`), as short references are ' \
line = line.strip 'displayed as plain text outside of GitLab'
)
next if line.length <= 72
failures = true
url_size = line.scan(%r((https?://\S+))).sum { |(url)| url.length } end
# If the line includes a URL, we'll allow it to exceed 72 characters, but failures
# only if the line _without_ the URL does not exceed this limit. end
next if line.length - url_size <= 72
def lint_commits(commits)
fail_commit( failed = commits.reject do |commit|
commit, lint_commit(commit)
'The commit body should not contain more than 72 characters per line'
)
failures = true
end
if !details && too_many_changed_lines?(commit)
fail_commit(
commit,
'Commits that change 30 or more lines across at least three files ' \
'must describe these changes in the commit body'
)
failures = true
end
if emoji_checker.includes_emoji?(commit.message)
fail_commit(
commit,
'Avoid the use of Markdown Emoji such as `:+1:`. ' \
'These add no value to the commit message, ' \
'and are displayed as plain text outside of GitLab'
)
failures = true
end
if commit.message.match?(unicode_emoji_regex)
fail_commit(
commit,
'Avoid the use of Unicode Emoji. ' \
'These add no value to the commit message, ' \
'and may not be displayed properly everywhere'
)
failures = true
end
if commit.message.match?(%r(([\w\-\/]+)?(#|!|&|%)\d+\b))
fail_commit(
commit,
'Use full URLs instead of short references ' \
'(`gitlab-org/gitlab-ce#123` or `!123`), as short references are ' \
'displayed as plain text outside of GitLab'
)
failures = true
end
end end
if failures if failed.any?
markdown(<<~MARKDOWN) markdown(<<~MARKDOWN)
## Commit message standards ## Commit message standards
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment