Title: [289856] trunk/Tools
Revision
289856
Author
[email protected]
Date
2022-02-15 15:09:30 -0800 (Tue, 15 Feb 2022)

Log Message

[webkitscmpy] Support draft pull-requests
https://bugs.webkit.org/show_bug.cgi?id=235721
<rdar://problem/88139678>

Rubber-stamped by Aakash Jain.

GitHub has the concept of a "draft" pull request. Our tooling should allow users
to request that the pull request they are updating or creating be converted to a draft.

* Tools/Scripts/libraries/webkitscmpy/setup.py: Bump version.
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py: Ditto.
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py:
(GitHub.request): Handle "draft" in upload.
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program/pull_request.py:
(PullRequest.parser): Add --draft option.
(PullRequest.main): When creating or uploading a pull-request, set draft state.
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/pull_request.py:
(PullRequest.__init__): Pass draft state.
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/bitbucket.py:
(BitBucket.PRGenerator.PullRequest): Pass draft state to PullRequest object.
(BitBucket.PRGenerator.create): Accept draft flag.
(BitBucket.PRGenerator.update): Ditto.
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/git_hub.py:
(GitHub.PRGenerator): Draft pull requests are a GitHub idea.
(GitHub.PRGenerator.PullRequest): Pass draft state to PullRequest object.
(GitHub.PRGenerator.create): Accept draft flag.
(GitHub.PRGenerator.update): Ditto.
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/scm.py:
(Scm.PRGenerator): Draft pull requests are a GitHub idea.
(Scm.PRGenerator.create): Accept draft flag.
(Scm.PRGenerator.update): Ditto.
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/checkout_unittest.py:
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/land_unittest.py:
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/pull_request_unittest.py:

Canonical link: https://commits.webkit.org/247298@main

Modified Paths

Diff

Modified: trunk/Tools/ChangeLog (289855 => 289856)


--- trunk/Tools/ChangeLog	2022-02-15 23:05:57 UTC (rev 289855)
+++ trunk/Tools/ChangeLog	2022-02-15 23:09:30 UTC (rev 289856)
@@ -1,5 +1,42 @@
 2022-02-15  Jonathan Bedard  <[email protected]>
 
+        [webkitscmpy] Support draft pull-requests
+        https://bugs.webkit.org/show_bug.cgi?id=235721
+        <rdar://problem/88139678>
+
+        Rubber-stamped by Aakash Jain.
+
+        GitHub has the concept of a "draft" pull request. Our tooling should allow users
+        to request that the pull request they are updating or creating be converted to a draft.
+
+        * Scripts/libraries/webkitscmpy/setup.py: Bump version.
+        * Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py: Ditto.
+        * Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py:
+        (GitHub.request): Handle "draft" in upload.
+        * Scripts/libraries/webkitscmpy/webkitscmpy/program/pull_request.py:
+        (PullRequest.parser): Add --draft option.
+        (PullRequest.main): When creating or uploading a pull-request, set draft state.
+        * Scripts/libraries/webkitscmpy/webkitscmpy/pull_request.py:
+        (PullRequest.__init__): Pass draft state.
+        * Scripts/libraries/webkitscmpy/webkitscmpy/remote/bitbucket.py:
+        (BitBucket.PRGenerator.PullRequest): Pass draft state to PullRequest object.
+        (BitBucket.PRGenerator.create): Accept draft flag.
+        (BitBucket.PRGenerator.update): Ditto.
+        * Scripts/libraries/webkitscmpy/webkitscmpy/remote/git_hub.py:
+        (GitHub.PRGenerator): Draft pull requests are a GitHub idea.
+        (GitHub.PRGenerator.PullRequest): Pass draft state to PullRequest object.
+        (GitHub.PRGenerator.create): Accept draft flag.
+        (GitHub.PRGenerator.update): Ditto.
+        * Scripts/libraries/webkitscmpy/webkitscmpy/remote/scm.py:
+        (Scm.PRGenerator): Draft pull requests are a GitHub idea.
+        (Scm.PRGenerator.create): Accept draft flag.
+        (Scm.PRGenerator.update): Ditto.
+        * Scripts/libraries/webkitscmpy/webkitscmpy/test/checkout_unittest.py:
+        * Scripts/libraries/webkitscmpy/webkitscmpy/test/land_unittest.py:
+        * Scripts/libraries/webkitscmpy/webkitscmpy/test/pull_request_unittest.py:
+
+2022-02-15  Jonathan Bedard  <[email protected]>
+
         [EWS] Support PRs when sending build failure emails (Follow-up fix)
         https://bugs.webkit.org/show_bug.cgi?id=235926
         <rdar://problem/88302122>

