Diff
Modified: trunk/Tools/ChangeLog (269116 => 269117)
--- trunk/Tools/ChangeLog 2020-10-28 20:01:28 UTC (rev 269116)
+++ trunk/Tools/ChangeLog 2020-10-28 20:06:50 UTC (rev 269117)
@@ -1,5 +1,38 @@
2020-10-28 Jonathan Bedard <[email protected]>
+ [webkitscmpy] Support finding commit by tag
+ https://bugs.webkit.org/show_bug.cgi?id=218212
+ <rdar://problem/70700121>
+
+ Reviewed by Dewei Zhu.
+
+ * Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py: Bump version.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/local/git.py:
+ (Git.commit): Find a commit referred to by a provided tag.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/local/scm.py:
+ (Scm.find): Find a commit by tag, if applicable.
+ (Scm.commit):
+ * Scripts/libraries/webkitscmpy/webkitscmpy/local/svn.py:
+ (Svn.info): Pull information by tag, support non-standard branches.
+ (Svn._cache_revisions): Support non-standard branches.
+ (Svn._branch_for): Return the non-standard branch name for tags.
+ (Svn.commit): Find a commit referred to by a provided tag.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/mocks/local/git.py:
+ (Git): Support tags.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/mocks/local/svn.py:
+ (Svn.__init__): Support tags.
+ (Svn.tags): Tags are simply specialized branches, return the names of those tags
+ based on the commit mapping.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/test/find_unittest.py:
+ * Scripts/libraries/webkitscmpy/webkitscmpy/test/git_unittest.py:
+ (TestGit):
+ (TestGit.test_tag):
+ * Scripts/libraries/webkitscmpy/webkitscmpy/test/svn_unittest.py:
+ (TestSvn):
+ (TestSvn.test_tag):
+
+2020-10-28 Jonathan Bedard <[email protected]>
+
[webkitflaskpy] Create shared library for WebKit's flask tooling
https://bugs.webkit.org/show_bug.cgi?id=218257
<rdar://problem/70736269>
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py (269116 => 269117)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py 2020-10-28 20:01:28 UTC (rev 269116)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py 2020-10-28 20:06:50 UTC (rev 269117)
@@ -46,7 +46,7 @@
"Please install webkitcorepy with `pip install webkitcorepy --extra-index-url <package index URL>`"
)
-version = Version(0, 2, 5)
+version = Version(0, 2, 6)
AutoInstall.register(Package('dateutil', Version(2, 8, 1), pypi_name='python-dateutil'))
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/git.py (269116 => 269117)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/git.py 2020-10-28 20:01:28 UTC (rev 269116)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/git.py 2020-10-28 20:06:50 UTC (rev 269117)
@@ -151,10 +151,13 @@
result = [branch.lstrip(' *') for branch in filter(lambda branch: '->' not in branch, branch.stdout.splitlines())]
return sorted(set(['/'.join(branch.split('/')[2:]) if branch.startswith('remotes/origin/') else branch for branch in result]))
- def commit(self, hash=None, revision=None, identifier=None, branch=None):
+ def commit(self, hash=None, revision=None, identifier=None, branch=None, tag=None):
if revision and not self.is_svn:
raise self.Exception('This git checkout does not support SVN revisions')
elif revision:
+ if hash:
+ raise ValueError('Cannot define both hash and revision')
+
revision = Commit._parse_revision(revision, do_assert=True)
revision_log = run(
[self.executable(), 'svn', 'find-rev', 'r{}'.format(revision)],
@@ -175,6 +178,8 @@
raise ValueError('Cannot define both revision and identifier')
if hash:
raise ValueError('Cannot define both hash and identifier')
+ if tag:
+ raise ValueError('Cannot define both tag and identifier')
parsed_branch_point, identifier, parsed_branch = Commit._parse_identifier(identifier, do_assert=True)
if parsed_branch:
@@ -213,12 +218,15 @@
if identifier < 0:
identifier = None
- elif branch:
+ elif branch or tag:
if hash:
- raise ValueError('Cannot define both branch and hash')
- log = run([self.executable(), 'log', branch, '-1'], cwd=self.root_path, capture_output=True, encoding='utf-8')
+ raise ValueError('Cannot define both tag/branch and hash')
+ if branch and tag:
+ raise ValueError('Cannot define both tag and branch')
+
+ log = run([self.executable(), 'log', branch or tag, '-1'], cwd=self.root_path, capture_output=True, encoding='utf-8')
if log.returncode:
- raise self.Exception("Failed to retrieve commit information for '{}'".format(branch))
+ raise self.Exception("Failed to retrieve commit information for '{}'".format(branch or tag))
else:
hash = Commit._parse_hash(hash, do_assert=True)
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/scm.py (269116 => 269117)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/scm.py 2020-10-28 20:01:28 UTC (rev 269116)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/scm.py 2020-10-28 20:06:50 UTC (rev 269117)
@@ -120,6 +120,9 @@
elif argument in self.branches:
result = self.commit(branch=argument)
+ elif argument in self.tags:
+ result = self.commit(tag=argument)
+
else:
if offset:
raise ValueError("'~' offsets are not supported for revisions and identifiers")
@@ -140,7 +143,7 @@
branch=result.branch,
)
- def commit(self, hash=None, revision=None, identifier=None, branch=None):
+ def commit(self, hash=None, revision=None, identifier=None, branch=None, tag=None):
raise NotImplementedError()
def prioritize_branches(self, branches):
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/svn.py (269116 => 269117)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/svn.py 2020-10-28 20:01:28 UTC (rev 269116)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/local/svn.py 2020-10-28 20:06:50 UTC (rev 269117)
@@ -69,9 +69,17 @@
self._metadata_cache = dict(version=str(self.CACHE_VERSION))
@decorators.Memoize(cached=False)
- def info(self, branch=None, revision=None):
+ def info(self, branch=None, revision=None, tag=None):
+ if tag and branch:
+ raise ValueError('Cannot specify both branch and tag')
+ if tag and revision:
+ raise ValueError('Cannot specify both branch and tag')
+
revision = Commit._parse_revision(revision)
- additional_args = ['^/branches/{}'.format(branch)] if branch and branch != self.default_branch else []
+ if branch and branch != self.default_branch and '/' not in branch:
+ branch = 'branches/{}'.format(branch)
+ additional_args = ['^/{}'.format(branch)] if branch and branch != self.default_branch else []
+ additional_args += ['^/tags/{}'.format(tag)] if tag else []
additional_args += ['-r', str(revision)] if revision else []
info_result = run([self.executable(), 'info'] + additional_args, cwd=self.root_path, capture_output=True, encoding='utf-8')
@@ -137,9 +145,12 @@
did_warn = False
count = 0
log = None
- candidate_index = -1 if is_default_branch else len(self._metadata_cache[self.default_branch])
- branch_arg = '^/{}{}'.format('' if is_default_branch else 'branches/', branch)
+ if is_default_branch or '/' in branch:
+ branch_arg = '^/{}'.format(branch)
+ else:
+ branch_arg = '^/branches/{}'.format(branch)
+
kwargs = dict()
if sys.version_info >= (3, 0):
kwargs = dict(encoding='utf-8')
@@ -238,9 +249,14 @@
if len(partial) <= 3:
raise self.Exception('Malformed set of edited files')
partial = partial[2:].split(' ')[0]
- return partial.split('/')[2 if partial.startswith('/branches') else 1]
+ candidate = partial.split('/')[2 if partial.startswith('/branches') else 1]
- def commit(self, hash=None, revision=None, identifier=None, branch=None):
+ # Tags are a unique case for SVN, because they're treated as branches in native SVN
+ if candidate == 'tags':
+ return partial[1:].rstrip('/')
+ return candidate
+
+ def commit(self, hash=None, revision=None, identifier=None, branch=None, tag=None):
if hash:
raise ValueError('SVN does not support Git hashes')
@@ -248,6 +264,8 @@
if identifier is not None:
if revision:
raise ValueError('Cannot define both revision and identifier')
+ if tag:
+ raise ValueError('Cannot define both tag and identifier')
parsed_branch_point, identifier, parsed_branch = Commit._parse_identifier(identifier, do_assert=True)
if parsed_branch:
@@ -286,15 +304,23 @@
elif revision:
if branch:
raise ValueError('Cannot define both branch and revision')
+ if tag:
+ raise ValueError('Cannot define both tag and revision')
revision = Commit._parse_revision(revision, do_assert=True)
branch = self._branch_for(revision)
info = self.info(cached=True, branch=branch, revision=revision)
else:
- branch = branch or self.branch
- info = self.info(branch=branch)
+ if branch and tag:
+ raise ValueError('Cannot define both branch and tag')
+
+ branch = None if tag else branch or self.branch
+ info = self.info(tag=tag) if tag else self.info(branch=branch)
if not info:
- raise self.Exception("'{}' is not a recognized branch".format(branch))
+ raise self.Exception("'{}' is not a recognized {}".format(
+ tag or branch,
+ 'tag' if tag else 'branch',
+ ))
revision = int(info['Last Changed Rev'])
if branch != self.default_branch:
branch = self._branch_for(revision)
@@ -324,7 +350,11 @@
if branch_point and parsed_branch_point and branch_point != parsed_branch_point:
raise ValueError("Provided 'branch_point' does not match branch point of specified branch")
- branch_arg = '^/{}{}'.format('' if branch == self.default_branch else 'branches/', branch)
+ if branch == self.default_branch or '/' in branch:
+ branch_arg = '^/{}'.format(branch)
+ else:
+ branch_arg = '^/branches/{}'.format(branch)
+
log = run(
[self.executable(), 'log', '-l', '1', '-r', str(revision), branch_arg], cwd=self.root_path,
capture_output=True, encoding='utf-8',
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/local/git.py (269116 => 269117)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/local/git.py 2020-10-28 20:01:28 UTC (rev 269116)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/local/git.py 2020-10-28 20:06:50 UTC (rev 269117)
@@ -43,7 +43,7 @@
self.detached = detached or False
self.branches = branches or []
- self.tags = tags or []
+ self.tags = tags or {}
try:
self.executable = local.Git.executable()
@@ -119,6 +119,9 @@
),
]
+ self.tags['tag-1'] = self.commits['branch-a'][-1]
+ self.tags['tag-2'] = self.commits['branch-b'][-1]
+
if git_svn:
git_svn_routes = [
mocks.Subprocess.Route(
@@ -222,7 +225,7 @@
cwd=self.path,
generator=lambda *args, **kwargs: mocks.ProcessCompletion(
returncode=0,
- stdout='\n'.join(self.tags) + '\n',
+ stdout='\n'.join(sorted(self.tags.keys())) + '\n',
),
), mocks.Subprocess.Route(
self.executable, 'rev-parse', '--abbrev-ref', 'origin/HEAD',
@@ -319,6 +322,8 @@
return self.commits[self.branch][-1]
if something in self.commits.keys():
return self.commits[something][-1]
+ if something in self.tags.keys():
+ return self.tags[something]
something = str(something)
if '..' in something:
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/local/svn.py (269116 => 269117)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/local/svn.py 2020-10-28 20:01:28 UTC (rev 269116)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/local/svn.py 2020-10-28 20:06:50 UTC (rev 269117)
@@ -45,13 +45,12 @@
date=datetime.fromtimestamp(commit.timestamp).strftime('%Y-%m-%d %H:%M:%S {} (%a, %d %b %Y)'.format(cls.UTC_OFFSET)),
)
- def __init__(self, path='/.invalid-svn', branch=None, remote=None, branches=None, tags=None):
+ def __init__(self, path='/.invalid-svn', branch=None, remote=None, branches=None):
self.path = path
self.branch = branch or 'trunk'
self.remote = remote or 'https://svn.mock.org/repository/{}'.format(os.path.basename(path))
self.branches = branches or []
- self.tags = tags or []
self.connected = True
try:
@@ -120,6 +119,28 @@
),
]
+ self.commits['tags/tag-1'] = [
+ self.commits['branch-a'][0],
+ self.commits['branch-a'][1], Commit(
+ identifier='2.3@tags/tag-1',
+ revision=9,
+ author=contributor,
+ timestamp=1601668100,
+ message='9th commit\n',
+ ),
+ ]
+ self.commits['tags/tag-2'] = [
+ self.commits['branch-b'][0],
+ self.commits['branch-b'][1],
+ self.commits['branch-b'][2], Commit(
+ identifier='2.4@tags/tag-2',
+ revision=10,
+ author=contributor,
+ timestamp=1601669100,
+ message='10th commit\n',
+ ),
+ ]
+
super(Svn, self).__init__(
mocks.Subprocess.Route(
'/usr/bin/which', 'svn',
@@ -130,7 +151,7 @@
), mocks.Subprocess.Route(
self.executable, 'info',
cwd=self.path,
- generator=lambda *args, **kwargs: self._info(cwd=kwargs.get('cwd',''))
+ generator=lambda *args, **kwargs: self._info(cwd=kwargs.get('cwd', ''))
), mocks.Subprocess.Route(
self.executable, 'info', self.BRANCH_RE,
cwd=self.path,
@@ -140,7 +161,7 @@
cwd=self.path,
generator=lambda *args, **kwargs: mocks.ProcessCompletion(
returncode=0,
- stdout='/\n'.join(sorted(set(self.branches) | set(self.commits.keys()) - {'trunk'})) + '/\n',
+ stdout='/\n'.join(sorted(set(self.branches) | set(self.commits.keys()) - {'trunk'} - self.tags)) + '/\n',
) if self.connected else mocks.ProcessCompletion(returncode=1),
), mocks.Subprocess.Route(
self.executable, 'list', '^/tags',
@@ -147,7 +168,7 @@
cwd=self.path,
generator=lambda *args, **kwargs: mocks.ProcessCompletion(
returncode=0,
- stdout='/\n'.join(self.tags) + '/\n',
+ stdout='/\n'.join([tag[len('tags/'):] for tag in sorted(self.tags)]) + '/\n',
) if self.connected else mocks.ProcessCompletion(returncode=1),
), mocks.Subprocess.Route(
self.executable, 'log', '-v', '-q', self.remote, '-r', re.compile(r'\d+'),
@@ -160,7 +181,7 @@
' M /{branch}/ChangeLog\n'
' M /{branch}/file.cpp\n'.format(
line=self.log_line(self.find(revision=args[6])),
- branch='trunk' if self.find(revision=args[6]).branch == 'trunk' else 'branches/{}'.format(self.find(revision=args[6]).branch)
+ branch=self.find(revision=args[6]).branch if self.find(revision=args[6]).branch.split('/')[0] in ['trunk', 'tags'] else 'branches/{}'.format(self.find(revision=args[6]).branch)
),
) if self.connected and self.find(revision=args[6]) else mocks.ProcessCompletion(returncode=1),
), mocks.Subprocess.Route(
@@ -195,6 +216,10 @@
),
)
+ @property
+ def tags(self):
+ return set(branch for branch in self.commits.keys() if branch.startswith('tags'))
+
def _info(self, branch=None, revision=None, cwd=''):
commit = self.find(branch=branch, revision=revision)
if not commit:
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/find_unittest.py (269116 => 269117)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/find_unittest.py 2020-10-28 20:01:28 UTC (rev 269116)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/find_unittest.py 2020-10-28 20:06:50 UTC (rev 269117)
@@ -166,3 +166,19 @@
branch='main',
message='4th commit\nsvn-id: https://svn.webkit.orgrepository/repository/trunk@4 268f45cc-cd09-0410-ab3c-d52691b4dbfc',
))
+
+ def test_tag_svn(self):
+ with mocks.local.Git(), mocks.local.Svn(self.path), MockTime, OutputCapture() as captured:
+ self.assertEqual(0, program.main(
+ args=('find', 'tag-1', '-q'),
+ path=self.path,
+ ))
+ self.assertEqual(captured.stdout.getvalue(), '2.3@tags/tag-1 | r9 | 9th commit\n')
+
+ def test_tag_git(self):
+ with mocks.local.Git(self.path, git_svn=True), mocks.local.Svn(), MockTime, OutputCapture() as captured:
+ self.assertEqual(0, program.main(
+ args=('find', 'tag-1', '-q'),
+ path=self.path,
+ ))
+ self.assertEqual(captured.stdout.getvalue(), '2.2@branch-a | 621652add7fc, r7 | 7th commit\n')
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/git_unittest.py (269116 => 269117)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/git_unittest.py 2020-10-28 20:01:28 UTC (rev 269116)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/git_unittest.py 2020-10-28 20:06:50 UTC (rev 269117)
@@ -63,7 +63,7 @@
)
def test_tags(self):
- with mocks.local.Git(self.path, tags=('tag-1', 'tag-2')):
+ with mocks.local.Git(self.path):
self.assertEqual(
local.Git(self.path).tags,
['tag-1', 'tag-2'],
@@ -196,7 +196,7 @@
def test_branches_priority(self):
for mock in [mocks.local.Git(self.path), mocks.local.Git(self.path, git_svn=True)]:
- with mocks.local.Git(self.path):
+ with mock:
self.assertEqual(
'main',
local.Git(self.path).prioritize_branches(['main', 'branch-a', 'dev/12345', 'safari-610-branch', 'safari-610.1-branch'])
@@ -216,3 +216,11 @@
'branch-a',
local.Git(self.path).prioritize_branches(['branch-a', 'dev/12345'])
)
+
+ def test_tag(self):
+ for mock in [mocks.local.Git(self.path), mocks.local.Git(self.path, git_svn=True)]:
+ with mock:
+ self.assertEqual(
+ '621652add7fc416099bd2063366cc38ff61afe36',
+ local.Git(self.path).commit(tag='tag-1').hash,
+ )
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/svn_unittest.py (269116 => 269117)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/svn_unittest.py 2020-10-28 20:01:28 UTC (rev 269116)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/svn_unittest.py 2020-10-28 20:06:50 UTC (rev 269117)
@@ -61,7 +61,7 @@
)
def test_tags(self):
- with mocks.local.Svn(self.path, tags=('tag-1', 'tag-2')):
+ with mocks.local.Svn(self.path):
self.assertEqual(
local.Svn(self.path).tags,
['tag-1', 'tag-2'],
@@ -107,7 +107,7 @@
# Out-of-bounds commit
with self.assertRaises(local.Svn.Exception):
- self.assertEqual(None, local.Svn(self.path).commit(revision=10))
+ self.assertEqual(None, local.Svn(self.path).commit(revision=11))
def test_commit_from_branch(self):
with mocks.local.Svn(self.path), OutputCapture():
@@ -196,3 +196,7 @@
local.Svn(dirname).commit(revision=3)
finally:
shutil.rmtree(dirname)
+
+ def test_tag(self):
+ with mocks.local.Svn(self.path), OutputCapture():
+ self.assertEqual(9, local.Svn(self.path).commit(tag='tag-1').revision)