Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-freezerclient for 
openSUSE:Factory checked in at 2026-06-03 20:22:01
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-freezerclient (Old)
 and      /work/SRC/openSUSE:Factory/.python-freezerclient.new.1937 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-freezerclient"

Wed Jun  3 20:22:01 2026 rev:15 rq:1356774 version:6.3.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-freezerclient/python-freezerclient.changes    
    2025-11-10 19:17:10.675938395 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-freezerclient.new.1937/python-freezerclient.changes
      2026-06-03 20:25:51.249752353 +0200
@@ -1,0 +2,24 @@
+Tue Jun  2 15:55:16 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 6.3.0:
+  * Re-enable tempest jobs
+  * Stop logging create/update requests to stdout
+  * Implement jobs retrieval for all projects
+  * Temporary disable tempest jobs
+  * Update master for stable/2026.1
+  * tox: Remove ineffective ignore_basepython_conflict and bump
+    minimum version
+
+-------------------------------------------------------------------
+Mon Mar  9 15:23:12 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 6.2.0:
+  * Drop support for Python 3.8 and 3.9
+  * Fix tag in README
+
+-------------------------------------------------------------------
+Mon Nov 10 13:04:16 UTC 2025 - Dirk Müller <[email protected]>
+
+- fix filelist
+
+-------------------------------------------------------------------

Old:
----
  python_freezerclient-6.1.0.tar.gz

New:
----
  python_freezerclient-6.3.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-freezerclient.spec ++++++
--- /var/tmp/diff_new_pack.BdHCW7/_old  2026-06-03 20:25:52.205792013 +0200
+++ /var/tmp/diff_new_pack.BdHCW7/_new  2026-06-03 20:25:52.209792179 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-freezerclient
 #
-# Copyright (c) 2025 SUSE LLC and contributors
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %global pythons %{primary_python}
 Name:           python-freezerclient
-Version:        6.1.0
+Version:        6.3.0
 Release:        0
 Summary:        Python API and CLI for OpenStack Freezer
 License:        Apache-2.0
@@ -79,8 +79,8 @@
 %files %{python_files}
 %doc README.rst
 %license LICENSE
-%{python3_sitelib}/freezerclient
-%{python3_sitelib}/python_freezerclient-%{version}.dist-info
+%{python_sitelib}/freezerclient
+%{python_sitelib}/python_freezerclient-%{version}.dist-info
 %{_bindir}/freezer
 
 %files -n python-freezerclient-doc

++++++ python_freezerclient-6.1.0.tar.gz -> python_freezerclient-6.3.0.tar.gz 
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python_freezerclient-6.1.0/AUTHORS 
new/python_freezerclient-6.3.0/AUTHORS
--- old/python_freezerclient-6.1.0/AUTHORS      2025-09-01 15:31:33.000000000 
+0200
+++ new/python_freezerclient-6.3.0/AUTHORS      2026-05-19 11:26:35.000000000 
+0200
@@ -10,6 +10,7 @@
 Chen <[email protected]>
 Corey Bryant <[email protected]>
 Deepak Jon <[email protected]>
+Dmitriy Rabotyagov <[email protected]>
 Dmitriy Rabotyagov <[email protected]>
 Doug Hellmann <[email protected]>
 Fabrizio Vanni <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python_freezerclient-6.1.0/ChangeLog 
new/python_freezerclient-6.3.0/ChangeLog
--- old/python_freezerclient-6.1.0/ChangeLog    2025-09-01 15:31:33.000000000 
+0200
+++ new/python_freezerclient-6.3.0/ChangeLog    2026-05-19 11:26:35.000000000 
+0200
@@ -1,6 +1,22 @@
 CHANGES
 =======
 
+6.3.0
+-----
+
+* Re-enable tempest jobs
+* Stop logging create/update requests to stdout
+* Implement jobs retrieval for all projects
+* Temporary disable tempest jobs
+* Update master for stable/2026.1
+* tox: Remove ineffective ignore\_basepython\_conflict and bump minimum version
+
+6.2.0
+-----
+
+* Drop support for Python 3.8 and 3.9
+* Fix tag in README
+
 6.1.0
 -----
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python_freezerclient-6.1.0/PKG-INFO 
new/python_freezerclient-6.3.0/PKG-INFO
--- old/python_freezerclient-6.1.0/PKG-INFO     2025-09-01 15:31:33.163253300 
+0200
+++ new/python_freezerclient-6.3.0/PKG-INFO     2026-05-19 11:26:35.345000500 
+0200
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
 Name: python-freezerclient
-Version: 6.1.0
+Version: 6.3.0
 Summary: OpenStack Disaster Recovery API Client Library
 Home-page: https://docs.openstack.org/python-freezerclient/latest/
 Author: OpenStack
@@ -11,11 +11,10 @@
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: Python :: 3 :: Only
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
 Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Natural Language :: English
 Classifier: Environment :: OpenStack
@@ -33,7 +32,7 @@
 Classifier: Topic :: System :: Archiving :: Backup
 Classifier: Topic :: System :: Archiving :: Compression
 Classifier: Topic :: System :: Archiving
-Requires-Python: >=3.8
+Requires-Python: >=3.10
 License-File: LICENSE
 Requires-Dist: 
setuptools!=24.0.0,!=34.0.0,!=34.0.1,!=34.0.2,!=34.0.3,!=34.1.0,!=34.1.1,!=34.2.0,!=34.3.0,!=34.3.1,!=34.3.2,!=36.2.0,>=21.0.0
 Requires-Dist: pbr!=2.1.0,>=2.0.0
