[Concept,21/32] patman: Add per-upstream send settings to the database

Message ID 20260226200106.1727176-22-sjg@u-boot.org
State New
Headers
Series patman: Add multi-upstream support |

Commit Message

Simon Glass Feb. 26, 2026, 8 p.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

The send settings are already in the v5 schema. Add accessor
functions to use them: upstream_get_send_settings() for looking up
all settings at once, and upstream_get_identity() for the identity
alone.

Update upstream_add() to accept send-settings parameters and
upstream_get_dict() to return them.

This allows different upstreams to use different email configurations.
For example, chromium patches can use a different SMTP identity and
skip maintainer lookups, while U-Boot patches use the defaults.

Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 tools/patman/cseries.py      | 27 ++++++++++++++--
 tools/patman/database.py     | 62 ++++++++++++++++++++++++++++++++----
 tools/patman/test_cseries.py |  9 +++---
 3 files changed, 85 insertions(+), 13 deletions(-)
  

Patch

diff --git a/tools/patman/cseries.py b/tools/patman/cseries.py
index 6369b626035..871e14458a8 100644
--- a/tools/patman/cseries.py
+++ b/tools/patman/cseries.py
@@ -932,6 +932,15 @@  class Cseries(cser_helper.CseriesHelper):
         if not ser.idnum:
             raise ValueError(f"Series '{ser.name}' not found in database")
 
+        if not getattr(args, 'identity', None):
+            ups = self.get_series_upstream(name)
+            if ups:
+                identity = self.db.upstream_get_identity(ups)
+                if identity:
+                    args.identity = identity
+                    print(f"Using sendemail identity '{identity}'"
+                          f" from upstream '{ups}'")
+
         args.branch = self._get_branch_name(ser.name, version)
         likely_sent = send.send(args, git_dir=self.gitdir, cwd=self.topdir)
 
@@ -1150,7 +1159,7 @@  class Cseries(cser_helper.CseriesHelper):
                 tout.info('Dry run completed')
 
     def upstream_add(self, name, url, project=None, pwork=None,
-                     patchwork_url=None):
+                     patchwork_url=None, identity=None):
         """Add a new upstream tree
 
         Args:
@@ -1161,8 +1170,9 @@  class Cseries(cser_helper.CseriesHelper):
                 the project
             patchwork_url (str or None): URL of the patchwork server for
                 this upstream
+            identity (str or None): Git sendemail identity to use
         """
-        self.db.upstream_add(name, url, patchwork_url)
+        self.db.upstream_add(name, url, patchwork_url, identity=identity)
         if project:
             if not pwork:
                 if not patchwork_url:
@@ -1174,6 +1184,8 @@  class Cseries(cser_helper.CseriesHelper):
         msg = f"Added upstream '{name}' ({url})"
         if patchwork_url:
             msg += f" patchwork '{patchwork_url}'"
+        if identity:
+            msg += f" identity '{identity}'"
         if project:
             msg += f" project '{project}'"
         tout.notice(msg)
@@ -1187,13 +1199,22 @@  class Cseries(cser_helper.CseriesHelper):
         udict = self.get_upstream_dict()
 
         for name, items in udict.items():
-            url, is_default, patchwork_url = items
+            (url, is_default, patchwork_url, identity, series_to,
+             no_maintainers, no_tags) = items
             default = 'default' if is_default else ''
             proj = self.db.patchwork_get(name)
             proj_name = proj[0] if proj else ''
             line = f'{name:10.10} {default:8} {proj_name:20} {url}'
             if patchwork_url:
                 line += f'  pw:{patchwork_url}'
+            if identity:
+                line += f'  id:{identity}'
+            if series_to:
+                line += f'  to:{series_to}'
+            if no_maintainers:
+                line += '  no-maintainers'
+            if no_tags:
+                line += '  no-tags'
             print(line)
 
     def upstream_set_default(self, name):
diff --git a/tools/patman/database.py b/tools/patman/database.py
index f7ab2d84877..19df3c3bc82 100644
--- a/tools/patman/database.py
+++ b/tools/patman/database.py
@@ -791,21 +791,29 @@  class Database:  # pylint:disable=R0904
 
     # upstream functions
 
