patman: Allow specifying the patchwork URL

Add a new argument to allow the URL of the patchwork server to be
speciified. For now this is hard-coded in the main file, but future
patches will move it to the settings file.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2020-11-03 13:54:14 -07:00
parent 3145b63513
commit 7cbf02e94d
4 changed files with 48 additions and 27 deletions

View File

@ -177,7 +177,7 @@ def send(args):
args.smtp_server) args.smtp_server)
def patchwork_status(branch, count, start, end, dest_branch, force, def patchwork_status(branch, count, start, end, dest_branch, force,
show_comments): show_comments, url):
"""Check the status of patches in patchwork """Check the status of patches in patchwork
This finds the series in patchwork using the Series-link tag, checks for new This finds the series in patchwork using the Series-link tag, checks for new
@ -196,6 +196,7 @@ def patchwork_status(branch, count, start, end, dest_branch, force,
force (bool): With dest_branch, force overwriting an existing branch force (bool): With dest_branch, force overwriting an existing branch
show_comments (bool): True to display snippets from the comments show_comments (bool): True to display snippets from the comments
provided by reviewers provided by reviewers
url (str): URL of patchwork server, e.g. 'https://patchwork.ozlabs.org'
Raises: Raises:
ValueError: if the branch has no Series-link value ValueError: if the branch has no Series-link value
@ -228,4 +229,4 @@ def patchwork_status(branch, count, start, end, dest_branch, force,
# are not present # are not present
from patman import status from patman import status
status.check_patchwork_status(series, found[0], branch, dest_branch, force, status.check_patchwork_status(series, found[0], branch, dest_branch, force,
show_comments) show_comments, url)

View File

@ -625,11 +625,15 @@ diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
os.chdir(orig_dir) os.chdir(orig_dir)
@staticmethod @staticmethod
def _fake_patchwork(subpath): def _fake_patchwork(url, subpath):
"""Fake Patchwork server for the function below """Fake Patchwork server for the function below
This handles accessing a series, providing a list consisting of a This handles accessing a series, providing a list consisting of a
single patch single patch
Args:
url (str): URL of patchwork server
subpath (str): URL subpath to use
""" """
re_series = re.match(r'series/(\d*)/$', subpath) re_series = re.match(r'series/(\d*)/$', subpath)
if re_series: if re_series:
@ -645,7 +649,7 @@ diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
series = Series() series = Series()
with capture_sys_output() as (_, err): with capture_sys_output() as (_, err):
status.collect_patches(series, 1234, self._fake_patchwork) status.collect_patches(series, 1234, None, self._fake_patchwork)
self.assertIn('Warning: Patchwork reports 1 patches, series has 0', self.assertIn('Warning: Patchwork reports 1 patches, series has 0',
err.getvalue()) err.getvalue())
@ -655,7 +659,8 @@ diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
series = Series() series = Series()
series.commits = [Commit('abcd')] series.commits = [Commit('abcd')]
patches = status.collect_patches(series, 1234, self._fake_patchwork) patches = status.collect_patches(series, 1234, None,
self._fake_patchwork)
self.assertEqual(1, len(patches)) self.assertEqual(1, len(patches))
patch = patches[0] patch = patches[0]
self.assertEqual('1', patch.id) self.assertEqual('1', patch.id)
@ -800,11 +805,15 @@ diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
"Cannot find commit for patch 3 ('Subject 2')"], "Cannot find commit for patch 3 ('Subject 2')"],
warnings) warnings)
def _fake_patchwork2(self, subpath): def _fake_patchwork2(self, url, subpath):
"""Fake Patchwork server for the function below """Fake Patchwork server for the function below
This handles accessing series, patches and comments, providing the data This handles accessing series, patches and comments, providing the data
in self.patches to the caller in self.patches to the caller
Args:
url (str): URL of patchwork server
subpath (str): URL subpath to use
""" """
re_series = re.match(r'series/(\d*)/$', subpath) re_series = re.match(r'series/(\d*)/$', subpath)
re_patch = re.match(r'patches/(\d*)/$', subpath) re_patch = re.match(r'patches/(\d*)/$', subpath)
@ -861,12 +870,12 @@ diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
# Check that the tags are picked up on the first patch # Check that the tags are picked up on the first patch
status.find_new_responses(new_rtag_list, review_list, 0, commit1, status.find_new_responses(new_rtag_list, review_list, 0, commit1,
patch1, self._fake_patchwork2) patch1, None, self._fake_patchwork2)
self.assertEqual(new_rtag_list[0], {'Reviewed-by': {self.joe}}) self.assertEqual(new_rtag_list[0], {'Reviewed-by': {self.joe}})
# Now the second patch # Now the second patch
status.find_new_responses(new_rtag_list, review_list, 1, commit2, status.find_new_responses(new_rtag_list, review_list, 1, commit2,
patch2, self._fake_patchwork2) patch2, None, self._fake_patchwork2)
self.assertEqual(new_rtag_list[1], { self.assertEqual(new_rtag_list[1], {
'Reviewed-by': {self.mary, self.fred}, 'Reviewed-by': {self.mary, self.fred},
'Tested-by': {self.leb}}) 'Tested-by': {self.leb}})
@ -876,7 +885,7 @@ diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
new_rtag_list = [None] * count new_rtag_list = [None] * count
commit1.rtags = {'Reviewed-by': {self.joe}} commit1.rtags = {'Reviewed-by': {self.joe}}
status.find_new_responses(new_rtag_list, review_list, 0, commit1, status.find_new_responses(new_rtag_list, review_list, 0, commit1,
patch1, self._fake_patchwork2) patch1, None, self._fake_patchwork2)
self.assertEqual(new_rtag_list[0], {}) self.assertEqual(new_rtag_list[0], {})
# For the second commit, add Ed and Fred, so only Mary should be left # For the second commit, add Ed and Fred, so only Mary should be left
@ -884,7 +893,7 @@ diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
'Tested-by': {self.leb}, 'Tested-by': {self.leb},
'Reviewed-by': {self.fred}} 'Reviewed-by': {self.fred}}
status.find_new_responses(new_rtag_list, review_list, 1, commit2, status.find_new_responses(new_rtag_list, review_list, 1, commit2,
patch2, self._fake_patchwork2) patch2, None, self._fake_patchwork2)
self.assertEqual(new_rtag_list[1], {'Reviewed-by': {self.mary}}) self.assertEqual(new_rtag_list[1], {'Reviewed-by': {self.mary}})
# Check that the output patches expectations: # Check that the output patches expectations:
@ -900,7 +909,7 @@ diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
series.commits = [commit1, commit2] series.commits = [commit1, commit2]
terminal.SetPrintTestMode() terminal.SetPrintTestMode()
status.check_patchwork_status(series, '1234', None, None, False, False, status.check_patchwork_status(series, '1234', None, None, False, False,
self._fake_patchwork2) None, self._fake_patchwork2)
lines = iter(terminal.GetPrintTestLines()) lines = iter(terminal.GetPrintTestLines())
col = terminal.Color() col = terminal.Color()
self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE), self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE),
@ -935,11 +944,15 @@ diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
'1 new response available in patchwork (use -d to write them to a new branch)', '1 new response available in patchwork (use -d to write them to a new branch)',
None), next(lines)) None), next(lines))
def _fake_patchwork3(self, subpath): def _fake_patchwork3(self, url, subpath):
"""Fake Patchwork server for the function below """Fake Patchwork server for the function below
This handles accessing series, patches and comments, providing the data This handles accessing series, patches and comments, providing the data
in self.patches to the caller in self.patches to the caller
Args:
url (str): URL of patchwork server
subpath (str): URL subpath to use
""" """
re_series = re.match(r'series/(\d*)/$', subpath) re_series = re.match(r'series/(\d*)/$', subpath)
re_patch = re.match(r'patches/(\d*)/$', subpath) re_patch = re.match(r'patches/(\d*)/$', subpath)
@ -1011,7 +1024,8 @@ diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
terminal.SetPrintTestMode() terminal.SetPrintTestMode()
status.check_patchwork_status(series, '1234', branch, dest_branch, status.check_patchwork_status(series, '1234', branch, dest_branch,
False, False, self._fake_patchwork3, repo) False, False, None, self._fake_patchwork3,
repo)
lines = terminal.GetPrintTestLines() lines = terminal.GetPrintTestLines()
self.assertEqual(12, len(lines)) self.assertEqual(12, len(lines))
self.assertEqual( self.assertEqual(
@ -1214,7 +1228,7 @@ Reviewed-by: %s
series.commits = [commit1, commit2] series.commits = [commit1, commit2]
terminal.SetPrintTestMode() terminal.SetPrintTestMode()
status.check_patchwork_status(series, '1234', None, None, False, True, status.check_patchwork_status(series, '1234', None, None, False, True,
self._fake_patchwork2) None, self._fake_patchwork2)
lines = iter(terminal.GetPrintTestLines()) lines = iter(terminal.GetPrintTestLines())
col = terminal.Color() col = terminal.Color()
self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE), self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE),