@@ -41,11 +40,26 @@
 Requires-Dist: cliff!=2.9.0,>=2.8.0
 Requires-Dist: oslo.serialization>=2.25.0
 Requires-Dist: oslo.utils>=3.33.0
+Dynamic: author
+Dynamic: author-email
+Dynamic: classifier
+Dynamic: description
+Dynamic: home-page
+Dynamic: keywords
+Dynamic: license
+Dynamic: license-file
+Dynamic: requires-dist
+Dynamic: requires-python
+Dynamic: summary
 
 =============================================================
 Python bindings to the OpenStack Backup/Restore API (Freezer)
 =============================================================
 
+.. image:: https://governance.openstack.org/tc/badges/python-freezerclient.svg
+
+.. Change things from this point on
+
 .. image:: https://img.shields.io/pypi/v/python-freezerclient.svg
     :target: https://pypi.org/project/python-freezerclient/
     :alt: Latest Version
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python_freezerclient-6.1.0/README.rst 
new/python_freezerclient-6.3.0/README.rst
--- old/python_freezerclient-6.1.0/README.rst   2025-09-01 15:31:07.000000000 
+0200
+++ new/python_freezerclient-6.3.0/README.rst   2026-05-19 11:26:00.000000000 
+0200
@@ -2,6 +2,10 @@
 Python bindings to the OpenStack Backup/Restore API (Freezer)
 =============================================================
 
+.. image:: https://governance.openstack.org/tc/badges/python-freezerclient.svg
+
+.. Change things from this point on
+
 .. image:: https://img.shields.io/pypi/v/python-freezerclient.svg
     :target: https://pypi.org/project/python-freezerclient/
     :alt: Latest Version
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python_freezerclient-6.1.0/freezerclient/tests/unit/v2/test_client_jobs.py 
new/python_freezerclient-6.3.0/freezerclient/tests/unit/v2/test_client_jobs.py
--- 
old/python_freezerclient-6.1.0/freezerclient/tests/unit/v2/test_client_jobs.py  
    2025-09-01 15:31:07.000000000 +0200
+++ 
new/python_freezerclient-6.3.0/freezerclient/tests/unit/v2/test_client_jobs.py  
    2026-05-19 11:26:00.000000000 +0200
@@ -18,6 +18,7 @@
 from oslo_serialization import jsonutils as json
 
 from freezerclient import exceptions
+from freezerclient.v2 import jobs as jobs_cmd
 from freezerclient.v2.managers import jobs
 
 
@@ -145,6 +146,40 @@
         self.assertRaises(exceptions.ApiClientException, self.job_manager.list)
 
     @mock.patch('freezerclient.v2.managers.jobs.requests')
