diff --git a/rhodecode/lib/helpers.py b/rhodecode/lib/helpers.py
--- a/rhodecode/lib/helpers.py
+++ b/rhodecode/lib/helpers.py
@@ -1602,16 +1602,24 @@ def urlify_commits(text_, repository):
def _process_url_func(match_obj, repo_name, uid, entry,
- return_raw_data=False):
+ return_raw_data=False, link_format='html'):
pref = ''
if match_obj.group().startswith(' '):
pref = ' '
issue_id = ''.join(match_obj.groups())
- tmpl = (
- '%(pref)s'
- '%(issue-prefix)s%(id-repr)s'
- '')
+
+ if link_format == 'html':
+ tmpl = (
+ '%(pref)s'
+ '%(issue-prefix)s%(id-repr)s'
+ '')
+ elif link_format == 'rst':
+ tmpl = '`%(issue-prefix)s%(id-repr)s <%(url)s>`_'
+ elif link_format == 'markdown':
+ tmpl = '[%(issue-prefix)s%(id-repr)s](%(url)s)'
+ else:
+ raise ValueError('Bad link_format:{}'.format(link_format))
(repo_name_cleaned,
parent_group_name) = RepoGroupModel().\
@@ -1644,7 +1652,12 @@ def _process_url_func(match_obj, repo_na
return tmpl % data
-def process_patterns(text_string, repo_name, config=None):
+def process_patterns(text_string, repo_name, link_format='html'):
+ allowed_formats = ['html', 'rst', 'markdown']
+ if link_format not in allowed_formats:
+ raise ValueError('Link format can be only one of:{} got {}'.format(
+ allowed_formats, link_format))
+
repo = None
if repo_name:
# Retrieving repo_name to avoid invalid repo_name to explode on
@@ -1656,6 +1669,7 @@ def process_patterns(text_string, repo_n
issues_data = []
newtext = text_string
+
for uid, entry in active_entries.items():
log.debug('found issue tracker entry with uid %s' % (uid,))
@@ -1682,7 +1696,8 @@ def process_patterns(text_string, repo_n
issues_data.append(data_func(match_obj))
url_func = partial(
- _process_url_func, repo_name=repo_name, entry=entry, uid=uid)
+ _process_url_func, repo_name=repo_name, entry=entry, uid=uid,
+ link_format=link_format)
newtext = pattern.sub(url_func, newtext)
log.debug('processed prefix:uid `%s`' % (uid,))
@@ -1750,7 +1765,8 @@ def renderer_from_filename(filename, exc
return None
-def render(source, renderer='rst', mentions=False, relative_url=None):
+def render(source, renderer='rst', mentions=False, relative_url=None,
+ repo_name=None):
def maybe_convert_relative_links(html_source):
if relative_url:
@@ -1758,11 +1774,21 @@ def render(source, renderer='rst', menti
return html_source
if renderer == 'rst':
+ if repo_name:
+ # process patterns on comments if we pass in repo name
+ source, issues = process_patterns(
+ source, repo_name, link_format='rst')
+
return literal(
'
%s
' %
maybe_convert_relative_links(
MarkupRenderer.rst(source, mentions=mentions)))
elif renderer == 'markdown':
+ if repo_name:
+ # process patterns on comments if we pass in repo name
+ source, issues = process_patterns(
+ source, repo_name, link_format='markdown')
+
return literal(
'%s
' %
maybe_convert_relative_links(
diff --git a/rhodecode/tests/lib/test_helpers.py b/rhodecode/tests/lib/test_helpers.py
--- a/rhodecode/tests/lib/test_helpers.py
+++ b/rhodecode/tests/lib/test_helpers.py
@@ -103,55 +103,62 @@ def test_extract_issues(backend, text_st
assert issues == expected
-@pytest.mark.parametrize('text_string, pattern, expected_text', [
- ('Fix #42', '(?:#)(?P\d+)',
- 'Fix #42'
- ),
- ('Fix #42', '(?:#)?\d+)', 'Fix #42'), # Broken regex
+@pytest.mark.parametrize('text_string, pattern, link_format, expected_text', [
+ ('Fix #42', '(?:#)(?P\d+)', 'html',
+ 'Fix #42'),
+
+ ('Fix #42', '(?:#)(?P\d+)', 'markdown',
+ 'Fix [#42](http://r.io/{repo}/i/42)'),
+
+ ('Fix #42', '(?:#)(?P\d+)', 'rst',
+ 'Fix `#42 `_'),
+
+ ('Fix #42', '(?:#)?\d+)', 'html',
+ 'Fix #42'), # Broken regex
])
-def test_process_patterns_repo(backend, text_string, pattern, expected_text):
+def test_process_patterns_repo(backend, text_string, pattern, expected_text, link_format):
repo = backend.create_repo()
- config = {'123': {
- 'uid': '123',
- 'pat': pattern,
- 'url': 'http://r.io/${repo}/i/${issue_id}',
- 'pref': '#',
- }
- }
def get_settings_mock(self, cache=True):
- return config
+ return {
+ '123': {
+ 'uid': '123',
+ 'pat': pattern,
+ 'url': 'http://r.io/${repo}/i/${issue_id}',
+ 'pref': '#',
+ }
+ }
with mock.patch.object(IssueTrackerSettingsModel,
'get_settings', get_settings_mock):
processed_text, issues = helpers.process_patterns(
- text_string, repo.repo_name, config)
+ text_string, repo.repo_name, link_format)
assert processed_text == expected_text.format(repo=repo.repo_name)
@pytest.mark.parametrize('text_string, pattern, expected_text', [
('Fix #42', '(?:#)(?P\d+)',
- 'Fix #42'
- ),
- ('Fix #42', '(?:#)?\d+)', 'Fix #42'), # Broken regex
+ 'Fix #42'),
+ ('Fix #42', '(?:#)?\d+)',
+ 'Fix #42'), # Broken regex
])
def test_process_patterns_no_repo(text_string, pattern, expected_text):
- config = {'123': {
- 'uid': '123',
- 'pat': pattern,
- 'url': 'http://r.io/i/${issue_id}',
- 'pref': '#',
- }
- }
def get_settings_mock(self, cache=True):
- return config
+ return {
+ '123': {
+ 'uid': '123',
+ 'pat': pattern,
+ 'url': 'http://r.io/i/${issue_id}',
+ 'pref': '#',
+ }
+ }
with mock.patch.object(IssueTrackerSettingsModel,
'get_global_settings', get_settings_mock):
processed_text, issues = helpers.process_patterns(
- text_string, '', config)
+ text_string, '')
assert processed_text == expected_text
@@ -161,21 +168,21 @@ def test_process_patterns_non_existent_r
pattern = '(?:#)(?P\d+)'
expected_text = ('Fix #42')
- config = {'123': {
- 'uid': '123',
- 'pat': pattern,
- 'url': 'http://r.io/${repo}/i/${issue_id}',
- 'pref': '#',
- }
- }
def get_settings_mock(self, cache=True):
- return config
+ return {
+ '123': {
+ 'uid': '123',
+ 'pat': pattern,
+ 'url': 'http://r.io/${repo}/i/${issue_id}',
+ 'pref': '#',
+ }
+ }
with mock.patch.object(IssueTrackerSettingsModel,
'get_global_settings', get_settings_mock):
processed_text, issues = helpers.process_patterns(
- text_string, 'do-not-exist', config)
+ text_string, 'do-not-exist')
assert processed_text == expected_text