Skip to content

Commit

Permalink
[webkitscmpy] Collect diff from GitHub remote repository
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=265590
rdar://118993239

Reviewed by Dewei Zhu.

* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py:
(GitHub.commit): 'HEAD' in GitHub means "latest commit on the default branch".
(GitHub._diff_response): Return a response with a mock text diff.
(GitHub.request): Respect the 'application/vnd.github.diff' header.
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/git_hub.py:
(GitHub):
(GitHub.diff): Given a commit or commit range, return a line-by-line diff of
the provided range. If the caller requests it, include the commit messages for
the specified commits in the same patch format used by 'git format-patch'.
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/git_unittest.py:

Canonical link: https://commits.webkit.org/271687@main
  • Loading branch information
JonWBedard committed Dec 7, 2023
1 parent bb91f7e commit 912bf75
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ def commit(self, ref):
return self.commits[ref][-1]
if ref in self.tags:
return self.tags[ref]
if ref == 'HEAD':
return self.commits[self.default_branch][-1]

for branch, commits in self.commits.items():
for commit in commits:
Expand Down Expand Up @@ -242,6 +244,22 @@ def _commit_response(self, url, ref):
'files': [dict(filename=name) for name in ('Source/main.cpp', 'Source/main.h')],
}, url=url)

def _diff_response(self, url, ref):
commit = self.commit(ref)
if not commit:
return mocks.Response.fromJson(
dict(message='No commit found for SHA: {}'.format(ref)),
url=url,
status_code=404,
)
return mocks.Response.fromText(
'diff --git a/ChangeLog b/ChangeLog\n'
'--- a/ChangeLog\n'
'+++ b/ChangeLog\n'
'@@ -1,0 +1,0 @@\n{}'.format('\n'.join(['+{}'.format(line) for line in commit.message.splitlines()])),
url=url,
)

def _compare_response(self, url, ref_a, ref_b):
commit_a = self.commit(ref_a)
commit_b = self.commit(ref_b)
Expand Down Expand Up @@ -374,7 +392,7 @@ def graphql(self, url, auth=None, json=None):

return mocks.Response.create404(url)

def request(self, method, url, data=None, params=None, auth=None, json=None, **kwargs):
def request(self, method, url, data=None, params=None, auth=None, json=None, headers=None, **kwargs):
if not url.startswith('http://') and not url.startswith('https://'):
return mocks.Response.create404(url)

