get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/133952/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 133952,
    "url": "https://patches.dpdk.org/api/patches/133952/?format=api",
    "web_url": "https://patches.dpdk.org/project/ci/patch/20231107203158.1261199-3-aconole@redhat.com/",
    "project": {
        "id": 5,
        "url": "https://patches.dpdk.org/api/projects/5/?format=api",
        "name": "CI",
        "link_name": "ci",
        "list_id": "ci.dpdk.org",
        "list_email": "ci@dpdk.org",
        "web_url": "",
        "scm_url": "git://dpdk.org/tools/dpdk-ci",
        "webscm_url": "https://git.dpdk.org/tools/dpdk-ci/",
        "list_archive_url": "https://inbox.dpdk.org/ci",
        "list_archive_url_format": "https://inbox.dpdk.org/ci/{}",
        "commit_url_format": ""
    },
    "msgid": "<20231107203158.1261199-3-aconole@redhat.com>",
    "list_archive_url": "https://inbox.dpdk.org/ci/20231107203158.1261199-3-aconole@redhat.com",
    "date": "2023-11-07T20:31:57",
    "name": "[RFC,v2,2/3] recheck: Add a recheck parser for patchwork comments",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "8a67bc7ff84081d6c98fba296a01a802cc0af2c6",
    "submitter": {
        "id": 332,
        "url": "https://patches.dpdk.org/api/people/332/?format=api",
        "name": "Aaron Conole",
        "email": "aconole@redhat.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/ci/patch/20231107203158.1261199-3-aconole@redhat.com/mbox/",
    "series": [
        {
            "id": 30191,
            "url": "https://patches.dpdk.org/api/series/30191/?format=api",
            "web_url": "https://patches.dpdk.org/project/ci/list/?series=30191",
            "date": "2023-11-07T20:31:55",
            "name": "Add a recheck framework to pw-ci",
            "version": 2,
            "mbox": "https://patches.dpdk.org/series/30191/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/133952/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/133952/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<ci-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 2FF3A432CA;\n\tTue,  7 Nov 2023 21:32:05 +0100 (CET)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 2933140698;\n\tTue,  7 Nov 2023 21:32:05 +0100 (CET)",
            "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.129.124])\n by mails.dpdk.org (Postfix) with ESMTP id 5CE254025E\n for <ci@dpdk.org>; Tue,  7 Nov 2023 21:32:03 +0100 (CET)",
            "from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73])\n by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-373-STaBDw0MObCopNCKFbOmFA-1; Tue,\n 07 Nov 2023 15:31:59 -0500",
            "from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com\n [10.11.54.5])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 88EF13C100A8;\n Tue,  7 Nov 2023 20:31:59 +0000 (UTC)",
            "from RHTPC1VM0NT.redhat.com (unknown [10.22.33.168])\n by smtp.corp.redhat.com (Postfix) with ESMTP id 4F45719E93;\n Tue,  7 Nov 2023 20:31:59 +0000 (UTC)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1699389122;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=zZiNvzrLQcJUzoWyUYa6+tbUy87KQew8wlxhjXcMRcY=;\n b=bXgkgh4pIKJOHk5JLEiCV4DNSOyPxR9O8PmPUZX4r+8a0bhfjqpv8C8bkXSj1W2WrWOt9Z\n n7ai4tUD/Ts9zfSvDVN39hDySIt/dzM9cB7LT7Isp+Li8Bnh1U5Cswbt00eqiGwuG0dORC\n IcDotd5LObmlf2mzoXn3e5QZEkbBnjs=",
        "X-MC-Unique": "STaBDw0MObCopNCKFbOmFA-1",
        "From": "Aaron Conole <aconole@redhat.com>",
        "To": "ci@dpdk.org",
        "Cc": "Michael Santana <msantana@redhat.com>,\n David Marchand <dmarchan@redhat.com>,\n Thomas Monjalon <thomas@monjalon.net>, Patrick Robb <probb@iol.unh.edu>,\n Dumitru Ceara <dceara@redhat.com>",
        "Subject": "[RFC v2 2/3] recheck: Add a recheck parser for patchwork comments",
        "Date": "Tue,  7 Nov 2023 15:31:57 -0500",
        "Message-ID": "<20231107203158.1261199-3-aconole@redhat.com>",
        "In-Reply-To": "<20231107203158.1261199-1-aconole@redhat.com>",
        "References": "<20231107203158.1261199-1-aconole@redhat.com>",
        "MIME-Version": "1.0",
        "X-Scanned-By": "MIMEDefang 3.4.1 on 10.11.54.5",
        "X-Mimecast-Spam-Score": "0",
        "X-Mimecast-Originator": "redhat.com",
        "Content-Transfer-Encoding": "8bit",
        "Content-Type": "text/plain; charset=\"US-ASCII\"; x-default=true",
        "X-BeenThere": "ci@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK CI discussions <ci.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/ci>,\n <mailto:ci-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/ci/>",
        "List-Post": "<mailto:ci@dpdk.org>",
        "List-Help": "<mailto:ci-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/ci>,\n <mailto:ci-request@dpdk.org?subject=subscribe>",
        "Errors-To": "ci-bounces@dpdk.org"
    },
    "content": "Add a recheck parsing tool that will allow for labs to build a\nrecheck workflow based on specific recheck labels and projects,\nwith an associated state machine and querying interface.\n\nThe output of the recheck parsing tool is json and can be fed to\njq or other json parsing utilities for better field support.\n\nSigned-off-by: Aaron Conole <aconole@redhat.com>\n---\n pw_mon           |  58 ++++++++++++++++++++++++++-\n recheck_tool     | 100 +++++++++++++++++++++++++++++++++++++++++++++++\n series_db_lib.sh |  64 +++++++++++++++++++++++++++++-\n 3 files changed, 220 insertions(+), 2 deletions(-)\n create mode 100755 recheck_tool",
    "diff": "diff --git a/pw_mon b/pw_mon\nindex da4b9a9..29a9cb4 100755\n--- a/pw_mon\n+++ b/pw_mon\n@@ -1,6 +1,6 @@\n #!/bin/sh\n # SPDX-Identifier: gpl-2.0-or-later\n-# Copyright (C) 2018, Red Hat, Inc.\n+# Copyright (C) 2018-2023 Red Hat, Inc.\n #\n # Monitors a project on a patchwork instance for new series submissions\n # Records the submissions in the series database (and emits them on the\n@@ -44,6 +44,7 @@ if [ \"$1\" != \"\" ]; then\n     fi\n fi\n \n+recheck_filter=\"\"\n \n while [ \"$1\" != \"\" ]; do\n     if echo \"$1\" | grep -q -s -E ^--pw-project= ; then\n@@ -67,6 +68,10 @@ while [ \"$1\" != \"\" ]; do\n         echo \"    --add-filter-recheck=filter\tAdds a filter to flag that a recheck needs to be done\"\n         echo \"\"\n         exit 0\n+    elif echo \"$1\" | grep -q -s -E ^--add-filter-recheck=; then\n+        filter_str=$(echo \"$1\" | sed s/--add-filter-recheck=//)\n+        recheck_filter=\"$filter_str $recheck_filter\"\n+        shift\n     else\n         echo \"Unknown option: '$1'\"\n         echo \"Rerun with --help for details\"\n@@ -191,7 +196,58 @@ function check_superseded_series() {\n     done\n }\n \n+function run_recheck() {\n+    local recheck_list=$(echo \"$7\" | sed -e 's/^Recheck-request: // ' -e 's/,/ /g')\n+\n+    for filter in $recheck_filter; do\n+        for check in $recheck_list; do\n+            if [ \"$filter\" == \"$check\" ]; then\n+                insert_recheck_request_if_needed \"$1\" \"$3\" \"$8\" \"$check\" \"$2\" \"$9\"\n+            fi\n+        done\n+    done\n+}\n+\n+function check_patch_for_retest_request() {\n+    local patch_url=\"$1\"\n+\n+    local patch_json=$(curl -s \"$userpw\" \"$patch_url\")\n+    local patch_comments_url=$(echo \"$patch_json\" | jq -rc '.comments')\n+    local patch_id=$(echo \"$patch_json\" | jq -rc '.id')\n+    if [ \"Xnull\" != \"X$patch_comments_url\" ]; then\n+        local comments_json=$(curl -s \"$userpw\" \"$patch_comments_url\")\n+\n+        local seq_end=$(echo \"$comments_json\" | jq -rc 'length')\n+        if [ \"$seq_end\" -a $seq_end -gt 0 ]; then\n+            seq_end=$((seq_end-1))\n+            for comment_id in $(seq 0 $seq_end); do\n+                local recheck_requested=$(echo \"$comments_json\" | jq -rc \".[$comment_id].content\" | grep \"^Recheck-request: \")\n+                if [ \"X$recheck_requested\" != \"X\" ]; then\n+                    local msgid=$(echo \"$comments_json\" | jq -rc \".[$comment_id].msgid\")\n+                    run_recheck \"$pw_instance\" \"$series_id\" \"$project\" \"$url\" \"$repo\" \"$branchname\" \"$recheck_requested\" \"$msgid\" \"$patch_id\"\n+                fi\n+            done\n+        fi\n+    fi\n+}\n+\n+function check_series_needs_retest() {\n+    local pw_instance=\"$1\"\n+\n+    series_get_active_branches \"$pw_instance\" | while IFS=\\| read -r series_id project url repo branchname; do\n+        local patch_comments_url=$(curl -s \"$userpw\" \"$url\" | jq -rc '.patches[] | .url')\n+\n+        for patch in $patch_comments_url; do\n+            check_patch_for_retest_request $patch\n+        done\n+    done\n+}\n+\n check_undownloaded_series \"$pw_instance\" \"$pw_project\"\n check_completed_series \"$pw_instance\" \"$pw_project\"\n check_new_series \"$pw_instance\" \"$pw_project\"\n check_superseded_series \"$pw_instance\"\n+\n+# check for retest requests after a series is still passing all the\n+# checks above\n+check_series_needs_retest \"$pw_instance\"\ndiff --git a/recheck_tool b/recheck_tool\nnew file mode 100755\nindex 0000000..98031a9\n--- /dev/null\n+++ b/recheck_tool\n@@ -0,0 +1,100 @@\n+#!/bin/sh\n+# SPDX-Identifier: gpl-2.0-or-later\n+# Copyright (C) 2023 Red Hat, Inc.\n+#\n+# Licensed under the terms of the GNU General Public License as published\n+# by the Free Software Foundation; either version 2 of the License, or\n+# (at your option) any later version.  You may obtain a copy of the\n+# license at\n+#\n+#    https://www.gnu.org/licenses/old-licenses/gpl-2.0.html\n+#\n+# Unless required by applicable law or agreed to in writing, software\n+# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n+# License for the specific language governing permissions and limitations\n+# under the License.\n+\n+mode=\"select\"\n+\n+while [ \"$1\" != \"\" ]; do\n+    if echo \"$1\" | grep -q -s -E ^--help ; then\n+        echo \"recheck / retest state machine script\"\n+        echo \"\"\n+        echo \"$0:\"\n+        echo \" --pw-project=<proj>:\tPatchwork project.\"\n+        echo \" --pw-instance=<inst>:\tPatchwork instance.\"\n+        echo \" --filter=<str>:\t\tJob / request for recheck.\"\n+        echo \" --state=<0..>:\t\tResync state ID.\"\n+        echo \" --msgid=<msgid>:\t\tMessage ID to select.\"\n+        echo \" --update:\t\tSet tool in update mode\"\n+        echo \" --new-state=<0..>:\tNew state ID to set\"\n+        echo \" --series-id=<..>:\tSeries ID\"\n+        echo \"\"\n+        echo \"Will spit out a parsable json for each db line when selecting\"\n+        exit 0\n+    elif echo \"$1\" | grep -q -s -E ^--pw-project= ; then\n+        pw_project=$(echo \"$1\" | sed s/^--pw-project=//)\n+    elif echo \"$1\" | grep -q -s -E ^--pw-instance= ; then\n+        pw_instance=$(echo \"$1\" | sed s/^--pw-instance=//)\n+    elif echo \"$1\" | grep -q -s -E ^--filter= ; then\n+        filter=$(echo \"$1\" | sed s/^--filter=//)\n+    elif echo \"$1\" | grep -q -s -E ^--state= ; then\n+        recheck_state=$(echo \"$1\" | sed s/^--state=//)\n+    elif echo \"$1\" | grep -q -s -E ^--msgid= ; then\n+        message_id=$(echo \"$1\" | sed s/^--msgid=//)\n+    elif echo \"$1\" | grep -q -s -E ^--update ; then\n+        mode=\"update\"\n+    elif echo \"$1\" | grep -q -s -E ^--new-state= ; then\n+        new_recheck_state=$(echo \"$1\" | sed s/^--new-state=//)\n+    elif echo \"$1\" | grep -q -s -E ^--series-id= ; then\n+        series_id=$(echo \"$1\" | sed s/^--series-id=//)\n+    else\n+        echo \"Unknown option: '$1'\"\n+        echo \"Rerun with --help for details\"\n+        exit 1\n+    fi\n+    shift\n+done\n+\n+source $(dirname $0)/series_db_lib.sh\n+\n+if [ \"$mode\" == \"select\" ]; then\n+    echo -n \"{\\\"rechecks\\\":[\"\n+    printed=\"\"\n+    for request in $(get_recheck_requests_by_project \"$pw_instance\" \\\n+                                                     \"$pw_project\" \\\n+                                                     \"$recheck_state\" \\\n+                                                     \"$filter\"); do\n+        message_id=$(echo $request | cut -d\\| -f1)\n+        series_id=$(echo $request | cut -d\\| -f2)\n+        patch_id=$(echo $request | cut -d\\| -f3)\n+\n+        sha=$(get_sha_for_series_id_and_patch \"$series_id\" \"$patch_id\" \\\n+                                              \"$pw_instance\")\n+        echo -n \"$printed{\\\"pw_instance\\\":\\\"$pw_instance\\\",\\\"series_id\\\":$series_id,\\\"patch_id\\\":$patch_id,\\\"sha\\\":\\\"$sha\\\",\\\"msg_id\\\":\\\"$message_id\\\",\\\"state\\\":\\\"$recheck_state\\\",\\\"requested\\\":\\\"$filter\\\"}\"\n+        printed=\",\"\n+    done\n+    echo \"]}\"\n+elif [ \"$mode\" == \"update\" ]; then\n+    if [ \"X$new_recheck_state\" == \"X\" -o \"X$series_id\" == \"X\" ]; then\n+        echo \"Need to set a series-id and a new recheck state when updating.\"\n+        exit 1\n+    fi\n+\n+    request=$(get_recheck_request \"$pw_instance\" \"$pw_project\" \"$message_id\" \\\n+                                  \"$filter\" \"$series_id\" \"$recheck_state\")\n+    if [ \"X$request\" == \"X\" ]; then\n+        echo \"{\\\"result\\\":\\\"notfound\\\"}\"\n+        exit 0\n+    fi\n+\n+    set_recheck_request_state \"$pw_instance\" \"$pw_project\" \"$message_id\" \\\n+                              \"$filter\" \"$series_id\" \"$new_recheck_state\"\n+\n+    echo \"{\\\"result\\\":\\\"executed\\\",\\\"recheck\\\":{\\\"pw_instance\\\": \\\"$pw_instance\\\", \\\"series_id\\\":$series_id, \\\"msg_id\\\":\\\"$message_id\\\", \\\"state\\\":\\\"$new_recheck_state\\\", \\\"requested\\\": \\\"$filter\\\"}}\"\n+else\n+    echo \"Unknown state: $mode\"\n+    exit 1\n+fi\n+\ndiff --git a/series_db_lib.sh b/series_db_lib.sh\nindex 6c2d98e..ca33c1f 100644\n--- a/series_db_lib.sh\n+++ b/series_db_lib.sh\n@@ -1,6 +1,6 @@\n #!/bin/sh\n # SPDX-Identifier: gpl-2.0-or-later\n-# Copyright (C) 2018,2019 Red Hat, Inc.\n+# Copyright (C) 2018-2023 Red Hat, Inc.\n #\n # Licensed under the terms of the GNU General Public License as published\n # by the Free Software Foundation; either version 2 of the License, or\n@@ -114,6 +114,22 @@ EOF\n         run_db_command \"INSERT INTO series_schema_version(id) values (7);\"\n     fi\n \n+    run_db_command \"select * from series_schema_version;\" | egrep '^8$' > /dev/null 2>&1\n+    if [ $? -eq 1 ]; then\n+        sqlite3 ${HOME}/.series-db <<EOF\n+CREATE TABLE recheck_requests (\n+recheck_id INTEGER,\n+recheck_message_id STRING,\n+recheck_requested_by STRING,\n+recheck_series STRING,\n+recheck_patch INTEGER,\n+patchwork_instance STRING,\n+patchwork_project STRING,\n+recheck_sync INTEGER\n+);\n+EOF\n+        run_db_command \"INSERT INTO series_schema_version(id) values (8);\"\n+    fi\n }\n \n function series_db_exists() {\n@@ -390,3 +406,49 @@ function get_patch_id_by_series_id_and_sha() {\n \n     echo \"select patch_id from git_builds where patchwork_instance=\\\"$instance\\\" and series_id=$series_id and sha=\\\"$sha\\\";\" | series_db_execute\n }\n+\n+function get_recheck_requests_by_project() {\n+    local recheck_instance=\"$1\"\n+    local recheck_project=\"$2\"\n+    local recheck_state=\"$3\"\n+    local recheck_requested_by=\"$4\"\n+\n+    series_db_exists\n+\n+    echo \"select recheck_message_id,recheck_series,recheck_patch from recheck_requests where patchwork_instance=\\\"$recheck_instance\\\" and patchwork_project=\\\"$recheck_project\\\" and recheck_sync=$recheck_state and recheck_requested_by=\\\"$recheck_requested_by\\\";\" | series_db_execute\n+}\n+\n+function insert_recheck_request_if_needed() {\n+    local recheck_instance=\"$1\"\n+    local recheck_project=\"$2\"\n+    local recheck_msgid=\"$3\"\n+    local recheck_requested_by=\"$4\"\n+    local recheck_series=\"$5\"\n+    local recheck_patch=\"$6\"\n+\n+    if ! echo \"select * from recheck_requests where recheck_message_id=\\\"$recheck_msgid\\\";\" | series_db_execute | grep $recheck_msgid >/dev/null 2>&1; then\n+        echo \"INSERT INTO recheck_requests (recheck_message_id, recheck_requested_by, recheck_series, recheck_patch, patchwork_instance, patchwork_project, recheck_sync) values (\\\"$recheck_msgid\\\", \\\"$recheck_requested_by\\\", \\\"$recheck_series\\\", $recheck_patch, \\\"$recheck_instance\\\", \\\"$recheck_project\\\", 0);\" | series_db_execute\n+    fi\n+}\n+\n+function get_recheck_request() {\n+    local recheck_instance=\"$1\"\n+    local recheck_project=\"$2\"\n+    local recheck_msgid=\"$3\"\n+    local recheck_requested_by=\"$4\"\n+    local recheck_series=\"$5\"\n+    local recheck_state=\"$6\"\n+\n+    echo \"select * from recheck_requests where patchwork_instance=\\\"$recheck_instance\\\" and patchwork_project=\\\"$recheck_project\\\" and recheck_requested_by=\\\"$recheck_requested_by\\\" and recheck_series=\\\"$recheck_series\\\" and recheck_message_id=\\\"$recheck_msgid\\\" and recheck_sync=$recheck_state;\" | series_db_execute\n+}\n+\n+function set_recheck_request_state() {\n+    local recheck_instance=\"$1\"\n+    local recheck_project=\"$2\"\n+    local recheck_msgid=\"$3\"\n+    local recheck_requested_by=\"$4\"\n+    local recheck_series=\"$5\"\n+    local recheck_state=\"$6\"\n+\n+    echo \"UPDATE recheck_requests set recheck_sync=$recheck_state where patchwork_instance=\\\"$recheck_instance\\\" and patchwork_project=\\\"$recheck_project\\\" and recheck_requested_by=\\\"$recheck_requested_by\\\" and recheck_series=\\\"$recheck_series\\\";\" | series_db_execute\n+}\n",
    "prefixes": [
        "RFC",
        "v2",
        "2/3"
    ]
}