Modified: trunk/Tools/Scripts/libraries/webkitscmpy/setup.py (289855 => 289856)


--- trunk/Tools/Scripts/libraries/webkitscmpy/setup.py	2022-02-15 23:05:57 UTC (rev 289855)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/setup.py	2022-02-15 23:09:30 UTC (rev 289856)
@@ -29,7 +29,7 @@
 
 setup(
     name='webkitscmpy',
-    version='4.1.5',
+    version='4.2.0',
     description='Library designed to interact with git and svn repositories.',
     long_description=readme(),
     classifiers=[

Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py (289855 => 289856)


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py	2022-02-15 23:05:57 UTC (rev 289855)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py	2022-02-15 23:09:30 UTC (rev 289856)
@@ -46,7 +46,7 @@
         "Please install webkitcorepy with `pip install webkitcorepy --extra-index-url <package index URL>`"
     )
 
-version = Version(4, 1, 5)
+version = Version(4, 2, 0)
 
 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/git_hub.py (289855 => 289856)


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py	2022-02-15 23:05:57 UTC (rev 289855)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py	2022-02-15 23:09:30 UTC (rev 289856)
@@ -370,6 +370,8 @@
                 )
             if json.get('state'):
                 pr['state'] = json.get('state')
+            if json.get('draft'):
+                pr['draft'] = json.get('draft')
 
         # Create specifically
         if method == 'POST' and auth and stripped_url == pr_base:
@@ -377,6 +379,7 @@
             pr['state'] = 'open'
             pr['user'] = dict(login=auth.username)
             pr['_links'] = dict(issue=dict(href=''.format(self.api_remote, pr['number'])))
+            pr['draft'] = pr.get('draft', False)
             self.pull_requests.append(pr)
             if pr['number'] not in self.issues:
                 self.issues[pr['number']] = dict(

Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program/pull_request.py (289855 => 289856)


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program/pull_request.py	2022-02-15 23:05:57 UTC (rev 289855)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program/pull_request.py	2022-02-15 23:09:30 UTC (rev 289856)
@@ -72,6 +72,10 @@
             help='Create numbered branches to track the history of a change',
             action=""
         )
+        parser.add_argument(
+            '--draft', dest='draft', action='', default=None,
+            help='Mark a pull request as a draft when creating it',
+        )
 
     @classmethod
     def create_commit(cls, args, repository, **kwargs):
@@ -195,6 +199,10 @@
         if not rmt.pull_requests:
             sys.stderr.write("'{}' cannot generate pull-requests\n".format(rmt.url))
             return 1
+        if args.draft and not rmt.pull_requests.SUPPORTS_DRAFTS:
+            sys.stderr.write("'{}' does not support draft pull requests, aborting\n".format(rmt.url))
+            return 1
+
         existing_pr = None
         for pr in rmt.pull_requests.find(opened=None, head=repository.branch):
             existing_pr = pr
@@ -222,7 +230,8 @@
                 commits=commits,
                 base=branch_point.branch,
                 head=repository.branch,
-                opened=None if existing_pr.opened else True
+                opened=None if existing_pr.opened else True,
+                draft=args.draft,
             )
             if not pr:
                 sys.stderr.write("Failed to update pull-request '{}'\n".format(existing_pr))
@@ -235,6 +244,7 @@
                 commits=commits,
                 base=branch_point.branch,
                 head=repository.branch,
