Diff
Modified: trunk/Tools/ChangeLog (283372 => 283373)
--- trunk/Tools/ChangeLog 2021-10-01 16:21:23 UTC (rev 283372)
+++ trunk/Tools/ChangeLog 2021-10-01 16:27:24 UTC (rev 283373)
@@ -1,3 +1,23 @@
+2021-10-01 Jonathan Bedard <jbed...@apple.com>
+
+ [webkitscmpy] Linkify http urls in pull-requests
+ https://bugs.webkit.org/show_bug.cgi?id=230655
+
+ Reviewed by Stephanie Lewis.
+
+ * Scripts/libraries/webkitscmpy/setup.py: Bump version.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py: Ditto.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/pull_request.py:
+ (PullRequest):
+ (PullRequest.escape_html): Escape any html and linkify http urls.
+ (PullRequest.unescape_html): Unescape escaped html and strip links from http urls.
+ (PullRequest.create_body): Use <pre> and escape html in commit messages.
+ (PullRequest.parse_body): Match both <pre> and ```, escape html if <pre> was used.
+ * Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/bitbucket.py:
+ (BitBucket.PRGenerator.create): Opt out of linkifying http in comment body.
+ (BitBucket.PRGenerator.update): Ditto.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/test/pull_request_unittest.py:
+
2021-10-01 Kimmo Kinnunen <kkinnu...@apple.com>
Add Kimmo Kinnunen as reviewer
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/setup.py (283372 => 283373)
--- trunk/Tools/Scripts/libraries/webkitscmpy/setup.py 2021-10-01 16:21:23 UTC (rev 283372)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/setup.py 2021-10-01 16:27:24 UTC (rev 283373)
@@ -29,7 +29,7 @@
setup(
name='webkitscmpy',
- version='2.2.2',
+ version='2.2.3',
description='Library designed to interact with git and svn repositories.',
long_description=readme(),
classifiers=[
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py (283372 => 283373)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py 2021-10-01 16:21:23 UTC (rev 283372)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py 2021-10-01 16:27:24 UTC (rev 283373)
@@ -46,7 +46,7 @@
"Please install webkitcorepy with `pip install webkitcorepy --extra-index-url <package index URL>`"
)
-version = Version(2, 2, 2)
+version = Version(2, 2, 3)
AutoInstall.register(Package('fasteners', Version(0, 15, 0)))
AutoInstall.register(Package('monotonic', Version(1, 5)))
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/pull_request.py (283372 => 283373)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/pull_request.py 2021-10-01 16:21:23 UTC (rev 283372)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/pull_request.py 2021-10-01 16:27:24 UTC (rev 283373)
@@ -26,8 +26,23 @@
class PullRequest(object):
- COMMIT_BODY_RE = re.compile(r'\A#### (?P<hash>[0-9a-f]+)\n```\n(?P<message>.+)\n```\n?\Z', flags=re.DOTALL)
+ COMMIT_BODY_RES = [
+ dict(
+ re=re.compile(r'\A#### (?P<hash>[0-9a-f]+)\n```\n(?P<message>.+)\n```\n?\Z', flags=re.DOTALL),
+ escaped=False,
+ ), dict(
+ re=re.compile(r'\A#### (?P<hash>[0-9a-f]+)\n<pre>\n(?P<message>.+)\n</pre>\n?\Z', flags=re.DOTALL),
+ escaped=True,
+ ),
+ ]
DIVIDER_LEN = 70
+ ESCAPE_TABLE = {
+ '"': '"',
+ "'": ''',
+ '>': ' >',
+ '<': '<',
+ '&': '&',
+ }
class State(object):
OPENED = 'opened'
@@ -34,12 +49,31 @@
CLOSED = 'closed'
@classmethod
- def create_body(cls, body, commits):
+ def escape_html(cls, message):
+ message = ''.join(cls.ESCAPE_TABLE.get(c, c) for c in message)
+ return re.sub(r'(https?://[^\s<>,:;]+)', r'<a href="" message)
+
+ @classmethod
+ def unescape_html(cls, message):
+ message = re.sub(r'<a href="" r'\1', message)
+ for c, escaped in cls.ESCAPE_TABLE.items():
+ message = message.replace(escaped, c)
+ return message
+
+ @classmethod
+ def create_body(cls, body, commits, linkify=True):
body = body or ''
if not commits:
return body
if body:
body = '{}\n\n{}\n'.format(body.rstrip(), '-' * cls.DIVIDER_LEN)
+ if linkify:
+ return body + '\n{}\n'.format('-' * cls.DIVIDER_LEN).join([
+ '#### {}\n<pre>\n{}\n</pre>'.format(
+ commit.hash,
+ cls.escape_html(commit.message.rstrip() if commit.message else '???'),
+ ) for commit in commits
+ ])
return body + '\n{}\n'.format('-' * cls.DIVIDER_LEN).join([
'#### {}\n```\n{}\n```'.format(commit.hash, commit.message.rstrip() if commit.message else '???') for commit in commits
])
@@ -53,16 +87,20 @@
commits = []
for part in parts:
- match = cls.COMMIT_BODY_RE.match(part)
- if match:
- commits.append(Commit(
- hash=match.group('hash'),
- message=match.group('message') if match.group('message') != '???' else None,
- ))
- elif body:
- body = '{}\n{}\n{}\n'.format(body.rstrip(), '-' * cls.DIVIDER_LEN, part.rstrip().lstrip())
+ for obj in cls.COMMIT_BODY_RES:
+ match = obj['re'].match(part)
+ if match:
+ message = cls.unescape_html(match.group('message')) if obj.get('escaped') else match.group('message')
+ commits.append(Commit(
+ hash=match.group('hash'),
+ message=message if message != '???' else None,
+ ))
+ break
else:
- body = part.rstrip().lstrip()
+ if body:
+ body = '{}\n{}\n{}\n'.format(body.rstrip(), '-' * cls.DIVIDER_LEN, part.rstrip().lstrip())
+ else:
+ body = part.rstrip().lstrip()
return body or None, commits
def __init__(self, number, title=None, body=None, author=None, head=None, base=None):
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/bitbucket.py (283372 => 283373)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/bitbucket.py 2021-10-01 16:21:23 UTC (rev 283372)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/bitbucket.py 2021-10-01 16:27:24 UTC (rev 283373)
@@ -74,7 +74,7 @@
if len(title) > self.TITLE_CHAR_LIMIT:
raise ValueError('Title length too long. Limit is: {}'.format(self.TITLE_CHAR_LIMIT))
- description = PullRequest.create_body(body, commits)
+ description = PullRequest.create_body(body, commits, linkify=False)
if description and len(description) > self.BODY_CHAR_LIMIT:
raise ValueError('Body length too long. Limit is: {}'.format(self.BODY_CHAR_LIMIT))
response = requests.post(
@@ -84,7 +84,7 @@
name=self.repository.name,
), json=dict(
title=title,
- description=PullRequest.create_body(body, commits),
+ description=PullRequest.create_body(body, commits, linkify=False),
fromRef=dict(
id='refs/heads/{}'.format(head),
repository=dict(
@@ -125,7 +125,7 @@
if title:
to_change['title'] = title
if body or commits:
- to_change['description'] = PullRequest.create_body(body, commits)
+ to_change['description'] = PullRequest.create_body(body, commits, linkify=False)
if head:
to_change['fromRef'] = dict(
id='refs/heads/{}'.format(head),
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/pull_request_unittest.py (283372 => 283373)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/pull_request_unittest.py 2021-10-01 16:21:23 UTC (rev 283372)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/pull_request_unittest.py 2021-10-01 16:27:24 UTC (rev 283373)
@@ -33,12 +33,25 @@
self.assertEqual('PR 123 | [scoping] Bug to fix', str(PullRequest(123, title='[scoping] Bug to fix')))
self.assertEqual('PR 1234', str(PullRequest(1234)))
- def test_create_body_single(self):
+ def test_create_body_single_linked(self):
self.assertEqual(
PullRequest.create_body(None, [Commit(
hash='11aa76f9fc380e9fe06157154f32b304e8dc4749',
message='[scoping] Bug to fix\n\nReviewed by Tim Contributor.\n',
)]), '''#### 11aa76f9fc380e9fe06157154f32b304e8dc4749
+<pre>
+[scoping] Bug to fix
+
+Reviewed by Tim Contributor.
+</pre>''',
+ )
+
+ def test_create_body_single_no_link(self):
+ self.assertEqual(
+ PullRequest.create_body(None, [Commit(
+ hash='11aa76f9fc380e9fe06157154f32b304e8dc4749',
+ message='[scoping] Bug to fix\n\nReviewed by Tim Contributor.\n',
+ )], linkify=False), '''#### 11aa76f9fc380e9fe06157154f32b304e8dc4749
```
[scoping] Bug to fix
@@ -58,17 +71,43 @@
self.assertEqual(commits[0].hash, '11aa76f9fc380e9fe06157154f32b304e8dc4749')
self.assertEqual(commits[0].message, '[scoping] Bug to fix\n\nReviewed by Tim Contributor.')
- def test_create_body_multiple(self):
+ def test_create_body_multiple_linked(self):
self.assertEqual(
PullRequest.create_body(None, [Commit(
hash='11aa76f9fc380e9fe06157154f32b304e8dc4749',
- message='[scoping] Bug to fix (Part 2)\n\nReviewed by Tim Contributor.\n',
+ message='[scoping] Bug to fix (Part 2)\nhttps://bugs.webkit.org/1234\n\nReviewed by Tim Contributor.\n',
), Commit(
hash='53ea230fcedbce327eb1c45a6ab65a88de864505',
- message='[scoping] Bug to fix (Part 1)\n\nReviewed by Tim Contributor.\n',
+ message='[scoping] Bug to fix (Part 1)\n<http://bugs.webkit.org/1234>\n\nReviewed by Tim Contributor.\n',
)]), '''#### 11aa76f9fc380e9fe06157154f32b304e8dc4749
+<pre>
+[scoping] Bug to fix (Part 2)
+<a href=""
+
+Reviewed by Tim Contributor.
+</pre>
+----------------------------------------------------------------------
+#### 53ea230fcedbce327eb1c45a6ab65a88de864505
+<pre>
+[scoping] Bug to fix (Part 1)
+<<a href="" >
+
+Reviewed by Tim Contributor.
+</pre>''',
+ )
+
+ def test_create_body_multiple_no_link(self):
+ self.assertEqual(
+ PullRequest.create_body(None, [Commit(
+ hash='11aa76f9fc380e9fe06157154f32b304e8dc4749',
+ message='[scoping] Bug to fix (Part 2)\nhttps://bugs.webkit.org/1234\n\nReviewed by Tim Contributor.\n',
+ ), Commit(
+ hash='53ea230fcedbce327eb1c45a6ab65a88de864505',
+ message='[scoping] Bug to fix (Part 1)\n<http://bugs.webkit.org/1234>\n\nReviewed by Tim Contributor.\n',
+ )], linkify=False), '''#### 11aa76f9fc380e9fe06157154f32b304e8dc4749
```
[scoping] Bug to fix (Part 2)
+https://bugs.webkit.org/1234
Reviewed by Tim Contributor.
```
@@ -76,6 +115,7 @@
#### 53ea230fcedbce327eb1c45a6ab65a88de864505
```
[scoping] Bug to fix (Part 1)
+<http://bugs.webkit.org/1234>
Reviewed by Tim Contributor.
```''',
@@ -104,13 +144,39 @@
self.assertEqual(commits[1].hash, '53ea230fcedbce327eb1c45a6ab65a88de864505')
self.assertEqual(commits[1].message, '[scoping] Bug to fix (Part 1)\n\nReviewed by Tim Contributor.')
+ def test_parse_html_body_multiple(self):
+ self.maxDiff = None
+ body, commits = PullRequest.parse_body('''#### 11aa76f9fc380e9fe06157154f32b304e8dc4749
+<pre>
+[scoping] Bug to fix (Part 2)
+<a href=""
+
+Reviewed by Tim Contributor.
+</pre>
+----------------------------------------------------------------------
+#### 53ea230fcedbce327eb1c45a6ab65a88de864505
+<pre>
+[scoping] Bug to fix (Part 1)
+<<a href="" >
+
+Reviewed by Tim Contributor.
+</pre>''')
+ self.assertIsNone(body)
+ self.assertEqual(len(commits), 2)
+
+ self.assertEqual(commits[0].hash, '11aa76f9fc380e9fe06157154f32b304e8dc4749')
+ self.assertEqual(commits[0].message, '[scoping] Bug to fix (Part 2)\nhttps://bugs.webkit.org/1234\n\nReviewed by Tim Contributor.')
+
+ self.assertEqual(commits[1].hash, '53ea230fcedbce327eb1c45a6ab65a88de864505')
+ self.assertEqual(commits[1].message, '[scoping] Bug to fix (Part 1)\n<http://bugs.webkit.org/1234>\n\nReviewed by Tim Contributor.')
+
def test_create_body_empty(self):
self.assertEqual(
PullRequest.create_body(None, [Commit(hash='11aa76f9fc380e9fe06157154f32b304e8dc4749')]),
'''#### 11aa76f9fc380e9fe06157154f32b304e8dc4749
-```
+<pre>
???
-```''',
+</pre>''',
)
def test_parse_body_empty(self):
@@ -123,6 +189,16 @@
self.assertEqual(commits[0].hash, '11aa76f9fc380e9fe06157154f32b304e8dc4749')
self.assertEqual(commits[0].message, None)
+ def test_parse_html_body_empty(self):
+ body, commits = PullRequest.parse_body('''#### 11aa76f9fc380e9fe06157154f32b304e8dc4749
+<pre>
+???
+</pre>''')
+ self.assertIsNone(body)
+ self.assertEqual(len(commits), 1)
+ self.assertEqual(commits[0].hash, '11aa76f9fc380e9fe06157154f32b304e8dc4749')
+ self.assertEqual(commits[0].message, None)
+
def test_create_body_comment(self):
self.assertEqual(
PullRequest.create_body('Comment body', [Commit(
@@ -132,11 +208,11 @@
----------------------------------------------------------------------
#### 11aa76f9fc380e9fe06157154f32b304e8dc4749
-```
+<pre>
[scoping] Bug to fix
Reviewed by Tim Contributor.
-```''',
+</pre>''',
)
def test_parse_body_single(self):
@@ -154,7 +230,22 @@
self.assertEqual(commits[0].hash, '11aa76f9fc380e9fe06157154f32b304e8dc4749')
self.assertEqual(commits[0].message, '[scoping] Bug to fix\n\nReviewed by Tim Contributor.')
+ def test_parse_html_body_single(self):
+ body, commits = PullRequest.parse_body('''Comment body
+----------------------------------------------------------------------
+#### 11aa76f9fc380e9fe06157154f32b304e8dc4749
+<pre>
+[scoping] Bug to fix
+
+Reviewed by Tim Contributor.
+</pre>''')
+ self.assertEqual(body, 'Comment body')
+ self.assertEqual(len(commits), 1)
+ self.assertEqual(commits[0].hash, '11aa76f9fc380e9fe06157154f32b304e8dc4749')
+ self.assertEqual(commits[0].message, '[scoping] Bug to fix\n\nReviewed by Tim Contributor.')
+
+
class TestDoPullRequest(testing.PathTestCase):
basepath = 'mock/repository'