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():