View File

@ -179,7 +179,8 @@ elif args.cmd == 'status':
try: try:
control.patchwork_status(args.branch, args.count, args.start, args.end, control.patchwork_status(args.branch, args.count, args.start, args.end,
args.dest_branch, args.force, args.dest_branch, args.force,
args.show_comments) args.show_comments,
'https://patchwork.ozlabs.org')
except Exception as e: except Exception as e:
terminal.Print('patman: %s: %s' % (type(e).__name__, e), terminal.Print('patman: %s: %s' % (type(e).__name__, e),
colour=terminal.Color.RED) colour=terminal.Color.RED)

View File

@ -198,10 +198,11 @@ def compare_with_series(series, patches):
return patch_for_commit, commit_for_patch, warnings return patch_for_commit, commit_for_patch, warnings
def call_rest_api(subpath): def call_rest_api(url, subpath):
"""Call the patchwork API and return the result as JSON """Call the patchwork API and return the result as JSON
Args: Args:
url (str): URL of patchwork server, e.g. 'https://patchwork.ozlabs.org'
subpath (str): URL subpath to use subpath (str): URL subpath to use
Returns: Returns:
@ -210,13 +211,13 @@ def call_rest_api(subpath):
Raises: Raises:
ValueError: the URL could not be read ValueError: the URL could not be read
""" """
url = 'https://patchwork.ozlabs.org/api/1.2/%s' % subpath full_url = '%s/api/1.2/%s' % (url, subpath)
response = requests.get(url) response = requests.get(full_url)
if response.status_code != 200: if response.status_code != 200:
raise ValueError("Could not read URL '%s'" % url) raise ValueError("Could not read URL '%s'" % full_url)
return response.json() return response.json()
def collect_patches(series, series_id, rest_api=call_rest_api): def collect_patches(series, series_id, url, rest_api=call_rest_api):
"""Collect patch information about a series from patchwork """Collect patch information about a series from patchwork
Uses the Patchwork REST API to collect information provided by patchwork Uses the Patchwork REST API to collect information provided by patchwork
@ -226,6 +227,7 @@ def collect_patches(series, series_id, rest_api=call_rest_api):
series (Series): Series object corresponding to the local branch series (Series): Series object corresponding to the local branch
containing the series containing the series
series_id (str): Patch series ID number series_id (str): Patch series ID number
url (str): URL of patchwork server, e.g. 'https://patchwork.ozlabs.org'
rest_api (function): API function to call to access Patchwork, for rest_api (function): API function to call to access Patchwork, for
testing testing
@ -236,7 +238,7 @@ def collect_patches(series, series_id, rest_api=call_rest_api):
ValueError: if the URL could not be read or the web page does not follow ValueError: if the URL could not be read or the web page does not follow
the expected structure the expected structure
""" """
data = rest_api('series/%s/' % series_id) data = rest_api(url, 'series/%s/' % series_id)
# Get all the rows, which are patches # Get all the rows, which are patches
patch_dict = data['patches'] patch_dict = data['patches']
@ -261,7 +263,7 @@ def collect_patches(series, series_id, rest_api=call_rest_api):
patches = sorted(patches, key=lambda x: x.seq) patches = sorted(patches, key=lambda x: x.seq)
return patches return patches
def find_new_responses(new_rtag_list, review_list, seq, cmt, patch, def find_new_responses(new_rtag_list, review_list, seq, cmt, patch, url,
rest_api=call_rest_api): rest_api=call_rest_api):
"""Find new rtags collected by patchwork that we don't know about """Find new rtags collected by patchwork that we don't know about
@ -279,6 +281,7 @@ def find_new_responses(new_rtag_list, review_list, seq, cmt, patch,
seq (int): Position in new_rtag_list to update seq (int): Position in new_rtag_list to update
cmt (Commit): Commit object for this commit cmt (Commit): Commit object for this commit
patch (Patch): Corresponding Patch object for this patch patch (Patch): Corresponding Patch object for this patch
url (str): URL of patchwork server, e.g. 'https://patchwork.ozlabs.org'
rest_api (function): API function to call to access Patchwork, for rest_api (function): API function to call to access Patchwork, for
testing testing
""" """
@ -286,14 +289,14 @@ def find_new_responses(new_rtag_list, review_list, seq, cmt, patch,
return return
# Get the content for the patch email itself as well as all comments # Get the content for the patch email itself as well as all comments
data = rest_api('patches/%s/' % patch.id) data = rest_api(url, 'patches/%s/' % patch.id)
pstrm = PatchStream.process_text(data['content'], True) pstrm = PatchStream.process_text(data['content'], True)
rtags = collections.defaultdict(set) rtags = collections.defaultdict(set)
for response, people in pstrm.commit.rtags.items(): for response, people in pstrm.commit.rtags.items():
rtags[response].update(people) rtags[response].update(people)
data = rest_api('patches/%s/comments/' % patch.id) data = rest_api(url, 'patches/%s/comments/' % patch.id)
reviews = [] reviews = []
for comment in data: for comment in data:
@ -407,7 +410,7 @@ def create_branch(series, new_rtag_list, branch, dest_branch, overwrite,
return num_added return num_added
def check_patchwork_status(series, series_id, branch, dest_branch, force, def check_patchwork_status(series, series_id, branch, dest_branch, force,
show_comments, rest_api=call_rest_api, show_comments, url, rest_api=call_rest_api,
test_repo=None): test_repo=None):
"""Check the status of a series on Patchwork """Check the status of a series on Patchwork
@ -421,11 +424,12 @@ def check_patchwork_status(series, series_id, branch, dest_branch, force,
dest_branch (str): Name of new branch to create, or None dest_branch (str): Name of new branch to create, or None
force (bool): True to force overwriting dest_branch if it exists force (bool): True to force overwriting dest_branch if it exists
show_comments (bool): True to show the comments on each patch show_comments (bool): True to show the comments on each patch
url (str): URL of patchwork server, e.g. 'https://patchwork.ozlabs.org'
rest_api (function): API function to call to access Patchwork, for rest_api (function): API function to call to access Patchwork, for
testing testing
test_repo (pygit2.Repository): Repo to use (use None unless testing) test_repo (pygit2.Repository): Repo to use (use None unless testing)
""" """
patches = collect_patches(series, series_id, rest_api) patches = collect_patches(series, series_id, url, rest_api)
col = terminal.Color() col = terminal.Color()
count = len(series.commits) count = len(series.commits)
new_rtag_list = [None] * count new_rtag_list = [None] * count
@ -440,7 +444,8 @@ def check_patchwork_status(series, series_id, branch, dest_branch, force,
with concurrent.futures.ThreadPoolExecutor(max_workers=16) as executor: with concurrent.futures.ThreadPoolExecutor(max_workers=16) as executor:
futures = executor.map( futures = executor.map(
find_new_responses, repeat(new_rtag_list), repeat(review_list), find_new_responses, repeat(new_rtag_list), repeat(review_list),
range(count), series.commits, patch_list, repeat(rest_api)) range(count), series.commits, patch_list, repeat(url),
repeat(rest_api))
for fresponse in futures: for fresponse in futures:
if fresponse: if fresponse:
raise fresponse.exception() raise fresponse.exception()