Expand All @@ -395,6 +413,8 @@ def request(self, method, url, data=None, params=None, auth=None, json=None, **k

# Extract single commit
if stripped_url.startswith('{}/commits/'.format(self.api_remote)):
if (headers or {}).get('Accept') == 'application/vnd.github.diff':
return self._diff_response(url=url, ref=stripped_url.split('/', 5)[-1])
return self._commit_response(url=url, ref=stripped_url.split('/', 5)[-1])

# Compare two commits
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class GitHub(Scm):
KNOWN_400_MESSAGES = [
'No commit found for SHA',
]
DIFF_HEADER = 'application/vnd.github.diff'

class PRGenerator(Scm.PRGenerator):
SUPPORTS_DRAFTS = True
Expand Down Expand Up @@ -710,7 +711,7 @@ def commits(self, begin=None, end=None, include_log=True, include_identifier=Tru
identifier = previous.identifier
if commit_data['sha'] == previous.hash:
cached = cached[:-1]
else:
elif identifier is not None:
identifier -= 1

if not identifier:
Expand Down Expand Up @@ -783,6 +784,50 @@ def find(self, argument, include_log=True, include_identifier=True):
raise ValueError("'{}' is not an argument recognized by git".format(argument))
return self.commit(hash=commit_data['sha'], include_log=include_log, include_identifier=include_identifier)

def diff(self, head='HEAD', base=None, include_log=False):
if base:
commits = list(self.commits(dict(argument=base), end=dict(argument=head), include_identifier=False))
else:
commits = [self.find(head, include_identifier=False), None]

if not commits or not commits[0]:
sys.stderr.write('Failed to find commits required to generate diff\n')
return
commits = commits[:-1]

patch_count = 1
for commit in commits:
response = self.request('commits/{}'.format(commit.hash), headers=dict(Accept=self.DIFF_HEADER))
if response.status_code // 100 != 2:
sys.stderr.write('Failed to retrieve diff of {} with status code {}\n'.format(commit, response.status_code))
return

if include_log:
yield 'From {}'.format(commit.hash)
yield 'From: {} <{}>'.format(commit.author.name, commit.author.email)
yield 'Date: {}'.format(datetime.fromtimestamp(commit.timestamp).strftime('%a %b %d %H:%M:%S %Y'))
if len(commits) <= 1:
subject = 'Subject: [PATCH]'
else:
subject = 'Subject: [PATCH {}/{}]'.format(patch_count, len(commits))
for line in commit.message.splitlines():
if subject is None:
yield line
elif line:
subject = '{} {}'.format(subject, line)
else:
yield subject
yield line
subject = None
if subject:
yield subject
yield '---'

for line in response.text.splitlines():
yield line

patch_count += 1

def files_changed(self, argument=None):
if not argument:
raise ValueError('No argument provided')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,60 @@ def test_checkout_url(self):
with self.assertRaises(ValueError):
remote.GitHub(self.remote).checkout_url(http=True, ssh=True)

def test_diff(self):
with mocks.remote.GitHub():
repo = remote.GitHub(self.remote)
self.assertEqual([
'diff --git a/ChangeLog b/ChangeLog',
'--- a/ChangeLog',
'+++ b/ChangeLog',
'@@ -1,0 +1,0 @@',
'+Patch Series',
], list(repo.diff(base='bae5d1e90999d4f916a8a15810ccfa43f37a2fd6')))

def test_diff_with_commit_message(self):
with mocks.remote.GitHub():
repo = remote.GitHub(self.remote)
self.assertEqual([
'From bae5d1e90999d4f916a8a15810ccfa43f37a2fd6',
'From: Jonathan Bedard <jbedard@apple.com>',
'Date: {}'.format(datetime.fromtimestamp(1601642800).strftime('%a %b %d %H:%M:%S %Y')),
'Subject: [PATCH] 8th commit',
'---',
'diff --git a/ChangeLog b/ChangeLog',
'--- a/ChangeLog',
'+++ b/ChangeLog',
'@@ -1,0 +1,0 @@',
'+8th commit',
], list(repo.diff(base='3@main', head='4@main', include_log=True)))

def test_diff_with_commit_message_multiple(self):
self.maxDiff = None
with mocks.remote.GitHub():
repo = remote.GitHub(self.remote)
self.assertEqual([
'From bae5d1e90999d4f916a8a15810ccfa43f37a2fd6',
'From: Jonathan Bedard <jbedard@apple.com>',
'Date: {}'.format(datetime.fromtimestamp(1601642800).strftime('%a %b %d %H:%M:%S %Y')),
'Subject: [PATCH 1/2] 8th commit',
'---',
'diff --git a/ChangeLog b/ChangeLog',
'--- a/ChangeLog',
'+++ b/ChangeLog',
'@@ -1,0 +1,0 @@',
'+8th commit',
'From 1abe25b443e985f93b90d830e4a7e3731336af4d',
'From: Jonathan Bedard <jbedard@apple.com>',
'Date: {}'.format(datetime.fromtimestamp(1601637800).strftime('%a %b %d %H:%M:%S %Y')),
'Subject: [PATCH 2/2] 4th commit',
'---',
'diff --git a/ChangeLog b/ChangeLog',
'--- a/ChangeLog',
'+++ b/ChangeLog',
'@@ -1,0 +1,0 @@',
'+4th commit',
], list(repo.diff(base='2@main', head='4@main', include_log=True)))


class TestBitBucket(testing.TestCase):
remote = 'https://bitbucket.example.com/projects/WEBKIT/repos/webkit'
Expand Down

0 comments on commit 912bf75

Please sign in to comment.