Diff
Modified: trunk/Tools/ChangeLog (281362 => 281363)
--- trunk/Tools/ChangeLog 2021-08-21 03:20:23 UTC (rev 281362)
+++ trunk/Tools/ChangeLog 2021-08-21 05:25:07 UTC (rev 281363)
@@ -1,3 +1,30 @@
+2021-08-20 Jonathan Bedard <jbed...@apple.com>
+
+ [git-webkit] Add pull-request command (Part 2)
+ https://bugs.webkit.org/show_bug.cgi?id=229089
+ <rdar://problem/81908751>
+
+ Reviewed by Dewei Zhu.
+
+ * Scripts/libraries/webkitscmpy/setup.py: Bump version.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py: Ditto.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/mocks/local/git.py:
+ (Git.__init__): Add 'check-ref-format' and 'checkout -b'.
+ (Git.checkout): Add ability to create branch.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/program/__init__.py:
+ (main): Add Branch command.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/program/branch.py:
+ (Branch.parser): Allow user to specify engineering branch name.
+ (Branch.normalize_issue): Turn provided string into eng branch if it isn't already.
+ (Branch.main): Create eng branch from current checkout state.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/test/branch_unittest.py:
+ (TestBranch):
+ (TestBranch.setUp):
+ (TestBranch.test_basic_svn):
+ (TestBranch.test_basic_git):
+ (TestBranch.test_prompt_git):
+ (TestBranch.test_invalid_branch):
+
2021-08-20 Alex Christensen <achristen...@webkit.org>
Make UIEventAttribution tests less platform dependent
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/setup.py (281362 => 281363)
--- trunk/Tools/Scripts/libraries/webkitscmpy/setup.py 2021-08-21 03:20:23 UTC (rev 281362)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/setup.py 2021-08-21 05:25:07 UTC (rev 281363)
@@ -29,7 +29,7 @@
setup(
name='webkitscmpy',
- version='1.1.5',
+ version='1.1.6',
description='Library designed to interact with git and svn repositories.',
long_description=readme(),
classifiers=[
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py (281362 => 281363)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py 2021-08-21 03:20:23 UTC (rev 281362)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py 2021-08-21 05:25:07 UTC (rev 281363)
@@ -46,7 +46,7 @@
"Please install webkitcorepy with `pip install webkitcorepy --extra-index-url <package index URL>`"
)
-version = Version(1, 1, 5)
+version = Version(1, 1, 6)
AutoInstall.register(Package('fasteners', Version(0, 15, 0)))
AutoInstall.register(Package('monotonic', Version(1, 5)))
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/local/git.py (281362 => 281363)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/local/git.py 2021-08-21 03:20:23 UTC (rev 281362)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/local/git.py 2021-08-21 05:25:07 UTC (rev 281363)
@@ -333,10 +333,15 @@
stdout='\n'.join(sorted(self.branches_on(args[4]))) + '\n',
) if self.find(args[4]) else mocks.ProcessCompletion(returncode=128),
), mocks.Subprocess.Route(
+ self.executable, 'checkout', '-b', re.compile(r'.+'),
+ cwd=self.path,
+ generator=lambda *args, **kwargs:
+ mocks.ProcessCompletion(returncode=0) if self.checkout(args[3], create=True) else mocks.ProcessCompletion(returncode=1)
+ ), mocks.Subprocess.Route(
self.executable, 'checkout', re.compile(r'.+'),
cwd=self.path,
generator=lambda *args, **kwargs:
- mocks.ProcessCompletion(returncode=0) if self.checkout(args[2]) else mocks.ProcessCompletion(returncode=1)
+ mocks.ProcessCompletion(returncode=0) if self.checkout(args[2], create=False) else mocks.ProcessCompletion(returncode=1)
), mocks.Subprocess.Route(
self.executable, 'filter-branch', '-f',
cwd=self.path,
@@ -381,6 +386,10 @@
returncode=0,
),
), mocks.Subprocess.Route(
+ self.executable, 'check-ref-format', re.compile(r'.+'),
+ generator=lambda *args, **kwargs:
+ mocks.ProcessCompletion(returncode=0) if re.match(r'^[A-Za-z0-9-]+/[A-Za-z0-9/-]+$', args[2]) else mocks.ProcessCompletion(),
+ ), mocks.Subprocess.Route(
self.executable,
cwd=self.path,
completion=mocks.ProcessCompletion(
@@ -473,8 +482,23 @@
result.add(branch)
return result
- def checkout(self, something):
+ def checkout(self, something, create=False):
commit = self.find(something)
+ if create:
+ if commit:
+ return False
+ if self.head.branch == self.default_branch:
+ self.commits[something] = [self.head]
+ else:
+ self.commits[something] = [
+ commit for commit in self.commits[self.head.branch]
+ if not commit.branch_point or commit.identifier <= self.head.identifier
+ ]
+ self.commits[something][-1] = Commit.from_json(Commit.Encoder().default(self.head))
+ self.head = self.commits[something][-1]
+ self.head.branch = something
+ return True
+
if commit:
self.head = commit
self.detached = something not in self.commits.keys()
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program/__init__.py (281362 => 281363)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program/__init__.py 2021-08-21 03:20:23 UTC (rev 281362)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program/__init__.py 2021-08-21 05:25:07 UTC (rev 281363)
@@ -26,6 +26,7 @@
import sys
from .blame import Blame
+from .branch import Branch
from .canonicalize import Canonicalize
from .clean import Clean
from .command import Command
@@ -65,7 +66,7 @@
subparsers = parser.add_subparsers(help='sub-command help')
- programs = [Blame, Canonicalize, Checkout, Clean, Find, Info, Log, Pull, Setup]
+ programs = [Branch, Blame, Canonicalize, Checkout, Clean, Find, Info, Log, Pull, Setup]
if subversion:
programs.append(SetupGitSvn)
Added: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program/branch.py (0 => 281363)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program/branch.py (rev 0)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program/branch.py 2021-08-21 05:25:07 UTC (rev 281363)
@@ -0,0 +1,78 @@
+# Copyright (C) 2021 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import re
+import sys
+
+from .command import Command
+
+from webkitcorepy import run, Terminal
+from webkitscmpy import local, log
+
+
+class Branch(Command):
+ name = 'branch'
+ help = 'Create a local development branch from the current checkout state'
+
+ PREFIX = 'eng'
+
+ @classmethod
+ def parser(cls, parser, loggers=None):
+ parser.add_argument(
+ '-i', '--issue', '-b', '--bug', '-r',
+ dest='issue', type=str,
+ help='Number (or name) of the issue or bug to create branch for',
+ )
+
+ @classmethod
+ def normalize_issue(cls, issue):
+ if not issue or issue.startswith(cls.PREFIX):
+ return issue
+ return '{}/{}'.format(cls.PREFIX, issue)
+
+ @classmethod
+ def main(cls, args, repository, **kwargs):
+ if not isinstance(repository, local.Git):
+ sys.stderr.write("Can only 'branch' on a native Git repository\n")
+ return 1
+
+ if not args.issue:
+ args.issue = Terminal.input('Branch name: ')
+ args.issue = cls.normalize_issue(args.issue)
+
+ if run([repository.executable(), 'check-ref-format', args.issue], capture_output=True).returncode:
+ sys.stderr.write("'{}' is an invalid branch name, cannot create it\n".format(args.issue))
+ return 1
+
+ remote_re = re.compile('remotes/.+/{}'.format(re.escape(args.issue)))
+ for branch in repository.branches:
+ if branch == args.issue or remote_re.match(branch):
+ sys.stderr.write("'{}' already exists\n".format(args.issue))
+ return 1
+
+ log.warning("Creating the local development branch '{}'...".format(args.issue))
+ if run([repository.executable(), 'checkout', '-b', args.issue], cwd=repository.root_path).returncode:
+ sys.stderr.write("Failed to create '{}'\n".format(args.issue))
+ return 1
+ repository._branch = args.issue # Assign the cache because of repository.branch's caching
+ print("Created the local development branch '{}'!".format(args.issue))
+ return 0
Added: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/branch_unittest.py (0 => 281363)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/branch_unittest.py (rev 0)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/branch_unittest.py 2021-08-21 05:25:07 UTC (rev 281363)
@@ -0,0 +1,73 @@
+# Copyright (C) 2021 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import json
+import os
+import shutil
+import tempfile
+
+from datetime import datetime
+from webkitcorepy import OutputCapture, testing
+from webkitcorepy.mocks import Time as MockTime, Terminal as MockTerminal
+from webkitscmpy import local, program, mocks
+
+
+class TestBranch(testing.PathTestCase):
+ basepath = 'mock/repository'
+
+ def setUp(self):
+ super(TestBranch, self).setUp()
+ os.mkdir(os.path.join(self.path, '.git'))
+ os.mkdir(os.path.join(self.path, '.svn'))
+
+ def test_basic_svn(self):
+ with OutputCapture() as captured, mocks.local.Git(), mocks.local.Svn(self.path), MockTime:
+ self.assertEqual(1, program.main(
+ args=('branch', '-i', '1234'),
+ path=self.path,
+ ))
+ self.assertEqual(captured.stderr.getvalue(), "Can only 'branch' on a native Git repository\n")
+
+ def test_basic_git(self):
+ with OutputCapture() as captured, mocks.local.Git(self.path), mocks.local.Svn(), MockTime:
+ self.assertEqual(0, program.main(
+ args=('branch', '-i', '1234'),
+ path=self.path,
+ ))
+ self.assertEqual(local.Git(self.path).branch, 'eng/1234')
+ self.assertEqual(captured.root.log.getvalue(), "Creating the local development branch 'eng/1234'...\n")
+ self.assertEqual(captured.stdout.getvalue(), "Created the local development branch 'eng/1234'!\n")
+
+ def test_prompt_git(self):
+ with MockTerminal.input('eng/example'), OutputCapture() as captured, mocks.local.Git(self.path), mocks.local.Svn(), MockTime:
+ self.assertEqual(0, program.main(args=('branch',), path=self.path))
+ self.assertEqual(local.Git(self.path).branch, 'eng/example')
+ self.assertEqual(captured.root.log.getvalue(), "Creating the local development branch 'eng/example'...\n")
+ self.assertEqual(captured.stdout.getvalue(), "Branch name: \nCreated the local development branch 'eng/example'!\n")
+
+ def test_invalid_branch(self):
+ with OutputCapture() as captured, mocks.local.Git(self.path), mocks.local.Svn(), MockTime:
+ self.assertEqual(1, program.main(
+ args=('branch', '-i', 'reject_underscores'),
+ path=self.path,
+ ))
+ self.assertEqual(captured.stderr.getvalue(), "'eng/reject_underscores' is an invalid branch name, cannot create it\n")