Expand the patchwork module so that it can match the current requirements of the 'patman status' command, i.e. reading the state of a series and the patches associated with it.
Since the format of each patchwork response is a little tricky to understand, add examples in comments at the top of each function. Signed-off-by: Simon Glass <s...@chromium.org> --- tools/patman/patchwork.py | 218 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) diff --git a/tools/patman/patchwork.py b/tools/patman/patchwork.py index bb3645455fe..e0adbdb6481 100644 --- a/tools/patman/patchwork.py +++ b/tools/patman/patchwork.py @@ -177,3 +177,221 @@ class Patchwork: except aiohttp.client_exceptions.ServerDisconnectedError: if i == RETRIES: raise + + async def get_series(self, client, link): + """Read information about a series + + Args: + client (aiohttp.ClientSession): Session to use + link (str): Patchwork series ID + + Returns: dict containing patchwork's series information + id (int): series ID unique across patchwork instance, e.g. 3 + url (str): Full URL, e.g. + 'https://patchwork.ozlabs.org/api/1.2/series/3/' + web_url (str): Full URL, e.g. + 'https://patchwork.ozlabs.org/project/uboot/list/?series=3 + project (dict): project information (id, url, name, link_name, + list_id, list_email, etc. + name (str): Series name, e.g. '[U-Boot] moveconfig: fix error' + date (str): Date, e.g. '2017-08-27T08:00:51' + submitter (dict): id, url, name, email, e.g.: + "id": 6125, + "url": "https://patchwork.ozlabs.org/api/1.2/people/6125/", + "name": "Chris Packham", + "email": "judge.pack...@gmail.com" + version (int): Version number + total (int): Total number of patches based on subject + received_total (int): Total patches received by patchwork + received_all (bool): True if all patches were received + mbox (str): URL of mailbox, e.g. + 'https://patchwork.ozlabs.org/series/3/mbox/' + cover_letter (dict) or None, e.g.: + "id": 806215, + "url": "https://patchwork.ozlabs.org/api/1.2/covers/806215/", + "web_url": "https://patchwork.ozlabs.org/project/uboot/cover/ + 20170827094411.8583-1-judge.pack...@gmail.com/", + "msgid": "<20170827094411.8583-1-judge.pack...@gmail.com>", + "list_archive_url": null, + "date": "2017-08-27T09:44:07", + "name": "[U-Boot,v2,0/4] usb: net: Migrate USB Ethernet", + "mbox": "https://patchwork.ozlabs.org/project/uboot/cover/ + 20170827094411.8583-1-judge.pack...@gmail.com/mbox/" + patches (list of dict), each e.g.: + "id": 806202, + "url": "https://patchwork.ozlabs.org/api/1.2/patches/806202/", + "web_url": "https://patchwork.ozlabs.org/project/uboot/patch/ + 20170827080051.816-1-judge.pack...@gmail.com/", + "msgid": "<20170827080051.816-1-judge.pack...@gmail.com>", + "list_archive_url": null, + "date": "2017-08-27T08:00:51", + "name": "[U-Boot] moveconfig: fix error message do_autoconf()", + "mbox": "https://patchwork.ozlabs.org/project/uboot/patch/ + 20170827080051.816-1-judge.pack...@gmail.com/mbox/" + """ + return await self._request(client, f'series/{link}/') + + async def get_patch(self, client, patch_id): + """Read information about a patch + + Args: + client (aiohttp.ClientSession): Session to use + patch_id (str): Patchwork patch ID + + Returns: dict containing patchwork's patch information + "id": 185, + "url": "https://patchwork.ozlabs.org/api/1.2/patches/185/", + "web_url": "https://patchwork.ozlabs.org/project/cbe-oss-dev/patch/ + 200809050416.27831.adet...@br.ibm.com/", + project (dict): project information (id, url, name, link_name, + list_id, list_email, etc. + "msgid": "<200809050416.27831.adet...@br.ibm.com>", + "list_archive_url": null, + "date": "2008-09-05T07:16:27", + "name": "powerpc/spufs: Fix possible scheduling of a context", + "commit_ref": "b2e601d14deb2083e2a537b47869ab3895d23a28", + "pull_url": null, + "state": "accepted", + "archived": false, + "hash": "bc1c0b80d7cff66c0d1e5f3f8f4d10eb36176f0d", + "submitter": { + "id": 93, + "url": "https://patchwork.ozlabs.org/api/1.2/people/93/", + "name": "Andre Detsch", + "email": "adet...@br.ibm.com" + }, + "delegate": { + "id": 1, + "url": "https://patchwork.ozlabs.org/api/1.2/users/1/", + "username": "jk", + "first_name": "Jeremy", + "last_name": "Kerr", + "email": "j...@ozlabs.org" + }, + "mbox": "https://patchwork.ozlabs.org/project/cbe-oss-dev/patch/ + 200809050416.27831.adet...@br.ibm.com/mbox/", + "series": [], + "comments": "https://patchwork.ozlabs.org/api/patches/185/ + comments/", + "check": "pending", + "checks": "https://patchwork.ozlabs.org/api/patches/185/checks/", + "tags": {}, + "related": [], + "headers": {...} + "content": "We currently have a race when scheduling a context + after we have found a runnable context in spusched_tick, the + context may have been scheduled by spu_activate(). + + This may result in a panic if we try to unschedule a context + been freed in the meantime. + + This change exits spu_schedule() if the context has already + scheduled, so we don't end up scheduling it twice. + + Signed-off-by: Andre Detsch <adet...@br.ibm.com>", + "diff": '''Index: spufs/arch/powerpc/platforms/cell/spufs/sched.c + ======================================================= + --- spufs.orig/arch/powerpc/platforms/cell/spufs/sched.c + +++ spufs/arch/powerpc/platforms/cell/spufs/sched.c + @@ -727,7 +727,8 @@ static void spu_schedule(struct spu *spu + \t/* not a candidate for interruptible because it's called + \t from the scheduler thread or from spu_deactivate */ + \tmutex_lock(&ctx->state_mutex); + -\t__spu_schedule(spu, ctx); + +\tif (ctx->state == SPU_STATE_SAVED) + +\t\t__spu_schedule(spu, ctx); + \tspu_release(ctx); + } + ''' + "prefixes": ["3/3", ...] + """ + return await self._request(client, f'patches/{patch_id}/') + + async def _get_patch_comments(self, client, patch_id): + """Read comments about a patch + + Args: + client (aiohttp.ClientSession): Session to use + patch_id (str): Patchwork patch ID + + Returns: list of dict: list of comments: + id (int): series ID unique across patchwork instance, e.g. 3331924 + web_url (str): Full URL, e.g. + 'https://patchwork.ozlabs.org/comment/3331924/' + msgid (str): Message ID, e.g. + '<d2526c98-8198-4b8b-ab10-20bda0151...@gmx.de>' + list_archive_url: (unknown?) + date (str): Date, e.g. '2024-06-20T13:38:03' + subject (str): email subject, e.g. 'Re: [PATCH 3/5] buildman: + Support building within a Python venv' + date (str): Date, e.g. '2017-08-27T08:00:51' + submitter (dict): id, url, name, email, e.g.: + "id": 61270, + "url": "https://patchwork.ozlabs.org/api/people/61270/", + "name": "Heinrich Schuchardt", + "email": "xypron.g...@gmx.de" + content (str): Content of email, e.g. 'On 20.06.24 15:19, + Simon Glass wrote: + >...' + headers: dict: email headers, see get_cover() for an example + """ + return await self._request(client, f'patches/{patch_id}/comments/') + + async def get_patch_comments(self, patch_id): + async with aiohttp.ClientSession() as client: + return await self._get_patch_comments(client, patch_id) + + async def _get_patch_status(self, client, patch_id): + """Get the patch status + + Args: + client (aiohttp.ClientSession): Session to use + patch_id (int): Patch ID to look up in patchwork + + Return: + PATCH: Patch information + + Requests: + 1 for patch, 1 for patch comments + """ + data = await self.get_patch(client, patch_id) + state = data['state'] + comment_data = await self._get_patch_comments(client, patch_id) + + return Patch(patch_id, state, data, comment_data) + + async def series_get_state(self, client, link, read_comments): + """Sync the series information against patchwork, to find patch status + + Args: + client (aiohttp.ClientSession): Session to use + link (str): Patchwork series ID + read_comments (bool): True to read the comments on the patches + + Return: tuple: + list of Patch objects + """ + data = await self.get_series(client, link) + patch_list = list(data['patches']) + + count = len(patch_list) + patches = [] + if read_comments: + # Returns a list of Patch objects + tasks = [self._get_patch_status(client, patch_list[i]['id']) + for i in range(count)] + + patch_status = await asyncio.gather(*tasks) + for patch_data, status in zip(patch_list, patch_status): + status.series_data = patch_data + patches.append(status) + else: + for i in range(count): + info = patch_list[i] + pat = Patch(info['id'], series_data=info) + pat.raw_subject = info['name'] + patches.append(pat) + if self._show_progress: + terminal.print_clear() + + return patches -- 2.43.0