Changeset 270447 in webkit
- Timestamp:
- Dec 4, 2020 12:03:53 PM (3 years ago)
- Location:
- trunk/Tools
- Files:
-
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Tools/ChangeLog
r270446 r270447 1 2020-12-04 Jonathan Bedard <jbedard@apple.com> 2 3 [git-webkit] Use contributors.json 4 https://bugs.webkit.org/show_bug.cgi?id=217732 5 <rdar://problem/70309518> 6 7 Reviewed by Dewei Zhu. 8 9 The interaction between Git, Svn and old commits means that our canonical record of 10 commit authors is somewhat incomplete. contributors.json has most of the information 11 we are missing, we should rely on it to map non-standard author names to their canonical 12 names and email addresses. 13 14 Additionally, making the record of Contributors owned by the repository instead of being global 15 to the entire process. 16 17 * Scripts/git-webkit: Parse contributors.json and add it to a Contributor.Mapping. 18 * Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py: Bump version. 19 * Scripts/libraries/webkitscmpy/webkitscmpy/commit.py: 20 (Commit): Contributor class object no longer owns record of contributors. 21 * Scripts/libraries/webkitscmpy/webkitscmpy/contributor.py: 22 (Contributor): 23 (Contributor.Mapping): Dictionary mapping Contributors and their potential aliases. 24 (Contributor.Mapping.__init__): 25 (Contributor.Mapping.add): Add Contributor to mapping. 26 (Contributor.Mapping.create): Find or create a contributor with the specified name and email 27 addresses and bind it to the record of contributors. 28 (Contributor.from_scm_log): Leverage Contributor.Mapping provided by caller. 29 (Contributor.clear): Deleted. 30 * Scripts/libraries/webkitscmpy/webkitscmpy/local/git.py: 31 (Git.__init__): Instantiate repository with existing Contributor.Mapping. 32 (Git.commit): Repository now owns the record of contributors. 33 * Scripts/libraries/webkitscmpy/webkitscmpy/local/scm.py: 34 (Scm.from_path): Instantiate repository with existing Contributor.Mapping. 35 (Scm.__init__): Ditto. 36 * Scripts/libraries/webkitscmpy/webkitscmpy/local/svn.py: 37 (Svn.__init__): Instantiate repository with existing Contributor.Mapping. 38 (Svn.commit): Repository now owns the record of contributors. 39 * Scripts/libraries/webkitscmpy/webkitscmpy/program.py: 40 (main): Allow caller to pass an existing record of contributors. 41 * Scripts/libraries/webkitscmpy/webkitscmpy/remote/scm.py: 42 (Scm.from_url): Instantiate repository with existing Contributor.Mapping. 43 (Scm.__init__): Ditto. 44 * Scripts/libraries/webkitscmpy/webkitscmpy/remote/svn.py: 45 (Svn.__init__): Instantiate repository with existing Contributor.Mapping. 46 (Svn.commit): Repository now owns the record of contributors. 47 * Scripts/libraries/webkitscmpy/webkitscmpy/scm_base.py: 48 (ScmBase.__init__): Instantiate repository with existing Contributor.Mapping. 49 * Scripts/libraries/webkitscmpy/webkitscmpy/test/commit_unittest.py: 50 * Scripts/libraries/webkitscmpy/webkitscmpy/test/contributor_unittest.py: 51 (TestContributor.test_git_log): No more global contributor record. 52 (TestContributor.test_git_svn_log): Ditto. 53 (TestContributor.test_git_no_author): Ditto. 54 (TestContributor.test_git_svn_no_author): Ditto. 55 (TestContributor.test_svn_log): Ditto. 56 (TestContributor.test_short_svn_log): Ditto. 57 (TestContributor.test_svn_patch_by_log): Ditto. 58 (TestContributor.test_author_mapping): Contributor record is owned by the caller of the caller 59 of Contributor management. 60 (TestContributor.test_email_mapping): Ditto. 61 (TestContributor.test_invalid_log): No more global contributor record. 62 1 63 2020-12-04 Kate Cheney <katherine_cheney@apple.com> 2 64 -
trunk/Tools/Scripts/git-webkit
r268433 r270447 24 24 25 25 import os 26 import webkitpy27 26 import sys 28 27 29 from webkitscmpy import program 28 from webkitpy.common.config.committers import CommitterList 29 from webkitscmpy import program, Contributor 30 30 31 sys.exit(program.main(path=os.path.dirname(__file__)))32 31 32 if '__main__' == __name__: 33 contributors = Contributor.Mapping() 34 for contributor in CommitterList().contributors(): 35 c = contributors.create(contributor.full_name, *contributor.emails) 36 if not c: 37 continue 38 for alias in contributor.aliases or []: 39 if alias not in contributors: 40 contributors[alias] = c 41 for nick in contributor.irc_nicknames or []: 42 if nick not in contributors: 43 contributors[nick] = c 44 45 sys.exit(program.main(path=os.path.dirname(__file__), contributors=contributors)) 46 -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py
r270412 r270447 47 47 ) 48 48 49 version = Version(0, 4, 5)49 version = Version(0, 5, 0) 50 50 51 51 AutoInstall.register(Package('dateutil', Version(2, 8, 1), pypi_name='python-dateutil')) -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/commit.py
r270365 r270447 188 188 self.timestamp = timestamp 189 189 190 if author and isinstance(author, six.string_types): 191 self.author = Contributor.by_email.get( 192 author, 193 Contributor.by_name.get(author), 194 ) 195 if not self.author: 196 raise ValueError("'{}' does not match a known contributor") 197 elif author and isinstance(author, dict) and author.get('name'): 190 if author and isinstance(author, dict) and author.get('name'): 198 191 self.author = Contributor(author.get('name'), author.get('emails')) 199 192 elif author and not isinstance(author, Contributor): -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/contributor.py
r270365 r270447 24 24 import re 25 25 26 from collections import defaultdict 26 27 from webkitcorepy import string_utils 27 28 … … 32 33 SVN_AUTHOR_RE = re.compile(r'r\d+ \| (?P<email>.*) \| (?P<date>.*) \| \d+ lines?') 33 34 SVN_PATCH_FROM_RE = re.compile(r'Patch by (?P<author>.*) <(?P<email>.*)> on \d+-\d+-\d+') 34 35 by_email = dict()36 by_name = dict()37 35 38 36 class Encoder(json.JSONEncoder): … … 48 46 return result 49 47 50 @classmethod 51 def clear(cls): 52 cls.by_email = dict() 53 cls.by_name = dict() 48 class Mapping(defaultdict): 49 def __init__(self): 50 super(Contributor.Mapping, self).__init__(lambda: None) 51 52 def add(self, contributor): 53 if not isinstance(contributor, Contributor): 54 raise ValueError("'{}' is not a Contributor object".format(type(contributor))) 55 return self.create(name=contributor.name, *contributor.emails) 56 57 def create(self, name=None, *emails): 58 emails = [email for email in emails or []] 59 if not name and not emails: 60 return None 61 62 contributor = None 63 for argument in [name] + (emails or []): 64 contributor = self[argument] 65 if contributor: 66 break 67 68 if contributor: 69 for email in emails or []: 70 if email not in contributor.emails: 71 contributor.emails.append(email) 72 if contributor.name in contributor.emails and name: 73 contributor.name = name 74 else: 75 contributor = Contributor(name or emails[0], emails=emails) 76 77 self[contributor.name] = contributor 78 for email in contributor.emails or []: 79 self[email] = contributor 80 return contributor 81 54 82 55 83 @classmethod 56 def from_scm_log(cls, line ):84 def from_scm_log(cls, line, contributors=None): 57 85 email = None 58 86 author = None … … 76 104 return None 77 105 78 contributor = cls.by_name.get(author or email) 79 if not contributor: 80 contributor = cls.by_email.get(email) 81 82 if not contributor: 83 contributor = cls(author or email, emails=[email]) 84 cls.by_name[contributor.name] = contributor 85 elif email not in contributor.emails: 86 contributor.emails.append(email) 87 88 cls.by_name[email] = contributor 89 return contributor 106 if contributors is not None: 107 return contributors.create(author, email) 108 return cls(author or email, emails=[email]) 90 109 91 110 def __init__(self, name, emails=None): -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/git.py
r270358 r270447 43 43 return run([cls.executable(), 'rev-parse', '--show-toplevel'], cwd=path, capture_output=True).returncode == 0 44 44 45 def __init__(self, path, dev_branches=None, prod_branches=None ):46 super(Git, self).__init__(path, dev_branches=dev_branches, prod_branches=prod_branches )45 def __init__(self, path, dev_branches=None, prod_branches=None, contributors=None): 46 super(Git, self).__init__(path, dev_branches=dev_branches, prod_branches=prod_branches, contributors=contributors) 47 47 if not self.root_path: 48 48 raise OSError('Provided path {} is not a git repository'.format(path)) … … 266 266 branch=branch, 267 267 timestamp=int(commit_time.stdout.lstrip()), 268 author=Contributor.from_scm_log(log.stdout.splitlines()[1] ),268 author=Contributor.from_scm_log(log.stdout.splitlines()[1], self.contributors), 269 269 message='\n'.join(line[4:] for line in log.stdout.splitlines()[4:]) if include_log else None, 270 270 ) -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/scm.py
r269891 r270447 49 49 50 50 @classmethod 51 def from_path(cls, path ):51 def from_path(cls, path, contributors=None): 52 52 from webkitscmpy import local 53 53 54 54 if local.Git.is_checkout(path): 55 return local.Git(path )55 return local.Git(path, contributors=contributors) 56 56 if local.Svn.is_checkout(path): 57 return local.Svn(path )57 return local.Svn(path, contributors=contributors) 58 58 raise OSError("'{}' is not a known SCM type".format(path)) 59 59 60 def __init__(self, path, dev_branches=None, prod_branches=None ):61 super(Scm, self).__init__(dev_branches=dev_branches, prod_branches=prod_branches )60 def __init__(self, path, dev_branches=None, prod_branches=None, contributors=None): 61 super(Scm, self).__init__(dev_branches=dev_branches, prod_branches=prod_branches, contributors=contributors) 62 62 63 63 if not isinstance(path, six.string_types): -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/svn.py
r270358 r270447 51 51 return run([cls.executable(), 'info'], cwd=path, capture_output=True).returncode == 0 52 52 53 def __init__(self, path, dev_branches=None, prod_branches=None ):54 super(Svn, self).__init__(path, dev_branches=dev_branches, prod_branches=prod_branches )53 def __init__(self, path, dev_branches=None, prod_branches=None, contributors=None): 54 super(Svn, self).__init__(path, dev_branches=dev_branches, prod_branches=prod_branches, contributors=contributors) 55 55 56 56 self._root_path = self.path … … 371 371 break 372 372 373 author = Contributor.from_scm_log(author_line )373 author = Contributor.from_scm_log(author_line, self.contributors) 374 374 message = '\n'.join(split_log[3:-1]) 375 375 else: … … 377 377 self.log('Failed to connect to remote, cannot compute commit message') 378 378 email = info.get('Last Changed Author') 379 author = Contributor.by_email.get( 380 email, 381 Contributor.by_name.get( 382 email, 383 Contributor(name=email, emails=[email]), 384 ), 385 ) if email else None 379 author = self.contributors.create(email, email) if '@' in email else self.contributors.create(email) 386 380 message = None 387 381 -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program.py
r270358 r270447 163 163 164 164 165 def main(args=None, path=None, loggers=None ):165 def main(args=None, path=None, loggers=None, contributors=None): 166 166 logging.basicConfig(level=logging.WARNING) 167 167 … … 192 192 193 193 if parsed.repository.startswith(('https://', 'http://')): 194 repository = remote.Scm.from_url(parsed.repository )194 repository = remote.Scm.from_url(parsed.repository, contributors=contributors) 195 195 else: 196 repository = local.Scm.from_path(path=parsed.repository )196 repository = local.Scm.from_path(path=parsed.repository, contributors=contributors) 197 197 198 198 return parsed.main(args=parsed, repository=repository) -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/scm.py
r270038 r270447 28 28 class Scm(ScmBase): 29 29 @classmethod 30 def from_url(cls, url ):30 def from_url(cls, url, contributors=None): 31 31 from webkitscmpy import remote 32 32 33 33 if remote.Svn.is_webserver(url): 34 return remote.Svn(url )34 return remote.Svn(url, contributors=contributors) 35 35 raise OSError("'{}' is not a known SCM server".format(url)) 36 36 37 def __init__(self, url, dev_branches=None, prod_branches=None ):38 super(Scm, self).__init__(dev_branches=dev_branches, prod_branches=prod_branches )37 def __init__(self, url, dev_branches=None, prod_branches=None, contributors=None): 38 super(Scm, self).__init__(dev_branches=dev_branches, prod_branches=prod_branches, contributors=contributors) 39 39 40 40 if not isinstance(url, six.string_types): -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/svn.py
r270412 r270447 47 47 return True if cls.URL_RE.match(url) else False 48 48 49 def __init__(self, url, dev_branches=None, prod_branches=None ):49 def __init__(self, url, dev_branches=None, prod_branches=None, contributors=None): 50 50 if url[-1] != '/': 51 51 url += '/' 52 52 if not self.is_webserver(url): 53 53 raise self.Exception("'{}' is not a valid SVN webserver".format(url)) 54 super(Svn, self).__init__(url, dev_branches=dev_branches, prod_branches=prod_branches )54 super(Svn, self).__init__(url, dev_branches=dev_branches, prod_branches=prod_branches, contributors=contributors) 55 55 56 56 if os.path.exists(self._cache_path): … … 427 427 name = info.get('Last Changed Author') 428 428 429 author = Contributor.by_email.get( 430 name, 431 Contributor.by_name.get( 432 name, 433 Contributor(name=name, emails=[name] if '@' in name else []), 434 ), 435 ) if name else None 429 author = self.contributors.create(name, name) if name and '@' in name else self.contributors.create(name) 436 430 437 431 return Commit( -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/scm_base.py
r270358 r270447 27 27 28 28 from logging import NullHandler 29 from webkitscmpy import Commit, log29 from webkitscmpy import Commit, Contributor, log 30 30 31 31 … … 39 39 PROD_BRANCHES = re.compile(r'\S+-[\d+\.]+-branch') 40 40 41 def __init__(self, dev_branches=None, prod_branches=None ):41 def __init__(self, dev_branches=None, prod_branches=None, contributors=None): 42 42 self.dev_branches = dev_branches or self.DEV_BRANCHES 43 43 self.prod_branches = prod_branches or self.PROD_BRANCHES 44 44 self.path = None 45 self.contributors = Contributor.Mapping() if contributors is None else contributors 45 46 46 47 @property -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/commit_unittest.py
r270365 r270447 196 196 197 197 def test_contributor(self): 198 Contributor.clear()199 198 contributor = Contributor.from_scm_log('Author: Jonathan Bedard <jbedard@apple.com>') 200 199 … … 202 201 self.assertEqual(commit.author, contributor) 203 202 204 commit = Commit(revision=1, identifier=1, author= 'Jonathan Bedard')203 commit = Commit(revision=1, identifier=1, author=Contributor.Encoder().default(contributor)) 205 204 self.assertEqual(commit.author, contributor) 206 205 207 commit = Commit(revision=1, identifier=1, author='jbedard@apple.com')208 self.assertEqual(commit.author, contributor)209 210 206 def test_invalid_contributor(self): 211 Contributor.clear() 212 with self.assertRaises(ValueError): 207 with self.assertRaises(TypeError): 213 208 Commit(revision=1, identifier=1, author='Jonathan Bedard') 214 209 … … 219 214 220 215 def test_json_encode(self): 221 Contributor.clear()222 216 contributor = Contributor.from_scm_log('Author: Jonathan Bedard <jbedard@apple.com>') 223 217 … … 244 238 245 239 def test_json_decode(self): 246 Contributor.clear()247 240 contributor = Contributor.from_scm_log('Author: Jonathan Bedard <jbedard@apple.com>') 248 241 … … 252 245 identifier='1@main', 253 246 timestamp=1000, 254 author= contributor,247 author=Contributor.Encoder().default(contributor), 255 248 message='Message' 256 249 ) -
trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/contributor_unittest.py
r270365 r270447 30 30 class TestContributor(unittest.TestCase): 31 31 def test_git_log(self): 32 Contributor.clear()33 32 contributor = Contributor.from_scm_log('Author: Jonathan Bedard <jbedard@apple.com>') 34 33 … … 37 36 38 37 def test_git_svn_log(self): 39 Contributor.clear()40 38 contributor = Contributor.from_scm_log('Author: Jonathan Bedard <jbedard@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>') 41 39 … … 44 42 45 43 def test_git_no_author(self): 46 Contributor.clear()47 44 contributor = Contributor.from_scm_log('Author: Automated Checkin <devnull>') 48 45 self.assertIsNone(contributor) 49 46 50 47 def test_git_svn_no_author(self): 51 Contributor.clear()52 48 contributor = Contributor.from_scm_log('Author: (no author) <(no author)@268f45cc-cd09-0410-ab3c-d52691b4dbfc>') 53 49 self.assertIsNone(contributor) 54 50 55 51 def test_svn_log(self): 56 Contributor.clear()57 52 contributor = Contributor.from_scm_log('r266751 | jbedard@apple.com | 2020-09-08 14:33:42 -0700 (Tue, 08 Sep 2020) | 10 lines') 58 53 … … 61 56 62 57 def test_short_svn_log(self): 63 Contributor.clear()64 58 contributor = Contributor.from_scm_log('r266751 | jbedard@apple.com | 2020-09-08 14:33:42 -0700 (Tue, 08 Sep 2020) | 1 line') 65 59 … … 68 62 69 63 def test_svn_patch_by_log(self): 70 Contributor.clear()71 64 contributor = Contributor.from_scm_log('Patch by Jonathan Bedard <jbedard@apple.com> on 2020-09-10') 72 65 … … 75 68 76 69 def test_author_mapping(self): 77 Contributor.clear()78 Contributor.from_scm_log('Author: Jonathan Bedard <jbedard@apple.com>' )79 contributor = Contributor.from_scm_log('Author: Jonathan Bedard <jbedard@webkit.org>' )70 contributors = Contributor.Mapping() 71 Contributor.from_scm_log('Author: Jonathan Bedard <jbedard@apple.com>', contributors) 72 contributor = Contributor.from_scm_log('Author: Jonathan Bedard <jbedard@webkit.org>', contributors) 80 73 81 74 self.assertEqual(contributor.name, 'Jonathan Bedard') … … 83 76 84 77 def test_email_mapping(self): 85 Contributor.clear()86 Contributor.from_scm_log('Author: Jonathan Bedard <jbedard@apple.com>' )87 contributor = Contributor.from_scm_log('r266751 | jbedard@apple.com | 2020-09-08 14:33:42 -0700 (Tue, 08 Sep 2020) | 10 lines' )78 contributors = Contributor.Mapping() 79 Contributor.from_scm_log('Author: Jonathan Bedard <jbedard@apple.com>', contributors) 80 contributor = Contributor.from_scm_log('r266751 | jbedard@apple.com | 2020-09-08 14:33:42 -0700 (Tue, 08 Sep 2020) | 10 lines', contributors) 88 81 89 82 self.assertEqual(contributor.name, 'Jonathan Bedard') … … 91 84 92 85 def test_invalid_log(self): 93 Contributor.clear()94 86 with self.assertRaises(ValueError): 95 87 Contributor.from_scm_log('Jonathan Bedard <jbedard@apple.com>')
Note: See TracChangeset
for help on using the changeset viewer.