From patchwork Mon Jun 17 22:18:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Hassick X-Patchwork-Id: 1948884 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=dI4Uov3R; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:2:0:216:3eff:fee1:b9f1; helo=lists.ozlabs.org; envelope-from=patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:2:0:216:3eff:fee1:b9f1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W34823l57z20KL for ; Tue, 18 Jun 2024 08:20:18 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=dI4Uov3R; dkim-atps=neutral Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4W34813GvFz3c5q for ; Tue, 18 Jun 2024 08:20:17 +1000 (AEST) X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=iol.unh.edu Authentication-Results: lists.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=dI4Uov3R; dkim-atps=neutral Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=iol.unh.edu (client-ip=2607:f8b0:4864:20::234; helo=mail-oi1-x234.google.com; envelope-from=ahassick@iol.unh.edu; receiver=lists.ozlabs.org) Received: from mail-oi1-x234.google.com (mail-oi1-x234.google.com [IPv6:2607:f8b0:4864:20::234]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4W346z3czbz3g9C for ; Tue, 18 Jun 2024 08:19:21 +1000 (AEST) Received: by mail-oi1-x234.google.com with SMTP id 5614622812f47-3c9cc681ee4so2404663b6e.0 for ; Mon, 17 Jun 2024 15:19:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iol.unh.edu; s=unh-iol; t=1718662756; x=1719267556; darn=lists.ozlabs.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=Ar47M7o6nrdY9gBB4pfYuwqRRqVcA74VS9+qKUcqIYY=; b=dI4Uov3RbamnVM2Q1bV0Cu6LIMapseceHu36DVAb7mQlZjrq9MMBK8Fc6rYxeZ5GN/ LlqLYLvhvtL5fH9iqRXqCZuKLfC5iOqDUKZzeD0cgs9ri0CVrWkhwaj/fzPEEtU0Ckii PNk+pA0wiGyfvOZKSt4H6M9+l1GBPNTZuEWuM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718662756; x=1719267556; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=Ar47M7o6nrdY9gBB4pfYuwqRRqVcA74VS9+qKUcqIYY=; b=G4BKm+et45sXDt5NdH/m7KhTnvmkmqTlyXBIB4Nm8H1wf8ITSUg9K3gt11yiX6sFGx RIfTO0xQP5mLO+bKRz6Eeo3TT0+95e3487E4lijB1tpl0V6wrK6TgQ8MS6S3+AyvNtWr iiNwLivRIkpJmKYXDAdoOPcQ42lOk5JCKDjD8IKBXmnouzorl8bzZXQmM/5XsgCrA1x6 dd39pyTyRH2DJsh/KYj7Nw3KJ3EXxGlk+AxJ1/Z89sYtjqarsVkcF5upDqNaK26eVq20 Bvfl3nMub3tB5UmQkp1wu1H17aBzD/9JSwSUfOzhx7YLlBberiSWhD7vuLkRj4aeJAjT kH2g== X-Gm-Message-State: AOJu0YwFZ0l56taTcAMOAqlets7veB2nbFs27oP2FDWxJAbbkua/RfFd q97FO8wEoujGsONEdvp2QRy3Xy8xduqwgSF2Y2F2O7t3xs0AJgoAMuF9RDcND9xCjmze1OAKZRK N0W8Kf/9ytAKzWmTNvJi8Huf0K4Gb1STq15dgNejuirvR+aASRnqj7i3GtiC38BhexBZxXKK9u/ bT6Y8+UlGyRwy771cqrkS85XTXLLIf1KdS1LIk/tkjWwz+2w== X-Google-Smtp-Source: AGHT+IFfSkdr9ALXX04B0nqetdv1/3vXnisTdkALIGp4Ct/GjkMDsk76pLiBZ8uizVkm8SIY4NKfig== X-Received: by 2002:a05:6808:30a4:b0:3d2:28a2:912f with SMTP id 5614622812f47-3d24e9c6613mr13417887b6e.47.1718662755679; Mon, 17 Jun 2024 15:19:15 -0700 (PDT) Received: from bubs.loudonlune.net ([71.254.3.64]) by smtp.gmail.com with ESMTPSA id af79cd13be357-798aaee0e52sm469808185a.37.2024.06.17.15.19.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jun 2024 15:19:15 -0700 (PDT) From: Adam Hassick To: patchwork@lists.ozlabs.org Subject: [PATCH v1 1/9] api: Add fields to series detail view Date: Mon, 17 Jun 2024 18:18:47 -0400 Message-ID: <20240617221900.156155-1-ahassick@iol.unh.edu> X-Mailer: git-send-email 2.45.2 MIME-Version: 1.0 X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" Adds the "dependencies" and "dependents" fields to the series detail view. Signed-off-by: Adam Hassick Reviewed-by: Stephen Finucane --- patchwork/api/series.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/patchwork/api/series.py b/patchwork/api/series.py index b88ed1f..2b23e48 100644 --- a/patchwork/api/series.py +++ b/patchwork/api/series.py @@ -5,7 +5,10 @@ from rest_framework.generics import ListAPIView from rest_framework.generics import RetrieveAPIView -from rest_framework.serializers import SerializerMethodField +from rest_framework.serializers import ( + SerializerMethodField, + HyperlinkedRelatedField, +) from patchwork.api.base import BaseHyperlinkedModelSerializer from patchwork.api.base import PatchworkPermission @@ -24,6 +27,12 @@ class SeriesSerializer(BaseHyperlinkedModelSerializer): mbox = SerializerMethodField() cover_letter = CoverSerializer(read_only=True) patches = PatchSerializer(read_only=True, many=True) + dependencies = HyperlinkedRelatedField( + read_only=True, view_name='api-series-detail', many=True + ) + dependents = HyperlinkedRelatedField( + read_only=True, view_name='api-series-detail', many=True + ) def get_web_url(self, instance): request = self.context.get('request') @@ -50,6 +59,8 @@ class SeriesSerializer(BaseHyperlinkedModelSerializer): 'mbox', 'cover_letter', 'patches', + 'dependencies', + 'dependents', ) read_only_fields = ( 'date', @@ -60,9 +71,15 @@ class SeriesSerializer(BaseHyperlinkedModelSerializer): 'mbox', 'cover_letter', 'patches', + 'dependencies', + 'dependents', ) versioned_fields = { '1.1': ('web_url',), + '1.4': ( + 'dependencies', + 'dependents', + ), } extra_kwargs = { 'url': {'view_name': 'api-series-detail'}, @@ -76,7 +93,12 @@ class SeriesMixin(object): def get_queryset(self): return ( Series.objects.all() - .prefetch_related('patches__project', 'cover_letter__project') + .prefetch_related( + 'patches__project', + 'cover_letter__project', + 'dependencies', + 'dependents', + ) .select_related('submitter', 'project') ) From patchwork Mon Jun 17 22:18:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Hassick X-Patchwork-Id: 1948882 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=EmNu3b3/; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=112.213.38.117; helo=lists.ozlabs.org; envelope-from=patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W347f1KQtz20Wb for ; Tue, 18 Jun 2024 08:19:58 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=EmNu3b3/; dkim-atps=neutral Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4W347b5dw2z3gCk for ; Tue, 18 Jun 2024 08:19:55 +1000 (AEST) X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=iol.unh.edu Authentication-Results: lists.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=EmNu3b3/; dkim-atps=neutral Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=iol.unh.edu (client-ip=2607:f8b0:4864:20::92a; helo=mail-ua1-x92a.google.com; envelope-from=ahassick@iol.unh.edu; receiver=lists.ozlabs.org) Received: from mail-ua1-x92a.google.com (mail-ua1-x92a.google.com [IPv6:2607:f8b0:4864:20::92a]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4W346z4DX1z3g9L for ; Tue, 18 Jun 2024 08:19:21 +1000 (AEST) Received: by mail-ua1-x92a.google.com with SMTP id a1e0cc1a2514c-80b8d45e6b7so1289363241.3 for ; Mon, 17 Jun 2024 15:19:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iol.unh.edu; s=unh-iol; t=1718662756; x=1719267556; darn=lists.ozlabs.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=lbBvq5OPhQXkSjwUs8cRzHYvqvVAD6vwCnyoRnqrzpc=; b=EmNu3b3/RqbHYBCQ5dpzyWGvEeBW0e2BN4bNEWFK6Na5ups68QxWDPAyjnRFv33tys 6VuxO2DvcwOkeH4NOnM0TelMcQL7e5DGMZq3SNeon+oRVL1wZrYtmjTy2/91UPQHSkZ3 nWX1AkVW7e2fkhdi8gmcMmmadrbtIpHjqkzwc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718662756; x=1719267556; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=lbBvq5OPhQXkSjwUs8cRzHYvqvVAD6vwCnyoRnqrzpc=; b=faDlwLOhxKSBLHy0WWa04v0rPSPBOFtM3X7Zsclk/8P0cbwRZ79TC91QebTVuOFOuL pSMSGrjQcFuIXmq4kQ9kVLyC88n1wCnYyeMFSGo/BhOKuOO3iN1ny7XRFBtpipek6YRw 83i69H4J5bjaXOrKR9Ta3FyqwtC6LBNWir0G2DRKTzI8oEwnDrPcpkAxyeOXnepL5dRj 4AfaVzul8zC3TS9CpfGS99m/2cQFnjLgc+bZb+OT//MxersAWa8DX1PVPvsePDwiM1Yt rdwMSAD6P/0s8jnIVQshiv6HunvkTKlBQTX3/lGAlBsOEu2VQJJixTiBLHJNbYU+qfNa ydow== X-Gm-Message-State: AOJu0YwbV0zPukkThjHxaPWTnjTyi5d8V1YV2dQ22YRfnUXlJpK5bA4i HtizdrhAub+02151UYg5ycfeqvSVbOZhF8zzkuisgJOPyevh3fMtYVjRrI0vQI1JXfLcBGiSAA8 RWYzPn8oOYfMbi49i66tNvD//bSL36HNlevYRiaqen9WjTvOXHNUDIZkUVpVCAAu1413w+OntVC SDqrMfDrK3mY2X3p4BXxfI1WVuJM/ysSFE5zNPacCZIb0Ndg== X-Google-Smtp-Source: AGHT+IFdQc0QC/Muvl0sj8WfTAIqWIfh+6JHMHkmpwwcVTS0km3FlOW7wThs/XlGrbSFyv4Y+10oqQ== X-Received: by 2002:a05:6102:834:b0:48d:98a9:d1ab with SMTP id ada2fe7eead31-48dae2b47d7mr9139707137.1.1718662756277; Mon, 17 Jun 2024 15:19:16 -0700 (PDT) Received: from bubs.loudonlune.net ([71.254.3.64]) by smtp.gmail.com with ESMTPSA id af79cd13be357-798aaee0e52sm469808185a.37.2024.06.17.15.19.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jun 2024 15:19:16 -0700 (PDT) From: Adam Hassick To: patchwork@lists.ozlabs.org Subject: [PATCH v1 2/9] models: Add field for series dependencies Date: Mon, 17 Jun 2024 18:18:48 -0400 Message-ID: <20240617221900.156155-2-ahassick@iol.unh.edu> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240617221900.156155-1-ahassick@iol.unh.edu> References: <20240617221900.156155-1-ahassick@iol.unh.edu> MIME-Version: 1.0 X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" Add a ManyToMany field to represent a dependency relationship between patch series. Signed-off-by: Adam Hassick Reviewed-by: Stephen Finucane --- patchwork/models.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/patchwork/models.py b/patchwork/models.py index 9a619bc..6f6a32d 100644 --- a/patchwork/models.py +++ b/patchwork/models.py @@ -840,6 +840,16 @@ class Series(FilenameMixin, models.Model): Cover, related_name='series', null=True, on_delete=models.CASCADE ) + # dependencies + dependencies = models.ManyToManyField( + 'self', + symmetrical=False, + blank=True, + help_text='Optional dependencies on this patch.', + related_name='dependents', + related_query_name='dependent', + ) + # metadata name = models.CharField( max_length=255, @@ -880,6 +890,13 @@ class Series(FilenameMixin, models.Model): def received_all(self): return self.total <= self.received_total + def add_dependencies(self, dependencies): + # for dependency in dependencies: + # dependency.dependents.add(self) + # dependency.save() + self.dependencies.add(*dependencies) + self.save() + def add_cover_letter(self, cover): """Add a cover letter to the series. From patchwork Mon Jun 17 22:18:49 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Hassick X-Patchwork-Id: 1948883 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=iqJFQbxQ; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:2:0:216:3eff:fee1:b9f1; helo=lists.ozlabs.org; envelope-from=patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:2:0:216:3eff:fee1:b9f1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W347q3Jg4z20XQ for ; Tue, 18 Jun 2024 08:20:07 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=iqJFQbxQ; dkim-atps=neutral Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4W347p2s67z3gHR for ; Tue, 18 Jun 2024 08:20:06 +1000 (AEST) X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=iol.unh.edu Authentication-Results: lists.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=iqJFQbxQ; dkim-atps=neutral Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=iol.unh.edu (client-ip=2607:f8b0:4864:20::72c; helo=mail-qk1-x72c.google.com; envelope-from=ahassick@iol.unh.edu; receiver=lists.ozlabs.org) Received: from mail-qk1-x72c.google.com (mail-qk1-x72c.google.com [IPv6:2607:f8b0:4864:20::72c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4W346z4Bb9z3g9K for ; Tue, 18 Jun 2024 08:19:21 +1000 (AEST) Received: by mail-qk1-x72c.google.com with SMTP id af79cd13be357-7965d034cedso311757885a.3 for ; Mon, 17 Jun 2024 15:19:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iol.unh.edu; s=unh-iol; t=1718662757; x=1719267557; darn=lists.ozlabs.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=kxDWOJyQXXXt1wvS/by2LOlfKjKJxSno6B4HHVHhD1o=; b=iqJFQbxQs9pW9rKvo9H4zuiMkn7AQpDxjwvWjEuAqhrgDvW+pSe3Vm8JoYnCINz/Y+ ay0L+anucNLHbZzhnAi2vqzYCRGML7EcRuRzFrZzUqh21ly88SCsKSIliSuZJmfQgLCN q1dcfEv7XKwoQVc2LvGMXs67a6AdugKvtI30s= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718662757; x=1719267557; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=kxDWOJyQXXXt1wvS/by2LOlfKjKJxSno6B4HHVHhD1o=; b=DCK1XMw3PKimkg26Sul0B1OPt4a0hB3/COd3ClJmOBhNA92ED+JK3Cu4GmvQtqvlLE ttIMGTLkImyN0zJR1SkDFMMRMO+KuUZ0+WhbBDCkOl9xsq6U6aKnu6vLmFZuhuuCj/JO zjWAdhkacp8QHSKITbWUZWvIpcLeJ5QndxGq1CRGGAv5RU5CwIs+x8bUfiCEGIt2bHKQ zR8Jg/pIaPuwXG+XJgmwNbTM+p2QaYiWrgLkWWtnSj+5ZNLCIZvAM0dmIPH+da++AEv7 RQXwVfx/bJiOUzDGCDkOjXpZqKbz2AcRi08I2Qh1OqBVt+l8drgKkisy5m2hxaLVHz6c gXtQ== X-Gm-Message-State: AOJu0YwIRMQuvcgp038g+7p23Qhlke6KoAU2FFJE63na+FXVhaWUwH+a Umjryb8Y9ddId0+MZPQtUSh9G5t9RYW+TUQQeKFZOLZbsAjRilqaBLXdgPhdMSReUhGAmR/ds6y xQR0Kwu77m+MwXuwUyMXMHJE8NyFJ6/KH62Hwc5dB7mHBTRI1iUPIAjV1YTbUxfB9s7ON3bopew q14gbfUWOsmy+xhTkom+MBIJABkha7gsGj97HNude5LU/zkg== X-Google-Smtp-Source: AGHT+IEtFOrsux88GzN261bzVZOaagOSBJaN/FpP9N6IEl1Pi3Gufkks19Lg1FMzOLJvb+HaVEcRUQ== X-Received: by 2002:a05:620a:318a:b0:796:100f:2536 with SMTP id af79cd13be357-798d23c56bamr1301706085a.9.1718662756905; Mon, 17 Jun 2024 15:19:16 -0700 (PDT) Received: from bubs.loudonlune.net ([71.254.3.64]) by smtp.gmail.com with ESMTPSA id af79cd13be357-798aaee0e52sm469808185a.37.2024.06.17.15.19.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jun 2024 15:19:16 -0700 (PDT) From: Adam Hassick To: patchwork@lists.ozlabs.org Subject: [PATCH v1 3/9] parser: Parse "Depends-on" tags in emails Date: Mon, 17 Jun 2024 18:18:49 -0400 Message-ID: <20240617221900.156155-3-ahassick@iol.unh.edu> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240617221900.156155-1-ahassick@iol.unh.edu> References: <20240617221900.156155-1-ahassick@iol.unh.edu> MIME-Version: 1.0 X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" Add a new function to parse "Depends-on" tags to the parser. The value may either be a "reference" to a patch or series object or the web URL to the object. For example, a reference may look like "patch-1234" or "series-5678". When this tag is found, the parser will add the series (or the series the patch belongs to) as a dependency to the patch series it is creating. Signed-off-by: Adam Hassick --- patchwork/parser.py | 109 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/patchwork/parser.py b/patchwork/parser.py index 09a53a0..90ec63b 100644 --- a/patchwork/parser.py +++ b/patchwork/parser.py @@ -14,11 +14,14 @@ from email.errors import HeaderParseError from fnmatch import fnmatch import logging import re +from urllib.parse import urlparse from django.contrib.auth.models import User from django.db.utils import IntegrityError from django.db import transaction from django.utils import timezone as tz_utils +from django.urls import resolve, Resolver404 +from django.conf import settings from patchwork.models import Cover from patchwork.models import CoverComment @@ -32,7 +35,6 @@ from patchwork.models import Series from patchwork.models import SeriesReference from patchwork.models import State - _msgid_re = re.compile(r'<[^>]+>') _hunk_re = re.compile(r'^\@\@ -\d+(?:,(\d+))? \+\d+(?:,(\d+))? \@\@') _filename_re = re.compile(r'^(---|\+\+\+) (\S+)') @@ -1054,6 +1056,102 @@ def parse_pull_request(content): return None +def find_series_from_url(url): + """ + Get series or patch from URL. + """ + + parse_result = urlparse(url) + + # Resolve the URL path to see if this is a patch or series detail URL. + try: + result = resolve(parse_result.path) + except Resolver404: + return None + + if result.view_name == 'patch-list' and parse_result.query: + # Parse the query string. + # This can be replaced with something much friendlier once the + # series detail view is implemented. + series_query_param = next( + filter( + lambda x: len(x) == 2 and x[0] == 'series', + map(lambda x: x.split('='), parse_result.query.split('&')), + ) + ) + + if series_query_param: + series_id = series_query_param[1] + + try: + series_id_num = int(series_id) + except ValueError: + return None + + return Series.objects.filter(id=series_id_num).first() + elif result.view_name == 'patch-detail': + msgid = Patch.decode_msgid(result.kwargs['msgid']) + patch = Patch.objects.filter(msgid=msgid).first() + + if patch: + return patch.series + + +def find_series_from_ref(match): + (obj_type, obj_id_str) = match + + try: + object_id = int(obj_id_str) + except ValueError: + return None + + if obj_type == 'series': + series = Series.objects.filter(id=object_id).first() + elif obj_type == 'patch': + patch = Patch.objects.filter(id=object_id).first() + + if not patch: + return None + + series = patch.series + + return series + + +def parse_depends_on(content): + """Parses any dependency hints in the comments.""" + depends_patterns = [ + ( + re.compile( + r'^Depends-on: ((?:patch)?(?:series)?)-([\d]+)(?: \("[^\n\r"]+"\))?\s*$', + re.MULTILINE | re.IGNORECASE, + ), + find_series_from_ref, + ), + ( + re.compile( + r'^Depends-on: (http[s]?:\/\/[\w\d\-.\/=&@:%?_\+()]+)\s*$', + re.MULTILINE | re.IGNORECASE, + ), + find_series_from_url, + ), + ] + + dependencies = list() + + for pat, mapper in depends_patterns: + matches = pat.findall(content) + + # Produce a list of tuples containing type and ID of each dependency. + # Eliminate elements where we could not parse the ID as an integer. + dependencies.extend( + filter(lambda series: series is not None, map(mapper, matches)) + ) + + # Return list of series objects to depend on. + return dependencies + + def find_state(mail): """Return the state with the given name or the default.""" state_name = clean_header(mail.get('X-Patchwork-State', '')) @@ -1171,6 +1269,12 @@ def parse_mail(mail, list_id=None): pull_url = parse_pull_request(message) + # Only look for "Depends-on" tags if the setting is enabled. + if settings.ENABLE_DEPENDS_ON_PARSING: + dependencies = parse_depends_on(message) + else: + dependencies = [] + # build objects if not is_comment and (diff or pull_url): # patches or pull requests @@ -1308,6 +1412,8 @@ def parse_mail(mail, list_id=None): # always have a series series.add_patch(patch, x) + series.add_dependencies(dependencies) + return patch elif x == 0: # (potential) cover letters # if refs are empty, it's implicitly a cover letter. If not, @@ -1374,6 +1480,7 @@ def parse_mail(mail, list_id=None): logger.debug('Cover letter saved') series.add_cover_letter(cover_letter) + series.add_dependencies(dependencies) return cover_letter From patchwork Mon Jun 17 22:18:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Hassick X-Patchwork-Id: 1948887 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=JJ9peTrg; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=112.213.38.117; helo=lists.ozlabs.org; envelope-from=patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W348g5Lhjz20KL for ; Tue, 18 Jun 2024 08:20:51 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=JJ9peTrg; dkim-atps=neutral Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4W348f4wsyz3gHg for ; Tue, 18 Jun 2024 08:20:50 +1000 (AEST) X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=iol.unh.edu Authentication-Results: lists.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=JJ9peTrg; dkim-atps=neutral Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=iol.unh.edu (client-ip=2607:f8b0:4864:20::232; helo=mail-oi1-x232.google.com; envelope-from=ahassick@iol.unh.edu; receiver=lists.ozlabs.org) Received: from mail-oi1-x232.google.com (mail-oi1-x232.google.com [IPv6:2607:f8b0:4864:20::232]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4W34703bbxz3gBS for ; Tue, 18 Jun 2024 08:19:21 +1000 (AEST) Received: by mail-oi1-x232.google.com with SMTP id 5614622812f47-3d229baccc4so2360630b6e.1 for ; Mon, 17 Jun 2024 15:19:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iol.unh.edu; s=unh-iol; t=1718662758; x=1719267558; darn=lists.ozlabs.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=GeAPhCn+k4vqb2PpXJZhyJk2GGeJ3Qz4k5fak5QVPeA=; b=JJ9peTrgEXBlTolkRxA7IESn/4K2BjhOc5hqxUL/2Aynb4D0hIUiqGjm+JiDtPbacU 7OcXvHL/64igYRzUVYNnG1eaLcxqZITYysQ3HoPDAsUdrqMKj/+h+G79zNU3LizUZ5yE vl3ylhjFE03/LzOw/n0sZOzOVzyq9H7Nx05nQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718662758; x=1719267558; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=GeAPhCn+k4vqb2PpXJZhyJk2GGeJ3Qz4k5fak5QVPeA=; b=BdVvSovS5TtXNVlVK+GgRwJGZlKS2r7/7QKp+V9OouyUR+37AWRM3eU58OPSo7kiWs n63frmgvzsUTSETf+PqLdUIuw3OSMkiqiI+hHF2haMkuzMqXMlByc4m8q4a31o3bygQr oUMdZKhcrk+GCGN3nOGwpWrYdI313WD7k03U1YduJkEvlUmbABTclyD19AnAz0E90UEN LYhHEMTGE0SP3byJMpSIvLFw7HeRjzPDgVs68XPvf+jQILZjKAJosGqnJ7QtysV966Pu HYID9kekyS0PDJJuN5mWNVt/SQ60dIvOvPZigw63HO6sk3gtgxOWGRbG9J4VNN1w8+DO ptcw== X-Gm-Message-State: AOJu0YxwA9H+ig0jqxRI4uFkOtuKIVE0SrEUNiLzYLr7b6oRoXf1nx/8 wVFtpJuCD0ICt5TgRVVfALAyBLI1bFoyPDOl6kYXkZ08+NtnOxbnAuYMAc/sGity2ISHD7G8zY9 LEua4B3qFnPnlzZvvihupgRUfl4JXvCIzhVquTZvMzvchepDJ3O79c/yU9YGbmnkDfFnPt0fOB5 KlUlzHlp1KcUZxlFKipk728fztl/FRaC8E3RG5iwUVOwoOXg== X-Google-Smtp-Source: AGHT+IHxGB8JGUY67eq3yxn03gmLTB+Ivc8SYpXgy99oHMgS8RKN5LzMaCUAuImP0hTWZ8PQ7CX9zA== X-Received: by 2002:a05:6808:1990:b0:3d2:1ed4:78b2 with SMTP id 5614622812f47-3d24e9e1e2emr12593661b6e.55.1718662757780; Mon, 17 Jun 2024 15:19:17 -0700 (PDT) Received: from bubs.loudonlune.net ([71.254.3.64]) by smtp.gmail.com with ESMTPSA id af79cd13be357-798aaee0e52sm469808185a.37.2024.06.17.15.19.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jun 2024 15:19:17 -0700 (PDT) From: Adam Hassick To: patchwork@lists.ozlabs.org Subject: [PATCH v1 4/9] settings: Add flag disable "Depends-on" parsing Date: Mon, 17 Jun 2024 18:18:50 -0400 Message-ID: <20240617221900.156155-4-ahassick@iol.unh.edu> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240617221900.156155-1-ahassick@iol.unh.edu> References: <20240617221900.156155-1-ahassick@iol.unh.edu> MIME-Version: 1.0 X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" Some operators of Patchwork instances may not want to allow series dependencies. By providing this setting, these operators may disable this behavior on their instance. Signed-off-by: Adam Hassick --- patchwork/settings/base.py | 3 +++ patchwork/settings/dev.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/patchwork/settings/base.py b/patchwork/settings/base.py index dccab6c..8b05d57 100644 --- a/patchwork/settings/base.py +++ b/patchwork/settings/base.py @@ -263,6 +263,9 @@ ENABLE_XMLRPC = False # Set to True to enable the Patchwork REST API ENABLE_REST_API = True +# Set to True to enable parsing "Depends-on" tags. +ENABLE_DEPENDS_ON_PARSING = False + REST_RESULTS_PER_PAGE = 30 MAX_REST_RESULTS_PER_PAGE = 250 diff --git a/patchwork/settings/dev.py b/patchwork/settings/dev.py index 75c4b34..3688b24 100644 --- a/patchwork/settings/dev.py +++ b/patchwork/settings/dev.py @@ -80,3 +80,5 @@ if dbbackup: ENABLE_XMLRPC = True ENABLE_REST_API = True + +ENABLE_DEPENDS_ON_PARSING = True From patchwork Mon Jun 17 22:18:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Hassick X-Patchwork-Id: 1948880 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=N4EKi/81; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:2:0:216:3eff:fee1:b9f1; helo=lists.ozlabs.org; envelope-from=patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:2:0:216:3eff:fee1:b9f1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W347G0hLcz20Wb for ; Tue, 18 Jun 2024 08:19:37 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=N4EKi/81; dkim-atps=neutral Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4W347B1xJLz3gFR for ; Tue, 18 Jun 2024 08:19:34 +1000 (AEST) X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=iol.unh.edu Authentication-Results: lists.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=N4EKi/81; dkim-atps=neutral Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=iol.unh.edu (client-ip=2001:4860:4864:20::2d; helo=mail-oa1-x2d.google.com; envelope-from=ahassick@iol.unh.edu; receiver=lists.ozlabs.org) Received: from mail-oa1-x2d.google.com (mail-oa1-x2d.google.com [IPv6:2001:4860:4864:20::2d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4W34700R7sz3g9c for ; Tue, 18 Jun 2024 08:19:23 +1000 (AEST) Received: by mail-oa1-x2d.google.com with SMTP id 586e51a60fabf-24cbb884377so2799225fac.0 for ; Mon, 17 Jun 2024 15:19:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iol.unh.edu; s=unh-iol; t=1718662759; x=1719267559; darn=lists.ozlabs.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BtiKS4SBUY5yXpAB4KDAus2XQ0Baa875HzIcgz2Dy1Y=; b=N4EKi/81Lj3iQb3MuJ/oQIbASP02+hAvKy9LhtiDtOEYMSJxp49l9YmvL9GnO2THxi 8bVuPJUa+QZd+uaNRT6TsX7SDkS+vTihjnjtVfFfmvrWR8+TybiYtVcAYklmSv0Ugsqz Zab6LzdvfIka4aAuyjYEsRR+iVCA+tSHJ6YCE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718662759; x=1719267559; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BtiKS4SBUY5yXpAB4KDAus2XQ0Baa875HzIcgz2Dy1Y=; b=nHiUXyN6soz3IAq5vpk8VXADLHOkf/mixJpCrXh41GMA5Xz2C4MG+XOey94K61M7wA Ut5ZW5/bfJr6E8fCkwVrE3ijtKXhSMae2Wg13N7NK8K3m6H/PrFlO2blG3TGp82H+clQ 76RDR6E4LgOd/prOzBKVVstFVCGt94svJ1mZldhFgyDcRv9DiwGXv7WA2F5DGPYvBOOp kV0LZwJy0tWrTP6J+win63ErsU2ycpBRuPHpIuQRm4iXQPSeoc+MyfsyFvlpQ0aKog6G P+f1JhdO/fbC+dSQbNjtHosqL1pZTdKn994lWS2DwP4PXl0v7h0qDKL8guPTJjKUsr3Z DyAg== X-Gm-Message-State: AOJu0YxdvrAslk+mQ0XTLcFyTOmsu+q+wyCny25UnB77RVM5jIAXraZ8 UWTtFQWV+kEUbiKMM4owQ5alJR+svdxDT0vj9IBfHexszLZguc6ByNiQYTevvJLGpZeHmx5lPrH ziN+3usZqY+QqujMJfugRG1RrItws8h0NzT5nv47co8+1qNee9WW6U7MZ735Z8sYz1JqNeEzDGP jvk1LODRLN0v3SC/HfsX+e6MDckLNlzB7K0qh95OOULDZ0pg== X-Google-Smtp-Source: AGHT+IHDM8ezWLqgwe22Zyc+qQGJ841st8K/vaUmY9HkYesAO05D+eSxrR9faMysZ+fEZQ5YhLAvLA== X-Received: by 2002:a05:6870:b011:b0:254:a89e:acca with SMTP id 586e51a60fabf-2584258a3d9mr11769789fac.0.1718662759061; Mon, 17 Jun 2024 15:19:19 -0700 (PDT) Received: from bubs.loudonlune.net ([71.254.3.64]) by smtp.gmail.com with ESMTPSA id af79cd13be357-798aaee0e52sm469808185a.37.2024.06.17.15.19.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jun 2024 15:19:18 -0700 (PDT) From: Adam Hassick To: patchwork@lists.ozlabs.org Subject: [PATCH v1 5/9] urls: Increment API version Date: Mon, 17 Jun 2024 18:18:52 -0400 Message-ID: <20240617221900.156155-6-ahassick@iol.unh.edu> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240617221900.156155-1-ahassick@iol.unh.edu> References: <20240617221900.156155-1-ahassick@iol.unh.edu> MIME-Version: 1.0 X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" Add version 1.4 because new fields were added to the API. Reviewed-by: Stephen Finucane --- patchwork/urls.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/patchwork/urls.py b/patchwork/urls.py index ecd3668..11cd8e7 100644 --- a/patchwork/urls.py +++ b/patchwork/urls.py @@ -347,12 +347,16 @@ if settings.ENABLE_REST_API: urlpatterns += [ re_path( - r'^api/(?:(?P(1.0|1.1|1.2|1.3))/)?', include(api_patterns) + r'^api/(?:(?P(1.0|1.1|1.2|1.3|1.4))/)?', + include(api_patterns), ), re_path( - r'^api/(?:(?P(1.1|1.2|1.3))/)?', include(api_1_1_patterns) + r'^api/(?:(?P(1.1|1.2|1.3|1.4))/)?', + include(api_1_1_patterns), + ), + re_path( + r'^api/(?:(?P(1.3|1.4))/)?', include(api_1_3_patterns) ), - re_path(r'^api/(?:(?P(1.3))/)?', include(api_1_3_patterns)), # token change path( 'user/generate-token/', From patchwork Mon Jun 17 22:18:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Adam Hassick X-Patchwork-Id: 1948886 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=TAjmMDm8; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=112.213.38.117; helo=lists.ozlabs.org; envelope-from=patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W348S5lnrz20KL for ; Tue, 18 Jun 2024 08:20:40 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=TAjmMDm8; dkim-atps=neutral Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4W348R5Fk4z3g9L for ; Tue, 18 Jun 2024 08:20:39 +1000 (AEST) X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=iol.unh.edu Authentication-Results: lists.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=TAjmMDm8; dkim-atps=neutral Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=iol.unh.edu (client-ip=2607:f8b0:4864:20::736; helo=mail-qk1-x736.google.com; envelope-from=ahassick@iol.unh.edu; receiver=lists.ozlabs.org) Received: from mail-qk1-x736.google.com (mail-qk1-x736.google.com [IPv6:2607:f8b0:4864:20::736]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4W346z3fb9z3g9H for ; Tue, 18 Jun 2024 08:19:23 +1000 (AEST) Received: by mail-qk1-x736.google.com with SMTP id af79cd13be357-797e2834c4eso403820285a.0 for ; Mon, 17 Jun 2024 15:19:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iol.unh.edu; s=unh-iol; t=1718662761; x=1719267561; darn=lists.ozlabs.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=efLH9hkk/uAJ2gDXDXkenO17m7/faN2nt93sB/ZBpX4=; b=TAjmMDm8V23MrAXOaBgT12fttDLZSqhWjf3nxpIzRXdf4O2qKVvm+ZAhdOCnReViNe LxWkIJgsqIgMqGc1elgwMbllfaq9GNuIx133/5cZmiLLq3F86uo/YnHw5jiUvVbzRpAz q7VAkJENE2bON6ngRD3zbsT2Fy4yVPG9SLrSY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718662761; x=1719267561; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=efLH9hkk/uAJ2gDXDXkenO17m7/faN2nt93sB/ZBpX4=; b=q6zYIR6rArlVy48PGbAiT9jKzkIaat+RY4BBByHwWFm5i5rnL5Y8XjwiupSViWO1S5 e+y0oL88S+HwThYr0wtWChJiVOkAKL8KtmNbLyZYaU2Hyc0tkMzEcBaqfgfe3p7UEOsA m/6l6bcUSO7FsRIaGOjJLEjUx4JObPNtk1bxx+VU857UXy3bMAVMpkuaZ5cGpsYG/Pnr EjMwAs+fpL0xfiSe6LQcC6hw3Jf3Smg1QaJYIf2SMwcT5fwrVzHU/LI3lC2hb45MrRJR pZ9plTsn+LL/tEnzaETNPW2xvpRWH4BYpBJjKjnz5QSVGjg+PaZuWfk6z914MW6PkFZP QcEA== X-Gm-Message-State: AOJu0YzyUy2Ti5QPJbXUV9UcDHcEsSgZ1na+L/njXNsj7P9EUWBXcIJh Cmt78o4MrIcJ5M4wqnfPJzpNTTtgutMlaSFUPFdh3wWAorP68Ozjw21mdQn5s1z8JQWnxWavC0h kIpBZlzvPEjqfQDNK8M/XvjZ0/aI2+DV5FSK03k2U/ta4wUwmHRLquIBzP2azhFCOrTfPTbb/Kh Mj2oqioXS6gwmUFlDqFnLGWfDSLFkTDMOr9qkwcLwA8FOEOg== X-Google-Smtp-Source: AGHT+IEePFs/9Qh3aj/m15FyHyhgXvpAWbaPv5rcgYjunslmlj4aV5VtvsZwedmpudTd73vH+y0cZA== X-Received: by 2002:a05:620a:170b:b0:795:55ca:b287 with SMTP id af79cd13be357-79ba775a11amr168184085a.34.1718662759868; Mon, 17 Jun 2024 15:19:19 -0700 (PDT) Received: from bubs.loudonlune.net ([71.254.3.64]) by smtp.gmail.com with ESMTPSA id af79cd13be357-798aaee0e52sm469808185a.37.2024.06.17.15.19.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jun 2024 15:19:19 -0700 (PDT) From: Adam Hassick To: patchwork@lists.ozlabs.org Subject: [PATCH v1 6/9] docs: Increment API version Date: Mon, 17 Jun 2024 18:18:53 -0400 Message-ID: <20240617221900.156155-7-ahassick@iol.unh.edu> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240617221900.156155-1-ahassick@iol.unh.edu> References: <20240617221900.156155-1-ahassick@iol.unh.edu> MIME-Version: 1.0 X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" Update the OpenAPI specification template and the API docs to reflect the new minor version. Signed-off-by: Adam Hassick Reviewed-by: Stephen Finucane --- docs/api/rest/index.rst | 42 +- docs/api/rest/schemas/v1.3.rst | 4 +- docs/api/rest/schemas/v1.4.rst | 5 + docs/api/schemas/generate-schemas.py | 4 +- docs/api/schemas/latest/patchwork.yaml | 18 +- docs/api/schemas/patchwork.j2 | 18 + docs/api/schemas/v1.4/patchwork.yaml | 3242 ++++++++++++++++++++++++ docs/usage/overview.rst | 12 + 8 files changed, 3320 insertions(+), 25 deletions(-) create mode 100644 docs/api/rest/schemas/v1.4.rst create mode 100644 docs/api/schemas/v1.4/patchwork.yaml diff --git a/docs/api/rest/index.rst b/docs/api/rest/index.rst index 67022e6..cdf9104 100644 --- a/docs/api/rest/index.rst +++ b/docs/api/rest/index.rst @@ -8,7 +8,7 @@ This guide provides an overview of how one can interact with the REST API. For detailed information on type and response format of the various resources exposed by the API, refer to the web browsable API. This can be found at: - https://patchwork.example.com/api/1.3/ + https://patchwork.example.com/api/1.4/ where `patchwork.example.com` refers to the URL of your Patchwork instance. @@ -57,16 +57,16 @@ Patchwork instance hosted at `patchwork.example.com`, run: .. code-block:: shell - $ curl -s 'https://patchwork.example.com/api/1.3/' | python -m json.tool + $ curl -s 'https://patchwork.example.com/api/1.4/' | python -m json.tool { - "bundles": "https://patchwork.example.com/api/1.3/bundles/", - "covers": "https://patchwork.example.com/api/1.3/covers/", - "events": "https://patchwork.example.com/api/1.3/events/", - "patches": "https://patchwork.example.com/api/1.3/patches/", - "people": "https://patchwork.example.com/api/1.3/people/", - "projects": "https://patchwork.example.com/api/1.3/projects/", - "series": "https://patchwork.example.com/api/1.3/series/", - "users": "https://patchwork.example.com/api/1.3/users/" + "bundles": "https://patchwork.example.com/api/1.4/bundles/", + "covers": "https://patchwork.example.com/api/1.4/covers/", + "events": "https://patchwork.example.com/api/1.4/events/", + "patches": "https://patchwork.example.com/api/1.4/patches/", + "people": "https://patchwork.example.com/api/1.4/people/", + "projects": "https://patchwork.example.com/api/1.4/projects/", + "series": "https://patchwork.example.com/api/1.4/series/", + "users": "https://patchwork.example.com/api/1.4/users/" } @@ -82,14 +82,14 @@ well-supported. To repeat the above example using `requests`:, run >>> r = requests.get('https://patchwork.example.com/api/1.3/') >>> print(json.dumps(r.json(), indent=2)) { - "bundles": "https://patchwork.example.com/api/1.3/bundles/", - "covers": "https://patchwork.example.com/api/1.3/covers/", - "events": "https://patchwork.example.com/api/1.3/events/", - "patches": "https://patchwork.example.com/api/1.3/patches/", - "people": "https://patchwork.example.com/api/1.3/people/", - "projects": "https://patchwork.example.com/api/1.3/projects/", - "series": "https://patchwork.example.com/api/1.3/series/", - "users": "https://patchwork.example.com/api/1.3/users/" + "bundles": "https://patchwork.example.com/api/1.4/bundles/", + "covers": "https://patchwork.example.com/api/1.4/covers/", + "events": "https://patchwork.example.com/api/1.4/events/", + "patches": "https://patchwork.example.com/api/1.4/patches/", + "people": "https://patchwork.example.com/api/1.4/people/", + "projects": "https://patchwork.example.com/api/1.4/projects/", + "series": "https://patchwork.example.com/api/1.4/series/", + "users": "https://patchwork.example.com/api/1.4/users/" } Tools like `curl` and libraries like `requests` can be used to build anything @@ -108,7 +108,7 @@ Versioning ---------- By default, all requests will receive the latest version of the API: currently -``1.3``: +``1.4``: .. code-block:: http @@ -119,7 +119,7 @@ changes breaking your application: .. code-block:: http - GET /api/1.3 HTTP/1.1 + GET /api/1.4 HTTP/1.1 Older API versions will be deprecated and removed over time. For more information, refer to :ref:`rest-api-versions`. @@ -275,6 +275,7 @@ Supported Versions 1.1, 2.1, ✓ 1.2, 2.2, ✓ 1.3, 3.1, ✓ + 1.4, unreleased, ✓ Further information about this and more can typically be found in :doc:`the release notes `. @@ -292,6 +293,7 @@ Auto-generated schema documentation is provided below. /api/rest/schemas/v1.1 /api/rest/schemas/v1.2 /api/rest/schemas/v1.3 + /api/rest/schemas/v1.4 .. Links diff --git a/docs/api/rest/schemas/v1.3.rst b/docs/api/rest/schemas/v1.3.rst index 17a4421..6bbf1a5 100644 --- a/docs/api/rest/schemas/v1.3.rst +++ b/docs/api/rest/schemas/v1.3.rst @@ -1,5 +1,5 @@ -API v1.3 (latest) -================= +API v1.3 +======== .. openapi:: ../../schemas/v1.3/patchwork.yaml :examples: diff --git a/docs/api/rest/schemas/v1.4.rst b/docs/api/rest/schemas/v1.4.rst new file mode 100644 index 0000000..11e34f6 --- /dev/null +++ b/docs/api/rest/schemas/v1.4.rst @@ -0,0 +1,5 @@ +API v1.4 (latest) +================= + +.. openapi:: ../../schemas/v1.4/patchwork.yaml + :examples: diff --git a/docs/api/schemas/generate-schemas.py b/docs/api/schemas/generate-schemas.py index 14b7414..52008df 100755 --- a/docs/api/schemas/generate-schemas.py +++ b/docs/api/schemas/generate-schemas.py @@ -14,8 +14,8 @@ except ImportError: yaml = None ROOT_DIR = os.path.dirname(os.path.realpath(__file__)) -VERSIONS = [(1, 0), (1, 1), (1, 2), (1, 3), None] -LATEST_VERSION = (1, 3) +VERSIONS = [(1, 0), (1, 1), (1, 2), (1, 3), (1, 4), None] +LATEST_VERSION = (1, 4) def generate_schemas(): diff --git a/docs/api/schemas/latest/patchwork.yaml b/docs/api/schemas/latest/patchwork.yaml index 93e56fa..2591654 100644 --- a/docs/api/schemas/latest/patchwork.yaml +++ b/docs/api/schemas/latest/patchwork.yaml @@ -13,7 +13,7 @@ info: license: name: GPL v2 License url: https://www.gnu.org/licenses/gpl-2.0.html - version: '1.3' + version: '1.4' paths: /api: get: @@ -2605,6 +2605,22 @@ components: $ref: '#/components/schemas/PatchEmbedded' readOnly: true uniqueItems: true + dependencies: + title: Dependencies + type: array + items: + type: string + format: url + readOnly: true + uniqueItems: true + dependents: + title: Dependents + type: array + items: + type: string + format: url + readOnly: true + uniqueItems: true User: type: object title: User diff --git a/docs/api/schemas/patchwork.j2 b/docs/api/schemas/patchwork.j2 index 516fbe8..67e9253 100644 --- a/docs/api/schemas/patchwork.j2 +++ b/docs/api/schemas/patchwork.j2 @@ -2699,6 +2699,24 @@ components: $ref: '#/components/schemas/PatchEmbedded' readOnly: true uniqueItems: true +{% if version >= (1, 4) %} + dependencies: + title: Dependencies + type: array + items: + type: string + format: url + readOnly: true + uniqueItems: true + dependents: + title: Dependents + type: array + items: + type: string + format: url + readOnly: true + uniqueItems: true +{% endif %} User: type: object title: User diff --git a/docs/api/schemas/v1.4/patchwork.yaml b/docs/api/schemas/v1.4/patchwork.yaml new file mode 100644 index 0000000..3c9786c --- /dev/null +++ b/docs/api/schemas/v1.4/patchwork.yaml @@ -0,0 +1,3242 @@ +# DO NOT EDIT THIS FILE. It is generated from a template. Changes should be +# proposed against the template and updated files generated using the +# 'generate-schemas.py' tool +--- +openapi: '3.1.0' +info: + title: Patchwork API + description: | + Patchwork is a web-based patch tracking system designed to facilitate the + contribution and management of contributions to an open-source project. + contact: + email: patchwork@lists.ozlabs.org + license: + name: GPL v2 License + url: https://www.gnu.org/licenses/gpl-2.0.html + version: '1.4' +paths: + /api/1.4/: + get: + summary: List API resources. + description: | + Show paths to all supported API resources. + operationId: api_list + parameters: [] + responses: + '200': + description: 'List of API resources' + content: + application/json: + schema: + $ref: '#/components/schemas/Index' + tags: + - api + /api/1.4/bundles: + get: + summary: List bundles. + description: | + List all bundles that the current user has access to. + For unauthenticated requests, only public bundles can be shown. + operationId: bundles_list + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PageSize' + - $ref: '#/components/parameters/Order' + - $ref: '#/components/parameters/Search' + - in: query + name: project + description: An ID or linkname of a project to filter bundles by. + schema: + title: '' + type: string + - in: query + name: owner + description: An ID or username of a user to filter bundles by. + schema: + title: '' + type: string + - in: query + name: public + description: Show only public (`true`) or private (`false`) bundles. + schema: + title: '' + type: string + enum: + - 'true' + - 'false' + responses: + '200': + description: 'List of bundles' + headers: + Link: + $ref: '#/components/headers/Link' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Bundle' + tags: + - bundles + post: + summary: Create a bundle. + description: | + Create a new bundle. + operationId: bundles_create + security: + - basicAuth: [] + - apiKeyAuth: [] + requestBody: + $ref: '#/components/requestBodies/Bundle' + responses: + '201': + description: 'Created bundle' + content: + application/json: + schema: + $ref: '#/components/schemas/Bundle' + '400': + description: 'Invalid request' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBundleCreateUpdate' + '403': + description: 'Forbidden' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - bundles + /api/1.4/bundles/{id}: + parameters: + - in: path + name: id + required: true + description: A unique integer value identifying this bundle. + schema: + title: ID + type: integer + get: + summary: Show a bundle. + description: | + Retrieve a bundle by its ID. + The bundle must be either be public or be owned by the currently authenticated user. + operationId: bundles_read + responses: + '200': + description: 'A bundle' + content: + application/json: + schema: + $ref: '#/components/schemas/Bundle' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - bundles + patch: + summary: Update a bundle (partial). + description: + Partially update an existing bundle. + The bundle must be owned by the currently authenticated user. + operationId: bundles_partial_update + security: + - basicAuth: [] + - apiKeyAuth: [] + requestBody: + $ref: '#/components/requestBodies/Bundle' + responses: + '200': + description: 'Updated bundle' + content: + application/json: + schema: + $ref: '#/components/schemas/Bundle' + '400': + description: 'Bad request' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBundleCreateUpdate' + '403': + description: 'Forbidden' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - bundles + put: + summary: Update a bundle. + description: + Update an existing bundle. + The bundle must be owned by the currently authenticated user. + operationId: bundles_update + security: + - basicAuth: [] + - apiKeyAuth: [] + requestBody: + $ref: '#/components/requestBodies/Bundle' + responses: + '200': + description: 'Updated bundle' + content: + application/json: + schema: + $ref: '#/components/schemas/Bundle' + '400': + description: 'Bad request' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBundleCreateUpdate' + '403': + description: 'Forbidden' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - bundles + /api/1.4/covers: + get: + summary: List cover letters. + description: | + List all cover letters. + operationId: covers_list + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PageSize' + - $ref: '#/components/parameters/Order' + - $ref: '#/components/parameters/Search' + - $ref: '#/components/parameters/BeforeFilter' + - $ref: '#/components/parameters/SinceFilter' + - in: query + name: project + description: | + An ID or linkname of a project to filter cover letters by. + schema: + title: '' + type: string + - in: query + name: series + description: An ID of a series to filter cover letters by. + schema: + title: '' + type: string + - in: query + name: submitter + description: | + An ID or email address of a person to filter cover letters by. + schema: + title: '' + type: string + - in: query + name: msgid + description: | + The cover message-id as a case-sensitive string, without leading or + trailing angle brackets, to filter by. + schema: + title: '' + type: string + responses: + '200': + description: 'List of cover letters' + headers: + Link: + $ref: '#/components/headers/Link' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/CoverList' + tags: + - covers + /api/1.4/covers/{id}: + parameters: + - in: path + name: id + description: A unique integer value identifying this cover letter. + required: true + schema: + title: ID + type: integer + get: + summary: Show a cover letter. + description: | + Retrieve a cover letter by its ID. + operationId: covers_read + responses: + '200': + description: 'A cover letter' + content: + application/json: + schema: + $ref: '#/components/schemas/CoverDetail' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - covers + /api/1.4/covers/{id}/comments: + parameters: + - in: path + name: id + description: | + A unique integer value identifying the parent cover letter. + required: true + schema: + title: ID + type: integer + get: + summary: List cover letter comments + description: | + List all comments for the given cover letter. + operationId: cover_comments_list + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PageSize' + - $ref: '#/components/parameters/Order' + - $ref: '#/components/parameters/Search' + responses: + '200': + description: 'List of comments' + headers: + Link: + $ref: '#/components/headers/Link' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Comment' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - comments + /api/1.4/covers/{cover_id}/comments/{comment_id}: + parameters: + - in: path + name: cover_id + description: A unique integer value identifying the parent cover. + required: true + schema: + title: Cover ID + type: integer + - in: path + name: comment_id + description: A unique integer value identifying this comment. + required: true + schema: + title: Comment ID + type: integer + get: + summary: Show a cover letter comment. + description: | + Retrieve a cover letter comment by its ID. + operationId: cover_comments_read + responses: + '200': + description: 'A cover letter comment' + content: + application/json: + schema: + $ref: '#/components/schemas/Comment' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - comments + patch: + summary: Update a cover letter comment (partial). + description: + Partially update an existing cover letter comment. + You must be a maintainer of the project that the cover letter comment belongs to. + operationId: cover_comments_partial_update + requestBody: + $ref: '#/components/requestBodies/Comment' + responses: + '200': + description: 'Updated cover letter comment' + content: + application/json: + schema: + $ref: '#/components/schemas/Comment' + '400': + description: 'Invalid request' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorCommentUpdate' + '403': + description: 'Forbidden' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - comments + /api/1.4/events: + get: + summary: List events. + description: | + List all events. + This list can be quite large. You are encouraged to use filters to narrow it to specific categories or project(s). + operationId: events_list + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PageSize' + - $ref: '#/components/parameters/Order' + - $ref: '#/components/parameters/Search' + - $ref: '#/components/parameters/BeforeFilter' + - $ref: '#/components/parameters/SinceFilter' + - in: query + name: project + description: An ID or linkname of a project to filter events by. + schema: + title: '' + type: string + - in: query + name: category + description: | + An event category to filter events by. These categories are subject + to change depending on the version of Patchwork deployed and are + not subject to the versionining constraints present across the rest + of the API. + schema: + title: '' + type: string + enum: + - cover-created + - patch-created + - patch-completed + - patch-state-changed + - patch-relation-changed + - patch-delegated + - check-created + - series-created + - series-completed + - cover-comment-created + - patch-comment-created + - in: query + name: series + description: An ID of a series to filter events by. + schema: + title: '' + type: integer + - in: query + name: patch + description: An ID of a patch to filter events by. + schema: + title: '' + type: integer + - in: query + name: cover + description: An ID of a cover letter to filter events by. + schema: + title: '' + type: integer + responses: + '200': + description: 'List of events' + headers: + Link: + $ref: '#/components/headers/Link' + content: + application/json: + schema: + type: array + items: + anyOf: + - $ref: '#/components/schemas/EventCoverCreated' + - $ref: '#/components/schemas/EventPatchCreated' + - $ref: '#/components/schemas/EventPatchCompleted' + - $ref: '#/components/schemas/EventPatchStateChanged' + - $ref: '#/components/schemas/EventPatchRelationChanged' + - $ref: '#/components/schemas/EventPatchDelegated' + - $ref: '#/components/schemas/EventCheckCreated' + - $ref: '#/components/schemas/EventSeriesCreated' + - $ref: '#/components/schemas/EventSeriesCompleted' + - $ref: '#/components/schemas/EventCoverCommentCreated' + - $ref: '#/components/schemas/EventPatchCommentCreated' + discriminator: + propertyName: category + mapping: + cover-created: '#/components/schemas/EventCoverCreated' + patch-created: '#/components/schemas/EventPatchCreated' + patch-completed: '#/components/schemas/EventPatchCompleted' + patch-state-changed: '#/components/schemas/EventPatchStateChanged' + patch-relation-changed: '#/components/schemas/EventPatchRelationChanged' + patch-delegated: '#/components/schemas/EventPatchDelegated' + check-created: '#/components/schemas/EventCheckCreated' + series-created: '#/components/schemas/EventSeriesCreated' + series-completed: '#/components/schemas/EventSeriesCompleted' + cover-comment-created: '#/components/schemas/EventCoverCommentCreated' + patch-comment-created: '#/components/schemas/EventPatchCommentCreated' + tags: + - events + /api/1.4/patches: + get: + summary: List patches. + description: | + List all patches. + operationId: patches_list + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PageSize' + - $ref: '#/components/parameters/Order' + - $ref: '#/components/parameters/Search' + - $ref: '#/components/parameters/BeforeFilter' + - $ref: '#/components/parameters/SinceFilter' + - in: query + name: project + description: An ID or linkname of a project to filter patches by. + schema: + title: '' + type: string + - in: query + name: series + description: An ID of a series to filter patches by. + schema: + title: '' + type: integer + - in: query + name: submitter + description: | + An ID or email address of a person to filter patches by. + schema: + title: '' + type: string + - in: query + name: delegate + description: An ID or username of a user to filter patches by. + schema: + title: '' + type: string + - in: query + name: state + description: A slug representation of a state to filter patches by. + schema: + title: '' + type: string + - in: query + name: archived + description: | + Show only archived (`true`) or non-archived (`false`) patches. + schema: + title: '' + type: string + enum: + - 'true' + - 'false' + - in: query + name: hash + description: | + The patch hash as a case-insensitive hexadecimal string, to filter by. + schema: + title: '' + type: string + - in: query + name: msgid + description: | + The patch message-id as a case-sensitive string, without leading or + trailing angle brackets, to filter by. + schema: + title: '' + type: string + responses: + '200': + description: 'List of patches' + headers: + Link: + $ref: '#/components/headers/Link' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/PatchList' + tags: + - patches + /api/1.4/patches/{id}: + parameters: + - in: path + name: id + description: A unique integer value identifying this patch. + required: true + schema: + title: ID + type: integer + get: + summary: Show a patch. + description: | + Retrieve a patch by its ID. + operationId: patches_read + responses: + '200': + description: 'A patch' + content: + application/json: + schema: + $ref: '#/components/schemas/PatchDetail' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - patches + patch: + summary: Update a patch (partial). + description: + Partially update an existing patch. + You must be a maintainer of the project that the patch belongs to. + operationId: patches_partial_update + security: + - basicAuth: [] + - apiKeyAuth: [] + requestBody: + $ref: '#/components/requestBodies/Patch' + responses: + '200': + description: 'An updated patch' + content: + application/json: + schema: + $ref: '#/components/schemas/PatchDetail' + '400': + description: 'Invalid request' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorPatchUpdate' + '403': + description: 'Forbidden' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '409': + description: 'Conflict' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - patches + put: + description: Update a patch. + operationId: patches_update + security: + - basicAuth: [] + - apiKeyAuth: [] + requestBody: + $ref: '#/components/requestBodies/Patch' + responses: + '200': + description: 'An updated patch' + content: + application/json: + schema: + $ref: '#/components/schemas/PatchDetail' + '400': + description: 'Invalid request' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorPatchUpdate' + '403': + description: 'Forbidden' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '409': + description: 'Conflict' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - patches + /api/1.4/patches/{id}/comments: + parameters: + - in: path + name: id + description: A unique integer value identifying the parent patch. + required: true + schema: + title: ID + type: integer + get: + summary: List patch comments + description: | + List all comments for the given patch. + operationId: patch_comments_list + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PageSize' + - $ref: '#/components/parameters/Order' + - $ref: '#/components/parameters/Search' + responses: + '200': + description: 'List of comments' + headers: + Link: + $ref: '#/components/headers/Link' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Comment' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - comments + /api/1.4/patches/{patch_id}/comments/{comment_id}: + parameters: + - in: path + name: patch_id + description: A unique integer value identifying the parent patch. + required: true + schema: + title: Patch ID + type: integer + - in: path + name: comment_id + description: A unique integer value identifying this comment. + required: true + schema: + title: Comment ID + type: integer + get: + summary: Show a patch comment. + description: | + Retrieve a patch comment by its ID and the ID of the patch. + operationId: patch_comments_read + responses: + '200': + description: 'A patch comment' + content: + application/json: + schema: + $ref: '#/components/schemas/Comment' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - comments + patch: + summary: Update a patch comment (partial). + description: + Partially update an existing patch comment. + You must be a maintainer of the project that the patch comment belongs to. + operationId: patch_comments_partial_update + requestBody: + $ref: '#/components/requestBodies/Comment' + responses: + '200': + description: 'Updated patch' + content: + application/json: + schema: + $ref: '#/components/schemas/Comment' + '400': + description: 'Invalid request' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorCommentUpdate' + '403': + description: 'Forbidden' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - comments + /api/1.4/patches/{patch_id}/checks: + parameters: + - in: path + name: patch_id + description: A unique integer value identifying the parent patch. + required: true + schema: + title: Patch ID + type: integer + get: + summary: List checks. + description: | + List all checks for the given patch. + operationId: checks_list + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PageSize' + - $ref: '#/components/parameters/Order' + - $ref: '#/components/parameters/Search' + - $ref: '#/components/parameters/BeforeFilter' + - $ref: '#/components/parameters/SinceFilter' + - in: query + name: user + description: An ID or username of a user to filter checks by. + schema: + title: '' + type: string + - in: query + name: state + description: A check state to filter checks by. + schema: + title: '' + type: string + enum: + - pending + - success + - warning + - fail + - in: query + name: context + description: A check context to filter checks by. + schema: + title: '' + type: string + responses: + '200': + description: 'List of checks' + headers: + Link: + $ref: '#/components/headers/Link' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Check' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - checks + post: + summary: Create a check. + operationId: checks_create + security: + - basicAuth: [] + - apiKeyAuth: [] + requestBody: + $ref: '#/components/requestBodies/Check' + responses: + '201': + description: 'Created check' + content: + application/json: + schema: + $ref: '#/components/schemas/Check' + '400': + description: 'Invalid request' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorCheckCreate' + '403': + description: 'Forbidden' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - checks + /api/1.4/patches/{patch_id}/checks/{check_id}: + parameters: + - in: path + name: patch_id + description: A unique integer value identifying the parent patch. + required: true + schema: + title: Patch ID + type: integer + - in: path + name: check_id + description: A unique integer value identifying this check. + required: true + schema: + title: Check ID + type: integer + get: + summary: Show a check. + description: | + Retrieve a check by its ID. + operationId: checks_read + responses: + '200': + description: 'A check' + content: + application/json: + schema: + $ref: '#/components/schemas/Check' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - checks + /api/1.4/people: + get: + summary: List people. + description: | + List all people. + A person is anyone that has submitted a patch, a series of patches, or a comment to any project. + operationId: people_list + security: + - basicAuth: [] + - apiKeyAuth: [] + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PageSize' + - $ref: '#/components/parameters/Order' + - $ref: '#/components/parameters/Search' + responses: + '200': + description: 'List of people' + headers: + Link: + $ref: '#/components/headers/Link' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Person' + '403': + description: 'Forbidden' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - people + /api/1.4/people/{id}: + parameters: + - in: path + name: id + description: A unique integer value identifying this person. + required: true + schema: + title: ID + type: integer + get: + summary: Show a person. + description: | + Retrieve a person by their ID. + A person is anyone that has submitted a patch, a series of patches, or a comment to any project. + operationId: people_read + security: + - basicAuth: [] + - apiKeyAuth: [] + responses: + '200': + description: 'A person' + content: + application/json: + schema: + $ref: '#/components/schemas/Person' + '403': + description: 'Forbidden' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - people + /api/1.4/projects: + get: + summary: List projects. + description: | + List all projects. + operationId: projects_list + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PageSize' + - $ref: '#/components/parameters/Order' + - $ref: '#/components/parameters/Search' + responses: + '200': + description: 'List of projects' + headers: + Link: + $ref: '#/components/headers/Link' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Project' + tags: + - projects + /api/1.4/projects/{id}: + parameters: + - in: path + name: id + description: A unique integer value identifying this project. + required: true + schema: + title: ID + # TODO: Add regex? + type: string + get: + summary: Show a project. + description: | + Retrieve a project by its ID. + operationId: projects_read + responses: + '200': + description: 'A project' + content: + application/json: + schema: + $ref: '#/components/schemas/Project' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - projects + patch: + summary: Update a project (partial). + description: + Partially update an existing project. + You must be a maintainer of the project. + operationId: projects_partial_update + security: + - basicAuth: [] + - apiKeyAuth: [] + requestBody: + $ref: '#/components/requestBodies/Project' + responses: + '200': + description: 'Updated project' + content: + application/json: + schema: + $ref: '#/components/schemas/Project' + '400': + description: 'Bad request' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorProjectUpdate' + '403': + description: 'Forbidden' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - projects + put: + description: Update a project. + operationId: projects_update + security: + - basicAuth: [] + - apiKeyAuth: [] + requestBody: + $ref: '#/components/requestBodies/Project' + responses: + '200': + description: 'Updated project' + content: + application/json: + schema: + $ref: '#/components/schemas/Project' + '400': + description: 'Bad request' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorProjectUpdate' + '403': + description: 'Forbidden' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - projects + /api/1.4/series: + get: + summary: List series. + description: | + List all series. + A series is a collection of patches with an optional cover letter. + operationId: series_list + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PageSize' + - $ref: '#/components/parameters/Order' + - $ref: '#/components/parameters/Search' + - $ref: '#/components/parameters/BeforeFilter' + - $ref: '#/components/parameters/SinceFilter' + - in: query + name: submitter + description: An ID or email address of a person to filter series by. + schema: + title: '' + type: string + - in: query + name: project + description: An ID or linkname of a project to filter series by. + schema: + title: '' + type: string + responses: + '200': + description: 'List of series' + headers: + Link: + $ref: '#/components/headers/Link' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Series' + tags: + - series + /api/1.4/series/{id}: + parameters: + - in: path + name: id + description: A unique integer value identifying this series. + required: true + schema: + title: ID + type: integer + get: + summary: Show a series. + description: | + Retrieve a series by its ID. + A series is a collection of patches with an optional cover letter. + operationId: series_read + responses: + '200': + description: 'A series' + content: + application/json: + schema: + $ref: '#/components/schemas/Series' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - series + /api/1.4/users: + get: + summary: List users. + description: | + List all users. + operationId: users_list + security: + - basicAuth: [] + - apiKeyAuth: [] + parameters: + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/PageSize' + - $ref: '#/components/parameters/Order' + - $ref: '#/components/parameters/Search' + responses: + '200': + description: 'List of users' + headers: + Link: + $ref: '#/components/headers/Link' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + '403': + description: 'Forbidden' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - users + /api/1.4/users/{id}: + parameters: + - in: path + name: id + description: A unique integer value identifying this user. + required: true + schema: + title: ID + type: integer + get: + summary: Show a user. + description: | + Retrieve a user by their ID. + operationId: users_read + security: + - basicAuth: [] + - apiKeyAuth: [] + responses: + '200': + description: 'A user' + content: + application/json: + schema: + $ref: '#/components/schemas/UserDetail' + '403': + description: 'Forbidden' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - users + patch: + summary: Update a user (partial). + description: + Partially update a user account. + Only super users are allowed to update other user's accounts. + operationId: users_partial_update + security: + - basicAuth: [] + - apiKeyAuth: [] + requestBody: + $ref: '#/components/requestBodies/User' + responses: + '200': + description: 'Updated user' + content: + application/json: + schema: + $ref: '#/components/schemas/UserDetail' + '400': + description: 'Bad request' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorUserUpdate' + '403': + description: 'Forbidden' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - users + put: + description: Update a user. + operationId: users_update + security: + - basicAuth: [] + - apiKeyAuth: [] + requestBody: + $ref: '#/components/requestBodies/User' + responses: + '200': + description: 'Updated user' + content: + application/json: + schema: + $ref: '#/components/schemas/UserDetail' + '400': + description: 'Bad request' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorUserUpdate' + '403': + description: 'Forbidden' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: 'Not found' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + tags: + - users +components: + securitySchemes: + basicAuth: + type: http + scheme: basic + description: | + Basic authentication. This should be avoided and may be removed in a future API release. + apiKeyAuth: + type: http + scheme: token + description: | + Token-based authentication. + cookieAuth: + type: apiKey + in: cookie + name: JSESSIONID + description: | + Cookie-based authentication. This is mainly used for the browsable API. + parameters: + Page: + in: query + name: page + description: A page number within the paginated result set. + schema: + title: Page + type: integer + PageSize: + in: query + name: per_page + description: Number of results to return per page. + schema: + title: Page size + type: integer + Order: + in: query + name: order + description: Which field to use when ordering the results. + schema: + title: Ordering + type: string + Search: + in: query + name: q + description: A search term. + schema: + title: Search + type: string + BeforeFilter: + in: query + name: before + description: Latest date-time to retrieve results for. + schema: + title: '' + type: string + SinceFilter: + in: query + name: since + description: Earliest date-time to retrieve results for. + schema: + title: '' + type: string + headers: + Link: + description: | + Links to related resources, in the format defined by + [RFC 5988](https://tools.ietf.org/html/rfc5988#section-5). + This will include a link with relation type `next` to the + next page and `prev` to the previous page, if there is a next + or previous page. It will also include links with the + relation type `first` and `last` pointing to the first and + last page, respectively. + schema: + type: string + requestBodies: + Bundle: + required: true + description: | + A patch bundle. + content: + application/json: + schema: + $ref: '#/components/schemas/BundleCreateUpdate' + multipart/form-data: + schema: + $ref: '#/components/schemas/BundleCreateUpdate' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/BundleCreateUpdate' + Check: + required: true + description: | + A patch check. + content: + application/json: + schema: + $ref: '#/components/schemas/CheckCreate' + multipart/form-data: + schema: + $ref: '#/components/schemas/CheckCreate' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/CheckCreate' + Comment: + required: true + description: | + A patch or cover letter comment. + content: + application/json: + schema: + $ref: '#/components/schemas/CommentUpdate' + Patch: + required: true + description: | + A patch. + content: + application/json: + schema: + $ref: '#/components/schemas/PatchUpdate' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchUpdate' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchUpdate' + Project: + required: true + description: | + A project. + content: + application/json: + schema: + $ref: '#/components/schemas/Project' + multipart/form-data: + schema: + $ref: '#/components/schemas/Project' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/Project' + User: + required: true + description: | + A user. + content: + application/json: + schema: + $ref: '#/components/schemas/UserDetail' + multipart/form-data: + schema: + $ref: '#/components/schemas/UserDetail' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UserDetail' + schemas: + Index: + type: object + name: Index + description: | + Paths to resource APIs + properties: + bundles: + title: Bundles URL + type: string + format: uri + readOnly: true + covers: + title: Covers URL + type: string + format: uri + readOnly: true + events: + title: Events URL + type: string + format: uri + readOnly: true + patches: + title: Patches URL + type: string + format: uri + readOnly: true + people: + title: People URL + type: string + format: uri + readOnly: true + projects: + title: Projects URL + type: string + format: uri + readOnly: true + users: + title: Users URL + type: string + format: uri + readOnly: true + series: + title: Series URL + type: string + format: uri + readOnly: true + Bundle: + required: + - name + type: object + title: Bundle + description: | + A patch bundle + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: URL + type: string + format: uri + readOnly: true + web_url: + title: Web URL + type: string + format: uri + readOnly: true + project: + $ref: '#/components/schemas/ProjectEmbedded' + name: + title: Name + type: string + minLength: 1 + maxLength: 50 + owner: + title: Owner + readOnly: true + type: + - 'null' + - 'object' + oneOf: + - type: 'null' + - $ref: '#/components/schemas/UserEmbedded' + patches: + title: Patches + type: array + items: + $ref: '#/components/schemas/PatchEmbedded' + uniqueItems: true + public: + title: Public + type: boolean + mbox: + title: Mbox + description: | + A URL to download the bundle in mbox format. Patches will be + ordered in the same order that they are defined in the bundle. + type: string + format: uri + readOnly: true + BundleCreateUpdate: + type: object + title: Bundle create or update + description: | + The fields to set on a new or existing bundle. + required: + - name + properties: + name: + title: Name + type: string + minLength: 1 + maxLength: 50 + patches: + title: Patches + type: array + items: + type: integer + uniqueItems: true + public: + title: Public + type: boolean + Check: + type: object + title: Check + description: | + A patch check + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: Url + type: string + format: uri + readOnly: true + user: + $ref: '#/components/schemas/UserEmbedded' + date: + title: Date + type: string + format: iso8601 + readOnly: true + state: + title: State + description: The state of the check. + type: string + enum: + - pending + - success + - warning + - fail + target_url: + title: Target URL + description: | + The target URL to associate with this check. This should be + specific to the patch. + type: + - 'null' + - 'string' + oneOf: + - type: 'null' + - type: string + format: uri + maxLength: 200 + context: + title: Context + description: | + A label to discern check from checks of other testing systems. + type: string + pattern: ^[-a-zA-Z0-9_]+$ + minLength: 1 + maxLength: 255 + description: + title: Description + description: A brief description of the check. + type: + - 'null' + - 'string' + CheckCreate: + type: object + title: Check + description: | + A patch check + required: + - state + properties: + state: + title: State + description: The state of the check. + type: string + enum: + - pending + - success + - warning + - fail + target_url: + title: Target URL + description: | + The target URL to associate with this check. This should be + specific to the patch. + type: + - 'null' + - 'string' + oneOf: + - type: 'null' + - type: string + format: uri + maxLength: 200 + context: + title: Context + description: | + A label to discern check from checks of other testing systems. + type: string + pattern: ^[-a-zA-Z0-9_]+$ + minLength: 1 + maxLength: 255 + description: + title: Description + description: A brief description of the check. + type: + - 'null' + - 'string' + Comment: + type: object + title: Comment + description: | + A comment + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: URL + type: string + format: uri + readOnly: true + web_url: + title: Web URL + type: string + format: uri + readOnly: true + msgid: + title: Message ID + type: string + readOnly: true + minLength: 1 + maxLength: 255 + list_archive_url: + title: List archive URL + readOnly: true + type: + - 'null' + - 'string' + oneOf: + - type: 'null' + - type: string + format: uri + maxLength: 2000 + date: + title: Date + type: string + format: iso8601 + readOnly: true + subject: + title: Subject + type: string + readOnly: true + submitter: + type: object + title: Submitter + readOnly: true + allOf: + - $ref: '#/components/schemas/PersonEmbedded' + content: + title: Content + type: string + readOnly: true + minLength: 1 + headers: + title: Headers + anyOf: + - type: object + additionalProperties: + type: array + items: + type: string + - type: object + additionalProperties: + type: string + readOnly: true + addressed: + title: Addressed + type: + - 'null' + - 'boolean' + CommentUpdate: + type: object + title: Comment update + description: | + The fields to set on an existing comment. + properties: + addressed: + title: Addressed + type: + - 'null' + - 'boolean' + CoverList: + type: object + title: Cover letters + description: | + A list of cover letters + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: URL + type: string + format: uri + readOnly: true + web_url: + title: Web URL + type: string + format: uri + readOnly: true + project: + $ref: '#/components/schemas/ProjectEmbedded' + msgid: + title: Message ID + type: string + readOnly: true + minLength: 1 + maxLength: 255 + list_archive_url: + title: List archive URL + readOnly: true + type: + - 'null' + - 'string' + oneOf: + - type: 'null' + - type: string + format: uri + maxLength: 2000 + date: + title: Date + type: string + format: iso8601 + readOnly: true + name: + title: Name + type: string + readOnly: true + minLength: 1 + maxLength: 255 + submitter: + type: object + title: Submitter + readOnly: true + allOf: + - $ref: '#/components/schemas/PersonEmbedded' + mbox: + title: Mbox + description: | + A URL to download the cover letter in mbox format. + type: string + format: uri + readOnly: true + series: + type: array + items: + $ref: '#/components/schemas/SeriesEmbedded' + readOnly: true + comments: + title: Comments + type: string + format: uri + readOnly: true + CoverDetail: + type: object + title: Cover letters + description: | + A list of cover letters + allOf: + - $ref: '#/components/schemas/CoverList' + - type: object + properties: + headers: + title: Headers + anyOf: + - type: object + additionalProperties: + type: array + items: + type: string + - type: object + additionalProperties: + type: string + readOnly: true + content: + title: Content + type: string + readOnly: true + minLength: 1 + EventBase: + type: object + title: Event base + description: | + Base event. Not directly used. + properties: + id: + title: ID + type: integer + readOnly: true + category: + title: Category + description: The category of the event. + type: string + readOnly: true + project: + $ref: '#/components/schemas/ProjectEmbedded' + date: + title: Date + description: The time this event was created. + type: string + format: iso8601 + readOnly: true + actor: + title: Actor + description: The user that caused/created this event. + readOnly: true + type: + - 'null' + - 'object' + oneOf: + - type: 'null' + - $ref: '#/components/schemas/UserEmbedded' + payload: + type: object + EventCoverCreated: + title: Cover created event + description: | + A cover created event. + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + category: + enum: + - cover-created + payload: + properties: + cover: + $ref: '#/components/schemas/CoverEmbedded' + EventPatchCreated: + title: Patch created event + description: | + A patch created event. + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + category: + enum: + - patch-created + payload: + properties: + patch: + $ref: '#/components/schemas/PatchEmbedded' + EventPatchCompleted: + title: Patch completed event + description: | + A patch completed event. + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + category: + enum: + - patch-completed + payload: + properties: + patch: + $ref: '#/components/schemas/PatchEmbedded' + series: + $ref: '#/components/schemas/SeriesEmbedded' + EventPatchStateChanged: + title: Patch state change event + description: | + A patch state changed event. + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + category: + enum: + - patch-state-changed + payload: + properties: + patch: + $ref: '#/components/schemas/PatchEmbedded' + previous_state: + title: Previous state + type: string + current_state: + title: Current state + type: string + EventPatchRelationChanged: + title: Patch relation change event + description: | + A patch relation changed event. + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + category: + enum: + - patch-relation-changed + payload: + properties: + patch: + $ref: '#/components/schemas/PatchEmbedded' + previous_relation: + title: Previous relation + type: + - 'null' + - 'string' + current_relation: + title: Current relation + type: + - 'null' + - 'string' + EventPatchDelegated: + title: Patch delegated event + description: | + A patch delegated event. + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + category: + enum: + - patch-delegated + payload: + properties: + patch: + $ref: '#/components/schemas/PatchEmbedded' + previous_delegate: + title: Previous delegate + type: + - 'null' + - 'object' + oneOf: + - type: 'null' + - $ref: '#/components/schemas/UserEmbedded' + current_delegate: + title: Current delegate + type: + - 'null' + - 'object' + oneOf: + - type: 'null' + - $ref: '#/components/schemas/UserEmbedded' + EventCheckCreated: + title: Check create event + description: | + A check created event. + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + category: + enum: + - check-created + payload: + properties: + patch: + $ref: '#/components/schemas/PatchEmbedded' + check: + $ref: '#/components/schemas/CheckEmbedded' + EventSeriesCreated: + title: Series create event + description: | + A series created event. + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + category: + enum: + - series-created + payload: + properties: + series: + $ref: '#/components/schemas/SeriesEmbedded' + EventSeriesCompleted: + title: Series completed event + description: | + A series completed event. + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + category: + enum: + - series-completed + payload: + properties: + series: + $ref: '#/components/schemas/SeriesEmbedded' + EventCoverCommentCreated: + title: Cover letter comment create event + description: | + A comment letter comment created event. + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + category: + enum: + - cover-comment-created + payload: + properties: + cover: + $ref: '#/components/schemas/CoverEmbedded' + comment: + $ref: '#/components/schemas/CommentEmbedded' + EventPatchCommentCreated: + title: Patch comment create event + description: | + A patch comment created event. + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + category: + enum: + - patch-comment-created + payload: + properties: + patch: + $ref: '#/components/schemas/PatchEmbedded' + comment: + $ref: '#/components/schemas/CommentEmbedded' + PatchList: + required: + - state + - delegate + type: object + title: Patches + description: | + A list of patches. + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: URL + type: string + format: uri + readOnly: true + web_url: + title: Web URL + type: string + format: uri + readOnly: true + project: + $ref: '#/components/schemas/ProjectEmbedded' + msgid: + title: Message ID + type: string + readOnly: true + minLength: 1 + maxLength: 255 + list_archive_url: + title: List archive URL + readOnly: true + type: + - 'null' + - 'string' + oneOf: + - type: 'null' + - type: string + format: uri + maxLength: 2000 + date: + title: Date + type: string + format: iso8601 + readOnly: true + name: + title: Name + type: string + readOnly: true + minLength: 1 + maxLength: 255 + commit_ref: + title: Commit ref + type: + - 'null' + - 'string' + oneOf: + - type: 'null' + - type: string + maxLength: 255 + pull_url: + title: Pull URL + type: + - 'null' + - 'string' + oneOf: + - type: 'null' + - type: string + format: uri + maxLength: 255 + state: + title: State + type: string + archived: + title: Archived + type: boolean + hash: + title: Hash + type: string + readOnly: true + minLength: 1 + submitter: + type: object + title: Submitter + readOnly: true + allOf: + - $ref: '#/components/schemas/PersonEmbedded' + delegate: + title: Delegate + readOnly: true + type: + - 'null' + - 'object' + oneOf: + - type: 'null' + - $ref: '#/components/schemas/UserEmbedded' + mbox: + title: Mbox + description: | + A URL to download the patch in mbox format. Add the `series=*` + querystring parameter to include series dependencies in the mbox + file. + type: string + format: uri + readOnly: true + series: + type: array + items: + $ref: '#/components/schemas/SeriesEmbedded' + readOnly: true + comments: + title: Comments + type: string + format: uri + readOnly: true + check: + title: Check + type: string + readOnly: true + enum: + - pending + - success + - warning + - fail + checks: + title: Checks + type: string + format: uri + readOnly: true + tags: + title: Tags + type: object + additionalProperties: + type: string + readOnly: true + related: + title: Relations + type: array + items: + $ref: '#/components/schemas/PatchEmbedded' + PatchDetail: + type: object + title: Patches + description: | + A list of patches. + allOf: + - $ref: '#/components/schemas/PatchList' + - type: object + properties: + headers: + title: Headers + anyOf: + - type: object + additionalProperties: + type: array + items: + type: string + - type: object + additionalProperties: + type: string + readOnly: true + content: + title: Content + type: string + readOnly: true + minLength: 1 + diff: + title: Diff + type: string + readOnly: true + minLength: 1 + prefixes: + title: Prefixes + type: array + items: + type: string + readOnly: true + PatchUpdate: + type: object + title: Patch update + description: | + The fields to set on an existing patch. + properties: + commit_ref: + title: Commit ref + type: + - 'null' + - 'string' + oneOf: + - type: 'null' + - type: string + maxLength: 255 + pull_url: + title: Pull URL + type: + - 'null' + - 'string' + oneOf: + - type: 'null' + - type: string + format: uri + maxLength: 255 + state: + title: State + type: string + archived: + title: Archived + type: boolean + delegate: + title: Delegate + type: + - 'null' + - 'integer' + related: + title: Relations + type: array + items: + type: integer + Person: + type: object + title: Person + description: | + A person + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: URL + type: string + format: uri + readOnly: true + name: + title: Name + type: string + readOnly: true + minLength: 1 + maxLength: 255 + email: + title: Email + type: string + format: email + readOnly: true + minLength: 1 + maxLength: 255 + user: + title: User + readOnly: true + type: + - 'null' + - 'object' + oneOf: + - type: 'null' + - $ref: '#/components/schemas/UserEmbedded' + Project: + type: object + title: Project + description: | + A project. + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: URL + type: string + format: uri + readOnly: true + name: + title: Name + type: string + readOnly: true + minLength: 1 + maxLength: 255 + link_name: + title: Link name + type: string + readOnly: true + minLength: 1 + maxLength: 255 + list_id: + title: List ID + type: string + readOnly: true + minLength: 1 + maxLength: 255 + list_email: + title: List email + type: string + format: email + readOnly: true + minLength: 1 + maxLength: 200 + web_url: + title: Web URL + type: string + format: uri + maxLength: 2000 + scm_url: + title: SCM URL + type: string + format: uri + maxLength: 2000 + webscm_url: + title: Web SCM URL + type: string + format: uri + maxLength: 2000 + maintainers: + type: array + items: + $ref: '#/components/schemas/UserEmbedded' + readOnly: true + uniqueItems: true + subject_match: + title: Subject match + description: | + Regex to match the subject against if only part of emails sent to + the list belongs to this project. Will be used with IGNORECASE and + MULTILINE flags. If rules for more projects match the first one + returned from DB is chosen; empty field serves as a default for + every email which has no other match. + type: string + readOnly: true + maxLength: 64 + list_archive_url: + title: List archive URL + type: + - 'null' + - 'string' + oneOf: + - type: 'null' + - type: string + format: uri + maxLength: 2000 + list_archive_url_format: + title: List archive URL format + description: | + URL format for the list archive's Message-ID redirector. {} will be + replaced by the Message-ID. + type: + - 'null' + - 'string' + oneOf: + - type: 'null' + - type: string + format: uri + maxLength: 2000 + commit_url_format: + title: Web SCM URL format for a particular commit + type: string + Series: + type: object + title: Series + description: | + A series + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: URL + type: string + format: uri + readOnly: true + web_url: + title: Web URL + type: string + format: uri + readOnly: true + project: + $ref: '#/components/schemas/ProjectEmbedded' + name: + title: Name + description: | + An optional name to associate with the series, e.g. "John's PCI + series". + type: + - 'null' + - 'string' + oneOf: + - type: 'null' + - type: 'string' + maxLength: 255 + date: + title: Date + type: string + format: iso8601 + readOnly: true + submitter: + type: object + title: Submitter + readOnly: true + allOf: + - $ref: '#/components/schemas/PersonEmbedded' + version: + title: Version + description: | + Version of series as indicated by the subject prefix(es). + type: integer + total: + title: Total + description: | + Number of patches in series as indicated by the subject prefix(es). + type: integer + readOnly: true + received_total: + title: Received total + type: integer + readOnly: true + received_all: + title: Received all + type: boolean + readOnly: true + mbox: + title: Mbox + description: | + A URL to download the series in mbox format. + type: string + format: uri + readOnly: true + cover_letter: + $ref: '#/components/schemas/CoverEmbedded' + patches: + title: Patches + type: array + items: + $ref: '#/components/schemas/PatchEmbedded' + readOnly: true + uniqueItems: true + dependencies: + title: Dependencies + type: array + items: + type: string + format: url + readOnly: true + uniqueItems: true + dependents: + title: Dependents + type: array + items: + type: string + format: url + readOnly: true + uniqueItems: true + User: + type: object + title: User + description: | + A user + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: URL + type: string + format: uri + readOnly: true + username: + title: Username + type: string + readOnly: true + minLength: 1 + maxLength: 150 + first_name: + title: First name + type: string + maxLength: 30 + last_name: + title: Last name + type: string + maxLength: 150 + email: + title: Email address + type: string + format: email + readOnly: true + minLength: 1 + UserDetail: + type: object + title: User + description: | + A user + allOf: + - $ref: '#/components/schemas/User' + - type: object + properties: + settings: + type: object + properties: + send_email: + title: Send email + description: | + Whether Patchwork should send email on your behalf. + Only present and configurable for your account. + type: boolean + items_per_page: + title: Items per page + description: | + Number of items to display per page (web UI). + Only present and configurable for your account. + type: integer + show_ids: + title: Show IDs + description: | + Show click-to-copy IDs in the list view (web UI). + Only present and configurable for your account. + type: boolean + CheckEmbedded: + type: object + title: Check + description: | + A patch check + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: Url + type: string + format: uri + readOnly: true + date: + title: Date + type: string + format: iso8601 + readOnly: true + state: + title: State + description: The state of the check. + type: string + readOnly: true + enum: + - pending + - success + - warning + - fail + target_url: + title: Target url + description: | + The target URL to associate with this check. This should be specific + to the patch. + readOnly: true + type: + - 'null' + - 'string' + oneOf: + - type: 'null' + - type: string + format: uri + maxLength: 200 + context: + title: Context + description: | + A label to discern check from checks of other testing systems. + type: string + pattern: ^[-a-zA-Z0-9_]+$ + maxLength: 255 + minLength: 1 + readOnly: true + CommentEmbedded: + type: object + title: Comment + description: | + A comment + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: URL + type: string + format: uri + readOnly: true + web_url: + title: Web URL + type: string + format: uri + readOnly: true + msgid: + title: Message ID + type: string + readOnly: true + minLength: 1 + list_archive_url: + title: List archive URL + readOnly: true + type: + - 'null' + - 'string' + date: + title: Date + type: string + format: iso8601 + readOnly: true + name: + title: Name + type: string + readOnly: true + minLength: 1 + CoverEmbedded: + type: object + title: Cover letter + description: | + A cover letter + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: URL + type: string + format: uri + readOnly: true + web_url: + title: Web URL + type: string + format: uri + readOnly: true + msgid: + title: Message ID + type: string + readOnly: true + minLength: 1 + list_archive_url: + title: List archive URL + readOnly: true + type: + - 'null' + - 'string' + date: + title: Date + type: string + format: iso8601 + readOnly: true + name: + title: Name + type: string + readOnly: true + minLength: 1 + mbox: + title: Mbox + description: | + A URL to download the cover letter in mbox format. + type: string + format: uri + readOnly: true + PatchEmbedded: + type: object + title: Patch + description: | + A patch + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: URL + type: string + format: uri + readOnly: true + web_url: + title: Web URL + type: string + format: uri + readOnly: true + msgid: + title: Message ID + type: string + readOnly: true + minLength: 1 + list_archive_url: + title: List archive URL + readOnly: true + type: + - 'null' + - 'string' + date: + title: Date + type: string + format: iso8601 + readOnly: true + name: + title: Name + type: string + readOnly: true + minLength: 1 + mbox: + title: Mbox + description: | + A URL to download the patch in mbox format. Add the `series=*` + querystring parameter to include series dependencies in the mbox + file. + type: string + format: uri + readOnly: true + PersonEmbedded: + type: object + title: Person + description: | + A person + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: URL + type: string + format: uri + readOnly: true + name: + title: Name + type: string + readOnly: true + minLength: 1 + email: + title: Email + type: string + format: email + readOnly: true + minLength: 1 + ProjectEmbedded: + type: object + title: Project + description: | + A project + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: URL + type: string + format: uri + readOnly: true + name: + title: Name + type: string + readOnly: true + minLength: 1 + link_name: + title: Link name + type: string + readOnly: true + maxLength: 255 + minLength: 1 + list_id: + title: List ID + type: string + readOnly: true + maxLength: 255 + minLength: 1 + list_email: + title: List email + type: string + format: email + readOnly: true + maxLength: 200 + minLength: 1 + web_url: + title: Web URL + type: string + format: uri + readOnly: true + maxLength: 2000 + scm_url: + title: SCM URL + type: string + format: uri + readOnly: true + maxLength: 2000 + webscm_url: + title: WebSCM URL + type: string + format: uri + readOnly: true + maxLength: 2000 + list_archive_url: + title: List archive URL + type: + - 'null' + - 'string' + oneOf: + - type: 'null' + - type: string + format: uri + maxLength: 2000 + list_archive_url_format: + title: List archive URL format + description: | + URL format for the list archive's Message-ID redirector. {} will be + replaced by the Message-ID. + type: + - 'null' + - 'string' + oneOf: + - type: 'null' + - type: string + format: uri + maxLength: 2000 + commit_url_format: + title: Web SCM URL format for a particular commit + type: string + readOnly: true + SeriesEmbedded: + type: object + title: Series + description: | + A series + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: URL + type: string + format: uri + readOnly: true + web_url: + title: Web URL + type: string + format: uri + readOnly: true + name: + title: Name + description: | + An optional name to associate with the series, e.g. "John's PCI + series". + readOnly: true + type: + - 'null' + - 'string' + oneOf: + - type: 'null' + - type: string + maxLength: 255 + date: + title: Date + type: string + format: iso8601 + readOnly: true + version: + title: Version + description: | + Version of series as indicated by the subject prefix(es). + type: integer + readOnly: true + mbox: + title: Mbox + description: | + A URL to download the series in mbox format. + type: string + format: uri + readOnly: true + UserEmbedded: + type: object + title: User + description: | + A user + properties: + id: + title: ID + type: integer + readOnly: true + url: + title: URL + type: string + format: uri + readOnly: true + username: + title: Username + type: string + readOnly: true + minLength: 1 + maxLength: 150 + first_name: + title: First name + type: string + maxLength: 30 + readOnly: true + last_name: + title: Last name + type: string + maxLength: 150 + readOnly: true + email: + title: Email address + type: string + format: email + readOnly: true + minLength: 1 + Error: + type: object + title: A generic error. + description: | + A generic error. + properties: + detail: + title: Detail + type: string + readOnly: true + ErrorBundleCreateUpdate: + type: object + title: A bundle creation or update error. + description: | + A mapping of field names to validation failures. + properties: + name: + title: Name + type: array + items: + type: string + readOnly: true + patches: + title: Patches + type: array + items: + type: string + readOnly: true + public: + title: Public + type: array + items: + type: string + ErrorCheckCreate: + type: object + title: A check creation error. + description: | + A mapping of field names to validation failures. + properties: + state: + title: State + type: array + items: + type: string + readOnly: true + target_url: + title: Target URL + type: array + items: + type: string + readOnly: true + context: + title: Context + type: array + items: + type: string + readOnly: true + description: + title: Description + type: array + items: + type: string + readOnly: true + ErrorCommentUpdate: + type: object + title: A comment update error. + description: | + A mapping of field names to validation failures. + properties: + addressed: + title: Addressed + type: array + items: + type: string + ErrorPatchUpdate: + type: object + title: A patch update error. + description: | + A mapping of field names to validation failures. + properties: + state: + title: State + type: array + items: + type: string + readOnly: true + delegate: + title: Delegate + type: array + items: + type: string + readOnly: true + commit_ref: + title: Commit ref + type: array + items: + type: string + readOnly: true + archived: + title: Archived + type: array + items: + type: string + readOnly: true + ErrorProjectUpdate: + type: object + title: A project update error. + description: | + A mapping of field names to validation failures. + properties: + web_url: + title: Web URL + type: string + format: uri + readOnly: true + scm_url: + title: SCM URL + type: string + format: uri + readOnly: true + webscm_url: + title: Web SCM URL + type: string + format: uri + readOnly: true + ErrorUserUpdate: + type: object + title: A user update error. + description: | + A mapping of field names to validation failures. + properties: + first_name: + title: First name + type: string + readOnly: true + last_name: + title: First name + type: string + readOnly: true +tags: + - name: api + description: General API operations + - name: patches + description: Patch operations + - name: covers + description: Cover letter operations + - name: series + description: Series operations + - name: comments + description: Comment operations + - name: people + description: Submitter operations + - name: users + description: User operations + - name: bundles + description: Bundle operations + - name: projects + description: Project operations + - name: bundles + description: Bundle operations + - name: checks + description: Check operations + - name: events + description: Event operations diff --git a/docs/usage/overview.rst b/docs/usage/overview.rst index 297569e..7d9d32c 100644 --- a/docs/usage/overview.rst +++ b/docs/usage/overview.rst @@ -139,6 +139,18 @@ the email. The following tags are available on a standard Patchwork install: Reviewed-by: Stephen Finucane +Patchwork includes an optional built-in tag for declaring dependencies between +series. The series ID, the ID of a patch in a series, or the web URL to either +may be used to indicate a dependency. This may be included in the cover letter +or any patch file: + +``Depends-on:`` + For example:: + + Depends-on: series-1234 + Depends-on: patch-4567 + Depends-on: https://patchwork.example.com/project/testproject/list?series=7890 + The available tags, along with the significance of said tags, varies from project to project and Patchwork instance to Patchwork instance. The `kernel project documentation`__ provides an overview of the supported tags for the From patchwork Mon Jun 17 22:18:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Hassick X-Patchwork-Id: 1948885 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=d7AFbQYy; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:2:0:216:3eff:fee1:b9f1; helo=lists.ozlabs.org; envelope-from=patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:2:0:216:3eff:fee1:b9f1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W348F31tjz20KL for ; Tue, 18 Jun 2024 08:20:29 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=d7AFbQYy; dkim-atps=neutral Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4W348D2cRyz3gHL for ; Tue, 18 Jun 2024 08:20:28 +1000 (AEST) X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=iol.unh.edu Authentication-Results: lists.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=d7AFbQYy; dkim-atps=neutral Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=iol.unh.edu (client-ip=2607:f8b0:4864:20::22b; helo=mail-oi1-x22b.google.com; envelope-from=ahassick@iol.unh.edu; receiver=lists.ozlabs.org) Received: from mail-oi1-x22b.google.com (mail-oi1-x22b.google.com [IPv6:2607:f8b0:4864:20::22b]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4W346z3b2Wz3g9B for ; Tue, 18 Jun 2024 08:19:22 +1000 (AEST) Received: by mail-oi1-x22b.google.com with SMTP id 5614622812f47-3d21f253a53so2400370b6e.2 for ; Mon, 17 Jun 2024 15:19:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iol.unh.edu; s=unh-iol; t=1718662760; x=1719267560; darn=lists.ozlabs.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=9C/x144/FyKzOcAc6O1S9BcXn1eil7Nhbrj7FJWKOfY=; b=d7AFbQYy8NXB8zz8O6ogBdSBfRpbTQfSEiZFQw7ECuFmmiZCogz3KZEhLYsXs5zUDj dwdyrrGflIJ1vcgpsWdwwl3IkZK4dXxDsbnmFCcQjD3wVHDH9N4nwCaEvgHWzhjHDnY6 aB88tbfW3kwEE3WQGL6WfTl6VKqLCVaNM8HLI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718662760; x=1719267560; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=9C/x144/FyKzOcAc6O1S9BcXn1eil7Nhbrj7FJWKOfY=; b=K02qsWkbVERCwPyJxX8rcwO4mXelKAAMoLmQ1cHQBvGJRMS2G8O5i+bd+ZTomSQ6Cd cUewYW/7kZ7QGRf+5j2n5ZqhuFqBHrIQ6z+EYNBYXRNKP97Go9LcVGvxGnt60wfbLugA RaXeORf7CSllo/nCVtujNCc6lYlc7ZiCuCLRTBuGLaYJDxzqWFt9QwsJUUcUP1AurtUL B1PpWeOdFCu7nwFOBAsfvJxI16gGqGwKBOX0+etDeSKr6Jgh+49kN8AbqkTivId/ZVlu 5YmjNLIozj2+r1zQJa9EBVKvlNpxEcjPz32VJ9SYJ9W30u+As50uAhGZWN+kD9OhM4TJ Yf+A== X-Gm-Message-State: AOJu0YwmtuVbXS5opV991FzrMOgThnOeWZjwnbdX8Nr6lC1VbvXc2+m0 NUoiSWwhxniY/weHM6h/7GfUVZqUNl+tCpvgjR3ynKt97MVrfsZ9r2TgN3yktBK/BsnkjvBDNxY gV8ZqJzA1o+UpnO61baBJ5hOMm5wyLhAiIQ79hvpgSrFoUWzYqYhT+e+bYtnB3ZdMkscRPjO4yP WIFqcpWvFpsUcxppKE/X23IKdOUiswK+nJBTvMIuk5H+l4lA== X-Google-Smtp-Source: AGHT+IGEUrEf1g/Wzpo8hdmwihsHLD3b/DpJU9QbgUNbAcRNexWWbAH4aX4st6sxHZI+jdX4Q5yrpw== X-Received: by 2002:a05:6808:1493:b0:3d2:178b:3332 with SMTP id 5614622812f47-3d24ea08ee4mr11916817b6e.49.1718662760502; Mon, 17 Jun 2024 15:19:20 -0700 (PDT) Received: from bubs.loudonlune.net ([71.254.3.64]) by smtp.gmail.com with ESMTPSA id af79cd13be357-798aaee0e52sm469808185a.37.2024.06.17.15.19.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jun 2024 15:19:20 -0700 (PDT) From: Adam Hassick To: patchwork@lists.ozlabs.org Subject: [PATCH v1 7/9] migrations: Add migration for new field Date: Mon, 17 Jun 2024 18:18:54 -0400 Message-ID: <20240617221900.156155-8-ahassick@iol.unh.edu> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240617221900.156155-1-ahassick@iol.unh.edu> References: <20240617221900.156155-1-ahassick@iol.unh.edu> MIME-Version: 1.0 X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" Signed-off-by: Adam Hassick --- .../migrations/0047_series_dependencies.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 patchwork/migrations/0047_series_dependencies.py diff --git a/patchwork/migrations/0047_series_dependencies.py b/patchwork/migrations/0047_series_dependencies.py new file mode 100644 index 0000000..5abbcc3 --- /dev/null +++ b/patchwork/migrations/0047_series_dependencies.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.6 on 2024-06-07 02:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ('patchwork', '0046_patch_comment_events'), + ] + + operations = [ + migrations.AddField( + model_name='series', + name='dependencies', + field=models.ManyToManyField( + blank=True, + help_text='Optional dependencies on this patch.', + related_name='dependents', + related_query_name='dependent', + to='patchwork.series', + ), + ), + ] From patchwork Mon Jun 17 22:18:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Hassick X-Patchwork-Id: 1948888 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=BNIFaMts; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:2:0:216:3eff:fee1:b9f1; helo=lists.ozlabs.org; envelope-from=patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:2:0:216:3eff:fee1:b9f1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W348t3Rn9z20KL for ; Tue, 18 Jun 2024 08:21:02 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=BNIFaMts; dkim-atps=neutral Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4W348s30lJz3g9K for ; Tue, 18 Jun 2024 08:21:01 +1000 (AEST) X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=iol.unh.edu Authentication-Results: lists.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=BNIFaMts; dkim-atps=neutral Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=iol.unh.edu (client-ip=2607:f8b0:4864:20::72a; helo=mail-qk1-x72a.google.com; envelope-from=ahassick@iol.unh.edu; receiver=lists.ozlabs.org) Received: from mail-qk1-x72a.google.com (mail-qk1-x72a.google.com [IPv6:2607:f8b0:4864:20::72a]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4W34701Zzxz3gB7 for ; Tue, 18 Jun 2024 08:19:23 +1000 (AEST) Received: by mail-qk1-x72a.google.com with SMTP id af79cd13be357-7955f3d4516so521004185a.1 for ; Mon, 17 Jun 2024 15:19:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iol.unh.edu; s=unh-iol; t=1718662761; x=1719267561; darn=lists.ozlabs.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=DHzS1tp27YQIMzCeT0awAKbmTy1QLJF1lBumYBT/T6I=; b=BNIFaMtsQhlqRBN63tgyvQhb59sdh0VicPf7zRAZTbD4qwFI47tcif2uaYe2ufjJhu y+pOyfqzYXNj3tWstwsI0dPxOHNJ3iI7kx+NiI5WlyjX7LHcGsA/KbmOTjKL8+DviqsI L8cZx4QXeEUM0q5CFuohn86wCHra6UPPdwbr4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718662761; x=1719267561; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=DHzS1tp27YQIMzCeT0awAKbmTy1QLJF1lBumYBT/T6I=; b=lJRDI/UOGFjDraLDyJgOnN2xRu1Ww/6tkpmQUvH0gzlsqYYy1Tm1lt/Yp57bB6OvPv GPlFLRv0qOowCNjkqhs4u+SxE7rl3pNO2xtTD4sQ7mzOQoM7PQ5PGkJW+kQZyrxMq+6n VeIjXMSyJVwXrIyUAqq/hAq7oFIp9Dxk5TGq4qfNlFU+hOxB8WBbjuyjyRu8N/fsrRDF obu6ipTrfm36YWPrv9vIwU62wVR8/D7CQA4qdpZ30n67HhIFquqeLcKtSFU8otv7yaIx Psl5/rD+jNqnjWPvVro4jR10nNGnHoiD+r0jj2DvBnPw5hwGNN95aYTF6meLDtyNd/Pv pOug== X-Gm-Message-State: AOJu0YxpNjREorJa594sAwKyBbIgJ+6kH/1SrU6bld+/9tgDGhjkVLbp b4/NOjK9+OIVharSgPwC9+kkxxOLosvOXko3V/vERLW+7PmJETZ6+0fJECNhgjdhCtVgzdFgfH5 8m+rRMlecdhrEdRq8gR5H4/PI1gp8rCqc3O8HEMV6p7IkG1AEWGYTnXhqs25RHHAGmJroL+38wI jTELhyLsHxb/p6sPBlHV1S/24L0i05xxFm9vAfoD2gV/AP+w== X-Google-Smtp-Source: AGHT+IHWZdADFbvSD98nJUV/VPd4m3AkviFxR8CLBziaF7n6B78r/JPtmBDzm78xMek91QDQl3SsKg== X-Received: by 2002:a05:620a:4088:b0:799:b171:b1fe with SMTP id af79cd13be357-79ba76d9afemr179508185a.14.1718662761160; Mon, 17 Jun 2024 15:19:21 -0700 (PDT) Received: from bubs.loudonlune.net ([71.254.3.64]) by smtp.gmail.com with ESMTPSA id af79cd13be357-798aaee0e52sm469808185a.37.2024.06.17.15.19.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jun 2024 15:19:20 -0700 (PDT) From: Adam Hassick To: patchwork@lists.ozlabs.org Subject: [PATCH v1 8/9] tests: Add tests for new functionality Date: Mon, 17 Jun 2024 18:18:55 -0400 Message-ID: <20240617221900.156155-9-ahassick@iol.unh.edu> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240617221900.156155-1-ahassick@iol.unh.edu> References: <20240617221900.156155-1-ahassick@iol.unh.edu> MIME-Version: 1.0 X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" * Adds tests for the API and parser changes. * Add new test mbox files. * Add new patch series tests. Signed-off-by: Adam Hassick Reviewed-by: Stephen Finucane --- patchwork/tests/api/test_series.py | 33 ++- .../tests/series/dependency-base-patch.mbox | 102 +++++++ .../series/dependency-multi-2.mbox.template | 110 ++++++++ .../series/dependency-multi.mbox.template | 109 ++++++++ .../series/dependency-one-cover.mbox.template | 128 +++++++++ .../dependency-one-first-patch.mbox.template | 125 +++++++++ patchwork/tests/test_parser.py | 49 ++++ patchwork/tests/test_series.py | 260 ++++++++++++++++++ 8 files changed, 915 insertions(+), 1 deletion(-) create mode 100644 patchwork/tests/series/dependency-base-patch.mbox create mode 100644 patchwork/tests/series/dependency-multi-2.mbox.template create mode 100644 patchwork/tests/series/dependency-multi.mbox.template create mode 100644 patchwork/tests/series/dependency-one-cover.mbox.template create mode 100644 patchwork/tests/series/dependency-one-first-patch.mbox.template diff --git a/patchwork/tests/api/test_series.py b/patchwork/tests/api/test_series.py index 730678a..86954b0 100644 --- a/patchwork/tests/api/test_series.py +++ b/patchwork/tests/api/test_series.py @@ -44,6 +44,20 @@ class TestSeriesAPI(utils.APITestCase): self.assertIn(series_obj.get_mbox_url(), series_json['mbox']) self.assertIn(series_obj.get_absolute_url(), series_json['web_url']) + for dep, item in zip( + series_obj.dependencies.all(), series_json['dependencies'] + ): + self.assertIn( + reverse('api-series-detail', kwargs={'pk': dep.id}), item + ) + + for dep, item in zip( + series_obj.dependents.all(), series_json['dependents'] + ): + self.assertIn( + reverse('api-series-detail', kwargs={'pk': dep.id}), item + ) + # nested fields self.assertEqual(series_obj.project.id, series_json['project']['id']) @@ -95,6 +109,21 @@ class TestSeriesAPI(utils.APITestCase): series_rsp = resp.data[0] self.assertSerialized(series, series_rsp) + def test_dependencies(self): + project_obj = create_project(linkname='myproject') + person_obj = create_person(email='test@example.com') + series1 = create_series(project=project_obj, submitter=person_obj) + create_cover(series=series1) + create_patch(series=series1) + series2 = create_series(project=project_obj, submitter=person_obj) + create_cover(series=series2) + create_patch(series=series2) + series1.add_dependencies([series2]) + resp = self.client.get(self.api_url()) + self.assertEqual(2, len(resp.data)) + self.assertSerialized(series2, resp.data[1]) + self.assertSerialized(series1, resp.data[0]) + def test_list_filter_project(self): """Filter series by project.""" series = self._create_series() @@ -152,7 +181,7 @@ class TestSeriesAPI(utils.APITestCase): create_cover(series=series_obj) create_patch(series=series_obj) - with self.assertNumQueries(6): + with self.assertNumQueries(8): self.client.get(self.api_url()) @utils.store_samples('series-detail') @@ -175,6 +204,8 @@ class TestSeriesAPI(utils.APITestCase): self.assertNotIn('web_url', resp.data['cover_letter']) self.assertNotIn('mbox', resp.data['cover_letter']) self.assertNotIn('web_url', resp.data['patches'][0]) + self.assertNotIn('dependents', resp.data) + self.assertNotIn('dependencies', resp.data) def test_detail_non_existent(self): """Ensure we get a 404 for a non-existent series.""" diff --git a/patchwork/tests/series/dependency-base-patch.mbox b/patchwork/tests/series/dependency-base-patch.mbox new file mode 100644 index 0000000..e7f9e94 --- /dev/null +++ b/patchwork/tests/series/dependency-base-patch.mbox @@ -0,0 +1,102 @@ +From ahassick@iol.unh.edu Mon Jun 10 21:09:07 2024 +Return-Path: +From: Adam Hassick +To: Adam.Hassick@unh.edu +Subject: [PATCH v1 0/2] Add test files for testing +Date: Mon, 10 Jun 2024 17:09:07 -0400 +Message-ID: <20240610210912.161735-1-ahassick@iol.unh.edu> +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit + +Add a test program and a makefile. +Big surprise here, but this is all for testing. + +Adam Hassick (2): + Add test program + Add a Makefile + + Makefile | 9 +++++++++ + test.c | 8 ++++++++ + 2 files changed, 17 insertions(+) + create mode 100644 Makefile + create mode 100644 test.c + +-- +2.45.2 + + +From ahassick@iol.unh.edu Mon Jun 10 21:09:09 2024 +Return-Path: +From: Adam Hassick +To: Adam.Hassick@unh.edu +Subject: [PATCH v1 1/2] Add test program +Date: Mon, 10 Jun 2024 17:09:09 -0400 +Message-ID: <20240610210912.161735-3-ahassick@iol.unh.edu> +In-Reply-To: <20240610210912.161735-1-ahassick@iol.unh.edu> +References: <20240610210912.161735-1-ahassick@iol.unh.edu> +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit + + + +Signed-off-by: Adam Hassick +--- + test.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + create mode 100644 test.c + +diff --git a/test.c b/test.c +new file mode 100644 +index 0000000..5096204 +--- /dev/null ++++ b/test.c +@@ -0,0 +1,8 @@ ++ ++#include ++ ++int main() { ++ printf("HELLOOOOO!!!! Hi there!"); ++ return 0; ++} ++ +-- +2.45.2 + + +From ahassick@iol.unh.edu Mon Jun 10 21:09:11 2024 +Return-Path: +From: Adam Hassick +To: Adam.Hassick@unh.edu +Subject: [PATCH v1 2/2] Add a Makefile +Date: Mon, 10 Jun 2024 17:09:11 -0400 +Message-ID: <20240610210912.161735-5-ahassick@iol.unh.edu> +In-Reply-To: <20240610210912.161735-1-ahassick@iol.unh.edu> +References: <20240610210912.161735-1-ahassick@iol.unh.edu> +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit + +How are people supposed to build this without a Makefile? + +Signed-off-by: Adam Hassick +--- + Makefile | 9 +++++++++ + 1 file changed, 9 insertions(+) + create mode 100644 Makefile + +diff --git a/Makefile b/Makefile +new file mode 100644 +index 0000000..2126a0e +--- /dev/null ++++ b/Makefile +@@ -0,0 +1,9 @@ ++ ++CC=gcc ++ ++test: test.c ++ $(CC) -O2 -march=native -mtune=native test.c -o test ++ ++test-debug: test.c ++ $(CC) -O0 -g test.c -o test ++ +-- +2.45.2 diff --git a/patchwork/tests/series/dependency-multi-2.mbox.template b/patchwork/tests/series/dependency-multi-2.mbox.template new file mode 100644 index 0000000..42296f4 --- /dev/null +++ b/patchwork/tests/series/dependency-multi-2.mbox.template @@ -0,0 +1,110 @@ +From ahassick@iol.unh.edu Wed Jun 12 20:40:05 2024 +Return-Path: +From: Adam Hassick +To: Adam.Hassick@unh.edu +Cc: Adam Hassick +Subject: [PATCH v1 0/2] More changes +Date: Wed, 12 Jun 2024 16:40:05 -0400 +Message-ID: <20240612204019.364820-1-ahassick@iol.unh.edu> +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit + +Tests. + +Adam Hassick (2): + test: Change the test function + Fix Makefile + + Makefile | 2 +- + test.c | 10 ++++++++-- + 2 files changed, 9 insertions(+), 3 deletions(-) + +-- +2.45.2 + + +From ahassick@iol.unh.edu Wed Jun 12 20:40:06 2024 +Return-Path: +From: Adam Hassick +To: Adam.Hassick@unh.edu +Cc: Adam Hassick +Subject: [PATCH v1 1/2] test: Change the test function +Date: Wed, 12 Jun 2024 16:40:06 -0400 +Message-ID: <20240612204019.364820-2-ahassick@iol.unh.edu> +In-Reply-To: <20240612204019.364820-1-ahassick@iol.unh.edu> +References: <20240612204019.364820-1-ahassick@iol.unh.edu> +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit + +I don't like what it did before. Let's make it do something more +interesting this time. + +Depends-on: {depends_token_1} +Signed-off-by: Adam Hassick +--- + test.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/test.c b/test.c +index f6cd16e..a868311 100644 +--- a/test.c ++++ b/test.c +@@ -1,11 +1,17 @@ + + #include ++#include + #include + + // This function does things. + void thingymabob(char *string) {{ +- printf("Here's your argument: %s\n", string); +- printf("Here is the length of your argument: %li\n", strlen(string)); ++ double f = atof(string); ++ ++ if (f > 5.0) {{ ++ printf("I'm satisfied.\n"); ++ }} else {{ ++ fprintf(stderr, "I'm not satisfied.\n"); ++ }} + }} + + // Entry point. +-- +2.45.2 + + +From ahassick@iol.unh.edu Wed Jun 12 20:40:07 2024 +Return-Path: +From: Adam Hassick +To: Adam.Hassick@unh.edu +Cc: Adam Hassick +Subject: [PATCH v1 2/2] Fix Makefile +Date: Wed, 12 Jun 2024 16:40:07 -0400 +Message-ID: <20240612204019.364820-3-ahassick@iol.unh.edu> +X-Mailer: git-send-email 2.45.2 +In-Reply-To: <20240612204019.364820-1-ahassick@iol.unh.edu> +References: <20240612204019.364820-1-ahassick@iol.unh.edu> +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit + +The test-debug target did not generate the correct file. + +Depends-on: {depends_token_2} +Signed-off-by: Adam Hassick +--- + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index 3583b93..78a2bf0 100644 +--- a/Makefile ++++ b/Makefile +@@ -9,5 +9,5 @@ test: test.c + $(CC) -O2 -march=native -mtune=native -Wall -Werror -pedantic test.c -o test + + test-debug: test.c +- $(CC) -O0 -g test.c -Wall -Werror -pedantic -o test ++ $(CC) -O0 -g test.c -Wall -Werror -pedantic -o test-debug + +-- +2.45.2 diff --git a/patchwork/tests/series/dependency-multi.mbox.template b/patchwork/tests/series/dependency-multi.mbox.template new file mode 100644 index 0000000..40fba59 --- /dev/null +++ b/patchwork/tests/series/dependency-multi.mbox.template @@ -0,0 +1,109 @@ +From ahassick@iol.unh.edu Wed Jun 12 20:40:05 2024 +Return-Path: +From: Adam Hassick +To: ach1062@usnh.edu +Cc: Adam Hassick +Subject: [PATCH v1 0/2] More changes +Date: Wed, 12 Jun 2024 16:40:05 -0400 +Message-ID: <20240612204019.364820-1-ahassick@iol.unh.edu> +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit + +Tests. + +Depends-on: {depends_token_1} +Depends-on: {depends_token_2} +Adam Hassick (2): + test: Change the test function + Fix Makefile + + Makefile | 2 +- + test.c | 10 ++++++++-- + 2 files changed, 9 insertions(+), 3 deletions(-) + +-- +2.45.2 + + +From ahassick@iol.unh.edu Wed Jun 12 20:40:06 2024 +Return-Path: +From: Adam Hassick +To: ach1062@usnh.edu +Cc: Adam Hassick +Subject: [PATCH v1 1/2] test: Change the test function +Date: Wed, 12 Jun 2024 16:40:06 -0400 +Message-ID: <20240612204019.364820-2-ahassick@iol.unh.edu> +In-Reply-To: <20240612204019.364820-1-ahassick@iol.unh.edu> +References: <20240612204019.364820-1-ahassick@iol.unh.edu> +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit + +I don't like what it did before. Let's make it do something more +interesting this time. + +Signed-off-by: Adam Hassick +--- + test.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/test.c b/test.c +index f6cd16e..a868311 100644 +--- a/test.c ++++ b/test.c +@@ -1,11 +1,17 @@ + + #include ++#include + #include + + // This function does things. + void thingymabob(char *string) {{ +- printf("Here's your argument: %s\n", string); +- printf("Here is the length of your argument: %li\n", strlen(string)); ++ double f = atof(string); ++ ++ if (f > 5.0) {{ ++ printf("I'm satisfied.\n"); ++ }} else {{ ++ fprintf(stderr, "I'm not satisfied.\n"); ++ }} + }} + + // Entry point. +-- +2.45.2 + + +From ahassick@iol.unh.edu Wed Jun 12 20:40:07 2024 +Return-Path: +From: Adam Hassick +To: ach1062@usnh.edu +Cc: Adam Hassick +Subject: [PATCH v1 2/2] Fix Makefile +Date: Wed, 12 Jun 2024 16:40:07 -0400 +Message-ID: <20240612204019.364820-3-ahassick@iol.unh.edu> +In-Reply-To: <20240612204019.364820-1-ahassick@iol.unh.edu> +References: <20240612204019.364820-1-ahassick@iol.unh.edu> +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit + +The test-debug target did not generate the correct file. + +Signed-off-by: Adam Hassick +--- + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index 3583b93..78a2bf0 100644 +--- a/Makefile ++++ b/Makefile +@@ -9,5 +9,5 @@ test: test.c + $(CC) -O2 -march=native -mtune=native -Wall -Werror -pedantic test.c -o test + + test-debug: test.c +- $(CC) -O0 -g test.c -Wall -Werror -pedantic -o test ++ $(CC) -O0 -g test.c -Wall -Werror -pedantic -o test-debug + +-- +2.45.2 diff --git a/patchwork/tests/series/dependency-one-cover.mbox.template b/patchwork/tests/series/dependency-one-cover.mbox.template new file mode 100644 index 0000000..8817e69 --- /dev/null +++ b/patchwork/tests/series/dependency-one-cover.mbox.template @@ -0,0 +1,128 @@ +From ahassick@iol.unh.edu Tue Jun 11 16:08:46 2024 +Return-Path: +From: Adam Hassick +To: Adam.Hassick@unh.edu +Cc: Adam Hassick +Subject: [PATCH v1 0/2] Improvements to the test project +Date: Tue, 11 Jun 2024 12:08:46 -0400 +Message-ID: <20240611160854.192806-1-ahassick@iol.unh.edu> +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit + +Various improvements to the test project. +Guy Manson hasn't merged my other patches yet. That sack of lazy bones! +We will have to depend on the first series to get this to pass the CI. + +Depends-on: {depends_token} +Adam Hassick (2): + Makefile: Improve the makefile + test: Improve the test application + + Makefile | 8 ++++++-- + test.c | 22 +++++++++++++++++++--- + 2 files changed, 25 insertions(+), 5 deletions(-) + +-- +2.45.2 + + +From ahassick@iol.unh.edu Tue Jun 11 16:08:47 2024 +Return-Path: +From: Adam Hassick +To: Adam.Hassick@unh.edu +Cc: Adam Hassick +Subject: [PATCH v1 1/2] Makefile: Improve the makefile +Date: Tue, 11 Jun 2024 12:08:47 -0400 +Message-ID: <20240611160854.192806-2-ahassick@iol.unh.edu> +In-Reply-To: <20240611160854.192806-1-ahassick@iol.unh.edu> +References: <20240611160854.192806-1-ahassick@iol.unh.edu> +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit + +We weren't checking for errors very well before. Let's fix that. +The test-debug target did not generate the correct file. + +Signed-off-by: Adam Hassick +--- + Makefile | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/Makefile b/Makefile +index 2126a0e..3583b93 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,9 +1,13 @@ + + CC=gcc + ++.PHONY: all ++ ++all: test test-debug ++ + test: test.c +- $(CC) -O2 -march=native -mtune=native test.c -o test ++ $(CC) -O2 -march=native -mtune=native -Wall -Werror -pedantic test.c -o test + + test-debug: test.c +- $(CC) -O0 -g test.c -o test ++ $(CC) -O0 -g test.c -Wall -Werror -pedantic -o test + +-- +2.45.2 + + +From ahassick@iol.unh.edu Tue Jun 11 16:08:48 2024 +Return-Path: +From: Adam Hassick +To: Adam.Hassick@unh.edu +Cc: Adam Hassick +Subject: [PATCH v1 2/2] test: Improve the test application +Date: Tue, 11 Jun 2024 12:08:48 -0400 +Message-ID: <20240611160854.192806-3-ahassick@iol.unh.edu> +In-Reply-To: <20240611160854.192806-1-ahassick@iol.unh.edu> +References: <20240611160854.192806-1-ahassick@iol.unh.edu> +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit + +The test application before wasn't very interesting. +Let's make it do something with an invariant this time. + +Signed-off-by: Adam Hassick +--- + test.c | 22 +++++++++++++++++++--- + 1 file changed, 19 insertions(+), 3 deletions(-) + +diff --git a/test.c b/test.c +index 5096204..f6cd16e 100644 +--- a/test.c ++++ b/test.c +@@ -1,8 +1,24 @@ + + #include ++#include + +-int main() {{ +- printf("HELLOOOOO!!!! Hi there!"); +- return 0; ++// This function does things. ++void thingymabob(char *string) {{ ++ printf("Here's your argument: %s\n", string); ++ printf("Here is the length of your argument: %li\n", strlen(string)); + }} + ++// Entry point. ++int main(int argc, char **argv) {{ ++ ++ // Make sure we get exactly one argument. ++ if (argc != 2) {{ ++ fprintf(stderr, "I want exactly one argument please!\n"); ++ return 1; ++ }} ++ ++ // Do something with it. ++ thingymabob(argv[1]); ++ ++ return 0; ++}} +-- +2.45.2 diff --git a/patchwork/tests/series/dependency-one-first-patch.mbox.template b/patchwork/tests/series/dependency-one-first-patch.mbox.template new file mode 100644 index 0000000..157b97b --- /dev/null +++ b/patchwork/tests/series/dependency-one-first-patch.mbox.template @@ -0,0 +1,125 @@ +From ahassick@iol.unh.edu Tue Jun 11 16:08:46 2024 +Return-Path: +From: Adam Hassick +To: Adam.Hassick@unh.edu +Cc: Adam Hassick +Subject: [PATCH v1 0/2] Improvements to the test project +Date: Tue, 11 Jun 2024 12:08:46 -0400 +Message-ID: <20240611160854.192806-1-ahassick@iol.unh.edu> +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit + +Various improvements to the test project. + +Adam Hassick (2): + Makefile: Improve the makefile + test: Improve the test application + + Makefile | 8 ++++++-- + test.c | 22 +++++++++++++++++++--- + 2 files changed, 25 insertions(+), 5 deletions(-) + +-- +2.45.2 + + +From ahassick@iol.unh.edu Tue Jun 11 16:08:47 2024 +Return-Path: +From: Adam Hassick +To: Adam.Hassick@unh.edu +Cc: Adam Hassick +Subject: [PATCH v1 1/2] Makefile: Improve the makefile +Date: Tue, 11 Jun 2024 12:08:47 -0400 +Message-ID: <20240611160854.192806-2-ahassick@iol.unh.edu> +In-Reply-To: <20240611160854.192806-1-ahassick@iol.unh.edu> +References: <20240611160854.192806-1-ahassick@iol.unh.edu> +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit + +We weren't checking for errors very well before. Let's fix that. + +Signed-off-by: Adam Hassick +Depends-on: {depends_token} +--- + Makefile | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/Makefile b/Makefile +index 2126a0e..3583b93 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,9 +1,13 @@ + + CC=gcc + ++.PHONY: all ++ ++all: test test-debug ++ + test: test.c +- $(CC) -O2 -march=native -mtune=native test.c -o test ++ $(CC) -O2 -march=native -mtune=native -Wall -Werror -pedantic test.c -o test + + test-debug: test.c +- $(CC) -O0 -g test.c -o test ++ $(CC) -O0 -g test.c -Wall -Werror -pedantic -o test + +-- +2.45.2 + + +From ahassick@iol.unh.edu Tue Jun 11 16:08:48 2024 +Return-Path: +From: Adam Hassick +To: Adam.Hassick@unh.edu +Cc: Adam Hassick +Subject: [PATCH v1 2/2] test: Improve the test application +Date: Tue, 11 Jun 2024 12:08:48 -0400 +Message-ID: <20240611160854.192806-3-ahassick@iol.unh.edu> +In-Reply-To: <20240611160854.192806-1-ahassick@iol.unh.edu> +References: <20240611160854.192806-1-ahassick@iol.unh.edu> +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit + +The test application before wasn't very interesting. +Let's make it do something with an invariant this time. + +Signed-off-by: Adam Hassick +--- + test.c | 22 +++++++++++++++++++--- + 1 file changed, 19 insertions(+), 3 deletions(-) + +diff --git a/test.c b/test.c +index 5096204..f6cd16e 100644 +--- a/test.c ++++ b/test.c +@@ -1,8 +1,24 @@ + + #include ++#include + +-int main() {{ +- printf("HELLOOOOO!!!! Hi there!"); +- return 0; ++// This function does things. ++void thingymabob(char *string) {{ ++ printf("Here's your argument: %s\n", string); ++ printf("Here is the length of your argument: %li\n", strlen(string)); + }} + ++// Entry point. ++int main(int argc, char **argv) {{ ++ ++ // Make sure we get exactly one argument. ++ if (argc != 2) {{ ++ fprintf(stderr, "I want exactly one argument please!\n"); ++ return 1; ++ }} ++ ++ // Do something with it. ++ thingymabob(argv[1]); ++ ++ return 0; ++}} +-- +2.45.2 diff --git a/patchwork/tests/test_parser.py b/patchwork/tests/test_parser.py index 919f9f4..d77a88a 100644 --- a/patchwork/tests/test_parser.py +++ b/patchwork/tests/test_parser.py @@ -1518,3 +1518,52 @@ class TestCommentCorrelation(TestCase): result = parser.find_cover_for_comment(project, [msgid]) self.assertEqual(cover, result) + + +class TestParseDependsOn(TestCase): + def setUp(self): + self.project = create_project() + self.series1 = create_series(project=self.project) + self.series2 = create_series(project=self.project) + self.patch = create_patch(project=self.project, series=self.series1) + + def test_parse_depends_on_garbage_ref_1(self): + self.assertFalse(parser.parse_depends_on('Depends-on: fubar-1298')) + + def test_parse_depends_on_garbage_ref_2(self): + self.assertFalse(parser.parse_depends_on('Depends-on: patch-NaN')) + + def test_parse_depends_on_garbage_url(self): + content = f'Depends-on: http://patchwork.dpdk.org/projects/{self.project.linkname}/list' + self.assertFalse(parser.parse_depends_on(content)) + + def test_parse_depends_on_ref(self): + self.assertIn( + self.series1, + parser.parse_depends_on(f'Depends-on: series-{self.series1.id}'), + ) + self.assertIn( + self.series1, + parser.parse_depends_on(f'Depends-on: patch-{self.patch.id}'), + ) + self.assertIn( + self.series2, + parser.parse_depends_on(f'Depends-on: series-{self.series2.id}'), + ) + + content = f'Depends-on: series-{self.series2.id}\nDepends-on: series-{self.series1.id}' + result = parser.parse_depends_on(content) + self.assertIn(self.series1, result) + self.assertIn(self.series2, result) + + def test_parse_depends_on_url(self): + content1 = f'Depends-on: http://test{self.series1.get_absolute_url()}' + content3 = f'Depends-on: http://test{self.series2.get_absolute_url()}' + content2 = f'Depends-on: http://test{self.patch.get_absolute_url()}' + self.assertIn(self.series1, parser.parse_depends_on(content1)) + self.assertIn(self.series1, parser.parse_depends_on(content2)) + self.assertIn(self.series2, parser.parse_depends_on(content3)) + + result = parser.parse_depends_on('\n'.join([content2, content3])) + self.assertIn(self.series1, result) + self.assertIn(self.series2, result) diff --git a/patchwork/tests/test_series.py b/patchwork/tests/test_series.py index ce11404..5b26848 100644 --- a/patchwork/tests/test_series.py +++ b/patchwork/tests/test_series.py @@ -6,6 +6,7 @@ import mailbox import os import unittest +import tempfile from django.test import TestCase @@ -804,3 +805,262 @@ class SeriesNameTestCase(TestCase): self.assertEqual(series.name, series_name) mbox.close() + + +class SeriesDependencyTestCase(TestCase): + def setUp(self): + self.project = utils.create_project() + utils.create_state() + + # @staticmethod + # def api_url(item=None, version=None): + # kwargs = {} + # if version: + # kwargs['version'] = version + + # if item is None: + # return reverse('api-series-list', kwargs=kwargs) + # kwargs['pk'] = item + # return reverse('api-series-detail', kwargs=kwargs) + + def _load_mbox_template(self, name, **kwargs): + """ + This function is necessary for this test so that we can template in + the series or patch ID that we want to depend on. + """ + with open(os.path.join(TEST_SERIES_DIR, name), 'r') as mbox_file: + mbox_content = mbox_file.read() + + # Write the templated mbox file to a temp file. + tmpfile = tempfile.mktemp() + + with open(tmpfile, 'w') as mbox_opt_file: + mbox_opt_file.write(mbox_content.format(**kwargs)) + + # Load the mbox. + mbox = mailbox.mbox(tmpfile, create=False) + + # Then, remove the temp file (to avoid leaking resources). + os.remove(tmpfile) + + return mbox + + def _load_mbox(self, name): + return mailbox.mbox(os.path.join(TEST_SERIES_DIR, name), create=False) + + def _parse_mbox(self, mbox): + return list( + map( + lambda mail: parser.parse_mail(mail, self.project.listid), mbox + ) + ) + + def test_dependency_ref_on_cover(self): + mbox1 = self._load_mbox('dependency-base-patch.mbox') + _, series1_patch1, _ = self._parse_mbox(mbox1) + mbox1.close() + + series1 = series1_patch1.series + + mbox2 = self._load_mbox_template( + 'dependency-one-cover.mbox.template', + depends_token=f'series-{series1.id}', + ) + _, series2_patch1, _ = self._parse_mbox(mbox2) + mbox2.close() + + series2 = series2_patch1.series + + self.assertIn(series2, series1.dependents.all()) + self.assertIn(series1, series2.dependencies.all()) + self.assertEqual(series1.dependencies.count(), 0) + self.assertEqual(series1.dependents.count(), 1) + self.assertEqual(series2.dependents.count(), 0) + self.assertEqual(series2.dependencies.count(), 1) + + def test_dependency_by_series_url(self): + mbox1 = self._load_mbox('dependency-base-patch.mbox') + _, series1_patch1, _ = self._parse_mbox(mbox1) + mbox1.close() + + series1 = series1_patch1.series + + mbox2 = self._load_mbox_template( + 'dependency-one-cover.mbox.template', + depends_token=f'http://test{series1.get_absolute_url()}', + ) + _, series2_patch1, _ = self._parse_mbox(mbox2) + mbox2.close() + + series2 = series2_patch1.series + + self.assertIn(series2, series1.dependents.all()) + self.assertIn(series1, series2.dependencies.all()) + self.assertEqual(series1.dependencies.count(), 0) + self.assertEqual(series1.dependents.count(), 1) + self.assertEqual(series2.dependents.count(), 0) + self.assertEqual(series2.dependencies.count(), 1) + + def test_dependency_by_patch_url(self): + mbox1 = self._load_mbox('dependency-base-patch.mbox') + _, series1_patch1, _ = self._parse_mbox(mbox1) + mbox1.close() + + series1 = series1_patch1.series + + mbox2 = self._load_mbox_template( + 'dependency-one-cover.mbox.template', + depends_token=f'http://test{series1_patch1.get_absolute_url()}', + ) + _, series2_patch1, _ = self._parse_mbox(mbox2) + mbox2.close() + + series2 = series2_patch1.series + + self.assertIn(series2, series1.dependents.all()) + self.assertIn(series1, series2.dependencies.all()) + self.assertEqual(series1.dependencies.count(), 0) + self.assertEqual(series1.dependents.count(), 1) + self.assertEqual(series2.dependents.count(), 0) + self.assertEqual(series2.dependencies.count(), 1) + + def test_dependency_ref_on_patch(self): + mbox1 = self._load_mbox('dependency-base-patch.mbox') + _, series1_patch1, _ = self._parse_mbox(mbox1) + mbox1.close() + + series1 = series1_patch1.series + + mbox2 = self._load_mbox_template( + 'dependency-one-first-patch.mbox.template', + depends_token=f'series-{series1.id}', + ) + _, series2_patch1, _ = self._parse_mbox(mbox2) + mbox2.close() + + series2 = series2_patch1.series + + self.assertIn(series2, series1.dependents.all()) + self.assertIn(series1, series2.dependencies.all()) + self.assertEqual(series1.dependencies.count(), 0) + self.assertEqual(series1.dependents.count(), 1) + self.assertEqual(series2.dependents.count(), 0) + self.assertEqual(series2.dependencies.count(), 1) + + def test_dependency_ref_by_patch1(self): + mbox1 = self._load_mbox('dependency-base-patch.mbox') + _, series1_patch1, _ = self._parse_mbox(mbox1) + mbox1.close() + + mbox2 = self._load_mbox_template( + 'dependency-one-cover.mbox.template', + depends_token=f'patch-{series1_patch1.id}', + ) + _, series2_patch1, _ = self._parse_mbox(mbox2) + mbox2.close() + + series1 = series1_patch1.series + series2 = series2_patch1.series + + self.assertIn(series2, series1.dependents.all()) + self.assertIn(series1, series2.dependencies.all()) + self.assertEqual(series1.dependencies.count(), 0) + self.assertEqual(series1.dependents.count(), 1) + self.assertEqual(series2.dependents.count(), 0) + self.assertEqual(series2.dependencies.count(), 1) + + def test_dependency_ref_by_patch2(self): + mbox1 = self._load_mbox('dependency-base-patch.mbox') + _, _, series1_patch2 = self._parse_mbox(mbox1) + mbox1.close() + + mbox2 = self._load_mbox_template( + 'dependency-one-cover.mbox.template', + depends_token=f'patch-{series1_patch2.id}', + ) + _, series2_patch1, _ = self._parse_mbox(mbox2) + mbox2.close() + + series1 = series1_patch2.series + series2 = series2_patch1.series + + self.assertIn(series2, series1.dependents.all()) + self.assertIn(series1, series2.dependencies.all()) + self.assertEqual(series1.dependencies.count(), 0) + self.assertEqual(series1.dependents.count(), 1) + self.assertEqual(series2.dependents.count(), 0) + self.assertEqual(series2.dependencies.count(), 1) + + def test_dependency_multi_1(self): + mbox1 = self._load_mbox('dependency-base-patch.mbox') + _, series1_patch1, _ = self._parse_mbox(mbox1) + mbox1.close() + + series1 = series1_patch1.series + + mbox2 = self._load_mbox_template( + 'dependency-one-cover.mbox.template', + depends_token=f'series-{series1.id}', + ) + _, series2_patch1, _ = self._parse_mbox(mbox2) + mbox2.close() + + series2 = series2_patch1.series + + mbox3 = self._load_mbox_template( + 'dependency-multi.mbox.template', + depends_token_1=f'series-{series1.id}', + depends_token_2=f'series-{series2.id}', + ) + _, series3_patch1, _ = self._parse_mbox(mbox3) + mbox3.close() + + series3 = series3_patch1.series + + self.assertIn(series2, series1.dependents.all()) + self.assertIn(series2, series3.dependencies.all()) + self.assertIn(series1, series2.dependencies.all()) + self.assertIn(series3, series2.dependents.all()) + self.assertEqual(series1.dependencies.count(), 0) + self.assertEqual(series1.dependents.count(), 2) + self.assertEqual(series2.dependents.count(), 1) + self.assertEqual(series2.dependencies.count(), 1) + self.assertEqual(series3.dependencies.count(), 2) + self.assertEqual(series3.dependents.count(), 0) + + def test_dependency_multi_2(self): + mbox1 = self._load_mbox('dependency-base-patch.mbox') + _, series1_patch1, _ = self._parse_mbox(mbox1) + mbox1.close() + + series1 = series1_patch1.series + + mbox2 = self._load_mbox_template( + 'dependency-one-cover.mbox.template', + depends_token=f'series-{series1.id}', + ) + _, series2_patch1, _ = self._parse_mbox(mbox2) + mbox2.close() + + series2 = series2_patch1.series + + mbox3 = self._load_mbox_template( + 'dependency-multi-2.mbox.template', + depends_token_1=f'series-{series1.id}', + depends_token_2=f'series-{series2.id}', + ) + _, series3_patch1, _ = self._parse_mbox(mbox3) + mbox3.close() + + series3 = series3_patch1.series + + self.assertIn(series2, series1.dependents.all()) + self.assertIn(series2, series3.dependencies.all()) + self.assertIn(series1, series2.dependencies.all()) + self.assertIn(series3, series2.dependents.all()) + self.assertEqual(series1.dependencies.count(), 0) + self.assertEqual(series1.dependents.count(), 2) + self.assertEqual(series2.dependents.count(), 1) + self.assertEqual(series2.dependencies.count(), 1) + self.assertEqual(series3.dependencies.count(), 2) + self.assertEqual(series3.dependents.count(), 0) From patchwork Mon Jun 17 22:18:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Hassick X-Patchwork-Id: 1948881 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=CfgtKeg3; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:2:0:216:3eff:fee1:b9f1; helo=lists.ozlabs.org; envelope-from=patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:2:0:216:3eff:fee1:b9f1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W347Q0tHCz20Wb for ; Tue, 18 Jun 2024 08:19:46 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=CfgtKeg3; dkim-atps=neutral Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4W347P0jmPz3gHZ for ; Tue, 18 Jun 2024 08:19:45 +1000 (AEST) X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=iol.unh.edu Authentication-Results: lists.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=iol.unh.edu header.i=@iol.unh.edu header.a=rsa-sha256 header.s=unh-iol header.b=CfgtKeg3; dkim-atps=neutral Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=iol.unh.edu (client-ip=2607:f8b0:4864:20::72f; helo=mail-qk1-x72f.google.com; envelope-from=ahassick@iol.unh.edu; receiver=lists.ozlabs.org) Received: from mail-qk1-x72f.google.com (mail-qk1-x72f.google.com [IPv6:2607:f8b0:4864:20::72f]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4W346z6tpdz3g9M for ; Tue, 18 Jun 2024 08:19:23 +1000 (AEST) Received: by mail-qk1-x72f.google.com with SMTP id af79cd13be357-797f222c9f9so282659685a.3 for ; Mon, 17 Jun 2024 15:19:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iol.unh.edu; s=unh-iol; t=1718662762; x=1719267562; darn=lists.ozlabs.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Oi53x8TtP2ZkPuoUjPwdv5PhT8CbbZX5x6oMLSnGTtM=; b=CfgtKeg3DYqFBWPKvGaM1/kokW8fYeQbqOKV0Yzh1lWyDZl19tJXS58OTcSK8Z8KEr i4hallpys8x5sinmeZxMQe4223eUQd3PVAxhFFkSGzCAM79HbyXFJHOxjiNcVRgBsWwK 8EbkqzTuf3hN5UHUxohW3jqlKl+HGUEPcrboY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718662762; x=1719267562; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Oi53x8TtP2ZkPuoUjPwdv5PhT8CbbZX5x6oMLSnGTtM=; b=pUizMvrpz91nzjXryUTUvyR1VVwGnPZI+KQumuUer1h3xvQnwtSQA+5xw1MaLu1NmW tdlbJjZsZUKNpfSVt4kn+pOdN2/K3XLVQZTyEym+P9B6W53y47ixQJcG1fzQKOsXhUvI /jYeudWnrh44+VkpUKqOhBZ4L200TX+lk96fwN189ERCAXCn3hw31w7JZZwEm7nrdtNv 2IMpyBuRqeev5JPNbDAvxeCys5TiEfPUm52hrUKm/rpK+3a5eQUnCdmiB9mX6x78Pl+I 7Rx4q1IUyNBLGkTH6je3XMT0mGQkqex/VoAzC4erVVmNnuy7F3DpGh4W2/aZuSP2oj7P 4p/Q== X-Gm-Message-State: AOJu0Ywke9FKvgbD20e32146ck4iMlkv0Yuz+Jm8A86Et661zXGcAhzM UaASeOH3emUYZwYxm3LRdd7fLg/W+ufVUIEVTQersKvUYj+dAAGI6Ztw7i7u91pQok4Ib7VmL7i r3Bm0MrL5vOSYhppp+cwMQdXBzgiDpktWDVHNnZJQgON/cD4ZTNgFmljYGGka4SbgEG6WYRLcqc ETis06Glx3eETvNRw9xiEu1Nl356gM54KSS31SjLP0pGYX5w== X-Google-Smtp-Source: AGHT+IH/uAlskjXulgXMLziifWjIix7bLTJVqNplo+4Q2sxaBz22RNMC3AQE0Qw2a0emPz3uA2YuuA== X-Received: by 2002:a05:620a:4511:b0:795:482f:768d with SMTP id af79cd13be357-798d26b915dmr1266720485a.78.1718662761735; Mon, 17 Jun 2024 15:19:21 -0700 (PDT) Received: from bubs.loudonlune.net ([71.254.3.64]) by smtp.gmail.com with ESMTPSA id af79cd13be357-798aaee0e52sm469808185a.37.2024.06.17.15.19.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jun 2024 15:19:21 -0700 (PDT) From: Adam Hassick To: patchwork@lists.ozlabs.org Subject: [PATCH v1 9/9] release-notes: Add release notes Date: Mon, 17 Jun 2024 18:18:56 -0400 Message-ID: <20240617221900.156155-10-ahassick@iol.unh.edu> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240617221900.156155-1-ahassick@iol.unh.edu> References: <20240617221900.156155-1-ahassick@iol.unh.edu> MIME-Version: 1.0 X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" Signed-off-by: Adam Hassick --- ...-series-dependencies-6696458586e795c7.yaml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 releasenotes/notes/add-series-dependencies-6696458586e795c7.yaml diff --git a/releasenotes/notes/add-series-dependencies-6696458586e795c7.yaml b/releasenotes/notes/add-series-dependencies-6696458586e795c7.yaml new file mode 100644 index 0000000..ad7cfda --- /dev/null +++ b/releasenotes/notes/add-series-dependencies-6696458586e795c7.yaml @@ -0,0 +1,20 @@ +--- +features: + - | + Series may now depend on eachother. Patchwork clients may use this + information to download and apply the dependencies when applying a series. + This dependency relationship is shallow; the dependencies of a dependency + should not be applied. Multiple dependencies are allowed. The order they + are applied in is the order they appear in the content from top to bottom. + - | + Patchwork will now look for "Depends-on" entries when parsing mails. + This may be done by referring to a patch or series ID in the commit message + of a patch or the cover letter content: + ``Depends-on: patch-1234`` or ``Depends-on: series-5678`` + Alternatively, the web URL of the patch or series may be given: + ``Depends-on: http://patchwork.example.com/project/test/list?series=1111`` + This feature is disabled by default, and may be enabled by adding + ``ENABLE_DEPENDS_ON_PARSING=True`` to the settings.py. +api: + - The API version has been updated to v1.4. + - Add the "dependencies" and "dependents" fields to the series detail view.