From patchwork Sun Mar 29 15:01:36 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 2085 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1774796552; bh=4lw7Az7i2fhFLEe0Qb32OB6scGatkdo77VM3TPYKKHA=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=WTb+ekqSOjGfn4eI1jdOZ0yj0GdJeVteJKvroKQwU+G5V57xM2iYJNNs2RfVhBdfl 1V39zhLqoVOdhMc9u7AtuQKlffv7dU0rKK/kXPdGxq46bRUEIHcrg0gOb4q2g4qUzB yR/7GrQYGWK62Hp+jqQ0cp/O7/Gn1rDMOSyufQ2V7wYrG19FkY+I/C0LN9IXg7HuxP vGGr0U37JFlbqFpH5EK7eCc8CByHKzRaMp9/9D3nHCEHMmG4geezdcnitA0Xi5Qg5I ArasaFbVbmWz9y0TGpBe6y1r3qhdW/UA8WExv4tQ/rFCx0qK5nnYZQThpn0cMq7sfn 0jaWV9KzLVsyA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 9D88F6A2D0 for ; Sun, 29 Mar 2026 09:02:32 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id EDx2qMPa2dSX for ; Sun, 29 Mar 2026 09:02:32 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1774796552; bh=4lw7Az7i2fhFLEe0Qb32OB6scGatkdo77VM3TPYKKHA=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=WTb+ekqSOjGfn4eI1jdOZ0yj0GdJeVteJKvroKQwU+G5V57xM2iYJNNs2RfVhBdfl 1V39zhLqoVOdhMc9u7AtuQKlffv7dU0rKK/kXPdGxq46bRUEIHcrg0gOb4q2g4qUzB yR/7GrQYGWK62Hp+jqQ0cp/O7/Gn1rDMOSyufQ2V7wYrG19FkY+I/C0LN9IXg7HuxP vGGr0U37JFlbqFpH5EK7eCc8CByHKzRaMp9/9D3nHCEHMmG4geezdcnitA0Xi5Qg5I ArasaFbVbmWz9y0TGpBe6y1r3qhdW/UA8WExv4tQ/rFCx0qK5nnYZQThpn0cMq7sfn 0jaWV9KzLVsyA== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 8C7926A2AB for ; Sun, 29 Mar 2026 09:02:32 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1774796550; bh=qvcOmPNp8p4lc4bCpZ7TypjI9FvZxN+oK7hDIPXvgUw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nn7UzaV6CXUcvLZvuwTIRfOxPl+Ux3GohnIW+v/lNsd/5Ihvmmvq6W1YXP9+TbOqn QXTkBnb75upmgxPCIieinOlRxRng2PI28J4OfwSfLl7iw4UMlyXG1ZHfdeIgsI5i3T 3NVLCPuFqSruaiVR+a0UeDT+Q5EJafr8ZmXnSmUTGWqYWDrezxWW55vCFVUDBAtTAo unPDsvb2S7x1qYcxRCpxN+iZNgJD34purTQdPtRKd041k53bQZIPNL4vN07gHvPOYN dzkztKzUqKsts8lesP0zCTS+idblXADhHmAgD8HsP3f63yhtcUVtFKcQWHOv56kwsK nDnipxhV+PYGQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 643F46A02E; Sun, 29 Mar 2026 09:02:30 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id HRbkut-vbW0M; Sun, 29 Mar 2026 09:02:30 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1774796546; bh=53E4m6P1btAt9r9gv7gbvkrBkFrB2ictqZvQJJgBv3c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rVibq7RB3zmCQgxQ1fSK8qGrdWCIER2JwayNWTvYB1Mx7jlIdzeQ//r9R6ce8hSmO 8cCkiyTfkOYEb3TokC2xMNQIyG3t7az3Q97TO1iOQ1IbmeUskepOabPLuVQ8NmBQEE 0swsLAd0c+E3MTP7Dluq4XhOh3nLA3h7BoD117nBMB6Cs4BTRNXypEU3rklxzClAGX M0bhOwjp17CiaZtIL70wIfFAt8pl1OjqPQiSzMGj5R8doAIfgTFLu1cZpGbPVjqhDX lwmB6DneFdJJF0Dg8AAS7bM9sEtqo+sKj+itlC1TkJ4dqFjEwiYaGCKC3QcV3Bivp/ ulJ9YxAH1mFoA== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id EFBEE6A2DB; Sun, 29 Mar 2026 09:02:25 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Sun, 29 Mar 2026 09:01:36 -0600 Message-ID: <20260329150140.4095446-12-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260329150140.4095446-1-sjg@u-boot.org> References: <20260329150140.4095446-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: 7RAGEKH3ZOPXGXOX7N65JPVHXYRZCYPP X-Message-ID-Hash: 7RAGEKH3ZOPXGXOX7N65JPVHXYRZCYPP X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 11/11] patman: Record ser_ver in workflow sent entries List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Add a ser_ver_id column to the workflow table (schema v7) so that SENT entries record which version of a series was sent. This is a foreign key referencing ser_ver.id, or NULL for entries like TODO that are not tied to a specific version. Show the version in the 'workflow list' output. Signed-off-by: Simon Glass --- tools/patman/cseries.py | 3 ++- tools/patman/database.py | 30 ++++++++++++++++++++++++------ tools/patman/test_cseries.py | 19 ++++++++++++++----- tools/patman/workflow.py | 14 ++++++++------ 4 files changed, 48 insertions(+), 18 deletions(-) diff --git a/tools/patman/cseries.py b/tools/patman/cseries.py index 4dddc70b679..0643d44cc01 100644 --- a/tools/patman/cseries.py +++ b/tools/patman/cseries.py @@ -990,7 +990,8 @@ class Cseries(cser_helper.CseriesHelper): likely_sent = send.send(args, git_dir=self.gitdir, cwd=self.topdir) if likely_sent: - workflow.sent(self, ser.idnum) + svid = self.get_series_svid(ser.idnum, version) + workflow.sent(self, ser.idnum, ser_ver_id=svid) if likely_sent and autolink: tout.notice(f'Autolinking with Patchwork ({autolink_wait} seconds)') diff --git a/tools/patman/database.py b/tools/patman/database.py index 3133a320694..ec1daa1c073 100644 --- a/tools/patman/database.py +++ b/tools/patman/database.py @@ -19,7 +19,7 @@ from u_boot_pylib import tout from patman.series import Series # Schema version (version 0 means there is no database yet) -LATEST = 6 +LATEST = 7 # Information about a series/version record SerVer = namedtuple( @@ -213,6 +213,16 @@ class Database: # pylint:disable=R0904 'type, series_id INTEGER, timestamp, archived BIT,' 'FOREIGN KEY (series_id) REFERENCES series (id))') + def _migrate_to_v7(self): + """Add ser_ver_id to workflow table for tracking which version was sent + + Fields: + ser_ver_id: Foreign key referencing ser_ver.id, or NULL for + entries not tied to a specific version (e.g. todo) + """ + self.cur.execute( + 'ALTER TABLE workflow ADD COLUMN ser_ver_id INTEGER') + def migrate_to(self, dest_version): """Migrate the database to the selected version @@ -243,6 +253,8 @@ class Database: # pylint:disable=R0904 self._migrate_to_v5() elif version == 6: self._migrate_to_v6() + elif version == 7: + self._migrate_to_v7() # Save the new version if we have a schema_version table if version > 1: @@ -1061,17 +1073,20 @@ class Database: # pylint:disable=R0904 # workflow functions - def workflow_add(self, wtype, series_id, timestamp): + def workflow_add(self, wtype, series_id, timestamp, ser_ver_id=None): """Add a workflow entry Args: wtype (str): Workflow type, e.g. 'todo' series_id (int): ID of the series timestamp (str): Timestamp string, e.g. '2025-01-15 10:30:00' + ser_ver_id (int or None): ID of the ser_ver record, if applicable """ self.execute( - 'INSERT INTO workflow (type, series_id, timestamp, archived) ' - 'VALUES (?, ?, ?, 0)', (wtype, series_id, timestamp)) + 'INSERT INTO workflow ' + '(type, series_id, timestamp, archived, ser_ver_id) ' + 'VALUES (?, ?, ?, 0, ?)', + (wtype, series_id, timestamp, ser_ver_id)) def workflow_archive(self, wtype, series_id): """Archive active workflow entries for a given type and series @@ -1144,10 +1159,13 @@ class Database: # pylint:disable=R0904 str: series description str: timestamp int: archived flag (0 or 1) + int or None: version number from ser_ver, if applicable """ - query = ('SELECT w.type, s.name, s.desc, w.timestamp, w.archived ' + query = ('SELECT w.type, s.name, s.desc, w.timestamp, w.archived,' + 'sv.version ' 'FROM workflow w ' - 'JOIN series s ON w.series_id = s.id') + 'JOIN series s ON w.series_id = s.id ' + 'LEFT JOIN ser_ver sv ON w.ser_ver_id = sv.id') if not include_archived: query += ' WHERE w.archived = 0' query += ' ORDER BY w.timestamp' diff --git a/tools/patman/test_cseries.py b/tools/patman/test_cseries.py index 4eea5922c84..7a5eede9f82 100644 --- a/tools/patman/test_cseries.py +++ b/tools/patman/test_cseries.py @@ -3557,7 +3557,7 @@ Date: .* self.assertEqual(f'Update database to v{version}', out.getvalue().strip()) self.assertEqual(version, db.get_schema_version()) - self.assertEqual(6, database.LATEST) + self.assertEqual(7, database.LATEST) def test_migrate_future_version(self): """Test that a database newer than patman is rejected""" @@ -4303,20 +4303,29 @@ Date: .* cser.fake_now = datetime(2025, 3, 1, 12, 0, 0) ser = cser.get_series_by_name('first') - # Record a send - wf.sent(cser, ser.idnum) + svid = cser.get_series_svid(ser.idnum, 1) + + # Record a send with ser_ver_id + wf.sent(cser, ser.idnum, ser_ver_id=svid) # Should have a SENT entry with current time ts = cser.db.workflow_get('sent', ser.idnum) self.assertEqual('2025-03-01 12:00:00', ts) - # Should have a TODO entry 7 days out + # The SENT entry should have the ser_ver_id + res = cser.db.execute( + 'SELECT ser_ver_id FROM workflow ' + 'WHERE type = ? AND series_id = ? AND archived = 0', + ('sent', ser.idnum)) + self.assertEqual(svid, res.fetchone()[0]) + + # Should have a TODO entry 7 days out (no ser_ver_id) ts = cser.db.workflow_get('todo', ser.idnum) self.assertEqual('2025-03-08 12:00:00', ts) # Sending again should archive old entries and create new ones cser.fake_now = datetime(2025, 3, 5, 12, 0, 0) - wf.sent(cser, ser.idnum) + wf.sent(cser, ser.idnum, ser_ver_id=svid) ts = cser.db.workflow_get('sent', ser.idnum) self.assertEqual('2025-03-05 12:00:00', ts) diff --git a/tools/patman/workflow.py b/tools/patman/workflow.py index d123e3068a2..85b38bd3f58 100644 --- a/tools/patman/workflow.py +++ b/tools/patman/workflow.py @@ -43,16 +43,17 @@ def friendly_time(now, when): return f'{days // 7}w ago' -def sent(cser, series_id): +def sent(cser, series_id, ser_ver_id=None): """Record that a series was sent and create a follow-up todo Args: cser (CseriesHelper): Series helper with open database series_id (int): ID of the series that was sent + ser_ver_id (int or None): ID of the ser_ver record that was sent """ ts = cser.get_now().strftime('%Y-%m-%d %H:%M:%S') cser.db.workflow_archive(Wtype.SENT, series_id) - cser.db.workflow_add(Wtype.SENT, series_id, ts) + cser.db.workflow_add(Wtype.SENT, series_id, ts, ser_ver_id=ser_ver_id) when = cser.get_now() + timedelta(days=7) todo_ts = when.strftime('%Y-%m-%d %H:%M:%S') cser.db.workflow_archive(Wtype.TODO, series_id) @@ -133,8 +134,8 @@ def list_entries(cser, show_all): if not entries: print('No workflow entries') return - hdr = f"{'Type':6} {'Series':17} {'When':>10}" - div = f"{'-' * 6} {'-' * 17} {'-' * 10}" + hdr = f"{'Type':6} {'Series':17} {'Ver':>3} {'When':>10}" + div = f"{'-' * 6} {'-' * 17} {'-' * 3} {'-' * 10}" if show_all: hdr += ' A' div += ' -' @@ -143,10 +144,11 @@ def list_entries(cser, show_all): print(hdr) print(div) now = cser.get_now() - for wtype, name, desc, ts, archived in entries: + for wtype, name, desc, ts, archived, version in entries: when = datetime.strptime(ts, '%Y-%m-%d %H:%M:%S') friendly = friendly_time(now, when) - line = f"{wtype:6} {name:17} {friendly:>10}" + ver = f'v{version}' if version else '' + line = f"{wtype:6} {name:17} {ver:>3} {friendly:>10}" if show_all: line += f" {'*' if archived else ' '}" line += f" {desc}"