Skip to content

Commit

Permalink
GitCommitBear.py: Require URL in commit body
Browse files Browse the repository at this point in the history
This ensures that the git commit contains a URL
that relates to an issue.

Fixes coala#1112
  • Loading branch information
nkprince007 committed Dec 17, 2016
1 parent e16a04a commit 0364586
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 0 deletions.
1 change: 1 addition & 0 deletions .coafile
Expand Up @@ -29,6 +29,7 @@ bears = SpaceConsistencyBear

[commit]
bears = GitCommitBear
host_site = github
shortlog_trailing_period = False
shortlog_regex = ([^:]*|[^:]+: [A-Z0-9*].*)

Expand Down
40 changes: 40 additions & 0 deletions bears/vcs/git/GitCommitBear.py
Expand Up @@ -3,6 +3,8 @@
import shutil
import os

from urllib.parse import urlparse

from coalib.bears.GlobalBear import GlobalBear
from coalib.bears.requirements.PipRequirement import PipRequirement
from coala_utils.ContextManagers import change_directory
Expand All @@ -21,6 +23,9 @@ class GitCommitBear(GlobalBear):
LICENSE = 'AGPL-3.0'
ASCIINEMA_URL = 'https://asciinema.org/a/e146c9739ojhr8396wedsvf0d'
CAN_DETECT = {'Formatting'}
GITHUB_KEYS = {'close', 'closes', 'closed', 'resolve',
'resolves', 'resolved', 'fix', 'fixes', 'fixed'}
GITLAB_KEYS = GITHUB_KEYS.union({'closing', 'resolving', 'fixing'})

@classmethod
def check_prerequisites(cls):
Expand Down Expand Up @@ -175,6 +180,7 @@ def check_imperative(self, paragraph):
def check_body(self, body,
body_line_length: int=72,
force_body: bool=False,
host_site: str=None,
ignore_length_regex: typed_list(str)=()):
"""
Checks the given commit body.
Expand All @@ -183,6 +189,10 @@ def check_body(self, body,
:param body_line_length: The maximum line-length of the body. The
newline character at each line end does not
count to the length.
:param host_site: The website used for hosting the git
repository. Choosing this value checks the
presence of full URLs in issue related
commits.
:param force_body: Whether a body shall exist or not.
:param ignore_length_regex: Lines matching each of the regular
expressions in this list will be ignored.
Expand All @@ -197,6 +207,36 @@ def check_body(self, body,
'HEAD commit. Please add one.')
return

if host_site:
body_string = '\n'.join(body).lower()
keys = set()

if 'github' in host_site.lower():
keys = self.GITHUB_KEYS
elif 'gitlab' in host_site.lower():
keys = self.GITLAB_KEYS

if any(key in body_string for key in keys):
urls = re.findall(r'(https?://\S+)', body_string)
good_url = False
for url in urls:
(scheme, netloc, path) = urlparse(url)[:3]
try:
if all([scheme, netloc, path]):
if host_site in netloc and '/issues/' in path:
int(path.split('/')[-1])
good_url = True
except ValueError:
yield Result(self, 'Invalid issue number present '
'in the body at HEAD commit.')
return

if not good_url:
yield Result(self, 'No issue related URL found in '
'the body at HEAD commit. '
'Please add one.')
return

ignore_regexes = [re.compile(regex) for regex in ignore_length_regex]
if any((len(line) > body_line_length and
not any(regex.search(line) for regex in ignore_regexes))
Expand Down
70 changes: 70 additions & 0 deletions tests/vcs/git/GitCommitBearTest.py
Expand Up @@ -267,6 +267,76 @@ def test_body_checks(self):
[])
self.assertTrue(self.msg_queue.empty())

# Commit has neither keywords nor issues
self.git_commit('Shortlog\n\n'
'This line is ok.\n'
'This line is by far too long (in this case).\n'
'This one too, blablablablablablablablabla.')
self.assertEqual(self.run_uut(host_site='github',), [])

# GitHub chosen and has an issue
self.git_commit('Shortlog\n\n'
'First line, blablablablablabla.\n'
'Another line, blablablablablabla.\n'
'Fix https://github.com/user/repo/issues/1234')
self.assertEqual(self.run_uut(host_site='github',), [])

# GitLab chosen and has an issue
self.git_commit('Shortlog\n\n'
'First line, blablablablablabla.\n'
'Another line, blablablablablabla.\n'
'Closing https://gitlab.com/user/repo/issues/100')
self.assertEqual(self.run_uut(host_site='gitlab',), [])

# Invalid issue number in URL
self.git_commit('Shortlog\n\n'
'First line, blablablablablabla.\n'
'Another line, blablablablablabla.\n'
'Closing https://gitlab.com/user/repo/issues/1af121')
self.assertEqual(self.run_uut(host_site='gitlab',),
['Invalid issue number present in the body '
'at HEAD commit.'])
self.assert_no_msgs()

# GitHub chosen and has keywords but no url
self.git_commit('Shortlog\n\n'
'First line, blablablablablabla.\n'
'Another line, blablablablablabla.\n'
'Fix #123')
self.assertEqual(self.run_uut(host_site='github',),
['No issue related URL found in '
'the body at HEAD commit. '
'Please add one.'])
self.assert_no_msgs()

# Git Host with no support
self.git_commit('Shortlog\n\n'
'First line, blablablablablabla.\n'
'Another line, blablablablablabla.\n'
'Fix #123')
self.assertEqual(self.run_uut(host_site='bitbucket',),
[])

# Has an invalid URL
self.git_commit('Shortlog\n\n'
'First line, blablablablablabla.\n'
'Another line, blablablablablabla.\n'
'Fix http://google.com')
self.assertEqual(self.run_uut(host_site='github',),
['No issue related URL found in '
'the body at HEAD commit. '
'Please add one.'])

# Has a URL but not issue related
self.git_commit('Shortlog\n\n'
'First line, blablablablablabla.\n'
'Another line, blablablablablabla.\n'
'Fix https://gitlab.com/user/repo')
self.assertEqual(self.run_uut(host_site='github',),
['No issue related URL found in '
'the body at HEAD commit. '
'Please add one.'])

def test_different_path(self):
no_git_dir = mkdtemp()
self.git_commit('Add a very long shortlog for a bad project history.')
Expand Down

0 comments on commit 0364586

Please sign in to comment.