+                draft=args.draft,
             )
             if not pr:
                 sys.stderr.write("Failed to create pull-request for '{}'\n".format(repository.branch))

Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/pull_request.py (289855 => 289856)


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/pull_request.py	2022-02-15 23:05:57 UTC (rev 289855)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/pull_request.py	2022-02-15 23:09:30 UTC (rev 289856)
@@ -139,7 +139,7 @@
         body=None, author=None,
         head=None, base=None,
         opened=None, generator=None, metadata=None,
-        url=""
+        url="" draft=None
     ):
         self.number = number
         self.title = title
@@ -147,6 +147,7 @@
         self.author = author
         self.head = head
         self.base = base
+        self.draft = draft
         self._opened = opened
         self._reviewers = None
         self._approvers = None

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


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/bitbucket.py	2022-02-15 23:05:57 UTC (rev 289855)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/bitbucket.py	2022-02-15 23:09:30 UTC (rev 289856)
@@ -52,6 +52,7 @@
                 opened=True if data.get('open') else (False if data.get('closed') else None),
                 generator=self,
                 url=''.format(self.repository.url, data['id']),
+                draft=False,
             )
 
             result._reviewers = []
@@ -106,7 +107,10 @@
                         continue
                     yield self.PullRequest(datum)
 
-        def create(self, head, title, body=None, commits=None, base=None):
+        def create(self, head, title, body=None, commits=None, base=None, draft=None):
+            if draft:
+                sys.stderr.write('Bitbucket does not support the concept of a "draft" pull request\n')
+
             for key, value in dict(head=head, title=title).items():
                 if not value:
                     raise ValueError("Must define '{}' when creating pull-request".format(key))
@@ -143,10 +147,13 @@
                 return None
             return self.PullRequest(response.json())
 
-        def update(self, pull_request, head=None, title=None, body=None, commits=None, base=None, opened=None):
+        def update(self, pull_request, head=None, title=None, body=None, commits=None, base=None, opened=None, draft=None):
             if not isinstance(pull_request, PullRequest):
                 raise ValueError("Expected 'pull_request' to be of type '{}' not '{}'".format(PullRequest, type(pull_request)))
 
+            if draft:
+                sys.stderr.write('Bitbucket does not support the concept of a "draft" pull request\n')
+
             pr_url = 'https://{domain}/rest/api/1.0/projects/{project}/repos/{name}/pull-requests/{id}'.format(
                 domain=self.repository.domain,
                 project=self.repository.project,

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


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/git_hub.py	2022-02-15 23:05:57 UTC (rev 289855)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/git_hub.py	2022-02-15 23:09:30 UTC (rev 289856)
@@ -42,6 +42,8 @@
     EMAIL_RE = re.compile(r'(?P<email>[^@]+@[^@]+)(@.*)?')
 
     class PRGenerator(Scm.PRGenerator):
+        SUPPORTS_DRAFTS = True
+
         def PullRequest(self, data):
             if not data:
                 return None
@@ -61,6 +63,7 @@
                 metadata=dict(
                     issue=self.repository.tracker.from_string(issue_ref) if issue_ref else None,
                 ), url=''.format(self.repository.url, data['number']),
+                draft=data['draft'],
             )
 
         def get(self, number):
@@ -86,7 +89,8 @@
                     continue
                 yield self.PullRequest(datum)
 
-        def create(self, head, title, body=None, commits=None, base=None):
+        def create(self, head, title, body=None, commits=None, base=None, draft=None):
+            draft = False if draft is None else draft
             for key, value in dict(head=head, title=title).items():
                 if not value:
                     raise ValueError("Must define '{}' when creating pull-request".format(key))
@@ -104,6 +108,7 @@
                     body=PullRequest.create_body(body, commits),
                     base=base or self.repository.default_branch,
                     head='{}:{}'.format(user, head),
+                    draft=draft,
                 ),
             )
             if response.status_code // 100 != 2:
@@ -115,11 +120,13 @@
                 sys.stderr.write("Failed to assign '{}' to '{}'\n".format(result, user))
             return result
 
-        def update(self, pull_request, head=None, title=None, body=None, commits=None, base=None, opened=None):
+        def update(self, pull_request, head=None, title=None, body=None, commits=None, base=None, opened=None, draft=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)) and opened is None:
                 raise ValueError('No arguments to update pull-request provided')
+            if draft is not None:
+                sys.stderr.write('GitHub does not allow editing draft state via API\n')
 
             user, _ = self.repository.credentials(required=True)
             updates = dict(

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


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/scm.py	2022-02-15 23:05:57 UTC (rev 289855)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/scm.py	2022-02-15 23:09:30 UTC (rev 289856)
@@ -27,6 +27,8 @@
 
 class Scm(ScmBase):
     class PRGenerator(object):
+        SUPPORTS_DRAFTS = False
+
         def __init__(self, repository):
             self.repository = repository
 
@@ -36,10 +38,10 @@
         def find(self, opened=True, head=None, base=None):
             raise NotImplementedError()
 
-        def create(self, head, title, body=None, commits=None, base=None):
+        def create(self, head, title, body=None, commits=None, base=None, draft=None):
             raise NotImplementedError()
 
-        def update(self, pull_request, head=None, title=None, body=None, commits=None, base=None, opened=None):
+        def update(self, pull_request, head=None, title=None, body=None, commits=None, base=None, opened=None, draft=None):
             raise NotImplementedError()
 
         def reviewers(self, pull_request):

Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/checkout_unittest.py (289855 => 289856)


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/checkout_unittest.py	2022-02-15 23:05:57 UTC (rev 289855)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/checkout_unittest.py	2022-02-15 23:09:30 UTC (rev 289856)
@@ -117,6 +117,7 @@
                 base=dict(ref='main'),
                 requested_reviews=[dict(login='rreviewer')],
                 reviews=[dict(user=dict(login='rreviewer'), state='CHANGES_REQUESTED')],
+                draft=False,
             )]
             repo.commits['eng/example'] = [Commit(
                 hash='a5fe8afe9bf7d07158fcd9e9732ff02a712db2fd',

Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/land_unittest.py (289855 => 289856)


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/land_unittest.py	2022-02-15 23:05:57 UTC (rev 289855)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/land_unittest.py	2022-02-15 23:09:30 UTC (rev 289856)
@@ -244,7 +244,7 @@
                 dict(user=dict(login='rreviewer'), state='CHANGES_REQUESTED')
             ] if approved is not None else [], _links=dict(
                 issue=dict(href=''.format(result.api_remote)),
-            ),
+            ), draft=False,
         )]
         return result
 

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


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/pull_request_unittest.py	2022-02-15 23:05:57 UTC (rev 289855)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/pull_request_unittest.py	2022-02-15 23:09:30 UTC (rev 289856)
@@ -329,6 +329,7 @@
                 args=('pull-request', '-i', 'pr-branch', '-v', '--no-history'),
                 path=self.path,
             ))
+            self.assertEqual(local.Git(self.path).remote().pull_requests.get(1).draft, False)
 
         self.assertEqual(
             captured.stdout.getvalue(),
@@ -351,6 +352,38 @@
             ],
         )
 
