From: Simon Glass <simon.glass@canonical.com> Currently patman uses a single global --patchwork-url flag. Add a patchwork_url field to each upstream so the URL can be looked up automatically from the database. Update upstream_add() and upstream_get_dict() to handle the new field and add upstream_get_patchwork_url() for direct lookup. Signed-off-by: Simon Glass <simon.glass@canonical.com> --- tools/patman/cmdline.py | 6 +++- tools/patman/control.py | 28 +++++++++++++++---- tools/patman/cseries.py | 27 ++++++++++++++---- tools/patman/database.py | 34 +++++++++++++++++++---- tools/patman/test_cseries.py | 53 ++++++++++++++++++++++++++++++------ 5 files changed, 122 insertions(+), 26 deletions(-) diff --git a/tools/patman/cmdline.py b/tools/patman/cmdline.py index 090d9845ec1..f24d0aacdff 100644 --- a/tools/patman/cmdline.py +++ b/tools/patman/cmdline.py @@ -406,7 +406,7 @@ def add_upstream_subparser(subparsers): upstream = subparsers.add_parser('upstream', aliases=ALIASES['upstream'], help='Manage upstream destinations') upstream.defaults_cmds = [ - ['add', 'us', 'http://fred', 'U-Boot'], + ['add', 'us', 'http://fred', '-p', 'http://pw', 'U-Boot'], ['delete', 'us'], ] upstream_subparsers = upstream.add_subparsers(dest='subcmd') @@ -416,6 +416,10 @@ def add_upstream_subparser(subparsers): uadd.add_argument( 'url', help='URL to use for this upstream, e.g. ' "'https://gitlab.denx.de/u-boot/u-boot.git'") + uadd.add_argument( + '-p', '--patchwork-url', + help='URL of patchwork server for this upstream, e.g. ' + "'https://patchwork.ozlabs.org'") uadd.add_argument( 'project_name', nargs='?', help="Patchwork project name, e.g. 'U-Boot'") diff --git a/tools/patman/control.py b/tools/patman/control.py index c65fd3d5f1f..e1f52300a17 100644 --- a/tools/patman/control.py +++ b/tools/patman/control.py @@ -134,8 +134,18 @@ def do_series(args, test_db=None, pwork=None, cser=None): cser.open_database() if args.subcmd in needs_patchwork: if not pwork: - pwork = Patchwork(args.patchwork_url) ups = cser.get_series_upstream(args.series) + pw_url = None + if ups: + pw_url = cser.db.upstream_get_patchwork_url(ups) + if not pw_url: + pw_url = args.patchwork_url + if not pw_url: + raise ValueError( + 'No patchwork URL found for upstream ' + f"'{ups}'; use 'patman upstream add' with " + '-p or pass --patchwork-url') + pwork = Patchwork(pw_url) proj = cser.project_get(ups) if not proj: proj = cser.project_get() @@ -239,11 +249,9 @@ def upstream(args, test_db=None): try: cser.open_database() if args.subcmd == 'add': - pwork = None - if args.project_name: - pwork = Patchwork(args.patchwork_url) cser.upstream_add(args.remote_name, args.url, - args.project_name, pwork) + args.project_name, + patchwork_url=args.patchwork_url) elif args.subcmd == 'default': if args.unset: cser.upstream_set_default(None) @@ -279,7 +287,15 @@ def patchwork(args, test_db=None, pwork=None): if not args.remote: raise ValueError('Please specify the remote name') if not pwork: - pwork = Patchwork(args.patchwork_url) + pw_url = cser.db.upstream_get_patchwork_url(args.remote) + if not pw_url: + pw_url = args.patchwork_url + if not pw_url: + raise ValueError( + f"No patchwork URL for remote '{args.remote}'" + "; use 'patman upstream add' with -p" + ' or pass --patchwork-url') + pwork = Patchwork(pw_url) cser.project_set(pwork, args.project_name, ups=args.remote) elif args.subcmd == 'get-project': diff --git a/tools/patman/cseries.py b/tools/patman/cseries.py index c48267964a1..612ccfda7dc 100644 --- a/tools/patman/cseries.py +++ b/tools/patman/cseries.py @@ -16,6 +16,7 @@ from u_boot_pylib import terminal from u_boot_pylib import tout from patman import patchstream +from patman.patchwork import Patchwork from patman import cser_helper from patman.cser_helper import AUTOLINK, oid from patman import send @@ -1145,7 +1146,8 @@ class Cseries(cser_helper.CseriesHelper): self.rollback() tout.info('Dry run completed') - def upstream_add(self, name, url, project=None, pwork=None): + def upstream_add(self, name, url, project=None, pwork=None, + patchwork_url=None): """Add a new upstream tree Args: @@ -1154,12 +1156,21 @@ class Cseries(cser_helper.CseriesHelper): project (str or None): Patchwork project name to associate pwork (Patchwork or None): Patchwork object for looking up the project + patchwork_url (str or None): URL of the patchwork server for + this upstream """ - self.db.upstream_add(name, url) + self.db.upstream_add(name, url, patchwork_url) if project: + if not pwork: + if not patchwork_url: + raise ValueError( + 'Patchwork URL is required when setting a project') + pwork = Patchwork(patchwork_url) self.project_set(pwork, project, ups=name, quiet=True) self.commit() msg = f"Added upstream '{name}' ({url})" + if patchwork_url: + msg += f" patchwork '{patchwork_url}'" if project: msg += f" project '{project}'" tout.notice(msg) @@ -1167,14 +1178,20 @@ class Cseries(cser_helper.CseriesHelper): def upstream_list(self): """List the upstream repos - Shows a list of the repos, obtained from the database + Shows a list of the repos, obtained from the database, along with + any associated patchwork project """ udict = self.get_upstream_dict() for name, items in udict.items(): - url, is_default = items + url, is_default, patchwork_url = items default = 'default' if is_default else '' - print(f'{name:15.15} {default:8} {url}') + 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}' + print(line) def upstream_set_default(self, name): """Set the default upstream target diff --git a/tools/patman/database.py b/tools/patman/database.py index 2f21e62605f..f7ab2d84877 100644 --- a/tools/patman/database.py +++ b/tools/patman/database.py @@ -791,19 +791,21 @@ class Database: # pylint:disable=R0904 # upstream functions - def upstream_add(self, name, url): + def upstream_add(self, name, url, patchwork_url=None): """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 Raises: ValueError if the name already exists in the database """ try: self.execute( - 'INSERT INTO upstream (name, url) VALUES (?, ?)', (name, url)) + 'INSERT INTO upstream (name, url, patchwork_url) ' + 'VALUES (?, ?, ?)', (name, url, patchwork_url)) except sqlite3.IntegrityError as exc: if 'UNIQUE constraint failed: upstream.name' in str(exc): raise ValueError(f"Upstream '{name}' already exists") from exc @@ -853,18 +855,38 @@ class Database: # pylint:disable=R0904 self.rollback() raise ValueError(f"No such upstream '{name}'") + def upstream_get_patchwork_url(self, name): + """Get the patchwork URL for an upstream + + Args: + name (str): Upstream name + + Return: + str or None: Patchwork URL, or None if not set + """ + res = self.execute( + 'SELECT patchwork_url FROM upstream WHERE name = ?', (name,)) + rec = res.fetchone() + if rec: + return rec[0] + return None + def upstream_get_dict(self): """Get a list of upstream entries from the database Return: OrderedDict: key (str): upstream name - value (str): url + value: tuple: + str: url + bool: is_default + str or None: patchwork_url """ - res = self.execute('SELECT name, url, is_default FROM upstream') + res = self.execute( + 'SELECT name, url, is_default, patchwork_url FROM upstream') udict = OrderedDict() - for name, url, is_default in res.fetchall(): - udict[name] = url, is_default + for name, url, is_default, patchwork_url in res.fetchall(): + udict[name] = url, is_default, patchwork_url return udict # patchwork functions diff --git a/tools/patman/test_cseries.py b/tools/patman/test_cseries.py index 083727889f8..b14c6c22ddc 100644 --- a/tools/patman/test_cseries.py +++ b/tools/patman/test_cseries.py @@ -1730,14 +1730,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), ulist['us']) + self.assertEqual(('https://one', None, None), 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), ulist['us']) - self.assertEqual(('git@two', None), ulist['ci']) + self.assertEqual(('https://one', None, None), ulist['us']) + self.assertEqual(('git@two', None, None), ulist['ci']) # Try to add a duplicate with self.assertRaises(ValueError) as exc: @@ -1748,8 +1748,39 @@ Tested-by: Mary Smith <msmith@wibble.com> # yak cser.upstream_list() lines = out.getvalue().splitlines() self.assertEqual(2, len(lines)) - self.assertEqual('us https://one', lines[0]) - self.assertEqual('ci git@two', lines[1]) + self.assertEqual( + 'us https://one', + lines[0]) + self.assertEqual( + 'ci git@two', + lines[1]) + + def test_upstream_add_patchwork_url(self): + """Test adding an upstream with a patchwork URL""" + cser = self.get_cser() + + with terminal.capture(): + cser.upstream_add('us', 'https://one', + patchwork_url='https://pw.example.com') + ulist = cser.get_upstream_dict() + self.assertEqual(1, len(ulist)) + self.assertEqual( + ('https://one', None, 'https://pw.example.com'), ulist['us']) + + # Check that the patchwork URL shows in the list + with terminal.capture() as (out, _): + cser.upstream_list() + lines = out.getvalue().splitlines() + self.assertEqual(1, len(lines)) + self.assertIn('pw:https://pw.example.com', lines[0]) + + # Check database lookup + pw_url = cser.db.upstream_get_patchwork_url('us') + self.assertEqual('https://pw.example.com', pw_url) + + # Non-existent upstream returns None + pw_url = cser.db.upstream_get_patchwork_url('nonexistent') + self.assertIsNone(pw_url) def test_upstream_add_cmdline(self): """Test adding an upsream with cmdline""" @@ -1760,7 +1791,9 @@ Tested-by: Mary Smith <msmith@wibble.com> # yak self.run_args('upstream', 'list') lines = out.getvalue().splitlines() self.assertEqual(1, len(lines)) - self.assertEqual('us https://one', lines[0]) + self.assertEqual( + 'us https://one', + lines[0]) def test_upstream_default(self): """Operation of the default upstream""" @@ -1791,8 +1824,12 @@ Tested-by: Mary Smith <msmith@wibble.com> # yak cser.upstream_list() lines = out.getvalue().splitlines() self.assertEqual(2, len(lines)) - self.assertEqual('us https://one', lines[0]) - self.assertEqual('ci default git@two', lines[1]) + self.assertEqual( + 'us https://one', + lines[0]) + self.assertEqual( + 'ci default git@two', + lines[1]) cser.upstream_set_default(None) self.assertIsNone(cser.upstream_get_default()) -- 2.43.0