@@ -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)')
@@ -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'
@@ -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)
@@ -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}"