+    def test_github_draft(self):
+        with OutputCapture(level=logging.INFO) as captured, mocks.remote.GitHub() as remote, \
+                mocks.local.Git(self.path, remote='https://{}'.format(remote.remote)) as repo, mocks.local.Svn():
+
+            repo.staged['added.txt'] = 'added'
+            self.assertEqual(0, program.main(
+                args=('pull-request', '-i', 'pr-branch', '-v', '--no-history', '--draft'),
+                path=self.path,
+            ))
+            self.assertEqual(local.Git(self.path).remote().pull_requests.get(1).draft, True)
+
+        self.assertEqual(
+            captured.stdout.getvalue(),
+            "Created the local development branch 'eng/pr-branch'\n"
+            "Created 'PR 1 | [Testing] Creating commits'!\n"
+            "https://github.example.com/WebKit/WebKit/pull/1\n",
+        )
+        self.assertEqual(captured.stderr.getvalue(), '')
+        log = captured.root.log.getvalue().splitlines()
+        self.assertEqual(
+            [line for line in log if 'Mock process' not in line], [
+                "Creating the local development branch 'eng/pr-branch'...",
+                '    Found 1 commit...',
+                'Creating commit...',
+                "Rebasing 'eng/pr-branch' on 'main'...",
+                "Rebased 'eng/pr-branch' on 'main!'",
+                "    Found 1 commit...",
+                "Pushing 'eng/pr-branch' to 'fork'...",
+                "Creating pull-request for 'eng/pr-branch'...",
+            ],
+        )
+
     def test_github_update(self):
         with mocks.remote.GitHub() as remote, mocks.local.Git(self.path, remote='https://{}'.format(remote.remote)) as repo, mocks.local.Svn():
             with OutputCapture():
@@ -526,6 +559,7 @@
                 args=('pull-request', '-i', 'pr-branch', '-v'),
                 path=self.path,
             ))
+            self.assertEqual(local.Git(self.path).remote().pull_requests.get(1).draft, False)
 
         self.assertEqual(
             captured.stdout.getvalue(),
@@ -548,6 +582,38 @@
             ],
         )
 
+    def test_bitbucket_draft(self):
+        with OutputCapture(level=logging.INFO) as captured, mocks.remote.BitBucket() as remote, mocks.local.Git(self.path, remote='ssh://git@{}/{}/{}.git'.format(
+            remote.hosts[0], remote.project.split('/')[1], remote.project.split('/')[3],
+        )) as repo, mocks.local.Svn():
+
+            repo.staged['added.txt'] = 'added'
+            self.assertEqual(1, program.main(
+                args=('pull-request', '-i', 'pr-branch', '-v', '--draft'),
+                path=self.path,
+            ))
+
+        self.assertEqual(
+            captured.stdout.getvalue(),
+            "Created the local development branch 'eng/pr-branch'\n",
+        )
+        self.assertEqual(
+            captured.stderr.getvalue(),
+            "'https://bitbucket.example.com/projects/WEBKIT/repos/webkit' does not support draft pull requests, aborting\n",
+        )
+        log = captured.root.log.getvalue().splitlines()
+        self.assertEqual(
+            [line for line in log if 'Mock process' not in line], [
+                "Creating the local development branch 'eng/pr-branch'...",
+                '    Found 1 commit...',
+                'Creating commit...',
+                "Rebasing 'eng/pr-branch' on 'main'...",
+                "Rebased 'eng/pr-branch' on 'main!'",
+                "    Found 1 commit...",
+                "Pushing 'eng/pr-branch' to 'origin'...",
+            ],
+        )
+
     def test_bitbucket_update(self):
         with mocks.remote.BitBucket() as remote, mocks.local.Git(self.path, remote='ssh://git@{}/{}/{}.git'.format(
             remote.hosts[0], remote.project.split('/')[1], remote.project.split('/')[3],
@@ -759,7 +825,7 @@
                 dict(user=dict(login='sreviewer'), state='CHANGES_REQUESTED'),
             ], _links=dict(
                 issue=dict(href=''.format(result.api_remote)),
-            ),
+            ), draft=False,
         )]
         return result
 
@@ -780,6 +846,7 @@
             self.assertEqual(pr.title, 'Example Change')
             self.assertEqual(pr.head, 'eng/pull-request')
             self.assertEqual(pr.base, 'main')
+            self.assertEqual(pr.draft, False)
 
     def test_reviewers(self):
         with self.webserver():
@@ -906,6 +973,7 @@
             self.assertEqual(pr.title, 'Example Change')
             self.assertEqual(pr.head, 'eng/pull-request')
             self.assertEqual(pr.base, 'main')
+            self.assertEqual(pr.draft, False)
 
     def test_reviewers(self):
         with self.webserver():
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to