From nobody Sat Apr 20 00:21:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=patchew-devel-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=patchew-devel-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1526972320825159.07580025648588; Mon, 21 May 2018 23:58:40 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D97FB3673DC; Tue, 22 May 2018 06:58:39 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id C6B855D756; Tue, 22 May 2018 06:58:39 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id B73214BB78; Tue, 22 May 2018 06:58:39 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w4M6vxqu028150 for ; Tue, 22 May 2018 02:57:59 -0400 Received: by smtp.corp.redhat.com (Postfix) id 70E1430BF204; Tue, 22 May 2018 06:57:59 +0000 (UTC) Received: from mx1.redhat.com (ext-mx18.extmail.prod.ext.phx2.redhat.com [10.5.110.47]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 6AD9930BF209 for ; Tue, 22 May 2018 06:57:57 +0000 (UTC) Received: from mail-pf0-f181.google.com (mail-pf0-f181.google.com [209.85.192.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A8F1D30C232F for ; Tue, 22 May 2018 06:57:46 +0000 (UTC) Received: by mail-pf0-f181.google.com with SMTP id w129-v6so8290338pfd.3 for ; Mon, 21 May 2018 23:57:46 -0700 (PDT) Received: from localhost.localdomain ([208.181.63.202]) by smtp.gmail.com with ESMTPSA id y2-v6sm19818676pgp.92.2018.05.21.23.57.45 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 21 May 2018 23:57:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=J7skVuSI1x97kfc1Ebzu27OhLpc4HVpPi084QZ7t98w=; b=OPKwfPGdJp+K5ea15GeyRRuGep16wUu0+ov1J08Cz4DkD9WrKfqKsAgKBxIc8TMTyd c/DWVdKQp7YmD2sMVdKyCD2BK8CyWgrg1Chw9Gi1MyiQz47c9mwK0ytvZvgcr6DTxt6P 5+1B4QMJVTq6jpkRKEdhES9xxvrW1SuckF5cxY1Z1kZr197l90fvtCBqURumKJuc3Qtd jgPCPrD/u/R8g9w4Wh+FlAWlnoMR39Z7K8Ih0S6dwA6SyvJjKoZbqwBDS1v242djQsS6 3jYzJnroK6KQkufTee6haigp6Z1Bos/3RbqnpBCXFNiGcpV5pjaSdA9E2SJCnHCr/LSI 8h6w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=J7skVuSI1x97kfc1Ebzu27OhLpc4HVpPi084QZ7t98w=; b=E6tONSwp0M2oznjstGOFledITMdEmoF+UB2u+uzbOhk+2cILAdn5zDzxMOKBPG7Zpx pKwfkLdY/3kUQgnyC/hALZPT2mKSR5i9e5Rc/lPp8qojHLKGpCi0gHRjbX/nCrk0T8Mu OJPEEH7nXBKSc6j7MwXt6bJLpOvZuxdI/JaU2gmQM37KEXztYyOSCSdrlbBYT2F4LfoP 6pahf3Hj+sFGFv8l1QpZ0ssPdVoQDAuNu6pM9Yh2yZFhXreoH5Bd4CZta++lfBUXUNAV Q5BUGF2jQ+M7uo+zAn7biFiz/ouLU2UguhsX0FEJ25cbUFPvhAM+yUG3W+IjXiOhzIsQ whxA== X-Gm-Message-State: ALKqPwdBJy7kbDMNWAkwpw/qU4KFzO6O4CST1bJWfReUJK4NIRhh5B4E L/i1+qbqw70FrZ8x76fmP2MLOWcE X-Google-Smtp-Source: AB8JxZrXgwWSlzNU6FfeEvoZoxlMX5fajfDsAMD3DxHegK8kNye7+oXyEy+RqblJNVbGOB8EbfFW0A== X-Received: by 2002:a62:c81d:: with SMTP id z29-v6mr22966231pff.81.1526972265789; Mon, 21 May 2018 23:57:45 -0700 (PDT) From: Paolo Bonzini To: patchew-devel@redhat.com Date: Tue, 22 May 2018 08:57:29 +0200 Message-Id: <20180522065740.9710-2-pbonzini@redhat.com> In-Reply-To: <20180522065740.9710-1-pbonzini@redhat.com> References: <20180522065740.9710-1-pbonzini@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.47]); Tue, 22 May 2018 06:57:46 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.47]); Tue, 22 May 2018 06:57:46 +0000 (UTC) for IP:'209.85.192.181' DOMAIN:'mail-pf0-f181.google.com' HELO:'mail-pf0-f181.google.com' FROM:'paolo.bonzini@gmail.com' RCPT:'' X-RedHat-Spam-Score: -1.2 (DKIM_SIGNED, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_PASS, T_DKIM_INVALID) 209.85.192.181 mail-pf0-f181.google.com 209.85.192.181 mail-pf0-f181.google.com X-RedHat-Possible-Forgery: Paolo Bonzini X-Scanned-By: MIMEDefang 2.84 on 10.5.110.47 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.26 X-loop: patchew-devel@redhat.com Subject: [Patchew-devel] [PATCH 01/12] testing: remove dead code X-BeenThere: patchew-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Patchew development and discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: patchew-devel-bounces@redhat.com Errors-To: patchew-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Tue, 22 May 2018 06:58:39 +0000 (UTC) X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Fixes issue #72. --- mods/testing.py | 12 ------------ tests/test_testing.py | 2 -- 2 files changed, 14 deletions(-) diff --git a/mods/testing.py b/mods/testing.py index 24841f1..cafe9a2 100644 --- a/mods/testing.py +++ b/mods/testing.py @@ -59,10 +59,6 @@ class TestingModule(PatchewModule): BooleanSchema("enabled", "Enabled", desc=3D"Whether this test is enabled= ", default=3DTrue), - StringSchema("users", "Users", - desc=3D"List of allowed users to run = this test"), - StringSchema("testers", "Testers", - desc=3D"List of allowed testers to ru= n this test"), StringSchema("requirements", "Requirements", desc=3D"List of requirements of the t= est"), IntegerSchema("timeout", "Timeout", @@ -256,10 +252,6 @@ class TestingModule(PatchewModule): }) return ret =20 - def _build_message_prop_url(message, prop): - return reverse("testing-get-prop", - kwargs=3D{"project_or_series": obj.message_id}) - def rest_results_hook(self, request, obj, results, detailed=3DFalse): for pn, p in obj.get_properties().items(): if not pn.startswith("testing.report."): @@ -410,10 +402,6 @@ class TestingGetView(APILoginRequiredView): if obj.get_property("testing.report." + tn): done_tests.add(tn) continue - if t.get("tester") and tester !=3D t["tester"]: - continue - if t.get("user") and user.username !=3D t["user"]: - continue # TODO: group? ok =3D True reqs =3D t.get("requirements", "") diff --git a/tests/test_testing.py b/tests/test_testing.py index 3dcb505..73d13f1 100755 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -22,8 +22,6 @@ def create_test(project, name): project.set_property(prefix + "enabled", True) project.set_property(prefix + "script", "#!/bin/bash\ntrue") project.set_property(prefix + "requirements", "") - project.set_property(prefix + "users", "") - project.set_property(prefix + "tester", "") =20 class TestingTestCase(PatchewTestCase, metaclass=3Dabc.ABCMeta): =20 --=20 2.17.0 _______________________________________________ Patchew-devel mailing list Patchew-devel@redhat.com https://www.redhat.com/mailman/listinfo/patchew-devel From nobody Sat Apr 20 00:21:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=patchew-devel-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=patchew-devel-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1526972281678659.6189357671798; Mon, 21 May 2018 23:58:01 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id AF8B463812; Tue, 22 May 2018 06:58:00 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 9B6B5601A1; Tue, 22 May 2018 06:58:00 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 8DCF74BB78; Tue, 22 May 2018 06:58:00 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w4M6vxhw028151 for ; Tue, 22 May 2018 02:57:59 -0400 Received: by smtp.corp.redhat.com (Postfix) id 72C3B30BF205; Tue, 22 May 2018 06:57:59 +0000 (UTC) Received: from mx1.redhat.com (ext-mx10.extmail.prod.ext.phx2.redhat.com [10.5.110.39]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 69C7C30BF208 for ; Tue, 22 May 2018 06:57:58 +0000 (UTC) Received: from mail-pf0-f182.google.com (mail-pf0-f182.google.com [209.85.192.182]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CE5051B395C for ; Tue, 22 May 2018 06:57:47 +0000 (UTC) Received: by mail-pf0-f182.google.com with SMTP id f189-v6so8295126pfa.7 for ; Mon, 21 May 2018 23:57:47 -0700 (PDT) Received: from localhost.localdomain ([208.181.63.202]) by smtp.gmail.com with ESMTPSA id y2-v6sm19818676pgp.92.2018.05.21.23.57.45 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 21 May 2018 23:57:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=Wg5PYIG0gglr41mZ9rMkfq72RK1uUFP0IOLsXi2jqmc=; b=ei88u38Bl6zXMVDIWR/UtxzW1bZYlukGWTz5CqNDbw7RDBumBlsr82ugrw7KMU1JF0 o77PjuscGXg/6XuEFY5M7Xb7294zof0tKXRB7AyFwGpJzrwluDrCiU0SA4D+hEGPClgW 3Jk8DX5+kAgYpXQNKex4So2agi3y4jGGS9IX4AE8F2NqbV5mZAE1JYGu3+/mQYz6FqD9 0uwkISSQh9b0emM6ibYJMeOCwl0w74gW4NqxySNvhAqX4voRuV8rzwnGvb3DDo3sYj20 i47DkeZfnLCPxED4B08d4F+HTM262go+M9LXEm6kXQcHMCoS/F/szZX5p/5aERUHXnp9 dLOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=Wg5PYIG0gglr41mZ9rMkfq72RK1uUFP0IOLsXi2jqmc=; b=JVCk/gBWjLqRe1zI9w0lWJN8o7P1AylGJQmp0neB0lAnqGlOlPiuaCOpvF2WpwnzC0 ORx61Lvr+TOp6tVEE3EWsIQ/fkHX/HpWzlOOWNpbPumuQBDyWC+H5w3Mo0mLJaJauH7k 7/6fm0ThxhDLaSvLfDtgFmGYkb/3ZQGG1OKze9tbl+FOOnV4TdJh77j9hrRebjqCL9pe EXblvBdcG7j3fVeGtWtMYTNpqhPyEJ5I4hs4bqk1G0oksGn1Ywh6m0zeFI5jFrwmcXrm VE0mjdfypJi5J3dXo13XfSTFy9VjFg0JQ11KrR04QSBgrL557AOom7KA82Apd/IZTcLC Udqg== X-Gm-Message-State: ALKqPwdLZwrPD4fRr6eyIl4RDUZ8D3zoWtT3Gxb9fdrnOkFs3Lieil9h uzjFtrZUWxbRx1BGz5CWUyZD32S1 X-Google-Smtp-Source: AB8JxZreZzHoQhx24E+UQzCKLptyioBHUzTJ7prp2P2kcVc9nOTRieiuIDVgOfYb4qbNyDa5ZRyyHg== X-Received: by 2002:a62:859a:: with SMTP id m26-v6mr22755991pfk.247.1526972266953; Mon, 21 May 2018 23:57:46 -0700 (PDT) From: Paolo Bonzini To: patchew-devel@redhat.com Date: Tue, 22 May 2018 08:57:30 +0200 Message-Id: <20180522065740.9710-3-pbonzini@redhat.com> In-Reply-To: <20180522065740.9710-1-pbonzini@redhat.com> References: <20180522065740.9710-1-pbonzini@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Tue, 22 May 2018 06:57:47 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Tue, 22 May 2018 06:57:47 +0000 (UTC) for IP:'209.85.192.182' DOMAIN:'mail-pf0-f182.google.com' HELO:'mail-pf0-f182.google.com' FROM:'paolo.bonzini@gmail.com' RCPT:'' X-RedHat-Spam-Score: -1.2 (DKIM_SIGNED, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_PASS, T_DKIM_INVALID) 209.85.192.182 mail-pf0-f182.google.com 209.85.192.182 mail-pf0-f182.google.com X-RedHat-Possible-Forgery: Paolo Bonzini X-Scanned-By: MIMEDefang 2.78 on 10.5.110.39 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.26 X-loop: patchew-devel@redhat.com Subject: [Patchew-devel] [PATCH 02/12] testing: unify two ifs with the same condition X-BeenThere: patchew-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Patchew development and discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: patchew-devel-bounces@redhat.com Errors-To: patchew-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Tue, 22 May 2018 06:58:00 +0000 (UTC) X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" --- mods/testing.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mods/testing.py b/mods/testing.py index cafe9a2..a791493 100644 --- a/mods/testing.py +++ b/mods/testing.py @@ -201,7 +201,6 @@ class TestingModule(PatchewModule): if all_tests.issubset(done_tests): obj.set_property("testing.done", True) obj.set_property("testing.ready", None) - if all_tests.issubset(done_tests): obj.set_property("testing.tested-head", head) emit_event("TestingReport", tester=3Dtester, user=3Duser.username, obj=3Dobj, passed=3Dpassed, test=3Dtest, log=3Dlog, lo= g_url=3Dlog_url, --=20 2.17.0 _______________________________________________ Patchew-devel mailing list Patchew-devel@redhat.com https://www.redhat.com/mailman/listinfo/patchew-devel From nobody Sat Apr 20 00:21:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=patchew-devel-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=patchew-devel-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1526972283086664.8665569319177; Mon, 21 May 2018 23:58:03 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2A856641FE; Tue, 22 May 2018 06:58:02 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 1604B5D70A; Tue, 22 May 2018 06:58:02 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 053324BB78; Tue, 22 May 2018 06:58:02 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w4M6vxZL028160 for ; Tue, 22 May 2018 02:57:59 -0400 Received: by smtp.corp.redhat.com (Postfix) id D05C530BF204; Tue, 22 May 2018 06:57:59 +0000 (UTC) Received: from mx1.redhat.com (ext-mx01.extmail.prod.ext.phx2.redhat.com [10.5.110.25]) by smtp.corp.redhat.com (Postfix) with ESMTPS id CA29930BF208 for ; Tue, 22 May 2018 06:57:59 +0000 (UTC) Received: from mail-pf0-f179.google.com (mail-pf0-f179.google.com [209.85.192.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E8F322090C for ; Tue, 22 May 2018 06:57:48 +0000 (UTC) Received: by mail-pf0-f179.google.com with SMTP id c10-v6so8275111pfi.12 for ; Mon, 21 May 2018 23:57:48 -0700 (PDT) Received: from localhost.localdomain ([208.181.63.202]) by smtp.gmail.com with ESMTPSA id y2-v6sm19818676pgp.92.2018.05.21.23.57.46 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 21 May 2018 23:57:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=XIWf/wQc70JS53Ry4EoYV69rNVDeEmVY3nounPMpAQ0=; b=jY0DEvO7hyoBG61cbNQ0wGf0TfpzP4BCUCHxsUV2SvpzJUca52ZCN8CG20rybd9/Yp SiFQ5eBI7l85ypLRuTGbHLwhJVoc2pflkQLeifviDG9py0Xmqq95Ra3+FikMVabr+12K jpURCceIci3RCEI2G72ZXK7UvLd6ACyPPK8/BJFq/au0JovloaS6VAjbVtx+lp2mGq4i WGClTceDyGw+mYteJMldbFf0VOW+8PLjf1R24uZEbzXy4Qs4S6q/JHOd97gAX9l1cpGB B7CoQM5rLwiP+IK41ZWpQtnmfGyxnYD5irrcVYprlsywY1ZXStJDL1IMdV7bUD22xbGV BmJQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=XIWf/wQc70JS53Ry4EoYV69rNVDeEmVY3nounPMpAQ0=; b=ZoXjgH6vEzDinlFTdp0laUSHsHi3npkzUs47DacaFlA2vDHLzcqSdQvyqg4ba3qZXI mbt+aBLK34aED59lZfj+WBAOApKgyLDiVqd5dM+zDK/Jjxoxl/gPRXLsRXo9gzlGytHK eTjACJiLOcsn3gDDjbD/S8ss7K5Cq77Ee1PR4tCRtT47LQWZy1pYiOuXpQEWbCC6nEEr j3cJhabbj3YhvwVSV/4pUTH6lGLfaV8gr6GL/o1t3qbbDfCewK++ltTfOxCyzp1Vhtl9 1ertvMMdQBCJub3bd8+LBwVr1sk4xXalOxQ0LjneFIaqhG2IEjQo/UUC8gweSVgVHUSy Gtxg== X-Gm-Message-State: ALKqPweIzzICjcLWHXS8B/7Fzf4w8/qoLqARtUjbc5D4+uVDwgHtEqA/ DH6iRX2OmX0WBTUZBnHPL71I0Ql2 X-Google-Smtp-Source: AB8JxZqGl62m2ha3uX46x+1srjIDNFCjZyT1HI29cT+Iwppw/rWubjapeu1rwh/JSEJtUKO1sc8vzQ== X-Received: by 2002:a62:981d:: with SMTP id q29-v6mr23024923pfd.65.1526972268076; Mon, 21 May 2018 23:57:48 -0700 (PDT) From: Paolo Bonzini To: patchew-devel@redhat.com Date: Tue, 22 May 2018 08:57:31 +0200 Message-Id: <20180522065740.9710-4-pbonzini@redhat.com> In-Reply-To: <20180522065740.9710-1-pbonzini@redhat.com> References: <20180522065740.9710-1-pbonzini@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Tue, 22 May 2018 06:57:49 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Tue, 22 May 2018 06:57:49 +0000 (UTC) for IP:'209.85.192.179' DOMAIN:'mail-pf0-f179.google.com' HELO:'mail-pf0-f179.google.com' FROM:'paolo.bonzini@gmail.com' RCPT:'' X-RedHat-Spam-Score: 0.597 (DKIM_SIGNED, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_NONE, SPF_PASS, T_DKIM_INVALID) 209.85.192.179 mail-pf0-f179.google.com 209.85.192.179 mail-pf0-f179.google.com X-RedHat-Possible-Forgery: Paolo Bonzini X-Scanned-By: MIMEDefang 2.83 on 10.5.110.25 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.26 X-loop: patchew-devel@redhat.com Subject: [Patchew-devel] [PATCH 03/12] testing: include "pending" testing results in REST API X-BeenThere: patchew-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Patchew development and discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: patchew-devel-bounces@redhat.com Errors-To: patchew-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Tue, 22 May 2018 06:58:02 +0000 (UTC) X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" If a test can be done but has not been started yet, its status should be "p= ending". Signed-off-by: Paolo Bonzini --- mods/testing.py | 9 +++++++++ tests/test_testing.py | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/mods/testing.py b/mods/testing.py index a791493..824df15 100644 --- a/mods/testing.py +++ b/mods/testing.py @@ -252,10 +252,15 @@ class TestingModule(PatchewModule): return ret =20 def rest_results_hook(self, request, obj, results, detailed=3DFalse): + all_tests =3D set([k for k, v in _instance.get_tests(obj).items() = if v["enabled"]]) for pn, p in obj.get_properties().items(): if not pn.startswith("testing.report."): continue tn =3D pn[len("testing.report."):] + try: + all_tests.remove(tn) + except: + pass failed =3D not p["passed"] log_url =3D self.reverse_testing_log(obj, tn, request=3Dreques= t, html=3DFalse) passed_str =3D Result.FAILURE if failed else Result.SUCCESS @@ -270,6 +275,10 @@ class TestingModule(PatchewModule): log=3Dlog, log_url=3Dlog_url, request=3D= request, data=3Ddata, renderer=3Dself)) =20 + if obj.get_property("testing.ready"): + for tn in all_tests: + results.append(Result(name=3D'testing.' + tn, obj=3Dobj, s= tatus=3D'pending')) + def prepare_message_hook(self, request, message, detailed): if not message.is_series_head: return diff --git a/tests/test_testing.py b/tests/test_testing.py index 73d13f1..8f831a1 100755 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -91,6 +91,10 @@ class TestingTestCase(PatchewTestCase, metaclass=3Dabc.A= BCMeta): capabilities=3D[]) self.assertFalse(td) =20 + def test_rest_basic(self): + resp =3D self.get_test_result('a') + self.assertEquals(resp.data['status'], 'pending') + def test_rest_done_success(self): self.do_testing_done(log=3D'everything good!', passed=3DTrue) resp =3D self.get_test_result('tests') --=20 2.17.0 _______________________________________________ Patchew-devel mailing list Patchew-devel@redhat.com https://www.redhat.com/mailman/listinfo/patchew-devel From nobody Sat Apr 20 00:21:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=patchew-devel-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=patchew-devel-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1526972286901851.0623950822859; Mon, 21 May 2018 23:58:06 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 074DF13511C; Tue, 22 May 2018 06:58:06 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E895B5C1B7; Tue, 22 May 2018 06:58:05 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id D7ED54BB78; Tue, 22 May 2018 06:58:05 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w4M6w46D028199 for ; Tue, 22 May 2018 02:58:04 -0400 Received: by smtp.corp.redhat.com (Postfix) id 1BE6C1001F46; Tue, 22 May 2018 06:58:04 +0000 (UTC) Received: from mx1.redhat.com (ext-mx17.extmail.prod.ext.phx2.redhat.com [10.5.110.46]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 1517D1057FA5 for ; Tue, 22 May 2018 06:58:01 +0000 (UTC) Received: from mail-pf0-f173.google.com (mail-pf0-f173.google.com [209.85.192.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3A54830C4CCE for ; Tue, 22 May 2018 06:57:50 +0000 (UTC) Received: by mail-pf0-f173.google.com with SMTP id j20-v6so8287448pff.10 for ; Mon, 21 May 2018 23:57:50 -0700 (PDT) Received: from localhost.localdomain ([208.181.63.202]) by smtp.gmail.com with ESMTPSA id y2-v6sm19818676pgp.92.2018.05.21.23.57.48 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 21 May 2018 23:57:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=ZWfpF+FLpnRbW++57v8Lf2m2QUjHusSIyMCLMA0pWRo=; b=NXS4xu5bacv4T7ro3PLrbKlTPIylGPBeIoIvaUhSsS+dLkQWFb5lruwHAmTl0MmUck 3LxDDvROqApaef6Fl653r4Tkzp2FOavkQGr7mIy4sjg2cJhIT7nU/oHrCHNP0QJhKXEY Efq9fbhPOFsass6Eqs62aTCcdz14FRsPs/RPni/oDnz6rnCK40yDX4H7DpBDkt63Tbym RDwnAQvGxHbkptYyRCFTX/TrSM5wRrpxCVGZ+xJRt4pOpJlRzfsTqjFht7JkhgNvnxcf 18u6jyR5yxwCv2Wv9+wEnC84mmMeP3/hi300bu+Yc9mGxdqPPksYgg8oXC9u+3u58fOp EJcg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=ZWfpF+FLpnRbW++57v8Lf2m2QUjHusSIyMCLMA0pWRo=; b=ARTbsaqhbqZDhx/QVuvMwfebHXNYFcilsLK9InFcJcMhBdalc6aI633XJP4JMt0/GQ ZMG5JkXUN/P5Fa9KbHOD2Iz4OUWahBICBaqjj4u+hFKVihcEEIZy3IXhH7nmCOPI99jF ASq0P8chEKhGWOMcfRz8T+HI/KH+egHfTDPgqAnLCTFGEcR1a9V1c9KdPj1FMt3mYj44 HOZTpN7VCMSkhbtJCiG/2qOUfb78OuKjOa8vHjViEYeQwMXhxy+InMy2rN1JwEKbEFIx za9sEc5ldZiuwiBrdEP/3rqVRluiu+6rFuAj1s8y/OnIvVzcYyPGbWIWkOKDdAT8yG4E 1aaQ== X-Gm-Message-State: ALKqPwckQwgeRRQuZiPzkq5UYpvpx1qOBoDa+3J1hlil+glfxpTU4Oly 1O+k0pUugFTL68GmyAamxlydctPG X-Google-Smtp-Source: AB8JxZpCwwM4frQzjwxDcl3sHiE2p5H8fL4DUZiU7A3BnNEHPcRnLvjbsOkgkGyOrow798Ghbt6jbQ== X-Received: by 2002:a62:4589:: with SMTP id n9-v6mr22977961pfi.158.1526972269094; Mon, 21 May 2018 23:57:49 -0700 (PDT) From: Paolo Bonzini To: patchew-devel@redhat.com Date: Tue, 22 May 2018 08:57:32 +0200 Message-Id: <20180522065740.9710-5-pbonzini@redhat.com> In-Reply-To: <20180522065740.9710-1-pbonzini@redhat.com> References: <20180522065740.9710-1-pbonzini@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.46]); Tue, 22 May 2018 06:57:50 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.46]); Tue, 22 May 2018 06:57:50 +0000 (UTC) for IP:'209.85.192.173' DOMAIN:'mail-pf0-f173.google.com' HELO:'mail-pf0-f173.google.com' FROM:'paolo.bonzini@gmail.com' RCPT:'' X-RedHat-Spam-Score: 0.597 (DKIM_SIGNED, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_NONE, SPF_PASS, T_DKIM_INVALID) 209.85.192.173 mail-pf0-f173.google.com 209.85.192.173 mail-pf0-f173.google.com X-RedHat-Possible-Forgery: Paolo Bonzini X-Scanned-By: MIMEDefang 2.84 on 10.5.110.46 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-loop: patchew-devel@redhat.com Subject: [Patchew-devel] [PATCH 04/12] models: move Result log_url from constructor to renderer X-BeenThere: patchew-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Patchew development and discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: patchew-devel-bounces@redhat.com Errors-To: patchew-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Tue, 22 May 2018 06:58:06 +0000 (UTC) X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The log_url is not going to be stored in the database. In preparation for changing Result to a model, retrieve it through a method in the renderer. (The constructor and the renderer are actually always the same object currently :) but there will be no constructor concept will also disappear once Results will be fetched from the database). This has other benefits too. It also removes the request argument parameter from the Result constructor (which would not have any equivalent for database-stored Results) and from the rest_results_hook; and it makes log_url a read-only field in the REST API, which will be the right thing once PUT of Results will be supported. Signed-off-by: Paolo Bonzini --- api/models.py | 16 +++++++++++----- api/rest.py | 11 +++++++---- mods/git.py | 15 ++++++++------- mods/testing.py | 19 +++++++++++-------- www/views.py | 4 ++-- 5 files changed, 39 insertions(+), 26 deletions(-) diff --git a/api/models.py b/api/models.py index 8f7ca19..0f25f85 100644 --- a/api/models.py +++ b/api/models.py @@ -614,7 +614,7 @@ class Module(models.Model): def __str__(self): return self.name =20 -class Result(namedtuple("Result", "name status log log_url obj data render= er")): +class Result(namedtuple("Result", "name status log obj data renderer")): __slots__ =3D () PENDING =3D 'pending' SUCCESS =3D 'success' @@ -622,12 +622,10 @@ class Result(namedtuple("Result", "name status log lo= g_url obj data renderer")): RUNNING =3D 'running' VALID_STATUSES =3D (PENDING, SUCCESS, FAILURE, RUNNING) =20 - def __new__(cls, name, status, obj, log=3DNone, log_url=3DNone, data= =3DNone, request=3DNone, renderer=3DNone): - if log_url is not None and request is not None: - log_url =3D request.build_absolute_uri(log_url) + def __new__(cls, name, status, obj, log=3DNone, data=3DNone, renderer= =3DNone): if status not in cls.VALID_STATUSES: raise ValueError("invalid value '%s' for status field" % statu= s) - return super(cls, Result).__new__(cls, status=3Dstatus, log=3Dlog,= log_url=3Dlog_url, + return super(cls, Result).__new__(cls, status=3Dstatus, log=3Dlog, obj=3Dobj, data=3Ddata, name=3Dn= ame, renderer=3Drenderer) =20 def is_success(self): @@ -649,3 +647,11 @@ class Result(namedtuple("Result", "name status log log= _url obj data renderer")): if self.renderer is None: return None return self.renderer.render_result(self) + + def get_log_url(self, request=3DNone): + if not self.is_completed() or self.renderer is None: + return None + log_url =3D self.renderer.get_result_log_url(self.obj, self.name) + if log_url is not None and request is not None: + log_url =3D request.build_absolute_uri(log_url) + return log_url diff --git a/api/rest.py b/api/rest.py index fa6ca3f..f36cf28 100644 --- a/api/rest.py +++ b/api/rest.py @@ -19,7 +19,7 @@ from .search import SearchEngine from rest_framework import (permissions, serializers, viewsets, filters, mixins, generics, renderers, status) from rest_framework.decorators import detail_route -from rest_framework.fields import SerializerMethodField, CharField, JSONFi= eld, EmailField +from rest_framework.fields import SerializerMethodField, CharField, JSONFi= eld, EmailField, SkipField from rest_framework.relations import HyperlinkedIdentityField from rest_framework.response import Response import rest_framework @@ -429,9 +429,13 @@ class ResultSerializer(serializers.Serializer): resource_uri =3D HyperlinkedResultField(view_name=3D'results-detail') name =3D CharField() status =3D CharField() # one of 'failure', 'success', 'pending', 'runn= ing' - log_url =3D CharField(required=3DFalse) + log_url =3D SerializerMethodField(required=3DFalse) data =3D JSONField(required=3DFalse) =20 + def get_log_url(self, obj): + request =3D self.context['request'] + return obj.get_log_url(request) + class ResultSerializerFull(ResultSerializer): log =3D CharField(required=3DFalse) =20 @@ -452,8 +456,7 @@ class ResultsViewSet(viewsets.ViewSet, generics.Generic= APIView): except IndexError: raise Http404 results =3D [] - dispatch_module_hook("rest_results_hook", request=3Dself.request, - obj=3Dobj, results=3Dresults, + dispatch_module_hook("rest_results_hook", obj=3Dobj, results=3Dres= ults, detailed=3Ddetailed) return {x.name: x for x in results} =20 diff --git a/mods/git.py b/mods/git.py index fe10423..a216ea2 100644 --- a/mods/git.py +++ b/mods/git.py @@ -126,7 +126,7 @@ class GitModule(PatchewModule): def rest_series_fields_hook(self, request, fields, detailed): fields['based_on'] =3D PluginMethodField(obj=3Dself, required=3DFa= lse) =20 - def rest_results_hook(self, request, obj, results, detailed=3DFalse): + def rest_results_hook(self, obj, results, detailed=3DFalse): if not isinstance(obj, Message): return log =3D obj.get_property("git.apply-log") @@ -148,13 +148,10 @@ class GitModule(PatchewModule): if git_base: data['base'] =3D git_base status =3D Result.SUCCESS - log_url =3D reverse("git-log", kwargs=3D{'series': obj.message= _id}) else: status =3D Result.PENDING - log_url =3D None results.append(Result(name=3D'git', obj=3Dobj, status=3Dstatus, - log=3Dlog, log_url=3Dlog_url, data=3Ddata, - request=3Drequest, renderer=3Dself)) + log=3Dlog, data=3Ddata, renderer=3Dself)) =20 def prepare_message_hook(self, request, message, detailed): if not message.is_series_head: @@ -199,9 +196,10 @@ class GitModule(PatchewModule): if not result.is_completed(): return None =20 - html_log_url =3D result.log_url + "?html=3D1" + log_url =3D result.get_log_url() + html_log_url =3D log_url + "?html=3D1" colorbox_a =3D format_html('apply log', - html_log_url, result.log_url) + html_log_url, log_url) if result.is_failure(): return format_html('Failed in applying to current master ({})'= , colorbox_a) else: @@ -218,6 +216,9 @@ class GitModule(PatchewModule): s +=3D format_html('
git fetch {} {}', gi= t_repo, git_tag) return s =20 + def get_result_log_url(self, obj, name): + return reverse("git-log", kwargs=3D{'series': obj.message_id}) + def prepare_project_hook(self, request, project): if not project.maintained_by(request.user): return diff --git a/mods/testing.py b/mods/testing.py index 824df15..2d379cb 100644 --- a/mods/testing.py +++ b/mods/testing.py @@ -165,8 +165,8 @@ class TestingModule(PatchewModule): "testing_name": test}) + "?type=3Dpr= oject" if html: log_url +=3D "&html=3D1" - # Generate a full URL, including the host and port, for use in ema= il - # notifications and REST API responses. + # Generate a full URL, including the host and port, for use in + # email notifications if request: log_url =3D request.build_absolute_uri(log_url) return log_url @@ -251,7 +251,7 @@ class TestingModule(PatchewModule): }) return ret =20 - def rest_results_hook(self, request, obj, results, detailed=3DFalse): + def rest_results_hook(self, obj, results, detailed=3DFalse): all_tests =3D set([k for k, v in _instance.get_tests(obj).items() = if v["enabled"]]) for pn, p in obj.get_properties().items(): if not pn.startswith("testing.report."): @@ -262,7 +262,6 @@ class TestingModule(PatchewModule): except: pass failed =3D not p["passed"] - log_url =3D self.reverse_testing_log(obj, tn, request=3Dreques= t, html=3DFalse) passed_str =3D Result.FAILURE if failed else Result.SUCCESS if detailed: log =3D obj.get_property("testing.log." + tn) @@ -272,8 +271,7 @@ class TestingModule(PatchewModule): data =3D p.copy() del data['passed'] results.append(Result(name=3D'testing.' + tn, obj=3Dobj, statu= s=3Dpassed_str, - log=3Dlog, log_url=3Dlog_url, request=3D= request, data=3Ddata, - renderer=3Dself)) + log=3Dlog, data=3Ddata, renderer=3Dself)) =20 if obj.get_property("testing.ready"): for tn in all_tests: @@ -305,15 +303,20 @@ class TestingModule(PatchewModule): "char": "T", }) =20 + def get_result_log_url(self, obj, name): + tn =3D name[len("testing."):] + return self.reverse_testing_log(obj, tn, html=3DFalse) + def render_result(self, result): if not result.is_completed(): return None pn =3D result.name tn =3D pn[len("testing."):] - html_log_url =3D result.log_url + '&html=3D1' + log_url =3D result.get_log_url() + html_log_url =3D log_url + '&html=3D1' passed_str =3D "failed" if result.is_failure() else "passed" return format_html('Test {} {}', - tn, html_log_url, result.log_url, passed_str) + tn, html_log_url, log_url, passed_str) =20 def check_active_testers(self, project): at =3D [] diff --git a/www/views.py b/www/views.py index 1eb6c3c..c2010c5 100644 --- a/www/views.py +++ b/www/views.py @@ -93,8 +93,8 @@ def prepare_series(request, s, skip_patches=3DFalse): =20 def prepare_results(request, obj): results =3D [] - dispatch_module_hook("rest_results_hook", request=3Drequest, - obj=3Dobj, results=3Dresults, detailed=3DFalse) + dispatch_module_hook("rest_results_hook", obj=3Dobj, + results=3Dresults, detailed=3DFalse) =20 results_dicts =3D [] for result in results: --=20 2.17.0 _______________________________________________ Patchew-devel mailing list Patchew-devel@redhat.com https://www.redhat.com/mailman/listinfo/patchew-devel From nobody Sat Apr 20 00:21:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=patchew-devel-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=patchew-devel-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1526972284851928.4556386674269; Mon, 21 May 2018 23:58:04 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E4388D8190; Tue, 22 May 2018 06:58:03 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id D409830BF205; Tue, 22 May 2018 06:58:03 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id C3DE34BB78; Tue, 22 May 2018 06:58:03 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w4M6w1YP028189 for ; Tue, 22 May 2018 02:58:01 -0400 Received: by smtp.corp.redhat.com (Postfix) id E5C5D30BF206; Tue, 22 May 2018 06:58:01 +0000 (UTC) Received: from mx1.redhat.com (ext-mx11.extmail.prod.ext.phx2.redhat.com [10.5.110.40]) by smtp.corp.redhat.com (Postfix) with ESMTPS id DF12130BF205 for ; Tue, 22 May 2018 06:58:01 +0000 (UTC) Received: from mail-pg0-f43.google.com (mail-pg0-f43.google.com [74.125.83.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BC38B30C0340 for ; Tue, 22 May 2018 06:57:50 +0000 (UTC) Received: by mail-pg0-f43.google.com with SMTP id d14-v6so3846348pgv.8 for ; Mon, 21 May 2018 23:57:50 -0700 (PDT) Received: from localhost.localdomain ([208.181.63.202]) by smtp.gmail.com with ESMTPSA id y2-v6sm19818676pgp.92.2018.05.21.23.57.49 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 21 May 2018 23:57:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=I7v7uXkGQ13Tbw/CO+Q8ukRwtCVARsA3Q80WoAyBFf4=; b=lUrWB1w0giC+aUSM6ja0rjFtnefDulMhOEQLRyS1YFEx+oX6wnU/A1jiMvJxqcN18o 696deEUT7ICTAZMWdbAORYOFa75gySbEcuH+DgFcxjG9xB9E4WSKuErXLmskAhagR+gD bL3ypH9xmnFo4h8yZoxTP+HE6mjOZ2ET/dJCmb6MYcjvfxptqTFynBnu7HdGCh4fNLM5 P1PXJIl9qgmD7XJwpCI/YZQyWjQaRAkcILiQHXjmrUSPkvnnfFHKd5fQoQcBp6GGpkyY rZrC6UjN980UbMH/rypAa7VG0UAq4CkvLJ2LL7SeCfZ9+hLRwXZeWMomLPBEAdVgR4vQ RjkA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=I7v7uXkGQ13Tbw/CO+Q8ukRwtCVARsA3Q80WoAyBFf4=; b=MkMmOsejfXkA/SxVIUvGnQwBqwyotvOWwDtZ59P56/PQzmMORuZHfj0BjAgf9a7Cxk 7DZioTKpbHLY1u6LcAqkFExH4n/0wLWxXUChcWoSNp2H7fycnzrbukolNtC9F31RqwYY HRvSdCiPBc50Evyiymq67Hg+Otxo7zG/O+a7+/VnJUXJniRmvVnu2LTjEVVJXEQo4fU6 WMVdOAjhcSA7X9NvvVSp8fq7j5qaVHLDHyfUF+ryfT999iCqh1nNm8keKXiCX6xaoG8v F6nSH8g3vLfdRBFDMYnokqDaGvagme6y/1bmv7Z1CMVeUD286r6qHcYjC8+PlwUypnGD hMQg== X-Gm-Message-State: ALKqPwfHM3Flhtby6o7Ah01rmHRmBJKKuqdb6QdRrDwtOQC7Db92pWyK narkChj2Gx2B1ooUL6DcPJmEFIWH X-Google-Smtp-Source: AB8JxZqAC3rs+dqwh5P1S38LCvabKVYQoF4C9rU0oVy3vYez8jtXNZv//5l3OGtdowLscdppRoiCsg== X-Received: by 2002:a62:78c:: with SMTP id 12-v6mr22993674pfh.178.1526972269818; Mon, 21 May 2018 23:57:49 -0700 (PDT) From: Paolo Bonzini To: patchew-devel@redhat.com Date: Tue, 22 May 2018 08:57:33 +0200 Message-Id: <20180522065740.9710-6-pbonzini@redhat.com> In-Reply-To: <20180522065740.9710-1-pbonzini@redhat.com> References: <20180522065740.9710-1-pbonzini@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.40]); Tue, 22 May 2018 06:57:50 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.40]); Tue, 22 May 2018 06:57:50 +0000 (UTC) for IP:'74.125.83.43' DOMAIN:'mail-pg0-f43.google.com' HELO:'mail-pg0-f43.google.com' FROM:'paolo.bonzini@gmail.com' RCPT:'' X-RedHat-Spam-Score: 0.597 (DKIM_SIGNED, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_NONE, SPF_PASS, T_DKIM_INVALID) 74.125.83.43 mail-pg0-f43.google.com 74.125.83.43 mail-pg0-f43.google.com X-RedHat-Possible-Forgery: Paolo Bonzini X-Scanned-By: MIMEDefang 2.84 on 10.5.110.40 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.26 X-loop: patchew-devel@redhat.com Subject: [Patchew-devel] [PATCH 05/12] models: extract blobs functions to a separate file X-BeenThere: patchew-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Patchew development and discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: patchew-devel-bounces@redhat.com Errors-To: patchew-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.26 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Tue, 22 May 2018 06:58:03 +0000 (UTC) X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" They will be used by migrations, and we don't want to import api.models there. --- api/blobs.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ api/models.py | 27 ++++----------------------- 2 files changed, 49 insertions(+), 23 deletions(-) create mode 100644 api/blobs.py diff --git a/api/blobs.py b/api/blobs.py new file mode 100644 index 0000000..7171b71 --- /dev/null +++ b/api/blobs.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# +# Copyright 2018 Red Hat, Inc. +# +# Authors: +# Fam Zheng +# Paolo Bonzini +# +# This work is licensed under the MIT License. Please see the LICENSE fil= e or +# http://opensource.org/licenses/MIT. + + +import os +import json +import uuid +import logging + +from django.conf import settings +import lzma + +def save_blob(data, name=3DNone): + if not name: + name =3D str(uuid.uuid4()) + fn =3D os.path.join(settings.DATA_DIR, "blob", name + ".xz") + lzma.open(fn, 'w').write(data.encode("utf-8")) + return name + +def load_blob(name): + fn =3D os.path.join(settings.DATA_DIR, "blob", name + ".xz") + return lzma.open(fn, 'r').read().decode("utf-8") + +def load_blob_json(name): + try: + return json.loads(load_blob(name)) + except json.decoder.JSONDecodeError as e: + logging.error('Failed to load blob %s: %s' %(name, e)) + return None + +def delete_blob(name): + fn =3D os.path.join(settings.DATA_DIR, "blob", name + ".xz") + try: + os.remove(fn) + except FileNotFoundError: + pass + diff --git a/api/models.py b/api/models.py index 0f25f85..497e43c 100644 --- a/api/models.py +++ b/api/models.py @@ -10,39 +10,20 @@ =20 =20 from collections import namedtuple -import os import json import datetime import re -import uuid -import logging =20 -from django.conf import settings from django.db import models from django.contrib.auth.models import User from django.urls import reverse import jsonfield -from mbox import MboxMessage -from event import emit_event, declare_event import lzma =20 -def save_blob(data, name=3DNone): - if not name: - name =3D str(uuid.uuid4()) - fn =3D os.path.join(settings.DATA_DIR, "blob", name + ".xz") - lzma.open(fn, 'w').write(data.encode("utf-8")) - return name - -def load_blob(name): - fn =3D os.path.join(settings.DATA_DIR, "blob", name + ".xz") - return lzma.open(fn, 'r').read().decode("utf-8") - -def load_blob_json(name): - try: - return json.loads(load_blob(name)) - except json.decoder.JSONDecodeError as e: - logging.error('Failed to load blob %s: %s' %(name, e)) - return None +from mbox import MboxMessage +from event import emit_event, declare_event +from .blobs import save_blob, load_blob, load_blob_json +import mod =20 class Project(models.Model): name =3D models.CharField(max_length=3D1024, db_index=3DTrue, unique= =3DTrue, --=20 2.17.0 _______________________________________________ Patchew-devel mailing list Patchew-devel@redhat.com https://www.redhat.com/mailman/listinfo/patchew-devel From nobody Sat Apr 20 00:21:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=patchew-devel-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=patchew-devel-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1526972288370260.5166504364157; Mon, 21 May 2018 23:58:08 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6AD253179B44; Tue, 22 May 2018 06:58:07 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 5BEEF601A1; Tue, 22 May 2018 06:58:07 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 43AC14BB78; Tue, 22 May 2018 06:58:07 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w4M6w6oc028211 for ; Tue, 22 May 2018 02:58:06 -0400 Received: by smtp.corp.redhat.com (Postfix) id 9198F30001EB; Tue, 22 May 2018 06:58:06 +0000 (UTC) Received: from mx1.redhat.com (ext-mx10.extmail.prod.ext.phx2.redhat.com [10.5.110.39]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 85EB43091AA6 for ; Tue, 22 May 2018 06:58:03 +0000 (UTC) Received: from mail-pf0-f169.google.com (mail-pf0-f169.google.com [209.85.192.169]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D8ABD16B1E9 for ; Tue, 22 May 2018 06:57:51 +0000 (UTC) Received: by mail-pf0-f169.google.com with SMTP id p12-v6so8271124pff.13 for ; Mon, 21 May 2018 23:57:51 -0700 (PDT) Received: from localhost.localdomain ([208.181.63.202]) by smtp.gmail.com with ESMTPSA id y2-v6sm19818676pgp.92.2018.05.21.23.57.49 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 21 May 2018 23:57:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=4wGAsQTEi4Qgp5h+YOog2hQUd2pljSipp7LhsEmoXVc=; b=m9sbt/IHA0FUZZcB5DekVM/7SxIz7dwQhMtaZCiL+e4nwZDCYHLcts41rL8syhK0gJ m9ibyWlFUHEcODMpXOCArLdn2iVaSbf/mQPwikTvFdOlAhj3WQCDQrNzChtN2JLuodaC CvXtVLAh9MhxZYUt628gz2SIErp+mX2MOnqicfgdtI6YjfOCMVDj8y6KfERLTZUTIfs4 lwRHinjvrkC55BB6oJ4jmBEsmCTUIaOdFUJI4ArCxN7gm0oE7FR2KxCEjGCodkrBW8lo IJZMKOIqlVItFi6T05/IlOr4/ZB2JSyRVB+M7plJ8cBpWBTCrrm8KYqkA0C9lg6AHnKx tzbA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=4wGAsQTEi4Qgp5h+YOog2hQUd2pljSipp7LhsEmoXVc=; b=ZrtFS3vvpqllFw9yZsTlD2URTj1hygA0wqN9tIwva5NbkjakkxIspAUtP4QB9WHUEC If6etCxWEYjySXclVuMkaRkEl1QO6TDAWrgSw/BEEfjKwLbViCZ2t1cmAqeb2HA4vwUc uBAZlhMrWEk892VcuciJa4xa9oFvWZi2k/kE+N0EIQIzQzjp7YE7B36OaEXtJompGBBb QmTxNgVjdm6+P7V1j3w8/TXJE3FKj8JY7goQJhxiwpmeKY0ugb6QZYRgqL32+YM6FPT6 uNbZdKij86Ek3S8icCncLn8crDd6MsaZRD59n7+/4nmxma0VHrkVbMzsv0UC3By/oNXS S8Kg== X-Gm-Message-State: ALKqPwdfxEEFAKl28St83QLopL9+GCXVLXLHK0G+4LYDHfX4n3xPuTiO cAYgVyHBSrHU4tAvpAkTHcnpC+St X-Google-Smtp-Source: AB8JxZoZMXoG8W0RSxv9BEQHsT8Aszzy2Jpd3ciRB1dRKHKYVy8lJOQ/neZlfnEN8OPatDuhNmkFSQ== X-Received: by 2002:a65:648a:: with SMTP id e10-v6mr18187269pgv.34.1526972270855; Mon, 21 May 2018 23:57:50 -0700 (PDT) From: Paolo Bonzini To: patchew-devel@redhat.com Date: Tue, 22 May 2018 08:57:34 +0200 Message-Id: <20180522065740.9710-7-pbonzini@redhat.com> In-Reply-To: <20180522065740.9710-1-pbonzini@redhat.com> References: <20180522065740.9710-1-pbonzini@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Tue, 22 May 2018 06:57:52 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Tue, 22 May 2018 06:57:52 +0000 (UTC) for IP:'209.85.192.169' DOMAIN:'mail-pf0-f169.google.com' HELO:'mail-pf0-f169.google.com' FROM:'paolo.bonzini@gmail.com' RCPT:'' X-RedHat-Spam-Score: -1.2 (DKIM_SIGNED, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_PASS, T_DKIM_INVALID) 209.85.192.169 mail-pf0-f169.google.com 209.85.192.169 mail-pf0-f169.google.com X-RedHat-Possible-Forgery: Paolo Bonzini X-Scanned-By: MIMEDefang 2.78 on 10.5.110.39 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.24 X-loop: patchew-devel@redhat.com Subject: [Patchew-devel] [PATCH 06/12] models: create Result model X-BeenThere: patchew-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Patchew development and discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: patchew-devel-bounces@redhat.com Errors-To: patchew-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.41]); Tue, 22 May 2018 06:58:07 +0000 (UTC) X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The Result model has more or less a 1:1 correspondence with the fields in the REST results detail view, and thus with ResultSerializerFull. Until all plugins are converted, everything will still go through namedtuple results, so the namedtuple is kept, renamed to ResultTuple. The duplicated code will disappear at the end of this series. There is an extra field tracking the time of the last update, which will be used by the testing module; for simplicity it is not yet presented by the serializers, though it will be added when ResultTuple is dropped. The external interface of Result and ResultTuple is more or less the same, except that we have to get rid of the two Python objects that the tuple stores, obj and renderer. The renderer is eliminated by convention: the renderer of the new Result objects is always a PatchewModule, and the name of the result up to the first period (if any) identifies the renderer. As for obj, the parent object, the Result object has no clue whether it comes from a project or a message, so it is passed as a new parameter to render() and get_log_url(). The new parameter is easy to integrate in both the REST API SerializerMethodField getter and in the web view. Compared to properties, logs are always stored in the database, independent of the size. However, they are always stored in xz format compared to the JSON string format used by properties. Using xz will complicate migrations a little, since the log property won't be available there, but not as much as handling blobs. Signed-off-by: Paolo Bonzini --- api/migrations/0027_auto_20180521_0152.py | 38 ++++++++ api/models.py | 103 +++++++++++++++++++--- mods/git.py | 4 +- mods/testing.py | 6 +- 4 files changed, 134 insertions(+), 17 deletions(-) create mode 100644 api/migrations/0027_auto_20180521_0152.py diff --git a/api/migrations/0027_auto_20180521_0152.py b/api/migrations/002= 7_auto_20180521_0152.py new file mode 100644 index 0000000..94aa0d8 --- /dev/null +++ b/api/migrations/0027_auto_20180521_0152.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.12 on 2018-05-21 20:05 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models +import jsonfield.fields + + +class Migration(migrations.Migration): + + dependencies =3D [ + ('api', '0026_auto_20180426_0829'), + ] + + operations =3D [ + migrations.CreateModel( + name=3D'Result', + fields=3D[ + ('id', models.AutoField(auto_created=3DTrue, primary_key= =3DTrue, serialize=3DFalse, verbose_name=3D'ID')), + ('name', models.CharField(max_length=3D256)), + ('last_update', models.DateTimeField()), + ('status', models.CharField(db_index=3DTrue, max_length=3D= 7, validators=3D[django.core.validators.RegexValidator(code=3D'invalid', me= ssage=3D'status must be one of pending, success, failure, running', regex= =3D'pending|success|failure|running')])), + ('log_xz', models.BinaryField(blank=3DTrue, null=3DTrue)), + ('data', jsonfield.fields.JSONField()), + ], + ), + migrations.AddField( + model_name=3D'message', + name=3D'results', + field=3Dmodels.ManyToManyField(blank=3DTrue, to=3D'api.Result'= ), + ), + migrations.AddField( + model_name=3D'project', + name=3D'results', + field=3Dmodels.ManyToManyField(blank=3DTrue, to=3D'api.Result'= ), + ), + ] diff --git a/api/models.py b/api/models.py index 497e43c..ee54d04 100644 --- a/api/models.py +++ b/api/models.py @@ -14,7 +14,9 @@ import json import datetime import re =20 +from django.core import validators from django.db import models +from django.db.models import Q from django.contrib.auth.models import User from django.urls import reverse import jsonfield @@ -25,6 +27,86 @@ from event import emit_event, declare_event from .blobs import save_blob, load_blob, load_blob_json import mod =20 +class Result(models.Model): + PENDING =3D 'pending' + SUCCESS =3D 'success' + FAILURE =3D 'failure' + RUNNING =3D 'running' + VALID_STATUSES =3D (PENDING, SUCCESS, FAILURE, RUNNING) + VALID_STATUSES_RE =3D '|'.join(VALID_STATUSES) + + name =3D models.CharField(max_length=3D256) + last_update =3D models.DateTimeField() + status =3D models.CharField(max_length=3D7, db_index=3DTrue, validator= s=3D[ + validators.RegexValidator(regex=3DVALID_STATUSES_RE, + message=3D'status must be one of ' + ', = '.join(VALID_STATUSES), + code=3D'invalid')]) + log_xz =3D models.BinaryField(blank=3DTrue, null=3DTrue) + data =3D jsonfield.JSONField() + + def is_success(self): + return self.status =3D=3D self.SUCCESS + + def is_failure(self): + return self.status =3D=3D self.FAILURE + + def is_completed(self): + return self.is_success() or self.is_failure() + + def is_pending(self): + return self.status =3D=3D self.PENDING + + def is_running(self): + return self.status =3D=3D self.RUNNING + + def save(self): + self.last_update =3D datetime.datetime.utcnow() + return super(Result, self).save() + + @property + def renderer(self): + found =3D re.match("^[^.]*", self.name) + return mod.get_module(found[0]) if found else None + + def render(self, obj): + if self.renderer is None: + return None + return self.renderer.render_result(self, obj) + + @property + def log(self): + if hasattr(self, "_log"): + return self._log + if self.log_xz is None: + self._log =3D None + else: + self._log =3D lzma.decompress(self.log_xz).decode("utf-8") + return self._log + + @log.setter + def log(self, value): + self._log =3D value + if value is None: + self.log_xz =3D None + else: + self.log_xz =3D lzma.compress(value.encode("utf-8")) + + def get_log_url(self, obj, request=3DNone): + if not self.is_completed() or self.renderer is None: + return None + log_url =3D self.renderer.get_result_log_url(obj, self.name) + if log_url is not None and request is not None: + log_url =3D request.build_absolute_uri(log_url) + return log_url + + @staticmethod + def get_result_tuples(obj, module, results): + name_filter =3D Q(name=3Dmodule) | Q(name__startswith=3Dmodule + '= .') + renderer =3D mod.get_module(module) + for r in obj.results.filter(name_filter): + results.append(ResultTuple(name=3Dr.name, obj=3Dobj, status=3D= r.status, + log=3Dr.log, data=3Dr.data, rendere= r=3Drenderer)) + class Project(models.Model): name =3D models.CharField(max_length=3D1024, db_index=3DTrue, unique= =3DTrue, help_text=3D"""The name of the project""") @@ -58,6 +140,7 @@ class Project(models.Model): top project which has parent_project=3DNULL""") maintainers =3D models.ManyToManyField(User, blank=3DTrue) + results =3D models.ManyToManyField(Result, blank=3DTrue) =20 def __str__(self): return self.name @@ -319,6 +402,7 @@ class Message(models.Model): num_patches =3D models.IntegerField(null=3DFalse, default=3D-1, blank= =3DTrue) =20 objects =3D MessageManager() + results =3D models.ManyToManyField(Result, blank=3DTrue) =20 def save_mbox(self, mbox_blob): save_blob(mbox_blob, self.message_id) @@ -595,34 +679,29 @@ class Module(models.Model): def __str__(self): return self.name =20 -class Result(namedtuple("Result", "name status log obj data renderer")): +class ResultTuple(namedtuple("ResultTuple", "name status log obj data rend= erer")): __slots__ =3D () - PENDING =3D 'pending' - SUCCESS =3D 'success' - FAILURE =3D 'failure' - RUNNING =3D 'running' - VALID_STATUSES =3D (PENDING, SUCCESS, FAILURE, RUNNING) =20 def __new__(cls, name, status, obj, log=3DNone, data=3DNone, renderer= =3DNone): - if status not in cls.VALID_STATUSES: + if status not in Result.VALID_STATUSES: raise ValueError("invalid value '%s' for status field" % statu= s) - return super(cls, Result).__new__(cls, status=3Dstatus, log=3Dlog, + return super(cls, ResultTuple).__new__(cls, status=3Dstatus, log= =3Dlog, obj=3Dobj, data=3Ddata, name=3Dn= ame, renderer=3Drenderer) =20 def is_success(self): - return self.status =3D=3D self.SUCCESS + return self.status =3D=3D Result.SUCCESS =20 def is_failure(self): - return self.status =3D=3D self.FAILURE + return self.status =3D=3D Result.FAILURE =20 def is_completed(self): return self.is_success() or self.is_failure() =20 def is_pending(self): - return self.status =3D=3D self.PENDING + return self.status =3D=3D Result.PENDING =20 def is_running(self): - return self.status =3D=3D self.RUNNING + return self.status =3D=3D Result.RUNNING =20 def render(self): if self.renderer is None: diff --git a/mods/git.py b/mods/git.py index a216ea2..eae9be6 100644 --- a/mods/git.py +++ b/mods/git.py @@ -18,7 +18,7 @@ from django.core.exceptions import PermissionDenied from django.utils.html import format_html from mod import PatchewModule from event import declare_event, register_handler, emit_event -from api.models import Message, MessageProperty, Result +from api.models import Message, MessageProperty, Result, ResultTuple from api.rest import PluginMethodField from api.views import APILoginRequiredView, prepare_series from patchew.logviewer import LogView @@ -150,7 +150,7 @@ class GitModule(PatchewModule): status =3D Result.SUCCESS else: status =3D Result.PENDING - results.append(Result(name=3D'git', obj=3Dobj, status=3Dstatus, + results.append(ResultTuple(name=3D'git', obj=3Dobj, status=3Dstatu= s, log=3Dlog, data=3Ddata, renderer=3Dself)) =20 def prepare_message_hook(self, request, message, detailed): diff --git a/mods/testing.py b/mods/testing.py index 2d379cb..98732e3 100644 --- a/mods/testing.py +++ b/mods/testing.py @@ -17,7 +17,7 @@ from mod import PatchewModule import time import math from api.views import APILoginRequiredView -from api.models import Message, MessageProperty, Project, Result +from api.models import Message, MessageProperty, Project, Result, ResultTu= ple from api.search import SearchEngine from event import emit_event, declare_event, register_handler from patchew.logviewer import LogView @@ -270,12 +270,12 @@ class TestingModule(PatchewModule): =20 data =3D p.copy() del data['passed'] - results.append(Result(name=3D'testing.' + tn, obj=3Dobj, statu= s=3Dpassed_str, + results.append(ResultTuple(name=3D'testing.' + tn, obj=3Dobj, = status=3Dpassed_str, log=3Dlog, data=3Ddata, renderer=3Dself)) =20 if obj.get_property("testing.ready"): for tn in all_tests: - results.append(Result(name=3D'testing.' + tn, obj=3Dobj, s= tatus=3D'pending')) + results.append(ResultTuple(name=3D'testing.' + tn, obj=3Do= bj, status=3D'pending')) =20 def prepare_message_hook(self, request, message, detailed): if not message.is_series_head: --=20 2.17.0 _______________________________________________ Patchew-devel mailing list Patchew-devel@redhat.com https://www.redhat.com/mailman/listinfo/patchew-devel From nobody Sat Apr 20 00:21:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=patchew-devel-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=patchew-devel-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1526972320835435.9713764499776; Mon, 21 May 2018 23:58:40 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id EA51FEE56F; Tue, 22 May 2018 06:58:39 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id DC92BA34C0; Tue, 22 May 2018 06:58:39 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id CBFB51801241; Tue, 22 May 2018 06:58:39 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w4M6w8bk028246 for ; Tue, 22 May 2018 02:58:08 -0400 Received: by smtp.corp.redhat.com (Postfix) id 568E05D75C; Tue, 22 May 2018 06:58:08 +0000 (UTC) Received: from mx1.redhat.com (ext-mx07.extmail.prod.ext.phx2.redhat.com [10.5.110.31]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 4C5725D757 for ; Tue, 22 May 2018 06:58:05 +0000 (UTC) Received: from mail-pg0-f45.google.com (mail-pg0-f45.google.com [74.125.83.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 355BEC08735B for ; Tue, 22 May 2018 06:57:53 +0000 (UTC) Received: by mail-pg0-f45.google.com with SMTP id p9-v6so7431147pgc.9 for ; Mon, 21 May 2018 23:57:53 -0700 (PDT) Received: from localhost.localdomain ([208.181.63.202]) by smtp.gmail.com with ESMTPSA id y2-v6sm19818676pgp.92.2018.05.21.23.57.50 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 21 May 2018 23:57:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=KeaGRkcCEU2SBPM3DbCgLlWTupx/rmBGwH7ooBuFHio=; b=Azl921NJ0DJtwRQoMdVv8qNzuHYzJ12ghVBQR2e+gx0Ud41XxXZZGDPvUYjwxNCWg3 H4gzJW5bwxWr091CIGqKNvI45D/9y0vJQEY2JIN6Egh3e3FzilU4rXegoyP1L2qDmfx5 eXma2VOc3aNkGiR48/OVJn2U/u+JyIyL7sH0v9EbQnkqdoBdgz7PMnKEjpbTyp0qrqgN v72bocnWRtvtIzmVJqzPgHV/HfYhGgyq4uAt7zR6uEOCrDMUhKeMqZFNZmZTFaoUQZgz 7l3aOsmCvRMJGVhf5ChUTF4w2R5GR/exDUJ4FictOnJ8frarD7j7pM4nxLoQv6d+Tw7I RPBw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=KeaGRkcCEU2SBPM3DbCgLlWTupx/rmBGwH7ooBuFHio=; b=FiN+cEyA0jqcgu2qKzUMT8Mdhqev8saioN/3qh9/FQfFkXb7Yj78QkpuyGZPfqCebM e8TUy1VdYxL8CeR+Gt30SXsnCypynUcabv3Ky1WcIjhWqjaQ/KZyJbYDxs9X/aZeLIIY R+7JPymEJK6YxJVXk5ouFCCxsKUWh8jDe2g+gJIg8AVjulfJE5DKN7kwsZ0QpDG/y8bQ VrT0qMp3G4brT5rzVuVECx0GJyr6jU0406iFbIPMa4YQC87sQSn80HUPNehLydXn/2/H ADHpUBAtJaVOYAJ0/6bIW8KWHv0ZsBCpnEQvB8JBVgQrhOPJwpzkqK7dNEPOvS5+cWUH daQA== X-Gm-Message-State: ALKqPwdn7LP8Z+VE1eZytz0wTuCVJDLhaQIVZzp77lBc7SxJiFcVzhtv HniZAFURJ20BrADMqJZ1M6NXnPRJ X-Google-Smtp-Source: AB8JxZohmkawCVwRHEpSS1IYwpRGbGRm5bEyNGdiYIY+VLpbPIRdz8xc/WfkeBqytW0XCMeGZ2uRig== X-Received: by 2002:a62:105:: with SMTP id 5-v6mr22912021pfb.1.1526972271973; Mon, 21 May 2018 23:57:51 -0700 (PDT) From: Paolo Bonzini To: patchew-devel@redhat.com Date: Tue, 22 May 2018 08:57:35 +0200 Message-Id: <20180522065740.9710-8-pbonzini@redhat.com> In-Reply-To: <20180522065740.9710-1-pbonzini@redhat.com> References: <20180522065740.9710-1-pbonzini@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Tue, 22 May 2018 06:57:53 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Tue, 22 May 2018 06:57:53 +0000 (UTC) for IP:'74.125.83.45' DOMAIN:'mail-pg0-f45.google.com' HELO:'mail-pg0-f45.google.com' FROM:'paolo.bonzini@gmail.com' RCPT:'' X-RedHat-Spam-Score: 0.577 (DKIM_SIGNED, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_PASS, T_DKIM_INVALID) 74.125.83.45 mail-pg0-f45.google.com 74.125.83.45 mail-pg0-f45.google.com X-RedHat-Possible-Forgery: Paolo Bonzini X-Scanned-By: MIMEDefang 2.78 on 10.5.110.31 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-loop: patchew-devel@redhat.com Subject: [Patchew-devel] [PATCH 07/12] git: switch to Result model X-BeenThere: patchew-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Patchew development and discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: patchew-devel-bounces@redhat.com Errors-To: patchew-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.27 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Tue, 22 May 2018 06:58:39 +0000 (UTC) X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Operate on a Result named 'git' instead of using multiple properties. Only the hook has to convert the Result to namedtuple format, until the REST API and web views are converted to access the database directly. --- api/migrations/0028_populate_git_results.py | 100 +++++++++++++++ api/migrations/__init__.py | 46 +++++++ mods/git.py | 131 ++++++++++---------- tests/test_git.py | 34 ++--- 4 files changed, 227 insertions(+), 84 deletions(-) create mode 100644 api/migrations/0028_populate_git_results.py diff --git a/api/migrations/0028_populate_git_results.py b/api/migrations/0= 028_populate_git_results.py new file mode 100644 index 0000000..8380262 --- /dev/null +++ b/api/migrations/0028_populate_git_results.py @@ -0,0 +1,100 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations +from django.db.models import Count +from api.migrations import get_property, set_property, delete_property_blob + +import datetime +import lzma + +# For Result's constant status values +import api.models + +def result_from_properties(apps, schema_editor): + # We can't import the models directly as they may be a newer + # version than this migration expects. We use the historical version. + # The code is mostly based on the implementation of the old + # "rest_results_hook" method in GitModule, which used to build + # a Result namedtuple from the properties + Message =3D apps.get_model('api', 'Message') + MessageProperty =3D apps.get_model('api', 'MessageProperty') + Result =3D apps.get_model('api', 'Result') + messages =3D Message.objects.filter(properties__name__startswith=3D'gi= t.').distinct() + for m in messages: + need_apply =3D get_property(MessageProperty, 'git.need-apply', mes= sage=3Dm) + if need_apply is None: + continue + log =3D get_property(MessageProperty, "git.apply-log", message=3Dm) + r =3D Result(name=3D'git') + if log: + r.log_xz =3D lzma.compress(log.encode("utf-8")) + if get_property(MessageProperty, "git.apply-failed", message= =3Dm): + r.status =3D api.models.Result.FAILURE + else: + git_repo =3D get_property(MessageProperty, "git.repo", mes= sage=3Dm) + git_tag =3D get_property(MessageProperty, "git.tag", messa= ge=3Dm) + git_url =3D get_property(MessageProperty, "git.url", messa= ge=3Dm) + git_base =3D get_property(MessageProperty, "git.base", mes= sage=3Dm) + data =3D {} + if git_repo and git_tag: + data['repo'] =3D git_repo + data['tag'] =3D 'refs/tags/' + git_tag + if git_url: + data['url'] =3D git_url + if git_base: + data['base'] =3D git_base + r.data =3D data + r.status =3D api.models.Result.SUCCESS + else: + status =3D api.models.Result.PENDING + r.last_update =3D datetime.datetime.utcnow() + r.save() + m.results.add(r) + messages =3D Message.objects.filter(properties__name=3D'git.apply-log'= , properties__blob=3DTrue) + for m in messages: + delete_property_blob(MessageProperty, "git.apply-log", message=3Dm) + MessageProperty.objects.filter(name__startswith=3D'git.').delete() + +def result_to_properties(apps, schema_editor): + # We can't import the models directly as they may be a newer + # version than this migration expects. We use the historical version. + Message =3D apps.get_model('api', 'Message') + MessageProperty =3D apps.get_model('api', 'MessageProperty') + Result =3D apps.get_model('api', 'Result') + messages =3D Message.objects.filter(results__name=3D'git') + for m in messages: + r =3D Result.objects.get(name=3D'git', message=3Dm) + if not r: + continue + if r.status =3D=3D api.models.Result.PENDING: + set_property(MessageProperty, 'git.need-apply', True, message= =3Dm) + else: + log =3D lzma.decompress(r.log_xz).decode("utf-8") + set_property(MessageProperty, 'git.need-apply', False, message= =3Dm) + set_property(MessageProperty, 'git.apply-log', log, message=3D= m) + if r.status =3D=3D api.models.Result.FAILURE: + set_property(MessageProperty, "git.apply-failed", True, me= ssage=3Dm) + else: + set_property(MessageProperty, "git.apply-failed", False, m= essage=3Dm) + if 'repo' in r.data: + set_property(MessageProperty, "git.repo", r.data['repo= '], message=3Dm) + if 'tag' in r.data: + set_property(MessageProperty, "git.tag", r.data['repo'= ][len('refs/tags/'):], message=3Dm) + if 'url' in r.data: + set_property(MessageProperty, "git.url", r.data['url']= , message=3Dm) + if 'base' in r.data: + set_property(MessageProperty, "git.base", r.data['base= '], message=3Dm) + Result.objects.filter(message=3Dm, name=3D'git').delete() + +class Migration(migrations.Migration): + + dependencies =3D [ + ('api', '0027_auto_20180521_0152'), + ] + + operations =3D [ + migrations.RunPython(result_from_properties, + reverse_code=3Dresult_to_properties), + ] diff --git a/api/migrations/__init__.py b/api/migrations/__init__.py index e69de29..9707fb2 100644 --- a/api/migrations/__init__.py +++ b/api/migrations/__init__.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# +# Copyright 2018 Red Hat, Inc. +# +# Authors: +# Paolo Bonzini +# +# This work is licensed under the MIT License. Please see the LICENSE fil= e or +# http://opensource.org/licenses/MIT. + + +import json +from api import blobs + +def load_blob_json_safe(name): + try: + return json.loads(blobs.load_blob(name)) + except Exception as e: + return 'Failed to load blob %s: %s' % (name, e) + +def get_property_raw(model, name, **kwargs): + mp =3D model.objects.get(name=3Dname, **kwargs) + return mp + +def load_property(mp): + if mp.blob: + return load_blob_json_safe(mp.value) + else: + return json.loads(mp.value) + +def get_property(model, name, **kwargs): + mp =3D get_property_raw(model, name, **kwargs) + return load_property(mp) if mp else None + +def delete_property_blob(model, name, **kwargs): + mp =3D get_property_raw(model, name, **kwargs) + if mp.blob: + blobs.delete_blob(mp.value) + +def set_property(model, name, value, **kwargs): + if value is not None: + value =3D json.dumps(value) + mp, created =3D model.objects.get_or_create(name=3Dname, **kwargs) + mp.value =3D value + mp.blob =3D False + mp.save() diff --git a/mods/git.py b/mods/git.py index eae9be6..d77ab0e 100644 --- a/mods/git.py +++ b/mods/git.py @@ -18,7 +18,7 @@ from django.core.exceptions import PermissionDenied from django.utils.html import format_html from mod import PatchewModule from event import declare_event, register_handler, emit_event -from api.models import Message, MessageProperty, Result, ResultTuple +from api.models import Message, MessageProperty, Project, Result, ResultTu= ple from api.rest import PluginMethodField from api.views import APILoginRequiredView, prepare_series from patchew.logviewer import LogView @@ -26,16 +26,24 @@ from schema import * =20 _instance =3D None =20 +def _get_git_result(msg): + try: + return msg.results.get(name=3D"git") + except: + return None +Message.git_result =3D property(_get_git_result) + + class GitLogViewer(LogView): def content(self, request, **kwargs): series =3D kwargs['series'] obj =3D Message.objects.find_series(series) if not obj: raise Http404("Object not found: " + series) - log =3D obj.get_property("git.apply-log") - if log is None: + r =3D obj.git_result + if r is None or not r.is_completed(): raise Http404("Git apply log not found") - return log + return r.log =20 =20 class GitModule(PatchewModule): @@ -66,9 +74,23 @@ class GitModule(PatchewModule): register_handler("SeriesComplete", self.on_series_update) register_handler("TagsUpdate", self.on_series_update) =20 + def mark_as_pending_apply(self, series): + r =3D series.git_result + need_add =3D False + if not r: + need_add =3D True + r =3D Result() + r.name =3D 'git' + r.log =3D None + r.status =3D Result.PENDING + r.data =3D {} + r.save() + if need_add: + series.results.add(r) + def on_series_update(self, event, series, **params): if series.is_complete: - series.set_property("git.need-apply", True) + self.mark_as_pending_apply(series) =20 def get_project_config(self, project, what): return project.get_property("git." + what) @@ -114,50 +136,20 @@ class GitModule(PatchewModule): =20 def get_based_on(self, message, request, format): git_base =3D self.get_base(message) - if not git_base: - return None - - return { - "repo": git_base.get_property("git.repo"), - "tag": 'refs/tags/' + git_base.get_property("git.tag") - } - + return git_base.data if git_base else None =20 def rest_series_fields_hook(self, request, fields, detailed): fields['based_on'] =3D PluginMethodField(obj=3Dself, required=3DFa= lse) =20 def rest_results_hook(self, obj, results, detailed=3DFalse): - if not isinstance(obj, Message): - return - log =3D obj.get_property("git.apply-log") - data =3D None - if log: - if obj.get_property("git.apply-failed"): - status =3D Result.FAILURE - else: - git_repo =3D obj.get_property("git.repo") - git_tag =3D obj.get_property("git.tag") - git_url =3D obj.get_property("git.url") - git_base =3D obj.get_property("git.base") - data =3D {} - if git_repo and git_tag: - data['repo'] =3D git_repo - data['tag'] =3D 'refs/tags/' + git_tag - if git_url: - data['url'] =3D git_url - if git_base: - data['base'] =3D git_base - status =3D Result.SUCCESS - else: - status =3D Result.PENDING - results.append(ResultTuple(name=3D'git', obj=3Dobj, status=3Dstatu= s, - log=3Dlog, data=3Ddata, renderer=3Dself)) + Result.get_result_tuples(obj, "git", results) =20 def prepare_message_hook(self, request, message, detailed): if not message.is_series_head: return - if message.get_property("git.apply-log"): - if message.get_property("git.apply-failed"): + r =3D message.git_result + if r and r.is_completed(): + if r.is_failure(): title =3D "Failed in applying to current master" message.status_tags.append({ "title": title, @@ -165,10 +157,10 @@ class GitModule(PatchewModule): "char": "G", }) else: - git_url =3D message.get_property("git.url") - git_repo =3D message.get_property("git.repo") - git_tag =3D message.get_property("git.tag") + git_url =3D r.data.get('url') if git_url: + git_repo =3D r.data['repo'] + git_tag =3D r.data['tag'] message.status_tags.append({ "url": git_url, "title": format_html("Applied as tag {} in repo {}= ", git_tag, git_repo), @@ -181,9 +173,7 @@ class GitModule(PatchewModule): "type": "info", "char": "G", }) - if request.user.is_authenticated: - if message.get_property("git.apply-failed") !=3D None or \ - message.get_property("git.need-apply") =3D=3D None: + if request.user.is_authenticated: url =3D reverse("git_reset", kwargs=3D{"series": message.message_id}) message.extra_ops.append({"url": url, @@ -238,7 +228,8 @@ class GitModule(PatchewModule): filter(project=3Dseries.project, message_id=3Dbase_id)= .first() if not base: return None - return base if base.get_property("git.repo") else None + r =3D base.git_result + return r if r and r.data.get("repo") else None =20 def prepare_series_hook(self, request, series, response): po =3D series.project @@ -247,8 +238,8 @@ class GitModule(PatchewModule): response[prop] =3D po.get_property(prop) base =3D self.get_base(series) if base: - response["git.repo"] =3D base.get_property("git.repo") - response["git.base"] =3D base.get_property("git.tag") + response["git.repo"] =3D base.data["repo"] + response["git.base"] =3D base.data["tag"] =20 def _poll_project(self, po): repo, branch =3D self._get_project_repo_and_branch(po) @@ -268,10 +259,7 @@ class GitModule(PatchewModule): obj =3D Message.objects.find_series(series) if not obj: raise Http404("Not found: " + series) - for p in obj.get_properties(): - if p.startswith("git.") and p !=3D "git.need-apply": - obj.set_property(p, None) - obj.set_property("git.need-apply", True) + self.mark_as_pending_apply(obj) return HttpResponseRedirect(request.META.get('HTTP_REFERER')) =20 def www_url_hook(self, urlpatterns): @@ -287,11 +275,9 @@ class ApplierGetView(APILoginRequiredView): allowed_groups =3D ["importers"] =20 def handle(self, request): - mp =3D MessageProperty.objects.filter(name=3D"git.need-apply", - value=3D'true', - message__is_complete=3DTrue).f= irst() - if mp: - return prepare_series(request, mp.message) + m =3D Message.objects.filter(results__name=3D"git", results__statu= s=3D"pending").first() + if m: + return prepare_series(request, m) =20 class ApplierReportView(APILoginRequiredView): name =3D "applier-report" @@ -299,12 +285,23 @@ class ApplierReportView(APILoginRequiredView): =20 def handle(self, request, project, message_id, tag, url, base, repo, failed, log): - s =3D Message.objects.series_heads().get(project__name=3Dproject, - message_id=3Dmessage_id) - s.set_property("git.tag", tag) - s.set_property("git.url", url) - s.set_property("git.base", base) - s.set_property("git.repo", repo) - s.set_property("git.apply-failed", failed) - s.set_property("git.apply-log", log) - s.set_property("git.need-apply", False) + p =3D Project.objects.get(name=3Dproject) + r =3D Message.objects.series_heads().get(project=3Dp, + message_id=3Dmessage_id).gi= t_result + r.log =3D log + if failed: + r.status =3D Result.FAILURE + else: + data =3D {} + data['repo'] =3D repo + data['tag'] =3D 'refs/tags/' + tag + if url: + data['url'] =3D url + elif url_template and tag: + url_template =3D p.get_property("git.url_template") + data['url'] =3D url_template.replace("%t", tag) + if base: + data['base'] =3D base + r.data =3D data + r.status =3D Result.SUCCESS + r.save() diff --git a/tests/test_git.py b/tests/test_git.py index d64f901..509949a 100755 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -14,7 +14,7 @@ sys.path.append(os.path.dirname(__file__)) from patchewtest import PatchewTestCase, main import shutil import subprocess -from api.models import Message +from api.models import Message, Result =20 class GitTest(PatchewTestCase): =20 @@ -34,37 +34,37 @@ class GitTest(PatchewTestCase): def do_apply(self): self.cli(["apply", "--applier-mode"]) for s in Message.objects.series_heads(): - self.assertFalse(s.get_property("git.need-apply")) + self.assertNotEqual(s.git_result.status, Result.PENDING) =20 def test_need_apply(self): self.cli_import("0001-simple-patch.mbox.gz") s =3D Message.objects.series_heads()[0] self.assertEqual(s.is_complete, True) - self.assertEqual(s.get_property("git.need-apply"), True) + self.assertEqual(s.git_result.status, Result.PENDING) self.do_apply() =20 def test_need_apply_multiple(self): self.cli_import("0004-multiple-patch-reviewed.mbox.gz") s =3D Message.objects.series_heads()[0] self.assertEqual(s.is_complete, True) - self.assertEqual(s.get_property("git.need-apply"), True) + self.assertEqual(s.git_result.status, Result.PENDING) self.do_apply() =20 def test_need_apply_incomplete(self): self.cli_import("0012-incomplete-series.mbox.gz") s =3D Message.objects.series_heads()[0] self.assertEqual(s.is_complete, False) - self.assertEqual(s.get_property("git.need-apply"), None) + self.assertEqual(s.git_result is None, True) =20 def test_apply(self): self.cli_import("0013-foo-patch.mbox.gz") self.do_apply() s =3D Message.objects.series_heads()[0] self.assertEqual(s.is_complete, True) - self.assertEqual(s.get_property("git.repo"), self.repo) - self.assertEqual(s.get_property("git.tag"), - "patchew/20160628014747.20971-1-famz@redhat.com") - self.assertEqual(s.get_property("git.url"), + self.assertEqual(s.git_result.data['repo'], self.repo) + self.assertEqual(s.git_result.data['tag'], + "refs/tags/patchew/20160628014747.20971-1-famz@re= dhat.com") + self.assertEqual(s.git_result.data['url'], self.repo + " patchew/20160628014747.20971-1-famz= @redhat.com") =20 def test_apply_with_base(self): @@ -74,10 +74,10 @@ class GitTest(PatchewTestCase): self.do_apply() s =3D Message.objects.series_heads().filter(message_id=3D"20160628= 014747.20971-2-famz@redhat.com")[0] self.assertEqual(s.is_complete, True) - self.assertEqual(s.get_property("git.repo"), self.repo) - self.assertEqual(s.get_property("git.tag"), - "patchew/20160628014747.20971-2-famz@redhat.com") - self.assertEqual(s.get_property("git.url"), + self.assertEqual(s.git_result.data['repo'], self.repo) + self.assertEqual(s.git_result.data['tag'], + "refs/tags/patchew/20160628014747.20971-2-famz@re= dhat.com") + self.assertEqual(s.git_result.data['url'], self.repo + " patchew/20160628014747.20971-2-famz= @redhat.com") =20 def test_apply_with_base_and_brackets(self): @@ -87,10 +87,10 @@ class GitTest(PatchewTestCase): self.do_apply() s =3D Message.objects.series_heads().filter(message_id=3D"20160628= 014747.20971-2-famz@redhat.com")[0] self.assertEqual(s.is_complete, True) - self.assertEqual(s.get_property("git.repo"), self.repo) - self.assertEqual(s.get_property("git.tag"), - "patchew/20160628014747.20971-2-famz@redhat.com") - self.assertEqual(s.get_property("git.url"), + self.assertEqual(s.git_result.data['repo'], self.repo) + self.assertEqual(s.git_result.data['tag'], + "refs/tags/patchew/20160628014747.20971-2-famz@re= dhat.com") + self.assertEqual(s.git_result.data['url'], self.repo + " patchew/20160628014747.20971-2-famz= @redhat.com") =20 def test_rest_need_apply(self): --=20 2.17.0 _______________________________________________ Patchew-devel mailing list Patchew-devel@redhat.com https://www.redhat.com/mailman/listinfo/patchew-devel From nobody Sat Apr 20 00:21:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=patchew-devel-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=patchew-devel-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1526972289063794.3382963025862; Mon, 21 May 2018 23:58:09 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 20CF6BB1E; Tue, 22 May 2018 06:58:08 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 0DD6060A9D; Tue, 22 May 2018 06:58:08 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id EF0F3180124E; Tue, 22 May 2018 06:58:07 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w4M6w6aG028216 for ; Tue, 22 May 2018 02:58:06 -0400 Received: by smtp.corp.redhat.com (Postfix) id B46882010CA5; Tue, 22 May 2018 06:58:06 +0000 (UTC) Received: from mx1.redhat.com (ext-mx13.extmail.prod.ext.phx2.redhat.com [10.5.110.42]) by smtp.corp.redhat.com (Postfix) with ESMTPS id AD42B2010CA3 for ; Tue, 22 May 2018 06:58:04 +0000 (UTC) Received: from mail-pg0-f45.google.com (mail-pg0-f45.google.com [74.125.83.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A16AC30BF189 for ; Tue, 22 May 2018 06:57:53 +0000 (UTC) Received: by mail-pg0-f45.google.com with SMTP id w3-v6so7426712pgv.12 for ; Mon, 21 May 2018 23:57:53 -0700 (PDT) Received: from localhost.localdomain ([208.181.63.202]) by smtp.gmail.com with ESMTPSA id y2-v6sm19818676pgp.92.2018.05.21.23.57.51 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 21 May 2018 23:57:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=GaMpNbjUytrjtFJBDEnMi40Fx2tsd2Y7xgncpDCEY/M=; b=LTTVFgTQJeGeSqNIN+/hLfuBcw8HhcIB5DudQ/QR9duWKaFSWj4gzNFmLRXH33uuax /212qJHA/4568kPrM6DD8LxYSMkn+I2oOho7fKOAurYzwlcpxmJMmlpZm23aqugWmIum 6h76vHjjs6xe9E3IXYFUNYXfXCCjDswPNY82VNeoQfaJJmzfMMXGlO+CS4DbYExzV3Dj YfYDFJlBMGG5CekneEcuPwu/h7cYe0oW96lkOQ3vFw0DJ8goQwM0uNLp55p3hG6xaAAN swVZc/NP44qNKZhXMf+GIsm2SoQlp5/5blRIWv4OdxlhHOdgo5yllaUfh6hcPuWvhcQN HKQQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=GaMpNbjUytrjtFJBDEnMi40Fx2tsd2Y7xgncpDCEY/M=; b=Pxn77e4P7bMmyzOT6PeVbpKF3aQzQ7j1tEW/xJUI9KLJc6G3UGkcgcHl3yR1D2BQmC +kPzkbArfpibLevhS5Q/8ltPM+UNWtVOMXyKDrGElYYMjJUkZW/mRNuj+MPoFcGRuhE4 Pm3pKmnssMGPU/WkW90quo+E/n0Ep2Z32Z7k/xQma/v3knCRN5xGugd156QYBLymVJAa zuQK4VaLX42pquSCbJrRi/yne/rnlhf6N6k81JFSZcYhCXjzO5iu8dh0mAfacP3u5UCp arbunRGdQDLyGU0aM3fCek06FAL3JjTCqtQk9zYMQSbaHrhoSQgCo9Uy+UHt2qWr33XI FTSQ== X-Gm-Message-State: ALKqPwdpD6xpzzjzS0F5qnbhXvtOOA7M/OVln+Jx5RnaTYxbgt9cMLTn t3TLjEG7/KBgRR1j9PsBdeFphzES X-Google-Smtp-Source: AB8JxZqX08yGqmKXg1aqLuoJ0dIKmpHQhkTYV5Jx0DUFjbq4IgBMKOIpMsfbxGuTTtBvs4R43ekjhA== X-Received: by 2002:a62:a21e:: with SMTP id m30-v6mr23194764pff.251.1526972272723; Mon, 21 May 2018 23:57:52 -0700 (PDT) From: Paolo Bonzini To: patchew-devel@redhat.com Date: Tue, 22 May 2018 08:57:36 +0200 Message-Id: <20180522065740.9710-9-pbonzini@redhat.com> In-Reply-To: <20180522065740.9710-1-pbonzini@redhat.com> References: <20180522065740.9710-1-pbonzini@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.42]); Tue, 22 May 2018 06:57:53 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.42]); Tue, 22 May 2018 06:57:53 +0000 (UTC) for IP:'74.125.83.45' DOMAIN:'mail-pg0-f45.google.com' HELO:'mail-pg0-f45.google.com' FROM:'paolo.bonzini@gmail.com' RCPT:'' X-RedHat-Spam-Score: 0.577 (DKIM_SIGNED, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_PASS, T_DKIM_INVALID) 74.125.83.45 mail-pg0-f45.google.com 74.125.83.45 mail-pg0-f45.google.com X-RedHat-Possible-Forgery: Paolo Bonzini X-Scanned-By: MIMEDefang 2.84 on 10.5.110.42 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.25 X-loop: patchew-devel@redhat.com Subject: [Patchew-devel] [PATCH 08/12] testing: track changes to the set of tests X-BeenThere: patchew-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Patchew development and discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: patchew-devel-bounces@redhat.com Errors-To: patchew-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Tue, 22 May 2018 06:58:08 +0000 (UTC) X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Use the new SetProperty event to recompute testing.done and testing.ready every time the set of tests changes. This removes the need to do so from the testing-get API, and it will also provide a perfect place to create PENDING records in the result table. --- mods/testing.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/mods/testing.py b/mods/testing.py index 98732e3..64952fb 100644 --- a/mods/testing.py +++ b/mods/testing.py @@ -118,6 +118,24 @@ class TestingModule(PatchewModule): elif isinstance(obj, Project) and name =3D=3D "git.head" \ and old_value !=3D value: self.clear_and_start_testing(obj) + elif isinstance(obj, Project) and name.startswith("testing.tests."= ) \ + and old_value !=3D value: + self.recalc_pending_tests(obj) + + def is_testing_done(self, obj, tn): + return obj.get_property("testing.report." + tn) + + def recalc_pending_tests(self, obj): + test_dict =3D self.get_tests(obj) + all_tests =3D set((k for k, v in test_dict.items() if v.get("enabl= ed", False))) + if len(all_tests): + done_tests =3D set((tn for tn in all_tests if self.is_testing_= done(obj, tn))) + if len(done_tests) < len(all_tests): + obj.set_property("testing.done", None) + obj.set_property("testing.ready", 1) + return + obj.set_property("testing.done", True) + obj.set_property("testing.ready", None) =20 def clear_and_start_testing(self, obj, test=3D""): for k in list(obj.get_properties().keys()): @@ -129,7 +147,7 @@ class TestingModule(PatchewModule): k.startswith("testing.report." + test) or \ k.startswith("testing.log." + test): obj.set_property(k, None) - obj.set_property("testing.ready", 1) + self.recalc_pending_tests(obj) =20 def www_view_testing_reset(self, request, project_or_series): if not request.user.is_authenticated: @@ -404,14 +422,10 @@ class TestingGetView(APILoginRequiredView): test=3Dtest) =20 def _find_applicable_test(self, user, project, tester, capabilities, o= bj): - all_tests =3D set([k for k, v in _instance.get_tests(obj).items() = if v["enabled"]]) - done_tests =3D set() for tn, t in _instance.get_tests(project).items(): if not t.get("enabled"): continue - all_tests.add(tn) - if obj.get_property("testing.report." + tn): - done_tests.add(tn) + if _instance.is_testing_done(obj, tn): continue # TODO: group? ok =3D True @@ -423,8 +437,6 @@ class TestingGetView(APILoginRequiredView): if not ok: continue return t - if len(all_tests) and all_tests.issubset(done_tests): - obj.set_property("testing.done", True) =20 def _find_project_test(self, request, po, tester, capabilities): if not po.get_property("testing.ready"): --=20 2.17.0 _______________________________________________ Patchew-devel mailing list Patchew-devel@redhat.com https://www.redhat.com/mailman/listinfo/patchew-devel From nobody Sat Apr 20 00:21:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=patchew-devel-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=patchew-devel-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 15269722894591010.1123947706388; Mon, 21 May 2018 23:58:09 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8AFD55A1F7; Tue, 22 May 2018 06:58:08 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 76DD130BF205; Tue, 22 May 2018 06:58:08 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 623E81801250; Tue, 22 May 2018 06:58:08 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w4M6w7LE028227 for ; Tue, 22 May 2018 02:58:07 -0400 Received: by smtp.corp.redhat.com (Postfix) id 789AE30001EB; Tue, 22 May 2018 06:58:07 +0000 (UTC) Received: from mx1.redhat.com (ext-mx05.extmail.prod.ext.phx2.redhat.com [10.5.110.29]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 7062830012C8 for ; Tue, 22 May 2018 06:58:07 +0000 (UTC) Received: from mail-pl0-f43.google.com (mail-pl0-f43.google.com [209.85.160.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 15C90385A57 for ; Tue, 22 May 2018 06:57:55 +0000 (UTC) Received: by mail-pl0-f43.google.com with SMTP id c19-v6so10307804pls.6 for ; Mon, 21 May 2018 23:57:55 -0700 (PDT) Received: from localhost.localdomain ([208.181.63.202]) by smtp.gmail.com with ESMTPSA id y2-v6sm19818676pgp.92.2018.05.21.23.57.52 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 21 May 2018 23:57:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=ecGiz2zEHzXwiajA82j3aQUE+pfBota3UBgnDtJqS1k=; b=BGePZIvQXE+DU8vRz/Vh9S5fvYQJDrOP+yPvR1VEQ326pkCTZDTOY0QjI/zT8RiclH F1xtAVI2H3Aoy1LZmIXMHIME3w1v+i/SKL1s0/08hLt2wQTTJgfsNsB/rafB57eOr1Nu lp6xH7HoQft9YL7UPlUAsy9LdXA1a9wxF5AWvrEczRT4ptqiMOVSmJqi6+6yuzC1t5kj zk+1u2z/ny5Mb/0xv4RckLMkJzcKORxfOe7+2G3XD1Mr33EyqOBiBLcEWz0OY9iKgus9 cdMWy2h2owmsd7jrOKTrwzsvhq7yXLcf/CGbrkcvmHZbudeHW83AszUaUs1UpPYLzEfU 9c1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=ecGiz2zEHzXwiajA82j3aQUE+pfBota3UBgnDtJqS1k=; b=q2Lwy52ubgSqUU2gxJQ+OPQIzcu9wP+x7V+heh725yg63/oRk8X+UBo+VRlx+2A/gb gyceOVk5tzXH+y6LeVaxj+l1jBLq5dz+nH53YD1xmr7Wx+0/2Wx7F/cmulTehv9ZjSfd byBlZ+rbh//R0QYxTVYUFgydd5AqlsV2Bjg0SNDibvoqEoz6yySyeS41XNBXMzGbEa2a 9/XA3JRU+2Oe7NtGJ9Z3QHCgpL7JLlkBSuZRXu7wPmk2979JphZPYZZKYUEMavk6lPLB tE1w7ZUW3epDsyxxUM2WmPwV3oMXVrTOgJTMMOaeq6xAbix41NolwxP06i6fNY/9REe2 hgSQ== X-Gm-Message-State: ALKqPwflEvGeajbtLbrceerH9D6syXxzaVLUgGrQL7JiVkAHWTLAMCcT ypuE3m8xCB0MO3xbCciI5vgYTGtM X-Google-Smtp-Source: AB8JxZp2T35WqwsylrnAthPHCt9ouowpY4NFlwaJfT2S0svPalqZ/200JxqT60sk56Y9PpU9m4ytVg== X-Received: by 2002:a17:902:24e:: with SMTP id 72-v6mr23110518plc.87.1526972273778; Mon, 21 May 2018 23:57:53 -0700 (PDT) From: Paolo Bonzini To: patchew-devel@redhat.com Date: Tue, 22 May 2018 08:57:37 +0200 Message-Id: <20180522065740.9710-10-pbonzini@redhat.com> In-Reply-To: <20180522065740.9710-1-pbonzini@redhat.com> References: <20180522065740.9710-1-pbonzini@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Tue, 22 May 2018 06:57:55 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Tue, 22 May 2018 06:57:55 +0000 (UTC) for IP:'209.85.160.43' DOMAIN:'mail-pl0-f43.google.com' HELO:'mail-pl0-f43.google.com' FROM:'paolo.bonzini@gmail.com' RCPT:'' X-RedHat-Spam-Score: -1.2 (DKIM_SIGNED, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_PASS, T_DKIM_INVALID) 209.85.160.43 mail-pl0-f43.google.com 209.85.160.43 mail-pl0-f43.google.com X-RedHat-Possible-Forgery: Paolo Bonzini X-Scanned-By: MIMEDefang 2.78 on 10.5.110.29 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.24 X-loop: patchew-devel@redhat.com Subject: [Patchew-devel] [PATCH 09/12] testing: switch to Result model X-BeenThere: patchew-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Patchew development and discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: patchew-devel-bounces@redhat.com Errors-To: patchew-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.26 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Tue, 22 May 2018 06:58:08 +0000 (UTC) X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" --- .../0029_populate_testing_results.py | 205 ++++++++++++++++++ mods/testing.py | 182 +++++++--------- tests/test_testing.py | 57 +++-- 3 files changed, 321 insertions(+), 123 deletions(-) create mode 100644 api/migrations/0029_populate_testing_results.py diff --git a/api/migrations/0029_populate_testing_results.py b/api/migratio= ns/0029_populate_testing_results.py new file mode 100644 index 0000000..0fa91ea --- /dev/null +++ b/api/migrations/0029_populate_testing_results.py @@ -0,0 +1,205 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations +from django.db.models import Count +from api.migrations import (get_property, get_property_raw, + load_property, set_property, delete_property_blob) + +import abc +from collections import defaultdict +from copy import copy +import datetime +import lzma + +# For Result's constant status values +import api.models + +class Converter(object, metaclass=3Dabc.ABCMeta): + def __init__(self, apps, schema_editor): + # We can't import the models directly as they may be a newer + # version than this migration expects. We use the historical versi= on. + self.Project =3D apps.get_model('api', 'Project') + self.Message =3D apps.get_model('api', 'Message') + self.MessageProperty =3D apps.get_model('api', 'MessageProperty') + self.ProjectProperty =3D apps.get_model('api', 'ProjectProperty') + self.Result =3D apps.get_model('api', 'Result') + + @abc.abstractmethod + def objects_filter_for_project(self, po): + pass + + @abc.abstractmethod + def set_property(self, obj, name, value): + pass + + @abc.abstractmethod + def get_property(self, obj, name): + pass + + @abc.abstractmethod + def get_properties(self, obj, **kwargs): + pass + + @abc.abstractmethod + def delete_property(self, obj, name): + pass + + def get_projects_with_tests(self): + return self.Project.objects.filter( + projectproperty__name__startswith=3D'testing.').distinct() + + def get_tests(self, po): + # Based on TestingModule.get_tests + ret =3D {} + props =3D self.ProjectProperty.objects.filter(name__startswith=3D'= testing.tests.', + project=3Dpo) + for p in props: + k =3D p.name + v =3D load_property(p) + tn =3D k[len("testing.tests."):] + if "." not in tn: + continue + an =3D tn[tn.find(".") + 1:] + tn =3D tn[:tn.find(".")] + ret.setdefault(tn, {}) + ret[tn][an] =3D v + return ret + + def do_result_from_properties(self): + for po in self.Project.objects.all(): + tests =3D self.get_tests(po) + for obj in self.objects_filter_for_project(po): + pending_status =3D api.models.Result.RUNNING \ + if self.get_property(obj, "testing.started") \ + else api.models.Result.PENDING + done_tests =3D set() + results =3D [] + for prop in self.get_properties(obj, name__startswith=3D't= esting.report.'): + tn =3D prop.name[len('testing.report.'):] + done_tests.add(tn) + r =3D self.Result() + report =3D load_property(prop) + passed =3D report["passed"] + del report["passed"] + log =3D self.get_property(obj, "testing.log." + tn) + r.name =3D 'testing.' + tn + r.status =3D api.models.Result.SUCCESS if passed else = api.models.Result.FAILURE + r.last_update =3D datetime.datetime.utcnow() + r.data =3D report + if log: + r.log_xz =3D lzma.compress(log.encode("utf-8")) + self.delete_property(obj, "testing.log." + tn) + r.save() + results.append(r) + self.delete_property(obj, "testing.report." + tn) + if self.get_property(obj, "testing.ready"): + for tn, test in tests.items(): + if tn in done_tests: + continue + r =3D self.Result() + r.name =3D 'testing.' + tn + r.status =3D pending_status + r.last_update =3D datetime.datetime.utcnow() + r.save() + results.append(r) + self.delete_property(obj, "testing.ready") + #print(obj, len(done_tests), len(tests) - len(done_tests)) + obj.results.add(*results) + try: + self.delete_property(obj, "testing.started") + self.delete_property(obj, "testing.failed") + self.delete_property(obj, "testing.start-time") + except: + pass + + def do_result_to_properties(self): + for po in self.Project.objects.all(): + for obj in self.objects_filter_for_project(po): + by_status =3D defaultdict(lambda: 0) + start_time =3D datetime.datetime.utcnow() + for r in obj.results.filter(name__startswith=3D'testing.'): + by_status[r.status] +=3D 1 + if r.status in (api.models.Result.SUCCESS, api.models.= Result.FAILURE): + tn =3D r.name[len('testing.'):] + report =3D copy(r.data) + report['passed'] =3D (r.status =3D=3D api.models.R= esult.SUCCESS) + self.set_property(obj, "testing.report." + tn, rep= ort) + if r.log_xz: + log =3D lzma.decompress(r.log_xz).decode("utf-= 8") + self.set_property(obj, "testing.log." + tn, lo= g) + else: + started =3D started or r.status =3D=3D api.models.= Result.RUNNING + if r.last_update < start_time: + start_time =3D r.last_update + #print(obj, dict(by_status)) + if by_status[api.models.Result.FAILURE]: + self.set_property(obj, "testing.failed", True) + if by_status[api.models.Result.RUNNING]: + self.set_property(obj, "testing.started", True) + self.set_property(obj, "testing.start-time", d.timesta= mp()) + if by_status[api.models.Result.RUNNING] + by_status[api.mo= dels.Result.PENDING]: + self.set_property(obj, "testing.ready", 1) + else: + self.set_property(obj, "testing.done", True) + obj.results.filter(name__startswith=3D'testing.').delete() + +class ProjectConverter(Converter): + def objects_filter_for_project(self, po): + yield po + + def set_property(self, obj, name, value): + set_property(self.ProjectProperty, name, value, project=3Dobj) + + def get_property(self, obj, name): + try: + return get_property(self.ProjectProperty, name, project=3Dobj) + except: + return None + + def get_properties(self, obj, **kwargs): + return self.ProjectProperty.objects.filter(project=3Dobj, **kwargs) + + def delete_property(self, obj, name): + delete_property_blob(self.ProjectProperty, name, project=3Dobj) + get_property_raw(self.ProjectProperty, name, project=3Dobj).delete= () + +class MessageConverter(Converter): + def objects_filter_for_project(self, po): + yield from self.Message.objects.filter(is_series_head=3DTrue, proj= ect=3Dpo) + + def set_property(self, obj, name, value): + set_property(self.MessageProperty, name, value, message=3Dobj) + + def get_property(self, obj, name): + try: + return get_property(self.MessageProperty, name, message=3Dobj) + except: + return None + + def get_properties(self, obj, **kwargs): + return self.MessageProperty.objects.filter(message=3Dobj, **kwargs) + + def delete_property(self, obj, name): + delete_property_blob(self.MessageProperty, name, message=3Dobj) + get_property_raw(self.MessageProperty, name, message=3Dobj).delete= () + +def result_from_properties(apps, schema_editor): + ProjectConverter(apps, schema_editor).do_result_from_properties() + MessageConverter(apps, schema_editor).do_result_from_properties() + +def result_to_properties(apps, schema_editor): + ProjectConverter(apps, schema_editor).do_result_to_properties() + MessageConverter(apps, schema_editor).do_result_to_properties() + +class Migration(migrations.Migration): + + dependencies =3D [ + ('api', '0028_populate_git_results'), + ] + + operations =3D [ + migrations.RunPython(result_from_properties, + reverse_code=3Dresult_to_properties), + ] diff --git a/mods/testing.py b/mods/testing.py index 64952fb..ed40a92 100644 --- a/mods/testing.py +++ b/mods/testing.py @@ -11,6 +11,7 @@ from django.conf.urls import url from django.http import HttpResponseForbidden, Http404, HttpResponseRedire= ct from django.core.exceptions import PermissionDenied +from django.db.models import Q from django.urls import reverse from django.utils.html import format_html from mod import PatchewModule @@ -42,10 +43,8 @@ class TestingLogViewer(LogView): obj =3D Message.objects.find_series(project_or_series) if not obj: raise Http404("Object not found: " + project_or_series) - log =3D obj.get_property("testing.log." + testing_name) - if log is None: - raise Http404("Testing log not found: " + testing_name) - return log + r =3D _instance.get_testing_result(obj, testing_name) + return r.log =20 =20 class TestingModule(PatchewModule): @@ -122,31 +121,44 @@ class TestingModule(PatchewModule): and old_value !=3D value: self.recalc_pending_tests(obj) =20 - def is_testing_done(self, obj, tn): - return obj.get_property("testing.report." + tn) + def get_testing_results(self, obj, *args, **kwargs): + return obj.results.filter(name__startswith=3D'testing.', *args, **= kwargs) + + def get_testing_result(self, obj, name): + try: + return obj.results.get(name=3D'testing.' + name) + except: + raise Http404("Test doesn't exist") + + def get_test_name(self, result): + return result.name[len('testing.'):] =20 def recalc_pending_tests(self, obj): test_dict =3D self.get_tests(obj) all_tests =3D set((k for k, v in test_dict.items() if v.get("enabl= ed", False))) + for r in self.get_testing_results(obj, status=3DResult.PENDING): + r.delete() + obj.results.remove(r) if len(all_tests): - done_tests =3D set((tn for tn in all_tests if self.is_testing_= done(obj, tn))) + done_tests =3D [self.get_test_name(r) for r in self.get_testin= g_results(obj)] + for tn in all_tests: + if not tn in done_tests: + r =3D Result(name=3D'testing.' + tn, status=3DResult.P= ENDING) + r.save() + obj.results.add(r) if len(done_tests) < len(all_tests): obj.set_property("testing.done", None) - obj.set_property("testing.ready", 1) return obj.set_property("testing.done", True) - obj.set_property("testing.ready", None) =20 def clear_and_start_testing(self, obj, test=3D""): for k in list(obj.get_properties().keys()): - if (not test and k =3D=3D "testing.started") or \ - (not test and k =3D=3D "testing.start-time") or \ - (not test and k =3D=3D "testing.failed") or \ - k =3D=3D "testing.done" or \ - k =3D=3D "testing.tested-head" or \ - k.startswith("testing.report." + test) or \ - k.startswith("testing.log." + test): + if k =3D=3D "testing.done" or \ + k =3D=3D "testing.tested-head": obj.set_property(k, None) + for r in self.get_testing_results(obj): + r.delete() + obj.results.remove(r) self.recalc_pending_tests(obj) =20 def www_view_testing_reset(self, request, project_or_series): @@ -202,24 +214,21 @@ class TestingModule(PatchewModule): raise Exception("Series doesn't exist") project =3D obj.project.name user =3D request.user - log_url =3D self.reverse_testing_log(obj, test, request=3Drequest) - html_log_url =3D self.reverse_testing_log(obj, test, request=3Dreq= uest, html=3DTrue) - obj.set_property("testing.report." + test, - {"passed": passed, - "is_timeout": is_timeout, - "user": user.username, - "tester": tester or user.username, - }) - obj.set_property("testing.log." + test, log) - if not passed: - obj.set_property("testing.failed", True) - reports =3D [x for x in obj.get_properties() if x.startswith("test= ing.report.")] - done_tests =3D set([x[len("testing.report."):] for x in reports]) - all_tests =3D set([k for k, v in self.get_tests(obj).items() if v[= "enabled"]]) - if all_tests.issubset(done_tests): + + r =3D self.get_testing_result(obj, test) + r.data =3D {"is_timeout": is_timeout, + "user": user.username, + "tester": tester or user.username} + r.log =3D log + r.status =3D Result.SUCCESS if passed else Result.FAILURE + r.save() + if not self.get_testing_results(obj, + status__in=3D(Result.PENDING, Result.RUNNING)).exis= ts(): obj.set_property("testing.done", True) - obj.set_property("testing.ready", None) obj.set_property("testing.tested-head", head) + + log_url =3D self.reverse_testing_log(obj, test, request=3Drequest) + html_log_url =3D self.reverse_testing_log(obj, test, request=3Dreq= uest, html=3DTrue) emit_event("TestingReport", tester=3Dtester, user=3Duser.username, obj=3Dobj, passed=3Dpassed, test=3Dtest, log=3Dlog, lo= g_url=3Dlog_url, html_log_url=3Dhtml_log_url, is_timeout=3Dis_timeout) @@ -257,11 +266,8 @@ class TestingModule(PatchewModule): "class": "warning", "icon": "refresh", }] - for pn, p in obj.get_properties().items(): - if not pn.startswith("testing.report."): - continue - tn =3D pn[len("testing.report."):] - failed =3D not p["passed"] + for r in self.get_testing_results(obj, ~Q(status=3DResult.PENDING)= ): + tn =3D self.get_test_name(r) ret.append({"url": url + "&test=3D" + tn, "title": format_html("Reset {} testing stat= e", tn), "class": "warning", @@ -270,39 +276,16 @@ class TestingModule(PatchewModule): return ret =20 def rest_results_hook(self, obj, results, detailed=3DFalse): - all_tests =3D set([k for k, v in _instance.get_tests(obj).items() = if v["enabled"]]) - for pn, p in obj.get_properties().items(): - if not pn.startswith("testing.report."): - continue - tn =3D pn[len("testing.report."):] - try: - all_tests.remove(tn) - except: - pass - failed =3D not p["passed"] - passed_str =3D Result.FAILURE if failed else Result.SUCCESS - if detailed: - log =3D obj.get_property("testing.log." + tn) - else: - log =3D None - - data =3D p.copy() - del data['passed'] - results.append(ResultTuple(name=3D'testing.' + tn, obj=3Dobj, = status=3Dpassed_str, - log=3Dlog, data=3Ddata, renderer=3Dself)) - - if obj.get_property("testing.ready"): - for tn in all_tests: - results.append(ResultTuple(name=3D'testing.' + tn, obj=3Do= bj, status=3D'pending')) + Result.get_result_tuples(obj, "testing", results) =20 def prepare_message_hook(self, request, message, detailed): if not message.is_series_head: return if message.project.maintained_by(request.user) \ - and message.get_property("testing.started"): + and self.get_testing_results(obj, ~Q(status=3DResult.PENDI= NG)).exists(): message.extra_ops +=3D self._build_reset_ops(message) =20 - if message.get_property("testing.failed"): + if self.get_testing_results(message, status=3DResult.FAILURE).exis= ts(): message.status_tags.append({ "title": "Testing failed", "url": reverse("series_detail", @@ -421,61 +404,56 @@ class TestingGetView(APILoginRequiredView): }, test=3Dtest) =20 - def _find_applicable_test(self, user, project, tester, capabilities, o= bj): - for tn, t in _instance.get_tests(project).items(): - if not t.get("enabled"): + def _find_applicable_test(self, user, po, tester, capabilities, **kwar= gs): + q =3D Result.objects.filter(status__in=3D(Result.PENDING, Result.R= UNNING), + name__startswith=3D'testing.', **kwargs) + tests =3D _instance.get_tests(po) + for r in q: + tn =3D _instance.get_test_name(r) + t =3D tests.get(tn, None) + # Shouldn't happen, but let's protect against it + if not t: continue - if _instance.is_testing_done(obj, tn): - continue - # TODO: group? - ok =3D True reqs =3D t.get("requirements", "") for r in [x.strip() for x in reqs.split(",") if x]: if r not in capabilities: - ok =3D False break - if not ok: - continue - return t + else: + yield r, t =20 def _find_project_test(self, request, po, tester, capabilities): - if not po.get_property("testing.ready"): - return head =3D po.get_property("git.head") repo =3D po.git tested =3D po.get_property("testing.tested-head") if not head or not repo: - return - test =3D self._find_applicable_test(request.user, po, - tester, capabilities, po) - if not test: - return - td =3D self._generate_project_test_data(po.name, repo, head, teste= d, test) - return po, td + return None + candidates =3D self._find_applicable_test(request.user, po, tester= , capabilities, + project=3Dpo) + for r, test in candidates: + td =3D self._generate_project_test_data(po.name, repo, head, t= ested, test) + return r, po, td + return None =20 def _find_series_test(self, request, po, tester, capabilities): - q =3D MessageProperty.objects.filter(name=3D"testing.ready", - value=3D1, - message__project=3Dpo) + candidates =3D self._find_applicable_test(request.user, po, tester= , capabilities, + message__project=3Dpo) candidate =3D None - for prop in q: - s =3D prop.message - test =3D self._find_applicable_test(request.user, po, - tester, capabilities, s) - if not test: - continue - if not s.get_property("testing.started"): - candidate =3D s, test + earliest_start_time =3D None + for r, test in candidates: + s =3D r.message_set.first() + if r.status =3D=3D Result.PENDING: + candidate =3D r, s, test break # Pick one series that started test the earliest if not candidate or \ - s.get_property("testing.start-time") < \ - candidate[0].get_property("testing.start-time"): - candidate =3D s, test + r.last_update < earliest_start_time: + candidate =3D r, s, test + earliest_start_time =3D r.last_update if not candidate: return None - return candidate[0], \ - self._generate_series_test_data(candidate[0], candidate[1]) + + td =3D self._generate_series_test_data(candidate[1], candidate[2]) + return candidate[0], candidate[1], td =20 def handle(self, request, project, tester, capabilities): # Try project head test first @@ -486,9 +464,9 @@ class TestingGetView(APILoginRequiredView): candidate =3D self._find_series_test(request, po, tester, capa= bilities) if not candidate: return - obj, test_data =3D candidate - obj.set_property("testing.started", True) - obj.set_property("testing.start-time", time.time()) + r, obj, test_data =3D candidate + r.status =3D Result.RUNNING + r.save() return test_data =20 class TestingReportView(APILoginRequiredView): diff --git a/tests/test_testing.py b/tests/test_testing.py index 8f831a1..b5314cf 100755 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -14,7 +14,7 @@ import os import subprocess sys.path.append(os.path.dirname(__file__)) from patchewtest import PatchewTestCase, main -from api.models import Message +from api.models import Message, Result =20 def create_test(project, name): prefix =3D "testing.tests." + name + "." @@ -35,14 +35,28 @@ class TestingTestCase(PatchewTestCase, metaclass=3Dabc.= ABCMeta): =20 create_test(self.p, "a") =20 - def _do_testing_done(self, obj, log, report): - if not 'passed' in report: - report['passed'] =3D True - obj.set_property("testing.report.tests", report) - if log is not None: - obj.set_property("testing.log.tests", log) + def modify_test_result(self, obj, **kwargs): + need_add =3D False + try: + r =3D obj.results.get(name=3D'testing.a') + except: + r =3D Result(name=3D'testing.a') + need_add =3D True + if not 'status' in kwargs: + kwargs['status'] =3D Result.PENDING + + if len(kwargs): + for k, v in kwargs.items(): + setattr(r, k, v) + r.save() + if need_add: + obj.results.add(r) + + def _do_testing_done(self, obj, **kwargs): + if not 'status' in kwargs: + kwargs['status'] =3D Result.SUCCESS + self.modify_test_result(obj, **kwargs) obj.set_property("testing.done", True) - obj.set_property("testing.ready", None) =20 def do_testing_report(self, **report): self.api_login() @@ -81,6 +95,8 @@ class TestingTestCase(PatchewTestCase, metaclass=3Dabc.AB= CMeta): tester=3D"dummy tester", capabilities=3D[]) self.assertIn("head", td) + resp =3D self.get_test_result('a') + self.assertEquals(resp.data['status'], 'running') =20 def test_done(self): self.do_testing_done() @@ -96,8 +112,8 @@ class TestingTestCase(PatchewTestCase, metaclass=3Dabc.A= BCMeta): self.assertEquals(resp.data['status'], 'pending') =20 def test_rest_done_success(self): - self.do_testing_done(log=3D'everything good!', passed=3DTrue) - resp =3D self.get_test_result('tests') + self.do_testing_done(log=3D'everything good!', status=3DResult.SUC= CESS) + resp =3D self.get_test_result('a') self.assertEquals(resp.data['status'], 'success') self.assertEquals(resp.data['log'], 'everything good!') log =3D self.client.get(resp.data['log_url']) @@ -105,10 +121,9 @@ class TestingTestCase(PatchewTestCase, metaclass=3Dabc= .ABCMeta): self.assertEquals(log.content, b'everything good!') =20 def test_rest_done_failure(self): - self.do_testing_done(log=3D'sorry no good', passed=3DFalse, random= _stuff=3D'xyz') - resp =3D self.get_test_result('tests') + self.do_testing_done(log=3D'sorry no good', status=3DResult.FAILUR= E) + resp =3D self.get_test_result('a') self.assertEquals(resp.data['status'], 'failure') - self.assertEquals(resp.data['data']['random_stuff'], 'xyz') self.assertEquals(resp.data['log'], 'sorry no good') log =3D self.client.get(resp.data['log_url']) self.assertEquals(log.status_code, 200) @@ -151,8 +166,8 @@ class MessageTestingTest(TestingTestCase): self.msg.set_property("git.tag", "dummy tag") self.msg.set_property("git.base", "dummy base") =20 - def do_testing_done(self, log=3DNone, **report): - self._do_testing_done(self.msg, log, report) + def do_testing_done(self, **kwargs): + self._do_testing_done(self.msg, **kwargs) =20 def do_testing_report(self, **report): r =3D super(MessageTestingTest, self).do_testing_report(**report) @@ -164,17 +179,18 @@ class MessageTestingTest(TestingTestCase): self.PROJECT_BASE, self.msg.message= _id, test_name)) =20 def test_testing_ready(self): - self.assertTrue(self.msg.get_property("testing.ready")) # Set property through series_heads elements must be handled the s= ame self.msg.set_property("git.repo", None) self.msg.set_property("git.tag", None) - self.msg.set_property("testing.ready", None) + self.assertEqual(self.msg.results.filter(name=3D'testing.a').first= ().status, + Result.PENDING) msg =3D Message.objects.series_heads()[0] self.assertEqual(self.msg.message_id, msg.message_id) msg.set_property("git.repo", "dummy repo") msg.set_property("git.tag", "dummy tag") msg.set_property("git.base", "dummy base") - self.assertTrue(msg.get_property("testing.ready")) + self.assertEqual(self.msg.results.filter(name=3D'testing.a').first= ().status, + Result.PENDING) =20 class ProjectTestingTest(TestingTestCase): =20 @@ -182,10 +198,9 @@ class ProjectTestingTest(TestingTestCase): super(ProjectTestingTest, self).setUp() self.p.set_property("git.head", "5678") self.p.set_property("testing.tested-head", "1234") - self.p.set_property("testing.ready", 1) =20 - def do_testing_done(self, log=3DNone, **report): - self._do_testing_done(self.p, log, report) + def do_testing_done(self, **kwargs): + self._do_testing_done(self.p, **kwargs) =20 def do_testing_report(self, **report): r =3D super(ProjectTestingTest, self).do_testing_report(**report) --=20 2.17.0 _______________________________________________ Patchew-devel mailing list Patchew-devel@redhat.com https://www.redhat.com/mailman/listinfo/patchew-devel From nobody Sat Apr 20 00:21:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=patchew-devel-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=patchew-devel-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1526972290106594.1447564920951; Mon, 21 May 2018 23:58:10 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3B20130025E7; Tue, 22 May 2018 06:58:09 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 27A665C1B7; Tue, 22 May 2018 06:58:09 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 131274BB78; Tue, 22 May 2018 06:58:09 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w4M6w7Nk028221 for ; Tue, 22 May 2018 02:58:07 -0400 Received: by smtp.corp.redhat.com (Postfix) id 060181001F50; Tue, 22 May 2018 06:58:07 +0000 (UTC) Received: from mx1.redhat.com (ext-mx09.extmail.prod.ext.phx2.redhat.com [10.5.110.38]) by smtp.corp.redhat.com (Postfix) with ESMTPS id F35A01001F46 for ; Tue, 22 May 2018 06:58:06 +0000 (UTC) Received: from mail-pg0-f44.google.com (mail-pg0-f44.google.com [74.125.83.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A59A6EC559 for ; Tue, 22 May 2018 06:57:55 +0000 (UTC) Received: by mail-pg0-f44.google.com with SMTP id a3-v6so2501854pgt.13 for ; Mon, 21 May 2018 23:57:55 -0700 (PDT) Received: from localhost.localdomain ([208.181.63.202]) by smtp.gmail.com with ESMTPSA id y2-v6sm19818676pgp.92.2018.05.21.23.57.53 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 21 May 2018 23:57:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=YgIqdwjr/doaYBmPWNn+KLg2E//gzZKfrAkGh3lEA/k=; b=WneHZXGWGv3z4ncrRIG8q+I4AnbjQk+DCiBO6vYeQ56tROV048sKb5b/ec3zCKs1MY emZLBgEpDH0khVaQlIk9pRqeQz0k48zkgYeBrJdn4zVH5qyI5TXIH0D2daF1CJjgFAtL b8qPxML5Mr/+1uKCRAltd5DYKnZCT3O+W1wCzx8leuDdnu75ErDf8lydaxg+SsPiwtAl Pi1ZIk045OxEBgRHWA379rOtOCehqTOZZE5nsxg8q+Jvbx2ZmzQJ+j2MRCAfmDqglfVs nGHiBc8eS3ctZ2NxM2BNGU9QQRo4ytDY6EGR1rjkxXXwljWY/yMfzD1sQHo+JCgwSOwo 0xAA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=YgIqdwjr/doaYBmPWNn+KLg2E//gzZKfrAkGh3lEA/k=; b=IKOe5WqOjMlWb1JUuFgDhfDmFKKXFnWcPrTIqSTpzi8pSCwK80KVXc1uLtq4JGFDMp g2aC/uGL4i2i1JO2dKyP64+AGJxU4fp3DnBAYS9k86RPvlX7+1a+H4TLDDEpfplnm3A0 Bi8twP9TQ6AFHicz49RywC0DxDabYpQRgJC7qP5OQhZHjX7Qwb1hsDrZ+UnGkBEHUj4e GS6Lrr0s9o9e7hBlJfkhUc+VYq0NwZI0miYzgKZG5MDeH5TKURhw1OMlsyUU2+oKCT83 boQkHg1B8Gp8fmn+ALD8TJTU0JPDGZpHxuDw6cOdEdED22uNZnHugPtrCyFm9CGxFAJJ 27Yg== X-Gm-Message-State: ALKqPwfdhj7k5dpL34kE47Nnrd7tCx8h2Ck01u0RPI5TZiDNaUt/c91l YMbgykeeSq3dizfRjBxlQy4T4kdy X-Google-Smtp-Source: AB8JxZqhGzZX2RivZH//VLqi5NEDnp8VcsLgnNLo6qxNdOZcIHjeEYAwFo52Zs42dC2tBwqy1DHZVw== X-Received: by 2002:a65:5382:: with SMTP id x2-v6mr7194437pgq.160.1526972274656; Mon, 21 May 2018 23:57:54 -0700 (PDT) From: Paolo Bonzini To: patchew-devel@redhat.com Date: Tue, 22 May 2018 08:57:38 +0200 Message-Id: <20180522065740.9710-11-pbonzini@redhat.com> In-Reply-To: <20180522065740.9710-1-pbonzini@redhat.com> References: <20180522065740.9710-1-pbonzini@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Tue, 22 May 2018 06:57:55 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Tue, 22 May 2018 06:57:55 +0000 (UTC) for IP:'74.125.83.44' DOMAIN:'mail-pg0-f44.google.com' HELO:'mail-pg0-f44.google.com' FROM:'paolo.bonzini@gmail.com' RCPT:'' X-RedHat-Spam-Score: -1.2 (DKIM_SIGNED, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_PASS, T_DKIM_INVALID) 74.125.83.44 mail-pg0-f44.google.com 74.125.83.44 mail-pg0-f44.google.com X-RedHat-Possible-Forgery: Paolo Bonzini X-Scanned-By: MIMEDefang 2.78 on 10.5.110.38 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-loop: patchew-devel@redhat.com Subject: [Patchew-devel] [PATCH 10/12] complete switch to database-based Results X-BeenThere: patchew-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Patchew development and discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: patchew-devel-bounces@redhat.com Errors-To: patchew-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.42]); Tue, 22 May 2018 06:58:09 +0000 (UTC) X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" All results are stored in the database now and there is no need for the ResultTuple infrastructure. Remove all the code invoking the rest_results_hook and switch ResultsViewSet and ResultSerializer to be model-based. Signed-off-by: Paolo Bonzini --- api/models.py | 46 --------------------------------- api/rest.py | 68 +++++++++++++++++++------------------------------ mods/git.py | 9 +++---- mods/testing.py | 9 +++---- www/views.py | 17 +++++-------- 5 files changed, 38 insertions(+), 111 deletions(-) diff --git a/api/models.py b/api/models.py index ee54d04..f7065ca 100644 --- a/api/models.py +++ b/api/models.py @@ -16,7 +16,6 @@ import re =20 from django.core import validators from django.db import models -from django.db.models import Q from django.contrib.auth.models import User from django.urls import reverse import jsonfield @@ -99,14 +98,6 @@ class Result(models.Model): log_url =3D request.build_absolute_uri(log_url) return log_url =20 - @staticmethod - def get_result_tuples(obj, module, results): - name_filter =3D Q(name=3Dmodule) | Q(name__startswith=3Dmodule + '= .') - renderer =3D mod.get_module(module) - for r in obj.results.filter(name_filter): - results.append(ResultTuple(name=3Dr.name, obj=3Dobj, status=3D= r.status, - log=3Dr.log, data=3Dr.data, rendere= r=3Drenderer)) - class Project(models.Model): name =3D models.CharField(max_length=3D1024, db_index=3DTrue, unique= =3DTrue, help_text=3D"""The name of the project""") @@ -678,40 +669,3 @@ class Module(models.Model): =20 def __str__(self): return self.name - -class ResultTuple(namedtuple("ResultTuple", "name status log obj data rend= erer")): - __slots__ =3D () - - def __new__(cls, name, status, obj, log=3DNone, data=3DNone, renderer= =3DNone): - if status not in Result.VALID_STATUSES: - raise ValueError("invalid value '%s' for status field" % statu= s) - return super(cls, ResultTuple).__new__(cls, status=3Dstatus, log= =3Dlog, - obj=3Dobj, data=3Ddata, name=3Dn= ame, renderer=3Drenderer) - - def is_success(self): - return self.status =3D=3D Result.SUCCESS - - def is_failure(self): - return self.status =3D=3D Result.FAILURE - - def is_completed(self): - return self.is_success() or self.is_failure() - - def is_pending(self): - return self.status =3D=3D Result.PENDING - - def is_running(self): - return self.status =3D=3D Result.RUNNING - - def render(self): - if self.renderer is None: - return None - return self.renderer.render_result(self) - - def get_log_url(self, request=3DNone): - if not self.is_completed() or self.renderer is None: - return None - log_url =3D self.renderer.get_result_log_url(self.obj, self.name) - if log_url is not None and request is not None: - log_url =3D request.build_absolute_uri(log_url) - return log_url diff --git a/api/rest.py b/api/rest.py index f36cf28..0a85f10 100644 --- a/api/rest.py +++ b/api/rest.py @@ -14,7 +14,7 @@ from django.http import Http404 from django.template import loader =20 from mod import dispatch_module_hook -from .models import Project, Message +from .models import Project, Message, Result from .search import SearchEngine from rest_framework import (permissions, serializers, viewsets, filters, mixins, generics, renderers, status) @@ -416,7 +416,7 @@ class MessagesViewSet(BaseMessageViewSet): =20 class HyperlinkedResultField(HyperlinkedIdentityField): def get_url(self, result, view_name, request, format): - obj =3D result.obj + obj =3D self.context['parent_obj'] kwargs =3D {'name': result.name} if isinstance(obj, Message): kwargs['projects_pk'] =3D obj.project_id @@ -425,65 +425,49 @@ class HyperlinkedResultField(HyperlinkedIdentityField= ): kwargs['projects_pk'] =3D obj.id return self.reverse(view_name, kwargs=3Dkwargs, request=3Drequest,= format=3Dformat) =20 -class ResultSerializer(serializers.Serializer): +class ResultSerializer(serializers.ModelSerializer): + class Meta: + model =3D Result + fields =3D ('resource_uri', 'name', 'status', 'last_update', 'data= ', 'log_url') + resource_uri =3D HyperlinkedResultField(view_name=3D'results-detail') - name =3D CharField() - status =3D CharField() # one of 'failure', 'success', 'pending', 'runn= ing' log_url =3D SerializerMethodField(required=3DFalse) data =3D JSONField(required=3DFalse) =20 def get_log_url(self, obj): + parent_obj =3D self.context['parent_obj'] request =3D self.context['request'] - return obj.get_log_url(request) + return obj.get_log_url(parent_obj, request) =20 class ResultSerializerFull(ResultSerializer): + class Meta: + model =3D Result + fields =3D ResultSerializer.Meta.fields + ('log',) + + # The database field is log_xz, so this is needed here log =3D CharField(required=3DFalse) =20 -class ResultsViewSet(viewsets.ViewSet, generics.GenericAPIView): +class ResultsViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, + viewsets.GenericViewSet): lookup_field =3D 'name' lookup_value_regex =3D '[^/]+' - permission_classes =3D (PatchewPermission,) + + def get_queryset(self): + return self.get_parent_object().results.all().order_by('name') + + def get_serializer_context(self): + return {'parent_obj': self.get_parent_object(), 'request': self.re= quest} =20 def get_serializer_class(self, *args, **kwargs): if self.lookup_field in self.kwargs: return ResultSerializerFull return ResultSerializer =20 - def get_results(self, detailed): - queryset =3D self.get_queryset() - try: - obj =3D queryset[0] - except IndexError: - raise Http404 - results =3D [] - dispatch_module_hook("rest_results_hook", obj=3Dobj, results=3Dres= ults, - detailed=3Ddetailed) - return {x.name: x for x in results} - - def list(self, request, *args, **kwargs): - results =3D self.get_results(detailed=3DFalse).values() - serializer =3D self.get_serializer(results, many=3DTrue) - # Fake paginator response for forwards-compatibility, in case - # this ViewSet becomes model-based - return Response(OrderedDict([ - ('count', len(results)), - ('results', serializer.data) - ])) - - def retrieve(self, request, name, *args, **kwargs): - results =3D self.get_results(detailed=3DTrue) - try: - result =3D results[name] - except KeyError: - raise Http404 - serializer =3D self.get_serializer(result) - return Response(serializer.data) - class ProjectResultsViewSet(ResultsViewSet): - def get_queryset(self): - return Project.objects.filter(id=3Dself.kwargs['projects_pk']) + def get_parent_object(self): + return Project.objects.filter(id=3Dself.kwargs['projects_pk']).fir= st() =20 class SeriesResultsViewSet(ResultsViewSet): - def get_queryset(self): + def get_parent_object(self): return Message.objects.filter(project=3Dself.kwargs['projects_pk'], - message_id=3Dself.kwargs['series_mes= sage_id']) + message_id=3Dself.kwargs['series_mes= sage_id']).first() diff --git a/mods/git.py b/mods/git.py index d77ab0e..67ef723 100644 --- a/mods/git.py +++ b/mods/git.py @@ -18,7 +18,7 @@ from django.core.exceptions import PermissionDenied from django.utils.html import format_html from mod import PatchewModule from event import declare_event, register_handler, emit_event -from api.models import Message, MessageProperty, Project, Result, ResultTu= ple +from api.models import Message, MessageProperty, Project, Result from api.rest import PluginMethodField from api.views import APILoginRequiredView, prepare_series from patchew.logviewer import LogView @@ -141,9 +141,6 @@ class GitModule(PatchewModule): def rest_series_fields_hook(self, request, fields, detailed): fields['based_on'] =3D PluginMethodField(obj=3Dself, required=3DFa= lse) =20 - def rest_results_hook(self, obj, results, detailed=3DFalse): - Result.get_result_tuples(obj, "git", results) - def prepare_message_hook(self, request, message, detailed): if not message.is_series_head: return @@ -182,11 +179,11 @@ class GitModule(PatchewModule): "class": "warning", }) =20 - def render_result(self, result): + def render_result(self, result, obj): if not result.is_completed(): return None =20 - log_url =3D result.get_log_url() + log_url =3D result.get_log_url(obj) html_log_url =3D log_url + "?html=3D1" colorbox_a =3D format_html('apply log', html_log_url, log_url) diff --git a/mods/testing.py b/mods/testing.py index ed40a92..b09989b 100644 --- a/mods/testing.py +++ b/mods/testing.py @@ -18,7 +18,7 @@ from mod import PatchewModule import time import math from api.views import APILoginRequiredView -from api.models import Message, MessageProperty, Project, Result, ResultTu= ple +from api.models import Message, MessageProperty, Project, Result from api.search import SearchEngine from event import emit_event, declare_event, register_handler from patchew.logviewer import LogView @@ -275,9 +275,6 @@ class TestingModule(PatchewModule): }) return ret =20 - def rest_results_hook(self, obj, results, detailed=3DFalse): - Result.get_result_tuples(obj, "testing", results) - def prepare_message_hook(self, request, message, detailed): if not message.is_series_head: return @@ -308,12 +305,12 @@ class TestingModule(PatchewModule): tn =3D name[len("testing."):] return self.reverse_testing_log(obj, tn, html=3DFalse) =20 - def render_result(self, result): + def render_result(self, result, obj): if not result.is_completed(): return None pn =3D result.name tn =3D pn[len("testing."):] - log_url =3D result.get_log_url() + log_url =3D result.get_log_url(obj) html_log_url =3D log_url + '&html=3D1' passed_str =3D "failed" if result.is_failure() else "passed" return format_html('Test {} {}', diff --git a/www/views.py b/www/views.py index c2010c5..5685f23 100644 --- a/www/views.py +++ b/www/views.py @@ -92,19 +92,14 @@ def prepare_series(request, s, skip_patches=3DFalse): return r =20 def prepare_results(request, obj): - results =3D [] - dispatch_module_hook("rest_results_hook", obj=3Dobj, - results=3Dresults, detailed=3DFalse) - - results_dicts =3D [] - for result in results: - html =3D result.render() + rendered_results =3D [] + for result in obj.results.all(): + html =3D result.render(obj) if html is None: continue - d =3D result._asdict() - d['html'] =3D html - results_dicts.append(d) - return results_dicts + result.html =3D html + rendered_results.append(result) + return rendered_results =20 def prepare_series_list(request, sl): return [prepare_message(request, s.project, s, False) for s in sl] --=20 2.17.0 _______________________________________________ Patchew-devel mailing list Patchew-devel@redhat.com https://www.redhat.com/mailman/listinfo/patchew-devel From nobody Sat Apr 20 00:21:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=patchew-devel-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=patchew-devel-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1526972289572843.2946300606432; Mon, 21 May 2018 23:58:09 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id AA5A71AD5D1; Tue, 22 May 2018 06:58:08 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 9A9B45D756; Tue, 22 May 2018 06:58:08 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 7CFFA180124E; Tue, 22 May 2018 06:58:08 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w4M6w7k8028239 for ; Tue, 22 May 2018 02:58:07 -0400 Received: by smtp.corp.redhat.com (Postfix) id E570F1001F50; Tue, 22 May 2018 06:58:07 +0000 (UTC) Received: from mx1.redhat.com (ext-mx08.extmail.prod.ext.phx2.redhat.com [10.5.110.32]) by smtp.corp.redhat.com (Postfix) with ESMTPS id DCD001001F46 for ; Tue, 22 May 2018 06:58:07 +0000 (UTC) Received: from mail-pg0-f52.google.com (mail-pg0-f52.google.com [74.125.83.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id AC4ACC005F86 for ; Tue, 22 May 2018 06:57:56 +0000 (UTC) Received: by mail-pg0-f52.google.com with SMTP id a13-v6so7437120pgu.4 for ; Mon, 21 May 2018 23:57:56 -0700 (PDT) Received: from localhost.localdomain ([208.181.63.202]) by smtp.gmail.com with ESMTPSA id y2-v6sm19818676pgp.92.2018.05.21.23.57.54 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 21 May 2018 23:57:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=tz1xxw376W8fEk8woSoKxZezbGh5wAYhdpLhFN+ffhE=; b=W5pFxRb1FS7eTxQZ/JwzY11TARFEWg5b2mJC9feDz1uB48CKumeKUbKappJN3lGH/z B265siueiNT0lG8e0AR6Rfoi1RTsMTX5YM61E3eE9cQuJU5ZVSjzngsFwj3JJy+RD5CS xrO/BmPTdgbCBwc1os+QaYKtyKebrJPHXfh0z9cQivdAc5+hlET8WjMwQOwUZotJhSmS sa21cgst1b4UhXy+ydww1gZ0q2JJ372BfgMHOkOPCwAsy2OBIqC9CIjEzFLgN3PVH2N7 wxcK7x44gF8Bokn2kfqESvEzYoseStEQKUIEfqJp1EhZkEXQu1lQcPV8Ewa5gYLSA/Ie Nf0Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=tz1xxw376W8fEk8woSoKxZezbGh5wAYhdpLhFN+ffhE=; b=mSxYsWOAI6AIFuuzvn5vT9aqzYbIrNy1mp1KcJj66Royyv1hzlTCf90Ao+A/4o3X90 RylV1PEmJv0HF3/FyA7kGYWZqofEPJxVA9Y0jGRnxzGB0+4uCLneli3E9Mone4l5LyQR 0KwSgIRDkiAYh/Fe6hzet8I5iLDq/c0FzIJ4ceIz7pD7xB3g5xIExJmv2WHtRtScktAy yn2n3nqnGd6ZGOwAEzpivo0jxCwfW9VoazmodaM0xNzPS1uSodU3pHMJO4JYOJm1wwr/ ExXCFvtqiWI+6cM/sCWkvqDxWgyQA6AOkiGc8B2n8RTytgD5SzvR2ncruvN+O+8x6Usy 0rTg== X-Gm-Message-State: ALKqPwdhAcoEL1Csfqwm07c3fyDD5N3by4damG3C07YDwYmgbzEqV809 7WU3x/d0F1p/uRAzKfKURL9cI4oj X-Google-Smtp-Source: AB8JxZohlhlJitUBVUOKEaqGS4/3+5zELtG1iINa4RNjx0+rarCGq4KnTagVcCNDidWcSt5pa62fWw== X-Received: by 2002:a63:2783:: with SMTP id n125-v6mr17782916pgn.377.1526972275812; Mon, 21 May 2018 23:57:55 -0700 (PDT) From: Paolo Bonzini To: patchew-devel@redhat.com Date: Tue, 22 May 2018 08:57:39 +0200 Message-Id: <20180522065740.9710-12-pbonzini@redhat.com> In-Reply-To: <20180522065740.9710-1-pbonzini@redhat.com> References: <20180522065740.9710-1-pbonzini@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Tue, 22 May 2018 06:57:56 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Tue, 22 May 2018 06:57:56 +0000 (UTC) for IP:'74.125.83.52' DOMAIN:'mail-pg0-f52.google.com' HELO:'mail-pg0-f52.google.com' FROM:'paolo.bonzini@gmail.com' RCPT:'' X-RedHat-Spam-Score: 0.577 (DKIM_SIGNED, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_PASS, T_DKIM_INVALID) 74.125.83.52 mail-pg0-f52.google.com 74.125.83.52 mail-pg0-f52.google.com X-RedHat-Possible-Forgery: Paolo Bonzini X-Scanned-By: MIMEDefang 2.78 on 10.5.110.32 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-loop: patchew-devel@redhat.com Subject: [Patchew-devel] [PATCH 11/12] do not load log when accessing api_result X-BeenThere: patchew-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Patchew development and discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: patchew-devel-bounces@redhat.com Errors-To: patchew-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Tue, 22 May 2018 06:58:08 +0000 (UTC) X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" This is a small optimization. log_xz can be largish, and we do not need it except in the log viewer or when retrieving it for the REST API. Skipping it by default in all result queries is the simplest thing to do. Signed-off-by: Paolo Bonzini --- mods/git.py | 2 +- mods/testing.py | 4 ++-- www/views.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mods/git.py b/mods/git.py index 67ef723..58b9c3d 100644 --- a/mods/git.py +++ b/mods/git.py @@ -28,7 +28,7 @@ _instance =3D None =20 def _get_git_result(msg): try: - return msg.results.get(name=3D"git") + return msg.results.defer('log_xz').get(name=3D"git") except: return None Message.git_result =3D property(_get_git_result) diff --git a/mods/testing.py b/mods/testing.py index b09989b..640389f 100644 --- a/mods/testing.py +++ b/mods/testing.py @@ -122,11 +122,11 @@ class TestingModule(PatchewModule): self.recalc_pending_tests(obj) =20 def get_testing_results(self, obj, *args, **kwargs): - return obj.results.filter(name__startswith=3D'testing.', *args, **= kwargs) + return obj.results.defer('log_xz').filter(name__startswith=3D'test= ing.', *args, **kwargs) =20 def get_testing_result(self, obj, name): try: - return obj.results.get(name=3D'testing.' + name) + return obj.results.defer('log_xz').get(name=3D'testing.' + nam= e) except: raise Http404("Test doesn't exist") =20 diff --git a/www/views.py b/www/views.py index 5685f23..ddae4ca 100644 --- a/www/views.py +++ b/www/views.py @@ -93,7 +93,7 @@ def prepare_series(request, s, skip_patches=3DFalse): =20 def prepare_results(request, obj): rendered_results =3D [] - for result in obj.results.all(): + for result in obj.results.defer('log_xz').all(): html =3D result.render(obj) if html is None: continue --=20 2.17.0 _______________________________________________ Patchew-devel mailing list Patchew-devel@redhat.com https://www.redhat.com/mailman/listinfo/patchew-devel From nobody Sat Apr 20 00:21:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=patchew-devel-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=patchew-devel-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 152697229165415.941702444240946; Mon, 21 May 2018 23:58:11 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.25]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BE9EFC03D462; Tue, 22 May 2018 06:58:10 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id AC28A2010CA5; Tue, 22 May 2018 06:58:10 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 9D7544BB78; Tue, 22 May 2018 06:58:10 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w4M6w9AZ028253 for ; Tue, 22 May 2018 02:58:09 -0400 Received: by smtp.corp.redhat.com (Postfix) id 0725B2010CA3; Tue, 22 May 2018 06:58:09 +0000 (UTC) Received: from mx1.redhat.com (ext-mx06.extmail.prod.ext.phx2.redhat.com [10.5.110.30]) by smtp.corp.redhat.com (Postfix) with ESMTPS id F20422010CA5 for ; Tue, 22 May 2018 06:58:08 +0000 (UTC) Received: from mail-pg0-f44.google.com (mail-pg0-f44.google.com [74.125.83.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C6FD6C6575 for ; Tue, 22 May 2018 06:57:57 +0000 (UTC) Received: by mail-pg0-f44.google.com with SMTP id p8-v6so7429254pgq.10 for ; Mon, 21 May 2018 23:57:57 -0700 (PDT) Received: from localhost.localdomain ([208.181.63.202]) by smtp.gmail.com with ESMTPSA id y2-v6sm19818676pgp.92.2018.05.21.23.57.55 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 21 May 2018 23:57:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=zwhqgVc5UMX3FMhW1cxTaLp8sPUvNyCVyq5JEVubxX8=; b=dSNhFTv/4VT/6e4EjWBGs/3aN3MvL/OnXVvpDiWOmmgSivSTsJWQ9NH75vYmWlE+VB cSt99mVqnvGKBVIQIs38oDQ3lR6Og5N6v5+wW1EaAEyTXYcbsqw/Z2DrMhaPbLC0R27G 0Co15P7d5xka2TfbYdOeg2D5OmP/gk1XhnZkVJP+I9nkJSK/YcpGhmIyb9seBDDPHQ1C ZkEx5uP0k88Y1G+X++PetweysaD7/6kjOdzfedmdBTBWifQRLUS0u6iWZ2PQ5pfZcJip PRhxNo4IRxOh6sWVYuU16R6yfvCHphZgEZ5ri2Ua0k8rMeXXpCVRxH2h1eZXhlNr+yYA hyQw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=zwhqgVc5UMX3FMhW1cxTaLp8sPUvNyCVyq5JEVubxX8=; b=XMzgFEMSVpI3d54pDouSZ14qlbv67ZJAlUdTO0cDr4rlQo6YNhO/RpSWSMtsjzTXB/ zCAm3vOcGyBYtfRPzKYtMjB6fo8cV3SOzRw6tDnPXWicmqasVUPTTs9H64gvXHRkT1yT C3qW5pN6GsyHtH7c7+cPv45U0udrY4zcZiIADHh++EXdCqSPe4FrdtBZx5uowsgZmP6a K06IYkZ3ALLFHYnIZHcfitLpMEi3oyGckDwIWHNxCRUrFFxGTvl1n9RT5EQqHThwbMPN QS9HygusL/2yyQQ8ZIL/T55QCdUWxokDL53i2eMZR1VCMFIphfBAjmYYiGL281LCqsrD QuvQ== X-Gm-Message-State: ALKqPweF5RGrG/LhhJYSk5o0uXssV+drgy4HpxfkHWYpoXDu+EoVqxuR HhMbuSfBeKP75/16M9WV6tQSgl5H X-Google-Smtp-Source: AB8JxZpTJuFVITrLYDlKat5Ozs0GyFMWWtJ9AFlJo0c99XiSIaQhNDIcgloU0IGwDxKfwSwmYF9oZA== X-Received: by 2002:a65:61c8:: with SMTP id j8-v6mr18041359pgv.370.1526972276826; Mon, 21 May 2018 23:57:56 -0700 (PDT) From: Paolo Bonzini To: patchew-devel@redhat.com Date: Tue, 22 May 2018 08:57:40 +0200 Message-Id: <20180522065740.9710-13-pbonzini@redhat.com> In-Reply-To: <20180522065740.9710-1-pbonzini@redhat.com> References: <20180522065740.9710-1-pbonzini@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Tue, 22 May 2018 06:57:57 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Tue, 22 May 2018 06:57:57 +0000 (UTC) for IP:'74.125.83.44' DOMAIN:'mail-pg0-f44.google.com' HELO:'mail-pg0-f44.google.com' FROM:'paolo.bonzini@gmail.com' RCPT:'' X-RedHat-Spam-Score: -1.2 (DKIM_SIGNED, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_PASS, T_DKIM_INVALID) 74.125.83.44 mail-pg0-f44.google.com 74.125.83.44 mail-pg0-f44.google.com X-RedHat-Possible-Forgery: Paolo Bonzini X-Scanned-By: MIMEDefang 2.78 on 10.5.110.30 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.25 X-loop: patchew-devel@redhat.com Subject: [Patchew-devel] [PATCH 12/12] models: convert MessageProperty and ProjectProperty to JSONField X-BeenThere: patchew-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Patchew development and discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: patchew-devel-bounces@redhat.com Errors-To: patchew-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.25 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Tue, 22 May 2018 06:58:10 +0000 (UTC) X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The huge logs are not stored anymore as properties, this means that the pro= perty tables can just use JSONField and the blob field can be removed. Signed-off-by: Paolo Bonzini --- api/blobs.py | 7 ---- api/migrations/0030_deblob_properties.py | 34 ++++++++++++++++++ api/migrations/0031_auto_20180520_1654.py | 34 ++++++++++++++++++ api/migrations/__init__.py | 7 ++-- api/models.py | 42 ++++------------------- 5 files changed, 79 insertions(+), 45 deletions(-) create mode 100644 api/migrations/0030_deblob_properties.py create mode 100644 api/migrations/0031_auto_20180520_1654.py diff --git a/api/blobs.py b/api/blobs.py index 7171b71..4ef5c96 100644 --- a/api/blobs.py +++ b/api/blobs.py @@ -29,13 +29,6 @@ def load_blob(name): fn =3D os.path.join(settings.DATA_DIR, "blob", name + ".xz") return lzma.open(fn, 'r').read().decode("utf-8") =20 -def load_blob_json(name): - try: - return json.loads(load_blob(name)) - except json.decoder.JSONDecodeError as e: - logging.error('Failed to load blob %s: %s' %(name, e)) - return None - def delete_blob(name): fn =3D os.path.join(settings.DATA_DIR, "blob", name + ".xz") try: diff --git a/api/migrations/0030_deblob_properties.py b/api/migrations/0030= _deblob_properties.py new file mode 100644 index 0000000..801f7a2 --- /dev/null +++ b/api/migrations/0030_deblob_properties.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations +from django.db.models import Count + +import json +from api import blobs + +def deblob_properties(apps, schema_editor): + def do_deblob_properties(model): + objects =3D model.objects.filter(blob=3DTrue) + for obj in objects: + obj.blob =3D False + if obj.value is not None: + obj.value =3D blobs.load_blob(obj.value) + obj.save() + + # We can't import the models directly as they may be a newer + # version than this migration expects. We use the historical version. + do_deblob_properties(apps.get_model('api', 'MessageProperty')) + do_deblob_properties(apps.get_model('api', 'ProjectProperty')) + +class Migration(migrations.Migration): + + dependencies =3D [ + ('api', '0029_populate_testing_results'), + ] + + operations =3D [ + migrations.RunPython(deblob_properties, + reverse_code=3Dmigrations.RunPython.noop), + ] diff --git a/api/migrations/0031_auto_20180520_1654.py b/api/migrations/003= 1_auto_20180520_1654.py new file mode 100644 index 0000000..edb0c4f --- /dev/null +++ b/api/migrations/0031_auto_20180520_1654.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.12 on 2018-05-20 16:54 +from __future__ import unicode_literals + +from django.db import migrations +import jsonfield.fields + + +class Migration(migrations.Migration): + + dependencies =3D [ + ('api', '0030_deblob_properties'), + ] + + operations =3D [ + migrations.RemoveField( + model_name=3D'messageproperty', + name=3D'blob', + ), + migrations.RemoveField( + model_name=3D'projectproperty', + name=3D'blob', + ), + migrations.AlterField( + model_name=3D'messageproperty', + name=3D'value', + field=3Djsonfield.fields.JSONField(), + ), + migrations.AlterField( + model_name=3D'projectproperty', + name=3D'value', + field=3Djsonfield.fields.JSONField(), + ), + ] diff --git a/api/migrations/__init__.py b/api/migrations/__init__.py index 9707fb2..d0f2621 100644 --- a/api/migrations/__init__.py +++ b/api/migrations/__init__.py @@ -23,7 +23,7 @@ def get_property_raw(model, name, **kwargs): return mp =20 def load_property(mp): - if mp.blob: + if hasattr(mp, 'blob') and mp.blob: return load_blob_json_safe(mp.value) else: return json.loads(mp.value) @@ -34,7 +34,7 @@ def get_property(model, name, **kwargs): =20 def delete_property_blob(model, name, **kwargs): mp =3D get_property_raw(model, name, **kwargs) - if mp.blob: + if hasattr(mp, 'blob') and mp.blob: blobs.delete_blob(mp.value) =20 def set_property(model, name, value, **kwargs): @@ -42,5 +42,6 @@ def set_property(model, name, value, **kwargs): value =3D json.dumps(value) mp, created =3D model.objects.get_or_create(name=3Dname, **kwargs) mp.value =3D value - mp.blob =3D False + if hasattr(mp, 'blob'): + mp.blob =3D False mp.save() diff --git a/api/models.py b/api/models.py index f7065ca..dd00da1 100644 --- a/api/models.py +++ b/api/models.py @@ -10,7 +10,6 @@ =20 =20 from collections import namedtuple -import json import datetime import re =20 @@ -23,8 +22,9 @@ import lzma =20 from mbox import MboxMessage from event import emit_event, declare_event -from .blobs import save_blob, load_blob, load_blob_json +from .blobs import save_blob, load_blob import mod +import lzma =20 class Result(models.Model): PENDING =3D 'pending' @@ -143,37 +143,23 @@ class Project(models.Model): def get_property(self, prop, default=3DNone): a =3D ProjectProperty.objects.filter(project=3Dself, name=3Dprop).= first() if a: - if a.blob: - return load_blob_json(a.value) - else: - return json.loads(a.value) + return a.value else: return default =20 def get_properties(self): r =3D {} for m in ProjectProperty.objects.filter(project=3Dself): - if m.blob: - r[m.name] =3D load_blob_json(m.value) - else: - r[m.name] =3D json.loads(m.value) + r[m.name] =3D m.value return r =20 def _do_set_property(self, prop, value): if value =3D=3D None: ProjectProperty.objects.filter(project=3Dself, name=3Dprop).de= lete() return - # TODO: drop old blob - json_data =3D json.dumps(value) - blob =3D len(json_data) > 1024 - if blob: - value =3D save_blob(json_data) - else: - value =3D json.dumps(value) pp, created =3D ProjectProperty.objects.get_or_create(project=3Dse= lf, name=3Dprop) pp.value =3D value - pp.blob =3D blob pp.save() =20 def set_property(self, prop, value): @@ -229,8 +215,7 @@ class Project(models.Model): class ProjectProperty(models.Model): project =3D models.ForeignKey('Project', on_delete=3Dmodels.CASCADE) name =3D models.CharField(max_length=3D1024, db_index=3DTrue) - value =3D models.CharField(max_length=3D1024) - blob =3D models.BooleanField(blank=3DTrue, default=3DFalse) + value =3D jsonfield.JSONField() =20 class Meta: unique_together =3D ('project', 'name',) @@ -494,10 +479,7 @@ class Message(models.Model): all_props =3D self.properties.all() r =3D {} for m in all_props: - if m.blob: - r[m.name] =3D load_blob_json(m.value) - else: - r[m.name] =3D json.loads(m.value) + r[m.name] =3D m.value self._properties =3D r return r =20 @@ -505,17 +487,9 @@ class Message(models.Model): if value =3D=3D None: MessageProperty.objects.filter(message=3Dself, name=3Dprop).de= lete() return - json_data =3D json.dumps(value) - blob =3D len(json_data) > 1024 mp, created =3D MessageProperty.objects.get_or_create(message=3Dse= lf, name=3Dprop) - # TODO: drop old blob - if blob: - value =3D save_blob(json_data) - else: - value =3D json_data mp.value =3D value - mp.blob =3D blob mp.save() # Invalidate cache self._properties =3D None @@ -646,9 +620,7 @@ class MessageProperty(models.Model): message =3D models.ForeignKey('Message', on_delete=3Dmodels.CASCADE, related_name=3D'properties') name =3D models.CharField(max_length=3D256) - # JSON encoded value - value =3D models.CharField(max_length=3D1024) - blob =3D models.BooleanField(blank=3DTrue, default=3DFalse) + value =3D jsonfield.JSONField() =20 def __str__(self): if len(self.value) > 30: --=20 2.17.0 _______________________________________________ Patchew-devel mailing list Patchew-devel@redhat.com https://www.redhat.com/mailman/listinfo/patchew-devel