##// END OF EJS Templates
issue-trackers: implemented more sophisticated ticket data extraction based on advanced regex module, and special...
marcink -
r4498:2fce90e4 stable
parent child Browse files
Show More
@@ -1816,6 +1816,17 b' self: super: {'
1816 license = [ pkgs.lib.licenses.mit ];
1816 license = [ pkgs.lib.licenses.mit ];
1817 };
1817 };
1818 };
1818 };
1819 "regex" = super.buildPythonPackage {
1820 name = "regex-2020.9.27";
1821 doCheck = false;
1822 src = fetchurl {
1823 url = "https://files.pythonhosted.org/packages/93/8c/17f45cdfb39b13d4b5f909e4b4c2917abcbdef9c0036919a0399769148cf/regex-2020.9.27.tar.gz";
1824 sha256 = "179ngfzwbsjvn5vhyzdahvmg0f7acahkwwy9bpjy1pv08bm2mwx6";
1825 };
1826 meta = {
1827 license = [ pkgs.lib.licenses.psfl ];
1828 };
1829 };
1819 "redis" = super.buildPythonPackage {
1830 "redis" = super.buildPythonPackage {
1820 name = "redis-3.4.1";
1831 name = "redis-3.4.1";
1821 doCheck = false;
1832 doCheck = false;
@@ -1946,6 +1957,7 b' self: super: {'
1946 self."tzlocal"
1957 self."tzlocal"
1947 self."pyzmq"
1958 self."pyzmq"
1948 self."py-gfm"
1959 self."py-gfm"
1960 self."regex"
1949 self."redis"
1961 self."redis"
1950 self."repoze.lru"
1962 self."repoze.lru"
1951 self."requests"
1963 self."requests"
@@ -56,6 +56,7 b' pytz==2019.3'
56 tzlocal==1.5.1
56 tzlocal==1.5.1
57 pyzmq==14.6.0
57 pyzmq==14.6.0
58 py-gfm==0.1.4
58 py-gfm==0.1.4
59 regex==2020.9.27
59 redis==3.4.1
60 redis==3.4.1
60 repoze.lru==0.7
61 repoze.lru==0.7
61 requests==2.22.0
62 requests==2.22.0
@@ -474,9 +474,18 b' class AdminSettingsView(BaseAppView):'
474 route_name='admin_settings_issuetracker_test', request_method='POST',
474 route_name='admin_settings_issuetracker_test', request_method='POST',
475 renderer='string', xhr=True)
475 renderer='string', xhr=True)
476 def settings_issuetracker_test(self):
476 def settings_issuetracker_test(self):
477 return h.urlify_commit_message(
477 error_container = []
478
479 urlified_commit = h.urlify_commit_message(
478 self.request.POST.get('test_text', ''),
480 self.request.POST.get('test_text', ''),
479 'repo_group/test_repo1')
481 'repo_group/test_repo1', error_container=error_container)
482 if error_container:
483 def converter(inp):
484 return h.html_escape(unicode(inp))
485
486 return 'ERRORS: ' + '\n'.join(map(converter, error_container))
487
488 return urlified_commit
480
489
481 @LoginRequired()
490 @LoginRequired()
482 @HasPermissionAllDecorator('hg.admin')
491 @HasPermissionAllDecorator('hg.admin')
@@ -113,7 +113,7 b' def _commits_as_dict(event, commit_ids, '
113 cs_data['permalink_url'] = RepoModel().get_commit_url(
113 cs_data['permalink_url'] = RepoModel().get_commit_url(
114 repo, cs_data['raw_id'], request=event.request,
114 repo, cs_data['raw_id'], request=event.request,
115 permalink=True)
115 permalink=True)
116 urlified_message, issues_data = process_patterns(
116 urlified_message, issues_data, errors = process_patterns(
117 cs_data['message'], repo.repo_name)
117 cs_data['message'], repo.repo_name)
118 cs_data['issues'] = issues_data
118 cs_data['issues'] = issues_data
119 cs_data['message_html'] = urlify_commit_message(
119 cs_data['message_html'] = urlify_commit_message(
@@ -38,6 +38,7 b' import re'
38 import time
38 import time
39 import string
39 import string
40 import hashlib
40 import hashlib
41 import regex
41 from collections import OrderedDict
42 from collections import OrderedDict
42
43
43 import pygments
44 import pygments
@@ -1653,7 +1654,7 b' def get_active_pattern_entries(repo_name'
1653 return active_entries
1654 return active_entries
1654
1655
1655
1656
1656 pr_pattern_re = re.compile(r'(?:(?:^!)|(?: !))(\d+)')
1657 pr_pattern_re = regex.compile(r'(?:(?:^!)|(?: !))(\d+)')
1657
1658
1658 allowed_link_formats = [
1659 allowed_link_formats = [
1659 'html', 'rst', 'markdown', 'html+hovercard', 'rst+hovercard', 'markdown+hovercard']
1660 'html', 'rst', 'markdown', 'html+hovercard', 'rst+hovercard', 'markdown+hovercard']
@@ -1670,6 +1671,7 b' def process_patterns(text_string, repo_n'
1670 active_entries = get_active_pattern_entries(repo_name)
1671 active_entries = get_active_pattern_entries(repo_name)
1671
1672
1672 issues_data = []
1673 issues_data = []
1674 errors = []
1673 new_text = text_string
1675 new_text = text_string
1674
1676
1675 log.debug('Got %s entries to process', len(active_entries))
1677 log.debug('Got %s entries to process', len(active_entries))
@@ -1687,9 +1689,11 b' def process_patterns(text_string, repo_n'
1687 pattern = entry['pat_compiled']
1689 pattern = entry['pat_compiled']
1688 else:
1690 else:
1689 try:
1691 try:
1690 pattern = re.compile(r'%s' % entry['pat'])
1692 pattern = regex.compile(r'%s' % entry['pat'])
1691 except re.error:
1693 except regex.error as e:
1692 log.exception('issue tracker pattern: `%s` failed to compile', entry['pat'])
1694 regex_err = ValueError('{}:{}'.format(entry['pat'], e))
1695 log.exception('issue tracker pattern: `%s` failed to compile', regex_err)
1696 errors.append(regex_err)
1693 continue
1697 continue
1694
1698
1695 data_func = partial(
1699 data_func = partial(
@@ -1721,11 +1725,11 b' def process_patterns(text_string, repo_n'
1721 new_text = pr_pattern_re.sub(pr_url_func, new_text)
1725 new_text = pr_pattern_re.sub(pr_url_func, new_text)
1722 log.debug('processed !pr pattern')
1726 log.debug('processed !pr pattern')
1723
1727
1724 return new_text, issues_data
1728 return new_text, issues_data, errors
1725
1729
1726
1730
1727 def urlify_commit_message(commit_text, repository=None, active_pattern_entries=None,
1731 def urlify_commit_message(commit_text, repository=None, active_pattern_entries=None,
1728 issues_container=None):
1732 issues_container=None, error_container=None):
1729 """
1733 """
1730 Parses given text message and makes proper links.
1734 Parses given text message and makes proper links.
1731 issues are linked to given issue-server, and rest is a commit link
1735 issues are linked to given issue-server, and rest is a commit link
@@ -1745,12 +1749,15 b' def urlify_commit_message(commit_text, r'
1745 new_text = urlify_commits(new_text, repository)
1749 new_text = urlify_commits(new_text, repository)
1746
1750
1747 # process issue tracker patterns
1751 # process issue tracker patterns
1748 new_text, issues = process_patterns(new_text, repository or '',
1752 new_text, issues, errors = process_patterns(
1749 active_entries=active_pattern_entries)
1753 new_text, repository or '', active_entries=active_pattern_entries)
1750
1754
1751 if issues_container is not None:
1755 if issues_container is not None:
1752 issues_container.extend(issues)
1756 issues_container.extend(issues)
1753
1757
1758 if error_container is not None:
1759 error_container.extend(errors)
1760
1754 return literal(new_text)
1761 return literal(new_text)
1755
1762
1756
1763
@@ -1805,7 +1812,7 b" def render(source, renderer='rst', menti"
1805 elif renderer == 'rst':
1812 elif renderer == 'rst':
1806 if repo_name:
1813 if repo_name:
1807 # process patterns on comments if we pass in repo name
1814 # process patterns on comments if we pass in repo name
1808 source, issues = process_patterns(
1815 source, issues, errors = process_patterns(
1809 source, repo_name, link_format='rst',
1816 source, repo_name, link_format='rst',
1810 active_entries=active_pattern_entries)
1817 active_entries=active_pattern_entries)
1811 if issues_container is not None:
1818 if issues_container is not None:
@@ -1819,7 +1826,7 b" def render(source, renderer='rst', menti"
1819 elif renderer == 'markdown':
1826 elif renderer == 'markdown':
1820 if repo_name:
1827 if repo_name:
1821 # process patterns on comments if we pass in repo name
1828 # process patterns on comments if we pass in repo name
1822 source, issues = process_patterns(
1829 source, issues, errors = process_patterns(
1823 source, repo_name, link_format='markdown',
1830 source, repo_name, link_format='markdown',
1824 active_entries=active_pattern_entries)
1831 active_entries=active_pattern_entries)
1825 if issues_container is not None:
1832 if issues_container is not None:
@@ -16,8 +16,8 b' examples = ['
16 ),
16 ),
17
17
18 (
18 (
19 'Redmine',
19 'Tickets with #123 (Redmine etc)',
20 '(^#|\s#)(?P<issue_id>\d+)',
20 '(?<![a-zA-Z0-9_/]{1,10}-?)(#)(?P<issue_id>\d+)',
21 'https://myissueserver.com/${repo}/issue/${issue_id}',
21 'https://myissueserver.com/${repo}/issue/${issue_id}',
22 ''
22 ''
23 ),
23 ),
@@ -38,14 +38,15 b' examples = ['
38
38
39 (
39 (
40 'JIRA - All tickets',
40 'JIRA - All tickets',
41 '(^|\s\w+-\d+)',
41 # official JIRA ticket pattern
42 'https://myjira.com/browse/${id}',
42 '(?<![a-zA-Z0-9_/#]-?)(?P<issue_id>[A-Z]{1,6}-(?:[1-9][0-9]{0,7}))',
43 'https://myjira.com/browse/${issue_id}',
43 ''
44 ''
44 ),
45 ),
45
46
46 (
47 (
47 'JIRA - Project (JRA)',
48 'JIRA - Single project (JRA-XXXXXXXX)',
48 '(?:(^|\s)(?P<issue_id>(?:JRA-|JRA-)(?:\d+)))',
49 '(?<![a-zA-Z0-9_/#]-?)(?P<issue_id>JRA-(?:[1-9][0-9]{0,7}))',
49 'https://myjira.com/${issue_id}',
50 'https://myjira.com/${issue_id}',
50 ''
51 ''
51 ),
52 ),
@@ -275,13 +276,19 b' examples = ['
275 <div class='textarea-full'>
276 <div class='textarea-full'>
276 <textarea id="test_pattern_data" rows="12">
277 <textarea id="test_pattern_data" rows="12">
277 This is an example text for testing issue tracker patterns.
278 This is an example text for testing issue tracker patterns.
278 This commit fixes ticket #451 and ticket #910.
279 This commit fixes ticket #451 and ticket #910, reference for JRA-401.
279 Following tickets will get mentioned:
280 The following tickets will get mentioned:
280 #123
281 #123
281 #456
282 #456 and PROJ-101
282 JRA-123
283 JRA-123 and #123
283 JRA-456
284 PROJ-456
284 Open a pull request !101 to contribute !
285
286 [my artifact](http://something.com/JRA-1234-build.zip)
287
288 - #1001
289 - JRA-998
290
291 Open a pull request !101 to contribute!
285 Added tag v1.3.0 for commit 0f3b629be725
292 Added tag v1.3.0 for commit 0f3b629be725
286
293
287 Add a test pattern here and hit preview to see the link.
294 Add a test pattern here and hit preview to see the link.
@@ -121,7 +121,7 b' def test_extract_issues(backend, text_st'
121
121
122 with mock.patch.object(IssueTrackerSettingsModel,
122 with mock.patch.object(IssueTrackerSettingsModel,
123 'get_settings', get_settings_mock):
123 'get_settings', get_settings_mock):
124 text, issues = helpers.process_patterns(text_string, repo.repo_name)
124 text, issues, errors = helpers.process_patterns(text_string, repo.repo_name)
125
125
126 expected = copy.deepcopy(expected)
126 expected = copy.deepcopy(expected)
127 for item in expected:
127 for item in expected:
@@ -159,7 +159,7 b' def test_process_patterns_repo(backend, '
159
159
160 with mock.patch.object(IssueTrackerSettingsModel,
160 with mock.patch.object(IssueTrackerSettingsModel,
161 'get_settings', get_settings_mock):
161 'get_settings', get_settings_mock):
162 processed_text, issues = helpers.process_patterns(
162 processed_text, issues, error = helpers.process_patterns(
163 text_string, repo.repo_name, link_format)
163 text_string, repo.repo_name, link_format)
164
164
165 assert processed_text == expected_text.format(repo=repo.repo_name)
165 assert processed_text == expected_text.format(repo=repo.repo_name)
@@ -186,7 +186,7 b' def test_process_patterns_no_repo(text_s'
186
186
187 with mock.patch.object(IssueTrackerSettingsModel,
187 with mock.patch.object(IssueTrackerSettingsModel,
188 'get_global_settings', get_settings_mock):
188 'get_global_settings', get_settings_mock):
189 processed_text, issues = helpers.process_patterns(
189 processed_text, issues, errors = helpers.process_patterns(
190 text_string, '')
190 text_string, '')
191
191
192 assert processed_text == expected_text
192 assert processed_text == expected_text
@@ -211,7 +211,7 b' def test_process_patterns_non_existent_r'
211
211
212 with mock.patch.object(IssueTrackerSettingsModel,
212 with mock.patch.object(IssueTrackerSettingsModel,
213 'get_global_settings', get_settings_mock):
213 'get_global_settings', get_settings_mock):
214 processed_text, issues = helpers.process_patterns(
214 processed_text, issues, errors = helpers.process_patterns(
215 text_string, 'do-not-exist')
215 text_string, 'do-not-exist')
216
216
217 assert processed_text == expected_text
217 assert processed_text == expected_text
General Comments 0
You need to be logged in to leave comments. Login now