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( |
|
1752 | new_text, issues, errors = process_patterns( | |
1749 |
|
|
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 |
'( |
|
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 - |
|
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 |
|
|
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 |
J |
|
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