Title: [284892] trunk/Tools
Revision
284892
Author
jbed...@apple.com
Date
2021-10-26 13:10:33 -0700 (Tue, 26 Oct 2021)

Log Message

[webkitscmpy] Comment and close pull-requests
https://bugs.webkit.org/show_bug.cgi?id=232095
<rdar://problem/84515738>

Reviewed by Dewei Zhu.

* Scripts/libraries/webkitscmpy/setup.py: Bump version.
* Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py: Ditto.
* Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/bitbucket.py:
(BitBucket.request): Add support for activities, opening and closing pull-request.
* Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py:
(GitHub.__init__): Add issues.
(GitHub.request): Access issue underlying pull-request (which includes global comments).
* Scripts/libraries/webkitscmpy/webkitscmpy/pull_request.py:
(PullRequest.Exception): Added.
(PullRequest.Comment): Added.
(PullRequest.__init__): Add list of pull-request comments, metadata used by generator.
(PullRequest.open): Re-open the pull-request.
(PullRequest.close): Close the pull-request.
(PullRequest.comment): Make a comment on the pull-request.
(PullRequest.comments): List all comments on a pull-request.
* Scripts/libraries/webkitscmpy/webkitscmpy/remote/bitbucket.py:
(BitBucket.PRGenerator.update): Handle closing and opening of the pull-request.
(BitBucket.PRGenerator.comment): Make a comment on a pull-request.
(BitBucket.PRGenerator.comments): List all comments on a pull-request.
* Scripts/libraries/webkitscmpy/webkitscmpy/remote/git_hub.py:
(GitHub.PRGenerator.update): Handle closing and opening of the pull-request.
(GitHub.PRGenerator.comment): Make a comment on a issue underpinning a pull-request.
(GitHub.PRGenerator.comments): List all comments on the pull-request.
* Scripts/libraries/webkitscmpy/webkitscmpy/remote/scm.py:
(Scm.PRGenerator.update): Add support for opening and closing a pull-request.
(Scm.PRGenerator.comment): Make a comment on a pull-request.
(Scm.PRGenerator.comments): List all comments for a pull-request
* Scripts/libraries/webkitscmpy/webkitscmpy/test/pull_request_unittest.py:

Modified Paths

Diff

Modified: trunk/Tools/ChangeLog (284891 => 284892)


--- trunk/Tools/ChangeLog	2021-10-26 19:51:18 UTC (rev 284891)
+++ trunk/Tools/ChangeLog	2021-10-26 20:10:33 UTC (rev 284892)
@@ -1,3 +1,40 @@
+2021-10-26  Jonathan Bedard  <jbed...@apple.com>
+
+        [webkitscmpy] Comment and close pull-requests
+        https://bugs.webkit.org/show_bug.cgi?id=232095
+        <rdar://problem/84515738>
+
+        Reviewed by Dewei Zhu.
+
+        * Scripts/libraries/webkitscmpy/setup.py: Bump version.
+        * Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py: Ditto.
+        * Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/bitbucket.py:
+        (BitBucket.request): Add support for activities, opening and closing pull-request.
+        * Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py:
+        (GitHub.__init__): Add issues.
+        (GitHub.request): Access issue underlying pull-request (which includes global comments).
+        * Scripts/libraries/webkitscmpy/webkitscmpy/pull_request.py:
+        (PullRequest.Exception): Added.
+        (PullRequest.Comment): Added.
+        (PullRequest.__init__): Add list of pull-request comments, metadata used by generator.
+        (PullRequest.open): Re-open the pull-request.
+        (PullRequest.close): Close the pull-request.
+        (PullRequest.comment): Make a comment on the pull-request.
+        (PullRequest.comments): List all comments on a pull-request.
+        * Scripts/libraries/webkitscmpy/webkitscmpy/remote/bitbucket.py:
+        (BitBucket.PRGenerator.update): Handle closing and opening of the pull-request.
+        (BitBucket.PRGenerator.comment): Make a comment on a pull-request.
+        (BitBucket.PRGenerator.comments): List all comments on a pull-request.
+        * Scripts/libraries/webkitscmpy/webkitscmpy/remote/git_hub.py:
+        (GitHub.PRGenerator.update): Handle closing and opening of the pull-request.
+        (GitHub.PRGenerator.comment): Make a comment on a issue underpinning a pull-request.
+        (GitHub.PRGenerator.comments): List all comments on the pull-request.
+        * Scripts/libraries/webkitscmpy/webkitscmpy/remote/scm.py:
+        (Scm.PRGenerator.update): Add support for opening and closing a pull-request.
+        (Scm.PRGenerator.comment): Make a comment on a pull-request.
+        (Scm.PRGenerator.comments): List all comments for a pull-request
+        * Scripts/libraries/webkitscmpy/webkitscmpy/test/pull_request_unittest.py:
+
 2021-10-26  Simon Fraser  <simon.fra...@apple.com>
 
         The script should decide when an image diff cases, not ImageDiff