-    def upstream_add(self, name, url, patchwork_url=None):
+    def upstream_add(self, name, url, patchwork_url=None, identity=None,
+                     series_to=None, no_maintainers=False, no_tags=False):
         """Add a new upstream record
 
         Args:
             name (str): Name of the tree
             url (str): URL for the tree
             patchwork_url (str or None): URL of the patchwork server
+            identity (str or None): Git sendemail identity to use
+            series_to (str or None): Patman alias for the To address
+            no_maintainers (bool): True to skip get_maintainer.pl
+            no_tags (bool): True to skip subject-tag alias processing
 
         Raises:
             ValueError if the name already exists in the database
         """
         try:
             self.execute(
-                'INSERT INTO upstream (name, url, patchwork_url) '
-                'VALUES (?, ?, ?)', (name, url, patchwork_url))
+                'INSERT INTO upstream (name, url, patchwork_url, identity,'
+                ' series_to, no_maintainers, no_tags) '
+                'VALUES (?, ?, ?, ?, ?, ?, ?)',
+                (name, url, patchwork_url, identity, series_to,
+                 no_maintainers, no_tags))
         except sqlite3.IntegrityError as exc:
             if 'UNIQUE constraint failed: upstream.name' in str(exc):
                 raise ValueError(f"Upstream '{name}' already exists") from exc
@@ -871,6 +879,43 @@  class Database:  # pylint:disable=R0904
             return rec[0]
         return None
 
+    def upstream_get_identity(self, name):
+        """Get the sendemail identity for an upstream
+
+        Args:
+            name (str): Upstream name
+
+        Return:
+            str or None: Identity name, or None if not set
+        """
+        res = self.execute(
+            'SELECT identity FROM upstream WHERE name = ?', (name,))
+        rec = res.fetchone()
+        if rec:
+            return rec[0]
+        return None
+
+    def upstream_get_send_settings(self, name):
+        """Get the send settings for an upstream
+
+        Args:
+            name (str): Upstream name
+
+        Return:
+            tuple or None:
+                str or None: identity
+                str or None: series_to
+                bool: no_maintainers
+                bool: no_tags
+        """
+        res = self.execute(
+            'SELECT identity, series_to, no_maintainers, no_tags '
+            'FROM upstream WHERE name = ?', (name,))
+        rec = res.fetchone()
+        if rec:
+            return rec
+        return None
+
     def upstream_get_dict(self):
         """Get a list of upstream entries from the database
 
@@ -881,12 +926,17 @@  class Database:  # pylint:disable=R0904
                     str: url
                     bool: is_default
                     str or None: patchwork_url
+                    str or None: identity
+                    str or None: series_to
+                    bool: no_maintainers
+                    bool: no_tags
         """
         res = self.execute(
-            'SELECT name, url, is_default, patchwork_url FROM upstream')
+            'SELECT name, url, is_default, patchwork_url, identity,'
+            ' series_to, no_maintainers, no_tags FROM upstream')
         udict = OrderedDict()
-        for name, url, is_default, patchwork_url in res.fetchall():
-            udict[name] = url, is_default, patchwork_url
+        for rec in res.fetchall():
+            udict[rec[0]] = rec[1:]
         return udict
 
     # patchwork functions
diff --git a/tools/patman/test_cseries.py b/tools/patman/test_cseries.py
index 98acc1de184..8f56627958e 100644
--- a/tools/patman/test_cseries.py
+++ b/tools/patman/test_cseries.py
@@ -1747,14 +1747,14 @@  Tested-by: Mary Smith <msmith@wibble.com>   # yak
             cser.upstream_add('us', 'https://one')
         ulist = cser.get_upstream_dict()
         self.assertEqual(1, len(ulist))
-        self.assertEqual(('https://one', None, None), ulist['us'])
+        self.assertEqual(('https://one', None, None, None, None, 0, 0), ulist['us'])
 
         with terminal.capture():
             cser.upstream_add('ci', 'git@two')
         ulist = cser.get_upstream_dict()
         self.assertEqual(2, len(ulist))
-        self.assertEqual(('https://one', None, None), ulist['us'])
-        self.assertEqual(('git@two', None, None), ulist['ci'])
+        self.assertEqual(('https://one', None, None, None, None, 0, 0), ulist['us'])
+        self.assertEqual(('git@two', None, None, None, None, 0, 0), ulist['ci'])
 
         # Try to add a duplicate
         with self.assertRaises(ValueError) as exc:
@@ -1782,7 +1782,8 @@  Tested-by: Mary Smith <msmith@wibble.com>   # yak
         ulist = cser.get_upstream_dict()
         self.assertEqual(1, len(ulist))
         self.assertEqual(
-            ('https://one', None, 'https://pw.example.com'), ulist['us'])
+            ('https://one', None, 'https://pw.example.com', None, None, 0, 0),
+            ulist['us'])
 
         # Check that the patchwork URL shows in the list
         with terminal.capture() as (out, _):