Changeset 285765 in webkit
- Timestamp:
- Nov 12, 2021, 5:16:24 PM (5 years ago)
- Location:
- trunk/Tools
- Files:
-
- 9 edited
-
ChangeLog (modified) (1 diff)
-
Scripts/libraries/webkitscmpy/setup.py (modified) (1 diff)
-
Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py (modified) (1 diff)
-
Scripts/libraries/webkitscmpy/webkitscmpy/local/git.py (modified) (2 diffs)
-
Scripts/libraries/webkitscmpy/webkitscmpy/mocks/local/git.py (modified) (2 diffs)
-
Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py (modified) (7 diffs)
-
Scripts/libraries/webkitscmpy/webkitscmpy/program/checkout.py (modified) (3 diffs)
-
Scripts/libraries/webkitscmpy/webkitscmpy/program/clean.py (modified) (1 diff)
-
Scripts/libraries/webkitscmpy/webkitscmpy/test/checkout_unittest.py (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Tools/ChangeLog
r285746 r285765 1 2021-11-12 Jonathan Bedard <jbedard@apple.com> 2 3 [git-webkit] Checkout pull-requests 4 https://bugs.webkit.org/show_bug.cgi?id=233042 5 <rdar://problem/85343364> 6 7 Reviewed by Dewei Zhu. 8 9 In GitHub, pull-requests are somewhat difficult to checkout because they're 10 attached to a specific user's mirror of WebKit. Automate this process. 11 12 * Scripts/libraries/webkitscmpy/setup.py: Bump version. 13 * Scripts/libraries/webkitscmpy/webkitscmpy/__init.py__: Ditto. 14 * Scripts/libraries/webkitscmpy/webkitscmpy/local/git.py: 15 (Git): Add username:branch regex. 16 (Git.checkout): Allow checking out of branches by username:branch. 17 * Scripts/libraries/webkitscmpy/webkitscmpy/mocks/local/git.py: 18 (Git.__init__): Add `git checkout -B`. 19 (Git.checkout): `-B` will force checkout a branch, even if one already exists. 20 * Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py: 21 (GitHub): Embed error message in 404 response. 22 * Scripts/libraries/webkitscmpy/webkitscmpy/program/checkout.py: 23 (Checkout.main): Allow direct checkout of pull-request instead of relying 24 exclusively on branches. 25 * Scripts/libraries/webkitscmpy/webkitscmpy/program/clean.py: 26 (Clean.main): Add newline. 27 * Scripts/libraries/webkitscmpy/webkitscmpy/test/checkout_unittest.py: 28 (TestCheckout.test_no_pr_github): 29 (TestCheckout.test_no_pr_bitbucket): 30 (TestCheckout.test_pr_github): 31 (TestCheckout.test_pr_bitbucket): 32 1 33 2021-11-12 Sihui Liu <sihui_liu@apple.com> 2 34 -
trunk/Tools/Scripts/libraries/webkitscmpy/setup.py
r285272 r285765 30 30 setup( 31 31 name='webkitscmpy', 32 version='3.0. 0',32 version='3.0.1', 33 33 description='Library designed to interact with git and svn repositories.', 34 34 long_description=readme(), -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py
r285272 r285765 47 47 ) 48 48 49 version = Version(3, 0, 0)49 version = Version(3, 0, 1) 50 50 51 51 AutoInstall.register(Package('fasteners', Version(0, 15, 0))) -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/git.py
r285272 r285765 300 300 HTTP_REMOTE = re.compile(r'(?P<protocol>https?)://(?P<host>[^\/]+)/(?P<path>.+).git') 301 301 REMOTE_BRANCH = re.compile(r'remotes\/(?P<remote>[^\/]+)\/(?P<branch>.+)') 302 USER_REMOTE = re.compile(r'(?P<username>[^:/]+):(?P<branch>.+)') 302 303 303 304 @classmethod … … 821 822 log_arg = [] 822 823 824 match = self.USER_REMOTE.match(argument) 825 rmt = self.remote() 826 if match and isinstance(rmt, remote.GitHub): 827 username = match.group('username') 828 if not self.url(match.group('username')): 829 url = self.url() 830 if '://' in url: 831 rmt = '{}://{}/{}/{}.git'.format(url.split(':')[0], url.split('/')[2], username, rmt.name) 832 elif ':' in url: 833 rmt = '{}:{}/{}.git'.format(url.split(':')[0], username, rmt.name) 834 else: 835 sys.stderr.write("Failed to convert '{}' to '{}' remote\n".format(url, username)) 836 return None 837 if run( 838 [self.executable(), 'remote', 'add', username, rmt], 839 capture_output=True, cwd=self.root_path, 840 ).returncode: 841 sys.stderr.write("Failed to add remote '{}' as '{}'\n".format(rmt, username)) 842 return None 843 self.url.clear() 844 branch = match.group('branch') 845 rc = run( 846 [self.executable(), 'checkout'] + ['-B', branch, '{}/{}'.format(username, branch)] + log_arg, 847 cwd=self.root_path, 848 ).returncode 849 if not rc: 850 return self.commit() 851 if rc == 128: 852 run([self.executable(), 'fetch', username], cwd=self.root_path) 853 return None if run( 854 [self.executable(), 'checkout'] + ['-B', branch, '{}/{}'.format(username, branch)] + log_arg, 855 cwd=self.root_path, 856 ).returncode else self.commit() 857 823 858 return None if run( 824 859 [self.executable(), 'checkout'] + [self._to_git_ref(argument)] + log_arg, -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/local/git.py
r285272 r285765 353 353 mocks.ProcessCompletion(returncode=0) if self.checkout(args[3], create=True) else mocks.ProcessCompletion(returncode=1) 354 354 ), mocks.Subprocess.Route( 355 self.executable, 'checkout', '-B', re.compile(r'.+'), 356 cwd=self.path, 357 generator=lambda *args, **kwargs: 358 mocks.ProcessCompletion(returncode=0) if self.checkout(args[3], create=True, force=True) else mocks.ProcessCompletion(returncode=1) 359 ), mocks.Subprocess.Route( 355 360 self.executable, 'checkout', re.compile(r'.+'), 356 361 cwd=self.path, … … 589 594 return result 590 595 591 def checkout(self, something, create=False ):596 def checkout(self, something, create=False, force=False): 592 597 commit = self.find(something) 593 598 if create: 594 599 if commit: 600 if force: 601 self.head = commit 602 self.detached = something not in self.commits.keys() 603 return True 595 604 return False 596 605 if self.head.branch == self.default_branch: -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py
r285733 r285765 22 22 23 23 import os 24 import json25 24 import time 26 25 26 import json as jsonlib 27 27 from webkitcorepy import mocks 28 28 from webkitscmpy import Commit, remote as scmremote … … 51 51 52 52 with open(datafile or os.path.join(os.path.dirname(os.path.dirname(__file__)), 'git-repo.json')) as file: 53 self.commits = json .load(file)53 self.commits = jsonlib.load(file) 54 54 for key, commits in self.commits.items(): 55 55 self.commits[key] = [Commit(**kwargs) for kwargs in commits] … … 146 146 status_code=404, 147 147 url=url, 148 text=json .dumps(dict(message='No commit found for SHA: {}'.format(ref))),148 text=jsonlib.dumps(dict(message='No commit found for SHA: {}'.format(ref))), 149 149 ) 150 150 … … 192 192 status_code=404, 193 193 url=url, 194 text=json .dumps(dict(message='No commit found for SHA: {}'.format(ref))),194 text=jsonlib.dumps(dict(message='No commit found for SHA: {}'.format(ref))), 195 195 ) 196 196 return mocks.Response.fromJson({ … … 220 220 status_code=404, 221 221 url=url, 222 text=json .dumps(dict(message='Not found')),222 text=jsonlib.dumps(dict(message='Not found')), 223 223 ) 224 224 … … 332 332 return self._parents_of_request(url=url, ref=stripped_url.split('/')[-1]) 333 333 334 # Check for exist ance of forked repo334 # Check for existence of forked repo 335 335 if stripped_url.startswith('{}/repos'.format(self.api_remote.split('/')[0])) and stripped_url.split('/')[-1] == self.remote.split('/')[-1]: 336 336 username = stripped_url.split('/')[-2] … … 382 382 key: value for key, value in candidate.items() if key not in ('requested_reviews', 'reviews') 383 383 }, url=url) 384 return mocks.Response.create404(url) 384 return mocks.Response( 385 status_code=404, 386 text=jsonlib.dumps(dict(message='Not found')), 387 url=url, 388 ) 385 389 386 390 # Create/update pull-request -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program/checkout.py
r277730 r285765 21 21 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 22 23 import re 23 24 import sys 24 25 25 26 from .command import Command 26 from webkitcorepy import arguments 27 from webkitscmpy import local 27 from webkitscmpy import local, log, remote 28 28 29 29 30 30 class Checkout(Command): 31 31 name = 'checkout' 32 help = 'Given an identifier, revision or hash, normalize and checkout that commit' 32 help = "Given an identifier, revision, hash or pull-request, normalize and checkout that commit." \ 33 " Pull requests expected in the form 'PR-#'" 34 35 PR_RE = re.compile(r'^\[?[Pp][Rr][ -](?P<number>\d+)]?$') 33 36 34 37 @classmethod … … 43 46 def main(cls, args, repository, **kwargs): 44 47 if not repository.path: 45 sys.stderr.write( "Cannot checkout on remote repository")48 sys.stderr.write('Cannot checkout on remote repository\n') 46 49 return 1 47 50 51 target = args.argument[0] 52 match = cls.PR_RE.match(target) 53 if match: 54 rmt = repository.remote() 55 if not rmt: 56 sys.stderr.write('Repository does not have associated remote\n') 57 return 1 58 if not rmt.pull_requests: 59 sys.stderr.write('No pull-requests associated with repository\n') 60 return 1 61 pr = rmt.pull_requests.get(number=int(match.group('number'))) 62 if not pr: 63 sys.stderr.write("Failed to find 'PR-{}' associated with this repository\n".format(match.group('number'))) 64 return 1 65 if isinstance(rmt, remote.GitHub) and pr.author.github: 66 target = '{}:{}'.format(pr.author.github, pr.head) 67 else: 68 target = pr.head 69 log.warning("Found associated branch '{}' for '{}'".format(target, pr)) 70 48 71 try: 49 commit = repository.checkout( args.argument[0])72 commit = repository.checkout(target) 50 73 except (local.Scm.Exception, ValueError) as exception: 51 74 # ValueErrors and Scm exceptions usually contain enough information to be displayed … … 55 78 56 79 if not commit: 57 sys.stderr.write("Failed to map'{}'\n".format(args.argument[0]))80 sys.stderr.write("Failed to checkout '{}'\n".format(args.argument[0])) 58 81 return 1 59 82 return 0 -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program/clean.py
r273142 r285765 35 35 def main(cls, args, repository, **kwargs): 36 36 if not repository.path: 37 sys.stderr.write('Cannot clean on remote repository ')37 sys.stderr.write('Cannot clean on remote repository\n') 38 38 return 1 39 39 -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/checkout_unittest.py
r279347 r285765 22 22 23 23 import os 24 import time 24 25 25 26 from webkitcorepy import OutputCapture, testing 26 27 from webkitcorepy.mocks import Time as MockTime 27 from webkitscmpy import program, mocks, local 28 from webkitscmpy import program, mocks, local, Contributor, Commit 28 29 29 30 … … 58 59 self.assertEqual('621652add7fc416099bd2063366cc38ff61afe36', local.Git(self.path).commit().hash) 59 60 61 def test_no_pr_github(self): 62 with OutputCapture() as captured, mocks.remote.GitHub() as remote, \ 63 mocks.local.Git(self.path, remote='https://{}'.format(remote.remote)), mocks.local.Svn(): 64 self.assertEqual(1, program.main( 65 args=('checkout', 'PR-1'), 66 path=self.path, 67 )) 68 69 self.assertEqual( 70 "Request to 'https://api.github.example.com/repos/WebKit/WebKit/pulls/1' returned status code '404'\n" 71 "Message: Not found\n" 72 "Failed to find 'PR-1' associated with this repository\n", 73 captured.stderr.getvalue(), 74 ) 75 76 def test_no_pr_bitbucket(self): 77 with OutputCapture() as captured, mocks.remote.BitBucket() as remote, mocks.local.Git(self.path, remote='ssh://git@{}/{}/{}.git'.format( 78 remote.hosts[0], remote.project.split('/')[1], remote.project.split('/')[3], 79 )), mocks.local.Svn(): 80 self.assertEqual(1, program.main( 81 args=('checkout', 'PR-1'), 82 path=self.path, 83 )) 84 85 self.assertEqual( 86 "Request to 'https://bitbucket.example.com/rest/api/1.0/projects/WEBKIT/repos/webkit/pull-requests/1' returned status code '404'\n" 87 "Failed to find 'PR-1' associated with this repository\n", 88 captured.stderr.getvalue(), 89 ) 90 91 def test_pr_github(self): 92 with OutputCapture(), mocks.remote.GitHub() as remote, \ 93 mocks.local.Git(self.path, remote='https://{}'.format(remote.remote)) as repo, mocks.local.Svn(): 94 remote.users = dict( 95 rreviewer=Contributor('Ricky Reviewer', ['rreviewer@webkit.org'], github='rreviewer'), 96 tcontributor=Contributor('Tim Contributor', ['tcontributor@webkit.org'], github='tcontributor'), 97 ) 98 remote.issues = { 99 1: dict( 100 comments=[], 101 assignees=[], 102 ) 103 } 104 remote.pull_requests = [dict( 105 number=1, 106 state='open', 107 title='Example Change', 108 user=dict(login='tcontributor'), 109 body='''#### a5fe8afe9bf7d07158fcd9e9732ff02a712db2fd 110 <pre> 111 To Be Committed 112 113 Reviewed by NOBODY (OOPS!). 114 </pre> 115 ''', 116 head=dict(ref='tcontributor:eng/example'), 117 base=dict(ref='main'), 118 requested_reviews=[dict(login='rreviewer')], 119 reviews=[dict(user=dict(login='rreviewer'), state='CHANGES_REQUESTED')], 120 )] 121 repo.commits['eng/example'] = [Commit( 122 hash='a5fe8afe9bf7d07158fcd9e9732ff02a712db2fd', 123 identifier='3.1@eng/example', 124 timestamp=int(time.time()) - 60, 125 author=Contributor('Tim Committer', ['tcommitter@webkit.org']), 126 message='To Be Committed\n\nReviewed by NOBODY (OOPS!).\n', 127 )] 128 129 self.assertEqual(0, program.main( 130 args=('checkout', 'PR-1'), 131 path=self.path, 132 )) 133 134 self.assertEqual('a5fe8afe9bf7d07158fcd9e9732ff02a712db2fd', local.Git(self.path).commit().hash) 135 136 def test_pr_bitbucket(self): 137 with OutputCapture(), mocks.remote.BitBucket() as remote, mocks.local.Git(self.path, remote='ssh://git@{}/{}/{}.git'.format( 138 remote.hosts[0], remote.project.split('/')[1], remote.project.split('/')[3], 139 )) as repo, mocks.local.Svn(): 140 remote.pull_requests = [dict( 141 id=1, 142 state='OPEN', 143 open=True, 144 closed=False, 145 activities=[], 146 title='Example Change', 147 author=dict( 148 user=dict( 149 name='tcontributor', 150 emailAddress='tcontributor@apple.com', 151 displayName='Tim Contributor', 152 ), 153 ), body='''#### a5fe8afe9bf7d07158fcd9e9732ff02a712db2fd 154 ``` 155 To Be Committed 156 157 Reviewed by NOBODY (OOPS!). 158 ``` 159 ''', 160 fromRef=dict(displayId='eng/example', id='refs/heads/eng/example'), 161 toRef=dict(displayId='main', id='refs/heads/main'), 162 reviewers=[ 163 dict( 164 user=dict( 165 displayName='Ricky Reviewer', 166 emailAddress='rreviewer@webkit.org', 167 ), approved=False, 168 status='NEEDS_WORK', 169 ), 170 ], 171 )] 172 repo.commits['eng/example'] = [Commit( 173 hash='a5fe8afe9bf7d07158fcd9e9732ff02a712db2fd', 174 identifier='3.1@eng/example', 175 timestamp=int(time.time()) - 60, 176 author=Contributor('Tim Committer', ['tcommitter@webkit.org']), 177 message='To Be Committed\n\nReviewed by NOBODY (OOPS!).\n', 178 )] 179 180 self.assertEqual(0, program.main( 181 args=('checkout', 'PR-1'), 182 path=self.path, 183 )) 184 185 self.assertEqual('a5fe8afe9bf7d07158fcd9e9732ff02a712db2fd', local.Git(self.path).commit().hash) 186 60 187 def test_checkout_svn(self): 61 188 with OutputCapture(), mocks.local.Git(), mocks.local.Svn(self.path), MockTime: … … 69 196 self.assertEqual(4, local.Svn(self.path).commit().revision) 70 197 198 def test_svn_pr(self): 199 with OutputCapture() as captured, mocks.local.Git(), mocks.local.Svn(self.path), MockTime: 200 self.assertEqual(1, program.main( 201 args=('checkout', 'PR-1'), 202 path=self.path, 203 )) 204 205 self.assertEqual( 206 'No pull-requests associated with repository\n', 207 captured.stderr.getvalue(), 208 ) 209 71 210 def test_checkout_remote(self): 72 211 with OutputCapture(), mocks.remote.Svn():
Note:
See TracChangeset
for help on using the changeset viewer.