Modified: trunk/Tools/Scripts/libraries/webkitscmpy/setup.py (284891 => 284892)


--- trunk/Tools/Scripts/libraries/webkitscmpy/setup.py	2021-10-26 19:51:18 UTC (rev 284891)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/setup.py	2021-10-26 20:10:33 UTC (rev 284892)
@@ -29,7 +29,7 @@
 
 setup(
     name='webkitscmpy',
-    version='2.2.15',
+    version='2.2.16',
     description='Library designed to interact with git and svn repositories.',
     long_description=readme(),
     classifiers=[

Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py (284891 => 284892)


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py	2021-10-26 19:51:18 UTC (rev 284891)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py	2021-10-26 20:10:33 UTC (rev 284892)
@@ -46,7 +46,7 @@
         "Please install webkitcorepy with `pip install webkitcorepy --extra-index-url <package index URL>`"
     )
 
-version = Version(2, 2, 15)
+version = Version(2, 2, 16)
 
 AutoInstall.register(Package('fasteners', Version(0, 15, 0)))
 AutoInstall.register(Package('jinja2', Version(2, 11, 3)))

Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/bitbucket.py (284891 => 284892)


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/bitbucket.py	2021-10-26 19:51:18 UTC (rev 284891)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/bitbucket.py	2021-10-26 20:10:33 UTC (rev 284892)
@@ -22,6 +22,7 @@
 
 import os
 import json
+import time
 
 from webkitcorepy import mocks
 from webkitscmpy import Commit, remote as scmremote
@@ -207,7 +208,7 @@
                 at = (params or {}).get('at', None)
                 if at and candidate.get('fromRef', {}).get('id') != at:
                     continue
-                prs.append(candidate)
+                prs.append({key: value for key, value in candidate.items() if key != 'activities'})
 
             return mocks.Response.fromJson(dict(
                 size=len(prs),
@@ -223,12 +224,14 @@
             json['fromRef']['displayId'] = json['fromRef']['id'].split('/')[-2:]
             json['toRef']['displayId'] = json['toRef']['id'].split('/')[-2:]
             json['state'] = 'OPEN'
+            json['activities'] = []
             self.pull_requests.append(json)
             return mocks.Response.fromJson(json)
 
         # Update or access pull-request
         if stripped_url.startswith(pr_base):
-            number = int(stripped_url.split('/')[-1])
+            split_url = stripped_url.split('/')
+            number = int(split_url[9])
             existing = None
             for i in range(len(self.pull_requests)):
                 if self.pull_requests[i].get('id') == number:
@@ -237,6 +240,33 @@
                 return mocks.Response.create404(url)
             if method == 'PUT':
                 self.pull_requests[existing].update(json)
-            return mocks.Response.fromJson(self.pull_requests[existing])
+            if len(split_url) < 11:
+                return mocks.Response.fromJson({key: value for key, value in self.pull_requests[existing].items() if key != 'activities'})
 
+            if method == 'GET' and split_url[-1] == 'activities':
+                return mocks.Response.fromJson(dict(
+                    size=len(self.pull_requests[existing].get('activities', [])),
+                    isLastPage=True,
+                    values=self.pull_requests[existing].get('activities', []),
+                ))
+            if method == 'POST' and split_url[-1] == 'comments':
+                self.pull_requests[existing]['activities'].append(dict(comment=dict(
+                    author=dict(displayName='Tim Committer', emailAddress='commit...@webkit.org'),
+                    createdDate=int(time.time() * 1000),
+                    updatedDate=int(time.time() * 1000),
+                    text=json.get('text', ''),
+                )))
+                return mocks.Response.fromJson({})
+            if method == 'POST' and split_url[-1] == 'decline':
+                self.pull_requests[existing]['open'] = False
+                self.pull_requests[existing]['closed'] = True
+                self.pull_requests[existing]['state'] = 'DECLINED'
+                return mocks.Response.fromJson({})
+            if method == 'POST' and split_url[-1] == 'reopen':
+                self.pull_requests[existing]['open'] = True
+                self.pull_requests[existing]['closed'] = False
+                self.pull_requests[existing]['state'] = 'OPEN'
+                return mocks.Response.fromJson({})
+            return mocks.Response.create404(url)
+
         return mocks.Response.create404(url)

Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py (284891 => 284892)


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py	2021-10-26 19:51:18 UTC (rev 284891)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py	2021-10-26 20:10:33 UTC (rev 284892)
@@ -22,6 +22,7 @@
 
 import os
 import json
+import time
 
 from webkitcorepy import mocks
 from webkitscmpy import Commit, remote as scmremote
@@ -59,6 +60,7 @@
         self.head = self.commits[self.default_branch][-1]
         self.tags = {}
         self.pull_requests = []
+        self.issues = dict()
         self.users = dict()
         self._environment = None
 
@@ -292,6 +294,8 @@
         ), url=""
 
     def request(self, method, url, data="" params=None, auth=None, json=None, **kwargs):
+        from datetime import datetime, timedelta
+
         if not url.startswith('http://') and not url.startswith('https://'):
             return mocks.Response.create404(url)
 
@@ -398,11 +402,14 @@
                     ref=json['base'],
                     user=dict(login=self.remote.split('/')[-2]),
                 )
+            if json.get('state'):
+                pr['state'] = json.get('state')
 
         # Create specifically
         if method == 'POST' and auth and stripped_url == pr_base:
             pr['number'] = 1 + max([0] + [pr.get('number', 0) for pr in self.pull_requests])
             pr['user'] = dict(login=auth.username)
+            pr['_links'] = dict(issue=dict(href=''.format(self.api_remote, pr['number'])))
             self.pull_requests.append(pr)
             return mocks.Response.fromJson(pr, url=""
 
@@ -422,4 +429,21 @@
         if method == 'GET' and stripped_url.startswith('{}/users'.format(self.api_remote.split('/')[0])):
             return self._users(url, stripped_url.split('/')[-1])
 
+        # Access underlying issue
+        if stripped_url.startswith('{}/issues/'.format(self.api_remote)):
+            number = int(stripped_url.split('/')[5])
+            issue = self.issues.get(number, dict(comments=[]))
+            if method == 'GET' and stripped_url.split('/')[6] == 'comments':
+                return mocks.Response.fromJson(issue['comments'], url=""
+            if method == 'POST' and stripped_url.split('/')[6] == 'comments':
+                self.issues[number] = issue
+                now = datetime.utcfromtimestamp(int(time.time()) - timedelta(hours=7).seconds).strftime('%Y-%m-%dT%H:%M:%SZ')
+                self.issues[number]['comments'].append(dict(
+                    user=dict(login=auth.username),
+                    created_at=now, updated_at=now,
+                    body=json.get('body', ''),
+                ))
+                return mocks.Response.fromJson(issue['comments'], url=""
+            return mocks.Response.create404(url)
+
         return mocks.Response.create404(url)

Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/pull_request.py (284891 => 284892)


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/pull_request.py	2021-10-26 19:51:18 UTC (rev 284891)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/pull_request.py	2021-10-26 20:10:33 UTC (rev 284892)
@@ -21,11 +21,46 @@
 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 import re
+import six
 
 from .commit import Commit
+from datetime import datetime
+from webkitscmpy import Contributor
 
 
 class PullRequest(object):
+    class Exception(RuntimeError):
+        pass
+
+    class Comment(object):
+        def __init__(self, author, timestamp, content):
+            if author and isinstance(author, dict) and author.get('name'):
+                self.author = Contributor(author.get('name'), author.get('emails'))
+            elif author and isinstance(author, six.string_types) and '@' in author:
+                self.author = Contributor(author, [author])
+            elif author and not isinstance(author, Contributor):
+                raise TypeError("Expected 'author' to be of type {}, got '{}'".format(Contributor, author))
+            else:
+                self.author = author
+
+            if isinstance(timestamp, six.string_types) and timestamp.isdigit():
+                timestamp = int(timestamp)
+            if timestamp and not isinstance(timestamp, int):
+                raise TypeError("Expected 'timestamp' to be of type int, got '{}'".format(timestamp))
+            self.timestamp = timestamp
+
+            if content and not isinstance(content, six.string_types):
+                raise ValueError("Expected 'content' to be a string, got '{}'".format(content))
+            self.content = content
+
+        def __repr__(self):
+            return '({} @ {}) {}'.format(
+                self.author,
+                datetime.utcfromtimestamp(self.timestamp) if self.timestamp else '-',
+                self.content,
+            )
+
+
     COMMIT_BODY_RES = [
         dict(
             re=re.compile(r'\A#### (?P<hash>[0-9a-f]+)\n```\n(?P<message>.+)\n```\n?\Z', flags=re.DOTALL),
@@ -99,7 +134,12 @@
                     body = part.rstrip().lstrip()
         return body or None, commits
 
-    def __init__(self, number, title=None, body=None, author=None, head=None, base=None, opened=None, generator=None):
+    def __init__(
+        self, number, title=None,
+        body=None, author=None,
+        head=None, base=None,
+        opened=None, generator=None, metadata=None,
+    ):
         self.number = number
         self.title = title
         self.body, self.commits = self.parse_body(body)
@@ -110,6 +150,8 @@
         self._reviewers = None
         self._approvers = None
         self._blockers = None
+        self._metadata = metadata
+        self._comments = None
         self.generator = generator
 
     @property
@@ -136,5 +178,32 @@
             return '?'
         return self._opened
 
+    def open(self):
+        if self.opened is True:
+            return self
+        if not self.generator:
+            raise self.Exception('No associated pull-request generator')
+        return self.generator.update(self, opened=True)
+
+    def close(self):
+        if self.opened is False:
+            return self
+        if not self.generator:
+            raise self.Exception('No associated pull-request generator')
+        return self.generator.update(self, opened=False)
+
+    def comment(self, content):
+        if not self.generator:
+            raise self.Exception('No associated pull-request generator')
+        self.generator.comment(self, content)
+        self._comments = None
+        return self
+
+    @property
+    def comments(self):
+        if self._comments is None and self.generator:
+            self._comments = list(self.generator.comments(self))
+        return self._comments
+
     def __repr__(self):
         return 'PR {}{}'.format(self.number, ' | {}'.format(self.title) if self.title else '')

Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/bitbucket.py (284891 => 284892)


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/bitbucket.py	2021-10-26 19:51:18 UTC (rev 284891)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/bitbucket.py	2021-10-26 20:10:33 UTC (rev 284892)
@@ -142,10 +142,32 @@
                 return None
             return self.PullRequest(response.json())
 
-        def update(self, pull_request, head=None, title=None, body=None, commits=None, base=None):
+        def update(self, pull_request, head=None, title=None, body=None, commits=None, base=None, opened=None):
             if not isinstance(pull_request, PullRequest):
-                raise ValueError(
-                    "Expected 'pull_request' to be of type '{}' not '{}'".format(PullRequest, type(pull_request)))
+                raise ValueError("Expected 'pull_request' to be of type '{}' not '{}'".format(PullRequest, type(pull_request)))
+
+            pr_url = 'https://{domain}/rest/api/1.0/projects/{project}/repos/{name}/pull-requests/{id}'.format(
+                domain=self.repository.domain,
+                project=self.repository.project,
+                name=self.repository.name,
+                id=pull_request.number,
+            )
+
+            if opened is not None:
+                response = requests.get(pr_url)
+                if response.status_code // 100 != 2:
+                    return None
+                response = requests.post(
+                    '{}/{}'.format(pr_url, 'reopen' if opened else 'decline'),
+                    json=dict(version=response.json().get('version', 0)),
+                )
+                if response.status_code // 100 != 2:
+                    return None
+
+                pull_request._opened = opened
+                if not any((head, title, body, commits, base)):
+                    return pull_request
+
             if not any((head, title, body, commits, base)):
                 raise ValueError('No arguments to update pull-request provided')
 
@@ -176,12 +198,6 @@
                     ),
                 )
 
-            pr_url = 'https://{domain}/rest/api/1.0/projects/{project}/repos/{name}/pull-requests/{id}'.format(
-                domain=self.repository.domain,
-                project=self.repository.project,
-                name=self.repository.name,
-                id=pull_request.number,
-            )
             response = requests.get(pr_url)
             if response.status_code // 100 != 2:
                 return None
@@ -213,6 +229,32 @@
             pull_request._approvers = got._approvers if got else []
             return pull_request
 
+        def comment(self, pull_request, content):
+            response = requests.post(
+                'https://{domain}/rest/api/1.0/projects/{project}/repos/{name}/pull-requests/{id}/comments'.format(
+                    domain=self.repository.domain,
+                    project=self.repository.project,
+                    name=self.repository.name,
+                    id=pull_request.number,
+                ), json=dict(text=content),
+            )
+            if response.status_code // 100 != 2:
+                sys.stderr.write("Failed to add comment to '{}'\n".format(pull_request))
+
+        def comments(self, pull_request):
+            for action in reversed(self.repository.request('pull-requests/{}/activities'.format(pull_request.number)) or []):
+                comment = action.get('comment', {})
+                user = comment.get('author', {})
+                if not comment or not user or not comment.get('text'):
+                    continue
+
+                yield PullRequest.Comment(
+                    author=self.repository.contributors.create(user['displayName'], user['emailAddress']),
+                    timestamp=comment.get('updatedDate', comment.get('createdDate')) // 1000,
+                    content=comment.get('text'),
+                )
+
+
     @classmethod
     def is_webserver(cls, url):
         return True if cls.URL_RE.match(url) else False

Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/git_hub.py (284891 => 284892)


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/git_hub.py	2021-10-26 19:51:18 UTC (rev 284891)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/git_hub.py	2021-10-26 20:10:33 UTC (rev 284892)
@@ -54,6 +54,9 @@
                     closed=False,
                 ).get(data.get('state'), None),
                 generator=self,
+                metadata=dict(
+                    issue=data.get('_links', {}).get('issue', {}).get('href'),
+                ),
             )
 
         def get(self, number):
@@ -103,10 +106,10 @@
                 return None
             return self.PullRequest(response.json())
 
-        def update(self, pull_request, head=None, title=None, body=None, commits=None, base=None):
+        def update(self, pull_request, head=None, title=None, body=None, commits=None, base=None, opened=None):
             if not isinstance(pull_request, PullRequest):
                 raise ValueError("Expected 'pull_request' to be of type '{}' not '{}'".format(PullRequest, type(pull_request)))
-            if not any((head, title, body, commits, base)):
+            if not any((head, title, body, commits, base)) and opened is None:
                 raise ValueError('No arguments to update pull-request provided')
 
             user, _ = self.repository.credentials(required=True)
@@ -117,6 +120,8 @@
             )
             if body or commits:
                 updates['body'] = PullRequest.create_body(body, commits)
+            if opened is not None:
+                updates['state'] = 'open' if opened else 'closed'
             response = requests.post(
                 '{api_url}/repos/{owner}/{name}/pulls/{number}'.format(
                     api_url=self.repository.api_url,
@@ -127,6 +132,9 @@
                 headers=dict(Accept='application/vnd.github.v3+json'),
                 json=updates,
             )
+            if response.status_code == 422:
+                pull_request._opened = False
+                return pull_request
             if response.status_code // 100 != 2:
                 return None
             data = ""
@@ -141,8 +149,11 @@
             pull_request._opened = dict(
                 open=True,
                 closed=False,
-            ).get(data.get('state'), None),
+            ).get(data.get('state'), None)
             pull_request.generator = self
+            pull_request._metadata = dict(
+                issue=data.get('_links', {}).get('issue', {}).get('href'),
+            )
 
             return pull_request
 
@@ -184,7 +195,57 @@
             pull_request._reviewers = sorted(pull_request._reviewers)
             return pull_request
 
+        def comment(self, pull_request, content):
+            issue = pull_request._metadata.get('issue')
+            if not issue:
+                old = pull_request
+                pull_request = self.get(old.number)
+                pull_request._reviewers = old._reviewers
+                pull_request._approvers = old._approvers
+                pull_request._blockers = old._blockers
+                issue = pull_request._metadata.get('issue')
+            if not issue:
+                raise self.repository.Exception('Failed to find issue underlying pull-request')
+            response = requests.post(
+                '{}/comments'.format(issue),
+                auth=HTTPBasicAuth(*self.repository.credentials(required=True)),
+                headers=dict(Accept='application/vnd.github.v3+json'),
+                json=dict(body=content),
+            )
+            if response.status_code // 100 != 2:
+                sys.stderr.write("Failed to add comment to '{}'\n".format(pull_request))
 
+        def comments(self, pull_request):
+            issue = pull_request._metadata.get('issue')
+            if not issue:
+                old = pull_request
+                pull_request = self.get(old.number)
+                pull_request._reviewers = old._reviewers
+                pull_request._approvers = old._approvers
+                pull_request._blockers = old._blockers
+                issue = pull_request._metadata.get('issue')
+            if not issue:
+                raise self.repository.Exception('Failed to find issue underlying pull-request')
+            response = requests.get(
+                '{}/comments'.format(issue),
+                auth=HTTPBasicAuth(*self.repository.credentials()),
+                headers=dict(Accept='application/vnd.github.v3+json'),
+            )
+            for node in response.json() if response.status_code // 100 == 2 else []:
+                user = node.get('user', {}).get('login')
+                if not user:
+                    continue
+                tm = node.get('updated_at', node.get('created_at'))
+                if tm:
+                    tm = int(calendar.timegm(datetime.strptime(tm, '%Y-%m-%dT%H:%M:%SZ').timetuple()))
+
+                yield PullRequest.Comment(
+                    author=self._contributor(user),
+                    timestamp=tm,
+                    content=node.get('body'),
+                )
+
+
     @classmethod
     def is_webserver(cls, url):
         return True if cls.URL_RE.match(url) else False

Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/scm.py (284891 => 284892)


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/scm.py	2021-10-26 19:51:18 UTC (rev 284891)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/scm.py	2021-10-26 20:10:33 UTC (rev 284892)
@@ -39,13 +39,19 @@
         def create(self, head, title, body=None, commits=None, base=None):
             raise NotImplementedError()
 
-        def update(self, pull_request, head=None, title=None, body=None, commits=None, base=None):
+        def update(self, pull_request, head=None, title=None, body=None, commits=None, base=None, opened=None):
             raise NotImplementedError()
 
         def reviewers(self, pull_request):
             raise NotImplementedError()
 
+        def comment(self, pull_request, content):
+            raise NotImplementedError()
 
+        def comments(self, pull_request):
+            raise NotImplementedError()
+
+
     @classmethod
     def from_url(cls, url, contributors=None):
         from webkitscmpy import remote

Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/pull_request_unittest.py (284891 => 284892)


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/pull_request_unittest.py	2021-10-26 19:51:18 UTC (rev 284891)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/pull_request_unittest.py	2021-10-26 20:10:33 UTC (rev 284892)
@@ -460,7 +460,9 @@
             reviews=[
                 dict(user=dict(login='ereviewer'), state='APPROVED'),
                 dict(user=dict(login='sreviewer'), state='CHANGES_REQUESTED'),
-            ],
+            ], _links=dict(
+                issue=dict(href=''.format(result.api_remote)),
+            ),
         )]
         return result
 
