From patchwork Wed Oct 23 14:33:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Axtens X-Patchwork-Id: 1182205 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46ytDn5k8cz9sNw for ; Thu, 24 Oct 2019 01:34:33 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=axtens.net Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=axtens.net header.i=@axtens.net header.b="Wo1XuleK"; dkim-atps=neutral Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 46ytDn0nhhzDqR6 for ; Thu, 24 Oct 2019 01:34:33 +1100 (AEDT) X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=axtens.net (client-ip=2607:f8b0:4864:20::442; helo=mail-pf1-x442.google.com; envelope-from=dja@axtens.net; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=axtens.net Authentication-Results: lists.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=axtens.net header.i=@axtens.net header.b="Wo1XuleK"; dkim-atps=neutral Received: from mail-pf1-x442.google.com (mail-pf1-x442.google.com [IPv6:2607:f8b0:4864:20::442]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 46ytD44br5zDqRM for ; Thu, 24 Oct 2019 01:33:55 +1100 (AEDT) Received: by mail-pf1-x442.google.com with SMTP id y22so13071846pfr.3 for ; Wed, 23 Oct 2019 07:33:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=axtens.net; s=google; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=EF8cjF2EYMRk6ZkdEz/2mf8uNQEQbG9Nu0TZyCeh7Jw=; b=Wo1XuleKjRbVuoSioEZzZfp30bmeGo+/rfoM1D8Zuv3MLG8R2p+FOrVjc/Xgs/xkTB a8dzlMaDdvV99JYDZ2ASllPtJ6gwELce6678lQhkK3wPt82GyoYdmhOJzUWYnIKZf49V 7TZsXCjO2wxuBosKx4uQllIbdYk2aNIYfN+0E= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=EF8cjF2EYMRk6ZkdEz/2mf8uNQEQbG9Nu0TZyCeh7Jw=; b=tv4se/yTpqF01cpZHbHvlexboLdrs6tusKTnTpwuFKPZ+TMN6QNyWY+GaR5P/z8hw6 zUnzEgahUD6/SSuB3YPW+//ZNXz/kyo2SLtTccTzVr3WCR1rGDgEyfn9HxGmC5P/9A9v eXoYVhdRS5by7P0fC30I27+86tBtFrJJFOUxeeDL5vZUYYmVMAd5PeNhu5DqIr5kw4AZ GXm6OyR2x7tkiS0nU1tLeOhZh1MPgMzX8BODfRoiCRr6nI+pbIKCyO3m3y6PoOVDPdRt yLKfDhbTPgOjiq9U5k3OWEIFxlBkoGJZ+Kff2wijvxrTyKofnS8IggkQB2x3TuTYwSOv +hXg== X-Gm-Message-State: APjAAAVjZVEZ7noTwzCeZjagrNE6BI+wqvdAtzqjcJi6x7TYfUdIqv3q 7FZIK/MUWz8AuxLNU5SAZT+egRadXIY= X-Google-Smtp-Source: APXvYqyjy+MR/E2kEKOKMXa0PfkW2sBpQsnlCdqi2sdwoHfh1VdHRj/U0JRtWpvqeC8TxbY84trDVw== X-Received: by 2002:a63:2f81:: with SMTP id v123mr10762689pgv.239.1571841230671; Wed, 23 Oct 2019 07:33:50 -0700 (PDT) Received: from localhost (ppp167-251-205.static.internode.on.net. [59.167.251.205]) by smtp.gmail.com with ESMTPSA id r19sm21189935pgj.43.2019.10.23.07.33.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Oct 2019 07:33:49 -0700 (PDT) From: Daniel Axtens To: patchwork@lists.ozlabs.org Subject: [PATCH] api: support filtering patches by hash Date: Thu, 24 Oct 2019 01:33:42 +1100 Message-Id: <20191023143342.12300-1-dja@axtens.net> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" This is a feature that the XML-RPC API has, and which is used in the wild [1], so support it in the REST API. I tried to version the new filter field, but it's not at all clear how to do this with django-filters. The best way I could find requires manually manipulating request.GET, which seems to defeat the point of django-filters. So document it for 1.2, and have it work on older versions as an undocumented feature. [1] https://git.kernel.org/pub/scm/linux/kernel/git/mricon/korg-helpers.git/tree/git-patchwork-bot.py?id=104e7374e1be8458e6d2e82478625a7bf8c822ff Cc: Konstantin Ryabitsev Signed-off-by: Daniel Axtens Acked-by: Konstantin Ryabitsev --- docs/api/schemas/latest/patchwork.yaml | 7 ++++ docs/api/schemas/patchwork.j2 | 9 +++++ docs/api/schemas/v1.2/patchwork.yaml | 7 ++++ patchwork/api/filters.py | 8 ++++- patchwork/tests/api/test_patch.py | 36 +++++++++++++++++++ .../rest-filter-hash-e031bd3db42eb540.yaml | 5 +++ 6 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/rest-filter-hash-e031bd3db42eb540.yaml diff --git docs/api/schemas/latest/patchwork.yaml docs/api/schemas/latest/patchwork.yaml index 46969000a65b..6c7564baf81b 100644 --- docs/api/schemas/latest/patchwork.yaml +++ docs/api/schemas/latest/patchwork.yaml @@ -463,6 +463,13 @@ paths: enum: - 'true' - 'false' + - in: query + name: hash + description: > + The patch hash as a case-insensitive hexadecimal string, to filter by. + schema: + title: '' + type: string responses: '200': description: '' diff --git docs/api/schemas/patchwork.j2 docs/api/schemas/patchwork.j2 index 4fc100eb4a92..12a6f67de32b 100644 --- docs/api/schemas/patchwork.j2 +++ docs/api/schemas/patchwork.j2 @@ -468,6 +468,15 @@ paths: enum: - 'true' - 'false' +{% if version >= (1, 2) %} + - in: query + name: hash + description: > + The patch hash as a case-insensitive hexadecimal string, to filter by. + schema: + title: '' + type: string +{% endif %} responses: '200': description: '' diff --git docs/api/schemas/v1.2/patchwork.yaml docs/api/schemas/v1.2/patchwork.yaml index 2ced470b7dc0..7dc95793faa3 100644 --- docs/api/schemas/v1.2/patchwork.yaml +++ docs/api/schemas/v1.2/patchwork.yaml @@ -463,6 +463,13 @@ paths: enum: - 'true' - 'false' + - in: query + name: hash + description: > + The patch hash as a case-insensitive hexadecimal string, to filter by. + schema: + title: '' + type: string responses: '200': description: '' diff --git patchwork/api/filters.py patchwork/api/filters.py index 37aca82d9ab2..4184ee8253f0 100644 --- patchwork/api/filters.py +++ patchwork/api/filters.py @@ -7,6 +7,7 @@ from django.contrib.auth.models import User from django.core.exceptions import ValidationError from django.db.models import Q from django_filters.rest_framework import FilterSet +from django_filters import CharFilter from django_filters import IsoDateTimeFilter from django_filters import ModelMultipleChoiceFilter from django.forms import ModelMultipleChoiceField as BaseMultipleChoiceField @@ -176,11 +177,16 @@ class PatchFilterSet(TimestampMixin, FilterSet): submitter = PersonFilter(queryset=Person.objects.all()) delegate = UserFilter(queryset=User.objects.all()) state = StateFilter(queryset=State.objects.all()) + hash = CharFilter(lookup_expr='iexact') class Meta: model = Patch + # NOTE(dja): ideally we want to version the hash field, but I cannot + # find a way to do that which is reliable and not extremely ugly. + # The best I can come up with is manually working with request.GET + # which seems to rather defeat the point of using django-filters. fields = ('project', 'series', 'submitter', 'delegate', - 'state', 'archived') + 'state', 'archived', 'hash') class CheckFilterSet(TimestampMixin, FilterSet): diff --git patchwork/tests/api/test_patch.py patchwork/tests/api/test_patch.py index edae9851c422..4afc15a9ba1c 100644 --- patchwork/tests/api/test_patch.py +++ patchwork/tests/api/test_patch.py @@ -22,6 +22,13 @@ from patchwork.tests.utils import create_user if settings.ENABLE_REST_API: from rest_framework import status +# a diff different from the default, required to test hash filtering +SAMPLE_DIFF = """--- /dev/null\t2019-01-01 00:00:00.000000000 +0800 ++++ a\t2019-01-01 00:00:00.000000000 +0800 +@@ -0,0 +1 @@ ++b +""" + @unittest.skipUnless(settings.ENABLE_REST_API, 'requires ENABLE_REST_API') class TestPatchAPI(utils.APITestCase): @@ -152,6 +159,35 @@ class TestPatchAPI(utils.APITestCase): 'submitter': 'test@example.org'}) self.assertEqual(0, len(resp.data)) + def test_list_filter_hash(self): + """Filter patches by hash.""" + patch = self._create_patch() + patch_new_diff = create_patch(state=patch.state, project=patch.project, + submitter=patch.submitter, + diff=SAMPLE_DIFF) + + # check regular filtering + resp = self.client.get(self.api_url(), {'hash': patch.hash}) + self.assertEqual([patch.id], [x['id'] for x in resp.data]) + + # 2 patches with identical diffs + patch_same_diff = create_patch(state=patch.state, + project=patch.project, + submitter=patch.submitter) + resp = self.client.get(self.api_url(), {'hash': patch.hash}) + self.assertEqual([patch.id, patch_same_diff.id], + [x['id'] for x in resp.data]) + + # case insensitive matching + resp = self.client.get(self.api_url(), + {'hash': patch_new_diff.hash.upper()}) + self.assertEqual([patch_new_diff.id], [x['id'] for x in resp.data]) + + # empty response if nothing matches + resp = self.client.get(self.api_url(), { + 'hash': 'da638d0746a115000bf890fada1f02679aa282e8'}) + self.assertEqual(0, len(resp.data)) + @utils.store_samples('patch-list-1-0') def test_list_version_1_0(self): """List patches using API v1.0.""" diff --git releasenotes/notes/rest-filter-hash-e031bd3db42eb540.yaml releasenotes/notes/rest-filter-hash-e031bd3db42eb540.yaml new file mode 100644 index 000000000000..b805931d4d80 --- /dev/null +++ releasenotes/notes/rest-filter-hash-e031bd3db42eb540.yaml @@ -0,0 +1,5 @@ +--- +api: + - | + The REST API now supports filtering patches by their hashes, using the + ``hash`` query parameter.