##// END OF EJS Templates
comments: allow parsing the issue tracker patterns inside the markup...
marcink -
r1672:a43e4e95 default
parent child Browse files
Show More
@@ -1602,16 +1602,24 b' def urlify_commits(text_, repository):'
1602
1602
1603
1603
1604 def _process_url_func(match_obj, repo_name, uid, entry,
1604 def _process_url_func(match_obj, repo_name, uid, entry,
1605 return_raw_data=False):
1605 return_raw_data=False, link_format='html'):
1606 pref = ''
1606 pref = ''
1607 if match_obj.group().startswith(' '):
1607 if match_obj.group().startswith(' '):
1608 pref = ' '
1608 pref = ' '
1609
1609
1610 issue_id = ''.join(match_obj.groups())
1610 issue_id = ''.join(match_obj.groups())
1611 tmpl = (
1611
1612 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1612 if link_format == 'html':
1613 '%(issue-prefix)s%(id-repr)s'
1613 tmpl = (
1614 '</a>')
1614 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1615 '%(issue-prefix)s%(id-repr)s'
1616 '</a>')
1617 elif link_format == 'rst':
1618 tmpl = '`%(issue-prefix)s%(id-repr)s <%(url)s>`_'
1619 elif link_format == 'markdown':
1620 tmpl = '[%(issue-prefix)s%(id-repr)s](%(url)s)'
1621 else:
1622 raise ValueError('Bad link_format:{}'.format(link_format))
1615
1623
1616 (repo_name_cleaned,
1624 (repo_name_cleaned,
1617 parent_group_name) = RepoGroupModel().\
1625 parent_group_name) = RepoGroupModel().\
@@ -1644,7 +1652,12 b' def _process_url_func(match_obj, repo_na'
1644 return tmpl % data
1652 return tmpl % data
1645
1653
1646
1654
1647 def process_patterns(text_string, repo_name, config=None):
1655 def process_patterns(text_string, repo_name, link_format='html'):
1656 allowed_formats = ['html', 'rst', 'markdown']
1657 if link_format not in allowed_formats:
1658 raise ValueError('Link format can be only one of:{} got {}'.format(
1659 allowed_formats, link_format))
1660
1648 repo = None
1661 repo = None
1649 if repo_name:
1662 if repo_name:
1650 # Retrieving repo_name to avoid invalid repo_name to explode on
1663 # Retrieving repo_name to avoid invalid repo_name to explode on
@@ -1656,6 +1669,7 b' def process_patterns(text_string, repo_n'
1656
1669
1657 issues_data = []
1670 issues_data = []
1658 newtext = text_string
1671 newtext = text_string
1672
1659 for uid, entry in active_entries.items():
1673 for uid, entry in active_entries.items():
1660 log.debug('found issue tracker entry with uid %s' % (uid,))
1674 log.debug('found issue tracker entry with uid %s' % (uid,))
1661
1675
@@ -1682,7 +1696,8 b' def process_patterns(text_string, repo_n'
1682 issues_data.append(data_func(match_obj))
1696 issues_data.append(data_func(match_obj))
1683
1697
1684 url_func = partial(
1698 url_func = partial(
1685 _process_url_func, repo_name=repo_name, entry=entry, uid=uid)
1699 _process_url_func, repo_name=repo_name, entry=entry, uid=uid,
1700 link_format=link_format)
1686
1701
1687 newtext = pattern.sub(url_func, newtext)
1702 newtext = pattern.sub(url_func, newtext)
1688 log.debug('processed prefix:uid `%s`' % (uid,))
1703 log.debug('processed prefix:uid `%s`' % (uid,))
@@ -1750,7 +1765,8 b' def renderer_from_filename(filename, exc'
1750 return None
1765 return None
1751
1766
1752
1767
1753 def render(source, renderer='rst', mentions=False, relative_url=None):
1768 def render(source, renderer='rst', mentions=False, relative_url=None,
1769 repo_name=None):
1754
1770
1755 def maybe_convert_relative_links(html_source):
1771 def maybe_convert_relative_links(html_source):
1756 if relative_url:
1772 if relative_url:
@@ -1758,11 +1774,21 b" def render(source, renderer='rst', menti"
1758 return html_source
1774 return html_source
1759
1775
1760 if renderer == 'rst':
1776 if renderer == 'rst':
1777 if repo_name:
1778 # process patterns on comments if we pass in repo name
1779 source, issues = process_patterns(
1780 source, repo_name, link_format='rst')
1781
1761 return literal(
1782 return literal(
1762 '<div class="rst-block">%s</div>' %
1783 '<div class="rst-block">%s</div>' %
1763 maybe_convert_relative_links(
1784 maybe_convert_relative_links(
1764 MarkupRenderer.rst(source, mentions=mentions)))
1785 MarkupRenderer.rst(source, mentions=mentions)))
1765 elif renderer == 'markdown':
1786 elif renderer == 'markdown':
1787 if repo_name:
1788 # process patterns on comments if we pass in repo name
1789 source, issues = process_patterns(
1790 source, repo_name, link_format='markdown')
1791
1766 return literal(
1792 return literal(
1767 '<div class="markdown-block">%s</div>' %
1793 '<div class="markdown-block">%s</div>' %
1768 maybe_convert_relative_links(
1794 maybe_convert_relative_links(
@@ -103,55 +103,62 b' def test_extract_issues(backend, text_st'
103 assert issues == expected
103 assert issues == expected
104
104
105
105
106 @pytest.mark.parametrize('text_string, pattern, expected_text', [
106 @pytest.mark.parametrize('text_string, pattern, link_format, expected_text', [
107 ('Fix #42', '(?:#)(?P<issue_id>\d+)',
107 ('Fix #42', '(?:#)(?P<issue_id>\d+)', 'html',
108 'Fix <a class="issue-tracker-link" href="http://r.io/{repo}/i/42">#42</a>'
108 'Fix <a class="issue-tracker-link" href="http://r.io/{repo}/i/42">#42</a>'),
109 ),
109
110 ('Fix #42', '(?:#)?<issue_id>\d+)', 'Fix #42'), # Broken regex
110 ('Fix #42', '(?:#)(?P<issue_id>\d+)', 'markdown',
111 'Fix [#42](http://r.io/{repo}/i/42)'),
112
113 ('Fix #42', '(?:#)(?P<issue_id>\d+)', 'rst',
114 'Fix `#42 <http://r.io/{repo}/i/42>`_'),
115
116 ('Fix #42', '(?:#)?<issue_id>\d+)', 'html',
117 'Fix #42'), # Broken regex
111 ])
118 ])
112 def test_process_patterns_repo(backend, text_string, pattern, expected_text):
119 def test_process_patterns_repo(backend, text_string, pattern, expected_text, link_format):
113 repo = backend.create_repo()
120 repo = backend.create_repo()
114 config = {'123': {
115 'uid': '123',
116 'pat': pattern,
117 'url': 'http://r.io/${repo}/i/${issue_id}',
118 'pref': '#',
119 }
120 }
121
121
122 def get_settings_mock(self, cache=True):
122 def get_settings_mock(self, cache=True):
123 return config
123 return {
124 '123': {
125 'uid': '123',
126 'pat': pattern,
127 'url': 'http://r.io/${repo}/i/${issue_id}',
128 'pref': '#',
129 }
130 }
124
131
125 with mock.patch.object(IssueTrackerSettingsModel,
132 with mock.patch.object(IssueTrackerSettingsModel,
126 'get_settings', get_settings_mock):
133 'get_settings', get_settings_mock):
127 processed_text, issues = helpers.process_patterns(
134 processed_text, issues = helpers.process_patterns(
128 text_string, repo.repo_name, config)
135 text_string, repo.repo_name, link_format)
129
136
130 assert processed_text == expected_text.format(repo=repo.repo_name)
137 assert processed_text == expected_text.format(repo=repo.repo_name)
131
138
132
139
133 @pytest.mark.parametrize('text_string, pattern, expected_text', [
140 @pytest.mark.parametrize('text_string, pattern, expected_text', [
134 ('Fix #42', '(?:#)(?P<issue_id>\d+)',
141 ('Fix #42', '(?:#)(?P<issue_id>\d+)',
135 'Fix <a class="issue-tracker-link" href="http://r.io/i/42">#42</a>'
142 'Fix <a class="issue-tracker-link" href="http://r.io/i/42">#42</a>'),
136 ),
143 ('Fix #42', '(?:#)?<issue_id>\d+)',
137 ('Fix #42', '(?:#)?<issue_id>\d+)', 'Fix #42'), # Broken regex
144 'Fix #42'), # Broken regex
138 ])
145 ])
139 def test_process_patterns_no_repo(text_string, pattern, expected_text):
146 def test_process_patterns_no_repo(text_string, pattern, expected_text):
140 config = {'123': {
141 'uid': '123',
142 'pat': pattern,
143 'url': 'http://r.io/i/${issue_id}',
144 'pref': '#',
145 }
146 }
147
147
148 def get_settings_mock(self, cache=True):
148 def get_settings_mock(self, cache=True):
149 return config
149 return {
150 '123': {
151 'uid': '123',
152 'pat': pattern,
153 'url': 'http://r.io/i/${issue_id}',
154 'pref': '#',
155 }
156 }
150
157
151 with mock.patch.object(IssueTrackerSettingsModel,
158 with mock.patch.object(IssueTrackerSettingsModel,
152 'get_global_settings', get_settings_mock):
159 'get_global_settings', get_settings_mock):
153 processed_text, issues = helpers.process_patterns(
160 processed_text, issues = helpers.process_patterns(
154 text_string, '', config)
161 text_string, '')
155
162
156 assert processed_text == expected_text
163 assert processed_text == expected_text
157
164
@@ -161,21 +168,21 b' def test_process_patterns_non_existent_r'
161 pattern = '(?:#)(?P<issue_id>\d+)'
168 pattern = '(?:#)(?P<issue_id>\d+)'
162 expected_text = ('Fix <a class="issue-tracker-link" '
169 expected_text = ('Fix <a class="issue-tracker-link" '
163 'href="http://r.io/do-not-exist/i/42">#42</a>')
170 'href="http://r.io/do-not-exist/i/42">#42</a>')
164 config = {'123': {
165 'uid': '123',
166 'pat': pattern,
167 'url': 'http://r.io/${repo}/i/${issue_id}',
168 'pref': '#',
169 }
170 }
171
171
172 def get_settings_mock(self, cache=True):
172 def get_settings_mock(self, cache=True):
173 return config
173 return {
174 '123': {
175 'uid': '123',
176 'pat': pattern,
177 'url': 'http://r.io/${repo}/i/${issue_id}',
178 'pref': '#',
179 }
180 }
174
181
175 with mock.patch.object(IssueTrackerSettingsModel,
182 with mock.patch.object(IssueTrackerSettingsModel,
176 'get_global_settings', get_settings_mock):
183 'get_global_settings', get_settings_mock):
177 processed_text, issues = helpers.process_patterns(
184 processed_text, issues = helpers.process_patterns(
178 text_string, 'do-not-exist', config)
185 text_string, 'do-not-exist')
179
186
180 assert processed_text == expected_text
187 assert processed_text == expected_text
181
188
General Comments 0
You need to be logged in to leave comments. Login now