rtutil: Add RTUtil.metadata_regexp() classmethod.
The accruals check script wants to be able to search RT links in all kinds of metadata, not just rt-id as the filter currently handles.
This commit is contained in:
parent
d41bc5e9b6
commit
d8507a1a35
4 changed files with 55 additions and 3 deletions
|
@ -17,6 +17,7 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from . import data
|
from . import data
|
||||||
|
from . import rtutil
|
||||||
|
|
||||||
from typing import (
|
from typing import (
|
||||||
Iterable,
|
Iterable,
|
||||||
|
@ -53,5 +54,5 @@ def filter_for_rt_id(postings: Postings, ticket_id: Union[int, str]) -> Postings
|
||||||
This functions yields postings where the *first* rt-id matches the given
|
This functions yields postings where the *first* rt-id matches the given
|
||||||
ticket number.
|
ticket number.
|
||||||
"""
|
"""
|
||||||
regexp = r'^\s*rt:(?://ticket/)?{}\b'.format(re.escape(str(ticket_id)))
|
regexp = rtutil.RT.metadata_regexp(ticket_id, first_link_only=True)
|
||||||
return filter_meta_match(postings, 'rt-id', regexp)
|
return filter_meta_match(postings, 'rt-id', regexp)
|
||||||
|
|
|
@ -266,6 +266,35 @@ class RT:
|
||||||
def exists(self, ticket_id: RTId, attachment_id: Optional[RTId]=None) -> bool:
|
def exists(self, ticket_id: RTId, attachment_id: Optional[RTId]=None) -> bool:
|
||||||
return self.url(ticket_id, attachment_id) is not None
|
return self.url(ticket_id, attachment_id) is not None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def metadata_regexp(self,
|
||||||
|
ticket_id: RTId,
|
||||||
|
attachment_id: Optional[RTId]=None,
|
||||||
|
*,
|
||||||
|
first_link_only: bool=False
|
||||||
|
) -> str:
|
||||||
|
"""Return a pattern to find RT links in metadata
|
||||||
|
|
||||||
|
Given a ticket ID and optional attachment ID, this method returns a
|
||||||
|
regular expression pattern that will find matching RT links in a
|
||||||
|
metadata value string, written in any format.
|
||||||
|
|
||||||
|
If the keyword-only argument first_link_only is true, the pattern will
|
||||||
|
only match the first link in a metadata string. Otherwise the pattern
|
||||||
|
matches any link in the string (the default).
|
||||||
|
"""
|
||||||
|
if first_link_only:
|
||||||
|
prolog = r'^\s*'
|
||||||
|
else:
|
||||||
|
prolog = r'(?:^|\s)'
|
||||||
|
if attachment_id is None:
|
||||||
|
attachment = ''
|
||||||
|
else:
|
||||||
|
attachment = r'/(?:attachments?/)?{}'.format(attachment_id)
|
||||||
|
ticket = r'rt:(?://ticket/)?{}'.format(ticket_id)
|
||||||
|
epilog = r'/?(?:$|\s)'
|
||||||
|
return f'{prolog}{ticket}{attachment}{epilog}'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def parse(cls, s: str) -> Optional[Tuple[str, Optional[str]]]:
|
def parse(cls, s: str) -> Optional[Tuple[str, Optional[str]]]:
|
||||||
for regexp in cls.PARSE_REGEXPS:
|
for regexp in cls.PARSE_REGEXPS:
|
||||||
|
|
|
@ -111,11 +111,9 @@ def test_filter_for_rt_id(cc_txn_pair, ticket_id, expected_indexes):
|
||||||
|
|
||||||
@pytest.mark.parametrize('rt_id', [
|
@pytest.mark.parametrize('rt_id', [
|
||||||
'rt:450/',
|
'rt:450/',
|
||||||
'rt:450/678',
|
|
||||||
' rt:450 rt:540',
|
' rt:450 rt:540',
|
||||||
'rt://ticket/450',
|
'rt://ticket/450',
|
||||||
'rt://ticket/450/',
|
'rt://ticket/450/',
|
||||||
'rt://ticket/450/678',
|
|
||||||
' rt://ticket/450',
|
' rt://ticket/450',
|
||||||
'rt://ticket/450 rt://ticket/540',
|
'rt://ticket/450 rt://ticket/540',
|
||||||
])
|
])
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
|
import itertools
|
||||||
|
import re
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -62,6 +64,28 @@ def test_url(rt, ticket_id, attachment_id, expected):
|
||||||
expected = DEFAULT_RT_URL + expected
|
expected = DEFAULT_RT_URL + expected
|
||||||
assert rt.url(ticket_id, attachment_id) == expected
|
assert rt.url(ticket_id, attachment_id) == expected
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('attachment_id,first_link_only', itertools.product(
|
||||||
|
[245, None],
|
||||||
|
[True, False],
|
||||||
|
))
|
||||||
|
def test_metadata_regexp(rt, attachment_id, first_link_only):
|
||||||
|
if attachment_id is None:
|
||||||
|
match_links = ['rt:220', 'rt://ticket/220']
|
||||||
|
else:
|
||||||
|
match_links = [f'rt:220/{attachment_id}',
|
||||||
|
f'rt://ticket/220/attachments/{attachment_id}']
|
||||||
|
regexp = rt.metadata_regexp(220, attachment_id, first_link_only=first_link_only)
|
||||||
|
for link in match_links:
|
||||||
|
assert re.search(regexp, link)
|
||||||
|
assert re.search(regexp, link + ' link2')
|
||||||
|
assert re.search(regexp, link + '0') is None
|
||||||
|
assert re.search(regexp, 'a' + link) is None
|
||||||
|
end_match = re.search(regexp, 'link0 ' + link)
|
||||||
|
if first_link_only:
|
||||||
|
assert end_match is None
|
||||||
|
else:
|
||||||
|
assert end_match
|
||||||
|
|
||||||
@pytest.mark.parametrize('attachment_id', [
|
@pytest.mark.parametrize('attachment_id', [
|
||||||
13,
|
13,
|
||||||
None,
|
None,
|
||||||
|
|
Loading…
Reference in a new issue