+    def test_list_all_all_projects(self, mock_requests):
+        self.mock_response.status_code = 200
+        job_list = [{'job_id_0': 'bomboloid'}, {'job_id_1': 'asdfasdf'}]
+        self.mock_response.json.return_value = {'jobs': job_list}
+        mock_requests.get.return_value = self.mock_response
+        retval = self.job_manager.list_all(all_projects=True)
+        self.assertEqual(job_list, retval)
+        mock_requests.get.assert_called_with(
+            self.job_manager.endpoint,
+            headers=self.headers,
+            params={'limit': 10, 'offset': 0, 'all_projects': True},
+            data=None,
+            verify=True
+        )
+
+    @mock.patch('freezerclient.v2.managers.jobs.requests')
+    def test_list_all_projects(self, mock_requests):
+        self.mock_response.status_code = 200
+        job_list = [{'job_id_0': 'bomboloid'}, {'job_id_1': 'asdfasdf'}]
+        self.mock_response.json.return_value = {'jobs': job_list}
+        mock_requests.get.return_value = self.mock_response
+        retval = self.job_manager.list(all_projects=True)
+        self.assertEqual(job_list, retval)
+        mock_requests.get.assert_called_with(
+            self.job_manager.endpoint,
+            headers=self.headers,
+            params={'limit': 10, 'offset': 0, 'all_projects': True},
+            data=json.dumps(
+                {'match': [{'client_id': 'test_client_id_78900987'}]}
+            ),
+            verify=True
+        )
+
+    @mock.patch('freezerclient.v2.managers.jobs.requests')
     def test_update_ok(self, mock_requests):
         self.mock_response.status_code = 200
         self.mock_response.json.return_value = {
@@ -271,3 +306,56 @@
         mock_requests.post.return_value = self.mock_response
         self.assertRaises(exceptions.ApiClientException,
                           self.job_manager.abort_job, job_id)
+
+
+class TestJobList(unittest.TestCase):
+    def setUp(self):
+        self.app = mock.Mock()
+        self.app.client = mock.Mock()
+        self.job_list = jobs_cmd.JobList(self.app, mock.Mock())
+
+    def test_get_parser(self):
+        parser = self.job_list.get_parser('test')
+        self.assertEqual('Specify a limit for search query',
+                         parser._option_string_actions['--limit'].help)
+        self.assertEqual('Get jobs for all projects',
+                         parser._option_string_actions['--all-projects'].help)
+
+    def test_take_action_all_projects(self):
+        parsed_args = mock.Mock()
+        parsed_args.limit = 10
+        parsed_args.offset = 0
+        parsed_args.search = ''
+        parsed_args.client_id = ''
+        parsed_args.all_projects = True
+
+        self.app.client.jobs.list_all.return_value = []
+
+        columns, data = self.job_list.take_action(parsed_args)
+
+        self.app.client.jobs.list_all.assert_called_once_with(
+            limit=10,
+            offset=0,
+            search={},
+            all_projects=True
+        )
+
+    def test_take_action_client_id_all_projects(self):
+        parsed_args = mock.Mock()
+        parsed_args.limit = 10
+        parsed_args.offset = 0
+        parsed_args.search = ''
+        parsed_args.client_id = 'test_client'
+        parsed_args.all_projects = True
+
+        self.app.client.jobs.list.return_value = []
+
+        columns, data = self.job_list.take_action(parsed_args)
+
+        self.app.client.jobs.list.assert_called_once_with(
+            limit=10,
+            offset=0,
+            search={},
+            client_id='test_client',
+            all_projects=True
+        )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python_freezerclient-6.1.0/freezerclient/v2/actions.py 
new/python_freezerclient-6.3.0/freezerclient/v2/actions.py
--- old/python_freezerclient-6.1.0/freezerclient/v2/actions.py  2025-09-01 
15:31:07.000000000 +0200
+++ new/python_freezerclient-6.3.0/freezerclient/v2/actions.py  2026-05-19 
11:26:00.000000000 +0200
@@ -25,6 +25,43 @@
 logging = logging.getLogger(__name__)
 
 
+def format_action(action):
+    column = (
+        'Action ID',
+        'Name',
+        'Action',
+        'Mode',
+        'Path to Backup or Restore',
+        'Storage',
+        'Snapshot',
+        'Container',
+        'Log_file',
+        'Remove_older_than',
+        'Max_retries_interval',
+        'Max_retries',
+        'User_id',
+        'Project_id'
+    )
+
+    data = (
+        action.get('action_id'),
+        action.get('freezer_action', {}).get('backup_name', ''),
+        action.get('freezer_action', {}).get('action', 'backup'),
+        action.get('freezer_action', {}).get('mode', 'fs'),
+        action.get('freezer_action', {}).get('path_to_backup', ''),
+        action.get('freezer_action', {}).get('storage', 'swift'),
+        action.get('freezer_action', {}).get('snapshot', 'False'),
+        action.get('freezer_action', {}).get('container', ''),
+        action.get('freezer_action', {}).get('log_file', ''),
+        action.get('freezer_action', {}).get('remove_older_than', '365'),
+        action.get('max_retries_interval', '6'),
+        action.get('max_retries', '5'),
+        action.get('user_id', ''),
+        action.get('project_id', ''),
+    )
+    return column, data
+
+
 class ActionShow(show.ShowOne):
     """Show a single action """
     def get_parser(self, prog_name):
@@ -39,41 +76,7 @@
         if not action:
             raise exceptions.ApiClientException('Action not found')
 
-        column = (
-            'Action ID',
-            'Name',
-            'Action',
-            'Mode',
-            'Path to Backup or Restore',
-            'Storage',
-            'Snapshot',
-            'Container',
-            'Log_file',
-            'Remove_older_than',
-            'Max_retries_interval',
-            'Max_retries',
-            'User_id',
-            'Project_id'
-        )
-
-        data = (
-            action.get('action_id'),
-            action.get('freezer_action', {}).get('backup_name', ''),
-            action.get('freezer_action', {}).get('action', 'backup'),
-            action.get('freezer_action', {}).get('mode', 'fs'),
-            action.get('freezer_action', {}).get('path_to_backup', ''),
-            action.get('freezer_action', {}).get('storage', 'swift'),
-            action.get('freezer_action', {}).get('snapshot', 'False'),
-            action.get('freezer_action', {}).get('container', ''),
-            action.get('freezer_action', {}).get('log_file', ''),
-            action.get('freezer_action', {}).get('remove_older_than', '365'),
-            action.get('max_retries_interval', '6'),
-            action.get('max_retries', '5'),
-            action.get('user_id', ''),
-            action.get('project_id', ''),
-        )
-
-        return column, data
+        return format_action(action)
 
 
 class ActionList(lister.Lister):
@@ -151,10 +154,9 @@
 
     def take_action(self, parsed_args):
         self.app.client.actions.delete(parsed_args.action_id)
-        logging.info('Action {0} deleted'.format(parsed_args.action_id))
 
 
-class ActionCreate(command.Command):
+class ActionCreate(show.ShowOne):
     """Create an action from a file"""
     def get_parser(self, prog_name):
         parser = super(ActionCreate, self).get_parser(prog_name)
@@ -165,12 +167,15 @@
         return parser
 
     def take_action(self, parsed_args):
-        action = utils.doc_from_json_file(parsed_args.file)
-        action_id = self.app.client.actions.create(action)
-        logging.info('Action {0} created'.format(action_id))
+        action_data = utils.doc_from_json_file(parsed_args.file)
+        action_id = self.app.client.actions.create(action_data)
+        action = self.app.client.actions.get(action_id)
+        if not action:
+            raise exceptions.ApiClientException('Action created but not found')
+        return format_action(action)
 
 
-class ActionUpdate(command.Command):
+class ActionUpdate(show.ShowOne):
     """Update an action from a file"""
     def get_parser(self, prog_name):
         parser = super(ActionUpdate, self).get_parser(prog_name)
@@ -182,6 +187,9 @@
         return parser
 
     def take_action(self, parsed_args):
-        action = utils.doc_from_json_file(parsed_args.file)
-        self.app.client.actions.update(parsed_args.action_id, action)
-        logging.info('Action {0} updated'.format(parsed_args.action_id))
+        action_data = utils.doc_from_json_file(parsed_args.file)
+        self.app.client.actions.update(parsed_args.action_id, action_data)
+        action = self.app.client.actions.get(parsed_args.action_id)
+        if not action:
+            raise exceptions.ApiClientException('Action not found')
+        return format_action(action)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python_freezerclient-6.1.0/freezerclient/v2/backups.py 
new/python_freezerclient-6.3.0/freezerclient/v2/backups.py
--- old/python_freezerclient-6.1.0/freezerclient/v2/backups.py  2025-09-01 
15:31:07.000000000 +0200
+++ new/python_freezerclient-6.3.0/freezerclient/v2/backups.py  2026-05-19 
11:26:00.000000000 +0200
@@ -27,6 +27,24 @@
 logging = logging.getLogger(__name__)
 
 
+def format_backup(backup):
+    column = (
+        'Backup ID',
+        'Project ID',
+        'User ID',
+        'User name',
+        'Metadata'
+    )
+    data = (
+        backup.get('backup_uuid'),
+        backup.get('project_id'),
+        backup.get('user_id'),
+        backup.get('user_name'),
+        pprint.pformat(backup.get('backup_metadata'))
+    )
+    return column, data
+
+
 class BackupShow(show.ShowOne):
     """Show the metadata of a single backup"""
     def get_parser(self, prog_name):
@@ -40,21 +58,7 @@
         if not backup:
             raise exceptions.ApiClientException('Backup not found')
 
-        column = (
-            'Backup ID',
-            'Project ID',
-            'User ID',
-            'User name',
-            'Metadata'
-        )
-        data = (
-            backup.get('backup_uuid'),
-            backup.get('project_id'),
-            backup.get('user_id'),
-            backup.get('user_name'),
-            pprint.pformat(backup.get('backup_metadata'))
-        )
-        return column, data
+        return format_backup(backup)
 
 
 class BackupList(lister.Lister):
@@ -126,10 +130,9 @@
 
     def take_action(self, parsed_args):
         self.app.client.backups.delete(parsed_args.backup_uuid)
-        logging.info('Backup {0} deleted'.format(parsed_args.backup_uuid))
 
 
-class BackupCreate(command.Command):
+class BackupCreate(show.ShowOne):
     """Create an backup from a file"""
     def get_parser(self, prog_name):
         parser = super(BackupCreate, self).get_parser(prog_name)
@@ -140,6 +143,9 @@
         return parser
 
     def take_action(self, parsed_args):
-        backup = utils.doc_from_json_file(parsed_args.file)
-        backup_id = self.app.client.backups.create(backup)
-        logging.info('Backup {0} created'.format(backup_id))
+        backup_metadata = utils.doc_from_json_file(parsed_args.file)
+        backup_id = self.app.client.backups.create(backup_metadata)
+        backup = self.app.client.backups.get(backup_id)
+        if not backup:
+            raise exceptions.ApiClientException('Backup created but not found')
+        return format_backup(backup)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python_freezerclient-6.1.0/freezerclient/v2/clients.py 
new/python_freezerclient-6.3.0/freezerclient/v2/clients.py
--- old/python_freezerclient-6.1.0/freezerclient/v2/clients.py  2025-09-01 
15:31:07.000000000 +0200
+++ new/python_freezerclient-6.3.0/freezerclient/v2/clients.py  2026-05-19 
11:26:00.000000000 +0200
@@ -25,6 +25,23 @@
 logging = logging.getLogger(__name__)
 
 
+def format_client(client):
+    column = (
+        'Client ID',
+        'Client UUID',
+        'hostname',
+        'description'
+    )
+    data = (
+        client.get('client', {}).get('client_id'),
+        client.get('client', {}).get('uuid'),
+        client.get('client', {}).get('hostname'),
+        client.get('client', {}).get('description', '')
+    )
+
+    return column, data
+
+
 class ClientShow(show.ShowOne):
     """Show a single client"""
     def get_parser(self, prog_name):
@@ -39,20 +56,7 @@
         if not client:
             raise exceptions.ApiClientException('Client not found')
 
-        column = (
-            'Client ID',
-            'Client UUID',
-            'hostname',
-            'description'
-        )
-        data = (
-            client.get('client', {}).get('client_id'),
-            client.get('client', {}).get('uuid'),
-            client.get('client', {}).get('hostname'),
-            client.get('client', {}).get('description', '')
-        )
-
-        return column, data
+        return format_client(client)
 
 
 class ClientList(lister.Lister):
@@ -114,10 +118,9 @@
 
     def take_action(self, parsed_args):
         self.app.client.clients.delete(parsed_args.client_id)
-        logging.info('Client {0} deleted'.format(parsed_args.client_id))
 
 
-class ClientRegister(command.Command):
+class ClientRegister(show.ShowOne):
     """Register a new client"""
     def get_parser(self, prog_name):
         parser = super(ClientRegister, self).get_parser(prog_name)
@@ -128,10 +131,14 @@
         return parser
 
     def take_action(self, parsed_args):
-        client = utils.doc_from_json_file(parsed_args.file)
+        client_data = utils.doc_from_json_file(parsed_args.file)
         try:
-            client_id = self.app.client.clients.create(client)
+            client_id = self.app.client.clients.create(client_data)
         except Exception as err:
             raise exceptions.ApiClientException(err.message)
         else:
-            logging.info("Client {0} registered".format(client_id))
+            client = self.app.client.clients.get(client_id)
+            if not client:
+                raise exceptions.ApiClientException(
+                    'Client registered but not found')
+            return format_client(client)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python_freezerclient-6.1.0/freezerclient/v2/jobs.py 
new/python_freezerclient-6.3.0/freezerclient/v2/jobs.py
--- old/python_freezerclient-6.1.0/freezerclient/v2/jobs.py     2025-09-01 
15:31:07.000000000 +0200
+++ new/python_freezerclient-6.3.0/freezerclient/v2/jobs.py     2026-05-19 
11:26:00.000000000 +0200
@@ -26,6 +26,40 @@
 logging = logging.getLogger(__name__)
 
 
+def format_job(job):
+    column = (
+        'Job ID',
+        'Client ID',
+        'User ID',
+        'Session ID',
+        'Description',
+        'Actions',
+        'Start Date',
+        'End Date',
+        'Interval',
+        'Status',
+        'Result',
+        'Current pid',
+        'Event',
+    )
+    data = (
+        job.get('job_id'),
+        job.get('client_id'),
+        job.get('user_id'),
+        job.get('session_id', ''),
+        job.get('description'),
+        pprint.pformat(job.get('job_actions')),
+        job.get('job_schedule', {}).get('schedule_start_date', ''),
+        job.get('job_schedule', {}).get('schedule_end_date', ''),
+        job.get('job_schedule', {}).get('schedule_interval', ''),
+        job.get('job_schedule', {}).get('status', ''),
+        job.get('job_schedule', {}).get('result', ''),
+        job.get('job_schedule', {}).get('current_pid', ''),
+        job.get('job_schedule', {}).get('event', ''),
+    )
+    return column, data
+
+
 class JobShow(show.ShowOne):
     """Show a single job"""
     def get_parser(self, prog_name):
@@ -40,37 +74,7 @@
         if not job:
             raise exceptions.ApiClientException('Job not found')
 
-        column = (
-            'Job ID',
-            'Client ID',
-            'User ID',
-            'Session ID',
-            'Description',
-            'Actions',
-            'Start Date',
-            'End Date',
-            'Interval',
-            'Status',
-            'Result',
-            'Current pid',
-            'Event',
-        )
-        data = (
-            job.get('job_id'),
-            job.get('client_id'),
-            job.get('user_id'),
-            job.get('session_id', ''),
-            job.get('description'),
-            pprint.pformat(job.get('job_actions')),
-            job.get('job_schedule', {}).get('schedule_start_date', ''),
-            job.get('job_schedule', {}).get('schedule_end_date', ''),
-            job.get('job_schedule', {}).get('schedule_interval', ''),
-            job.get('job_schedule', {}).get('status', ''),
-            job.get('job_schedule', {}).get('result', ''),
-            job.get('job_schedule', {}).get('current_pid', ''),
-            job.get('job_schedule', {}).get('event', ''),
-        )
-        return column, data
+        return format_job(job)
 
 
 class JobList(lister.Lister):
@@ -105,6 +109,13 @@
             default='',
             help='Get jobs for a specific client',
         )