@@ -509,7 +511,25 @@
             self.assertEqual(pr.approvers, [])
             self.assertEqual(pr.blockers, [Contributor('Suspicious Reviewer', ['srevie...@webkit.org'])])
 
+    def test_comments(self):
+        with self.webserver():
+            repo = remote.GitHub(self.remote)
+            pr = repo.pull_requests.get(1)
+            self.assertEqual(pr.comments, [])
+            pr.comment('Commenting!')
+            self.assertEqual([c.content for c in pr.comments], ['Commenting!'])
 
+    def test_open_close(self):
+        with self.webserver():
+            repo = remote.GitHub(self.remote)
+            pr = repo.pull_requests.get(1)
+            self.assertTrue(pr.opened)
+            pr.close()
+            self.assertFalse(pr.opened)
+            pr.open()
+            self.assertTrue(pr.opened)
+
+
 class TestNetworkPullRequestBitBucket(unittest.TestCase):
     remote = 'https://bitbucket.example.com/projects/WEBKIT/repos/webkit'
 
@@ -521,6 +541,7 @@
             state='OPEN',
             open=True,
             closed=False,
+            activities=[],
             title='Example Change',
             author=dict(
                 user=dict(
@@ -606,3 +627,21 @@
             ])
             self.assertEqual(pr.approvers, [])
             self.assertEqual(pr.blockers, [Contributor('Suspicious Reviewer', ['srevie...@webkit.org'])])
+
+    def test_comments(self):
+        with self.webserver():
+            repo = remote.BitBucket(self.remote)
+            pr = repo.pull_requests.get(1)
+            self.assertEqual(pr.comments, [])
+            pr.comment('Commenting!')
+            self.assertEqual([c.content for c in pr.comments], ['Commenting!'])
+
+    def test_open_close(self):
+        with self.webserver():
+            repo = remote.BitBucket(self.remote)
+            pr = repo.pull_requests.get(1)
+            self.assertTrue(pr.opened)
+            pr.close()
+            self.assertFalse(pr.opened)
+            pr.open()
+            self.assertTrue(pr.opened)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to