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:
Brett Smith 2020-04-23 10:27:47 -04:00
parent d41bc5e9b6
commit d8507a1a35
4 changed files with 55 additions and 3 deletions

View file

@ -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)

View file

@ -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:

View file

@ -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',
]) ])

View file

@ -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,