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