+
+        parser.add_argument(
+            '--all-projects',
+            dest='all_projects',
+            action='store_true',
+            help='Get jobs for all projects',
+        )
         return parser
 
     def take_action(self, parsed_args):
@@ -116,13 +127,15 @@
                 limit=parsed_args.limit,
                 offset=parsed_args.offset,
                 search=search,
-                client_id=parsed_args.client_id
+                client_id=parsed_args.client_id,
+                all_projects=parsed_args.all_projects,
             )
         else:
             jobs = self.app.client.jobs.list_all(
                 limit=parsed_args.limit,
                 offset=parsed_args.offset,
-                search=search
+                search=search,
+                all_projects=parsed_args.all_projects,
             )
 
         columns = ('Job ID', 'Description', '# Actions', 'Result', 'Status',
@@ -188,10 +201,9 @@
 
     def take_action(self, parsed_args):
         self.app.client.jobs.delete(parsed_args.job_id)
-        logging.info('Job {0} deleted'.format(parsed_args.job_id))
 
 
-class JobCreate(command.Command):
+class JobCreate(show.ShowOne):
     """Create a new job from a file"""
     def get_parser(self, prog_name):
         parser = super(JobCreate, self).get_parser(prog_name)
@@ -211,10 +223,13 @@
         return parser
 
     def take_action(self, parsed_args):
-        job = utils.doc_from_json_file(parsed_args.file)
-        job['client_id'] = parsed_args.client_id
-        job_id = self.app.client.jobs.create(job)
-        logging.info('Job {0} created'.format(job_id))
+        job_data = utils.doc_from_json_file(parsed_args.file)
+        job_data['client_id'] = parsed_args.client_id
+        job_id = self.app.client.jobs.create(job_data)
+        job = self.app.client.jobs.get(job_id)
+        if not job:
+            raise exceptions.ApiClientException('Job created but not found')
+        return format_job(job)
 
 
 class JobStart(command.Command):
@@ -227,8 +242,6 @@
 
     def take_action(self, parsed_args):
         self.app.client.jobs.start_job(parsed_args.job_id)
-        logging.info("Start request sent "
-                     "for job {0}".format(parsed_args.job_id))
 
 
 class JobStop(command.Command):
@@ -241,8 +254,6 @@
 
     def take_action(self, parsed_args):
         self.app.client.jobs.stop_job(parsed_args.job_id)
-        logging.info("Stop request sent "
-                     "for job {0}".format(parsed_args.job_id))
 
 
 class JobAbort(command.Command):
@@ -255,11 +266,9 @@
 
     def take_action(self, parsed_args):
         self.app.client.jobs.abort_job(parsed_args.job_id)
-        logging.info("Abort request sent "
-                     "for job {0}".format(parsed_args.job_id))
 
 
-class JobUpdate(command.Command):
+class JobUpdate(show.ShowOne):
     """Update a job from a file"""
     def get_parser(self, prog_name):
         parser = super(JobUpdate, self).get_parser(prog_name)
@@ -271,6 +280,9 @@
         return parser
 
     def take_action(self, parsed_args):
-        job = utils.doc_from_json_file(parsed_args.file)
-        self.app.client.jobs.update(parsed_args.job_id, job)
-        logging.info('Job {0} updated'.format(parsed_args.job_id))
+        job_data = utils.doc_from_json_file(parsed_args.file)
+        self.app.client.jobs.update(parsed_args.job_id, job_data)
+        job = self.app.client.jobs.get(parsed_args.job_id)
+        if not job:
+            raise exceptions.ApiClientException('Job not found')
+        return format_job(job)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python_freezerclient-6.1.0/freezerclient/v2/managers/jobs.py 
new/python_freezerclient-6.3.0/freezerclient/v2/managers/jobs.py
--- old/python_freezerclient-6.1.0/freezerclient/v2/managers/jobs.py    
2025-09-01 15:31:07.000000000 +0200
+++ new/python_freezerclient-6.3.0/freezerclient/v2/managers/jobs.py    
2026-05-19 11:26:00.000000000 +0200
@@ -51,21 +51,26 @@
         if r.status_code != 204:
             raise exceptions.ApiClientException(r)
 
-    def list_all(self, limit=10, offset=0, search=None):
+    def list_all(self, limit=10, offset=0, search=None, all_projects=False):
         data = json.dumps(search) if search else None
-        query = {'limit': int(limit), 'offset': int(offset)}
+        query = {
+            'limit': int(limit),
+            'offset': int(offset),
+            'all_projects': all_projects,
+        }
         r = requests.get(self.endpoint, headers=self.headers,
                          params=query, data=data, verify=self.verify)
         if r.status_code != 200:
             raise exceptions.ApiClientException(r)
         return r.json()['jobs']
 
-    def list(self, limit=10, offset=0, search={}, client_id=None):
+    def list(self, limit=10, offset=0, search={}, client_id=None,
+             all_projects=False):
         client_id = client_id or self.client.client_id
         new_search = search.copy()
         new_search['match'] = search.get('match', [])
         new_search['match'].append({'client_id': client_id})
-        return self.list_all(limit, offset, new_search)
+        return self.list_all(limit, offset, new_search, all_projects)
 
     def get(self, job_id):
         endpoint = self.endpoint + job_id
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python_freezerclient-6.1.0/freezerclient/v2/sessions.py 
new/python_freezerclient-6.3.0/freezerclient/v2/sessions.py
--- old/python_freezerclient-6.1.0/freezerclient/v2/sessions.py 2025-09-01 
15:31:07.000000000 +0200
+++ new/python_freezerclient-6.3.0/freezerclient/v2/sessions.py 2026-05-19 
11:26:00.000000000 +0200
@@ -26,6 +26,41 @@
 logging = logging.getLogger(__name__)
 
 
+def format_session(session):
+    column = (
+        'Session ID',
+        'Session tag',
+        'Description',
+        'Status',
+        'Result',
+        'Jobs',
+        'Hold off',
+        'Schedule',
+        'Last start',
+        'Time start',
+        'Time end',
+        'Project id',
+        'User id',
+    )
+
+    data = (
+        session.get('session_id'),
+        session.get('session_tag'),
+        session.get('description'),
+        session.get('status'),
+        session.get('result'),
+        pprint.pformat(session.get('jobs')),
+        session.get('hold_off'),
+        pprint.pformat(session.get('schedule')),
+        session.get('last_start'),
+        session.get('time_start'),
+        session.get('time_end'),
+        session.get('project_id'),
+        session.get('user_id'),
+    )
+    return column, data
+
+
 class SessionShow(show.ShowOne):
     """Show a single session"""
     def get_parser(self, prog_name):
@@ -40,38 +75,7 @@
         if not session:
             raise exceptions.ApiClientException('Session not found')
 
-        column = (
-            'Session ID',
-            'Session tag',
-            'Description',
-            'Status',
-            'Result',
-            'Jobs',
-            'Hold off',
-            'Schedule',
-            'Last start',
-            'Time start',
-            'Time end',
-            'Project id',
-            'User id',
-        )
-
-        data = (
-            session.get('session_id'),
-            session.get('session_tag'),
-            session.get('description'),
-            session.get('status'),
-            session.get('result'),
-            pprint.pformat(session.get('jobs')),
-            session.get('hold_off'),
-            pprint.pformat(session.get('schedule')),
-            session.get('last_start'),
-            session.get('time_start'),
-            session.get('time_end'),
-            session.get('project_id'),
-            session.get('user_id'),
-        )
-        return column, data
+        return format_session(session)
 
 
 class SessionList(lister.Lister):
@@ -126,7 +130,7 @@
         return columns, data
 
 
-class SessionCreate(command.Command):
+class SessionCreate(show.ShowOne):
     """Create a session from a file"""
     def get_parser(self, prog_name):
         parser = super(SessionCreate, self).get_parser(prog_name)
@@ -137,9 +141,13 @@
         return parser
 
     def take_action(self, parsed_args):
-        session = utils.doc_from_json_file(parsed_args.file)
-        session_id = self.app.client.sessions.create(session)
-        logging.info('Session {0} created'.format(session_id))
+        session_data = utils.doc_from_json_file(parsed_args.file)
+        session_id = self.app.client.sessions.create(session_data)
+        session = self.app.client.sessions.get(session_id)
+        if not session:
+            raise exceptions.ApiClientException(
+                'Session created but not found')
+        return format_session(session)
 
 
 class SessionDelete(command.Command):
@@ -153,11 +161,9 @@
     def take_action(self, parsed_args):
         session = self.app.client.sessions.get(parsed_args.session_id)
         if not session:
-            logging.info('Unable to delete specified session.')
             raise exceptions.ApiClientException('Session not found')
 
         self.app.client.sessions.delete(parsed_args.session_id)
-        logging.info('Session {0} deleted'.format(parsed_args.session_id))
 
 
 class SessionAddJob(command.Command):
@@ -177,8 +183,6 @@
     def take_action(self, parsed_args):
         self.app.client.sessions.add_job(parsed_args.session_id,
                                          parsed_args.job_id)
-        logging.info('Job {0} added correctly to session {1}'.format(
-            parsed_args.job_id, parsed_args.session_id))
 
 
 class SessionRemoveJob(command.Command):
@@ -209,12 +213,9 @@
                 pass
             else:
                 raise exceptions.ApiClientException(error.message)
-        else:
-            logging.info('Job {0} removed correctly from session {1}'.format(
-                parsed_args.job_id, parsed_args.session_id))
 
 
-class SessionUpdate(command.Command):
+class SessionUpdate(show.ShowOne):
     """Update a session from a file"""
     def get_parser(self, prog_name):
         parser = super(SessionUpdate, self).get_parser(prog_name)
@@ -226,9 +227,12 @@
         return parser
 
     def take_action(self, parsed_args):
-        session = utils.doc_from_json_file(parsed_args.file)
-        self.app.client.sessions.update(parsed_args.session_id, session)
-        logging.info('Session {0} updated'.format(parsed_args.session_id))
+        session_data = utils.doc_from_json_file(parsed_args.file)
+        self.app.client.sessions.update(parsed_args.session_id, session_data)
+        session = self.app.client.sessions.get(parsed_args.session_id)
+        if not session:
+            raise exceptions.ApiClientException('Session not found')
+        return format_session(session)
 
 
 class SessionStart(command.Command):
@@ -253,7 +257,6 @@
     def take_action(self, parsed_args):
         session = self.app.client.sessions.get(parsed_args.session_id)
         if not session:
-            logging.info('Unable to start specified session.')
             raise exceptions.ApiClientException('Session not found')
 
         self.app.client.sessions.start_session(
@@ -261,5 +264,3 @@
             parsed_args.job_id,
             parsed_args.job_tag
         )
-        logging.info('Session {0} start requested'.format(
-            parsed_args.session_id))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python_freezerclient-6.1.0/python_freezerclient.egg-info/PKG-INFO 
new/python_freezerclient-6.3.0/python_freezerclient.egg-info/PKG-INFO
--- old/python_freezerclient-6.1.0/python_freezerclient.egg-info/PKG-INFO       
2025-09-01 15:31:33.000000000 +0200
+++ new/python_freezerclient-6.3.0/python_freezerclient.egg-info/PKG-INFO       
2026-05-19 11:26:35.000000000 +0200
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
 Name: python-freezerclient
-Version: 6.1.0
+Version: 6.3.0
 Summary: OpenStack Disaster Recovery API Client Library
 Home-page: https://docs.openstack.org/python-freezerclient/latest/
 Author: OpenStack
@@ -11,11 +11,10 @@
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: Python :: 3 :: Only
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
 Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Natural Language :: English
 Classifier: Environment :: OpenStack
@@ -33,7 +32,7 @@
 Classifier: Topic :: System :: Archiving :: Backup
 Classifier: Topic :: System :: Archiving :: Compression
 Classifier: Topic :: System :: Archiving
-Requires-Python: >=3.8
+Requires-Python: >=3.10
 License-File: LICENSE
 Requires-Dist: 
setuptools!=24.0.0,!=34.0.0,!=34.0.1,!=34.0.2,!=34.0.3,!=34.1.0,!=34.1.1,!=34.2.0,!=34.3.0,!=34.3.1,!=34.3.2,!=36.2.0,>=21.0.0
 Requires-Dist: pbr!=2.1.0,>=2.0.0
@@ -41,11 +40,26 @@
 Requires-Dist: cliff!=2.9.0,>=2.8.0
 Requires-Dist: oslo.serialization>=2.25.0
 Requires-Dist: oslo.utils>=3.33.0
+Dynamic: author
+Dynamic: author-email
+Dynamic: classifier
+Dynamic: description
+Dynamic: home-page
+Dynamic: keywords
+Dynamic: license
+Dynamic: license-file
+Dynamic: requires-dist
+Dynamic: requires-python
+Dynamic: summary
 
 =============================================================
 Python bindings to the OpenStack Backup/Restore API (Freezer)
 =============================================================
 
+.. image:: https://governance.openstack.org/tc/badges/python-freezerclient.svg
+
+.. Change things from this point on
+
 .. image:: https://img.shields.io/pypi/v/python-freezerclient.svg
     :target: https://pypi.org/project/python-freezerclient/
     :alt: Latest Version
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python_freezerclient-6.1.0/python_freezerclient.egg-info/SOURCES.txt 
new/python_freezerclient-6.3.0/python_freezerclient.egg-info/SOURCES.txt
--- old/python_freezerclient-6.1.0/python_freezerclient.egg-info/SOURCES.txt    
2025-09-01 15:31:33.000000000 +0200
+++ new/python_freezerclient-6.3.0/python_freezerclient.egg-info/SOURCES.txt    
2026-05-19 11:26:35.000000000 +0200
@@ -87,10 +87,12 @@
 python_freezerclient.egg-info/requires.txt
 python_freezerclient.egg-info/top_level.txt
 releasenotes/notes/drop-py-2-7-9a3fc069f66d62bc.yaml
+releasenotes/notes/drop-python-38-and-39.yaml
 releasenotes/notes/freezerclient-v2-d0729e1ee77d341b.yaml
 releasenotes/source/2023.1.rst
 releasenotes/source/2023.2.rst
 releasenotes/source/2025.1.rst
+releasenotes/source/2026.1.rst
 releasenotes/source/conf.py
 releasenotes/source/index.rst
 releasenotes/source/newton.rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python_freezerclient-6.1.0/python_freezerclient.egg-info/pbr.json 
new/python_freezerclient-6.3.0/python_freezerclient.egg-info/pbr.json
--- old/python_freezerclient-6.1.0/python_freezerclient.egg-info/pbr.json       
2025-09-01 15:31:33.000000000 +0200
+++ new/python_freezerclient-6.3.0/python_freezerclient.egg-info/pbr.json       
2026-05-19 11:26:35.000000000 +0200
@@ -1 +1 @@
-{"git_version": "958e9ca", "is_release": true}
\ No newline at end of file
+{"git_version": "b8f4e60", "is_release": true}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python_freezerclient-6.1.0/releasenotes/notes/drop-python-38-and-39.yaml 
new/python_freezerclient-6.3.0/releasenotes/notes/drop-python-38-and-39.yaml
--- 
old/python_freezerclient-6.1.0/releasenotes/notes/drop-python-38-and-39.yaml    
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/python_freezerclient-6.3.0/releasenotes/notes/drop-python-38-and-39.yaml    
    2026-05-19 11:26:00.000000000 +0200
@@ -0,0 +1,4 @@
+---
+upgrade:
+  - |
+    Support for Python 3.8 and 3.9 has been dropped.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python_freezerclient-6.1.0/releasenotes/source/2026.1.rst 
new/python_freezerclient-6.3.0/releasenotes/source/2026.1.rst
--- old/python_freezerclient-6.1.0/releasenotes/source/2026.1.rst       
1970-01-01 01:00:00.000000000 +0100
+++ new/python_freezerclient-6.3.0/releasenotes/source/2026.1.rst       
2026-05-19 11:26:00.000000000 +0200
@@ -0,0 +1,6 @@
+===========================
+2026.1 Series Release Notes
+===========================
+
+.. release-notes::
+   :branch: stable/2026.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python_freezerclient-6.1.0/releasenotes/source/index.rst 
new/python_freezerclient-6.3.0/releasenotes/source/index.rst
--- old/python_freezerclient-6.1.0/releasenotes/source/index.rst        
2025-09-01 15:31:07.000000000 +0200
+++ new/python_freezerclient-6.3.0/releasenotes/source/index.rst        
2026-05-19 11:26:00.000000000 +0200
@@ -8,6 +8,7 @@
    :maxdepth: 2
 
    unreleased
+   2026.1
    2025.1
    2023.2
    2023.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python_freezerclient-6.1.0/setup.cfg 
new/python_freezerclient-6.3.0/setup.cfg
--- old/python_freezerclient-6.1.0/setup.cfg    2025-09-01 15:31:33.163253300 
+0200
+++ new/python_freezerclient-6.3.0/setup.cfg    2026-05-19 11:26:35.345000500 
+0200
@@ -7,17 +7,16 @@
 author = OpenStack
 author_email = [email protected]
 home_page = https://docs.openstack.org/python-freezerclient/latest/
-python_requires = >=3.8
+python_requires = >=3.10
 classifier = 
        Programming Language :: Python
        Programming Language :: Python :: Implementation :: CPython
        Programming Language :: Python :: 3 :: Only
        Programming Language :: Python :: 3
-       Programming Language :: Python :: 3.8
-       Programming Language :: Python :: 3.9
        Programming Language :: Python :: 3.10
        Programming Language :: Python :: 3.11
        Programming Language :: Python :: 3.12
+       Programming Language :: Python :: 3.13
        Development Status :: 5 - Production/Stable
        Natural Language :: English
        Environment :: OpenStack
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python_freezerclient-6.1.0/tox.ini 
new/python_freezerclient-6.3.0/tox.ini
--- old/python_freezerclient-6.1.0/tox.ini      2025-09-01 15:31:07.000000000 
+0200
+++ new/python_freezerclient-6.3.0/tox.ini      2026-05-19 11:26:00.000000000 
+0200
@@ -1,14 +1,12 @@
 [tox]
-minversion = 3.1.1
+minversion = 4.6.0
 envlist = py3,pep8,pylint,docs
 skipsdist = True
-ignore_basepython_conflict = True
 
 [testenv]
-basepython = python3
 usedevelop = True
 deps =
-    
-c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
+    
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
     -r{toxinidir}/requirements.txt
     -r{toxinidir}/test-requirements.txt
 
@@ -38,14 +36,10 @@
 [testenv:venv]
 commands = {posargs}
 
-[testenv:py39]
-basepython = python3.9
-
 [testenv:py312]
 basepython = python3.12
 
 [testenv:cover]
-basepython = python3
 setenv =
     {[testenv]setenv}
     PYTHON=coverage run --source freezerclient --parallel-mode
@@ -57,7 +51,9 @@
     coverage report
 
 [testenv:docs]
-deps = -r{toxinidir}/doc/requirements.txt
+deps =
+    
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
+    -r{toxinidir}/doc/requirements.txt
 commands = sphinx-build -b html doc/source doc/build/html
 
 [testenv:pep8]
@@ -79,10 +75,6 @@
 show-source = True
 exclude = .venv,.tox,dist,doc,*egg,releasenotes
 
-
 [testenv:releasenotes]
-deps =
-    
-c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
-    -r{toxinidir}/requirements.txt
-    -r{toxinidir}/doc/requirements.txt
+deps = {[testenv:docs]deps}
 commands = sphinx-build -a -E -d releasenotes/build/doctrees -b html 
releasenotes/source releasenotes/build/html

Reply via email to