Title: [283373] trunk/Tools
Revision
283373
Author
jbed...@apple.com
Date
2021-10-01 09:27:24 -0700 (Fri, 01 Oct 2021)

Log Message

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

Modified Paths

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 = {
+        '"': '&quot;',
+        "'": '&apos;',
+        '>': ' &gt;',
+        '<': '&lt;',
+        '&': '&amp;',
+    }
 
     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)
+&lt;<a href="" &gt;
+
+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)
+&lt;<a href="" &gt;
+
+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'
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to