From 1c8cbd96ca41c7c80d107b177a038844d9a65714 Mon Sep 17 00:00:00 2001 From: Peter van Arkel Date: Thu, 21 May 2026 02:52:42 +0200 Subject: [PATCH] (refactor) Normalize maintainer command labels Prefer --schedule-expression for scripted schedule updates while keeping --cron as a compatibility alias. Clean up management command help, errors, and output so operator-facing text talks about hosts, global config, and Django backup configuration instead of model names or old SQL-backed pobsync wording. --- docs/development.md | 2 +- .../commands/configure_pobsync_global.py | 6 +++--- .../commands/configure_pobsync_host.py | 6 +++--- .../commands/configure_pobsync_schedule.py | 20 ++++++++++++------- .../commands/discover_pobsync_snapshots.py | 4 ++-- .../management/commands/run_pobsync_backup.py | 2 +- .../commands/run_pobsync_retention.py | 2 +- .../tests/test_configure_commands.py | 4 ++-- 8 files changed, 26 insertions(+), 20 deletions(-) diff --git a/docs/development.md b/docs/development.md index 994235c..a221f9d 100644 --- a/docs/development.md +++ b/docs/development.md @@ -70,7 +70,7 @@ automation/debugging path rather than the normal UI workflow: ``` pobsync django configure_pobsync_host --address -pobsync django configure_pobsync_schedule --cron "15 2 * * *" +pobsync django configure_pobsync_schedule --schedule-expression "15 2 * * *" ``` ## Installer Development diff --git a/src/pobsync_backend/management/commands/configure_pobsync_global.py b/src/pobsync_backend/management/commands/configure_pobsync_global.py index 730f053..c093c0b 100644 --- a/src/pobsync_backend/management/commands/configure_pobsync_global.py +++ b/src/pobsync_backend/management/commands/configure_pobsync_global.py @@ -11,7 +11,7 @@ from pobsync_backend.models import GlobalConfig class Command(BaseCommand): - help = "Create or update the SQL-backed global pobsync configuration." + help = "Create or update the default global backup configuration." def add_arguments(self, parser) -> None: parser.add_argument("--name", default="default") @@ -48,8 +48,8 @@ class Command(BaseCommand): } if GlobalConfig.objects.filter(name=options["name"]).exists() and not options["force"]: - raise CommandError(f"GlobalConfig {options['name']!r} already exists; use --force to update") + raise CommandError(f"Global config {options['name']!r} already exists; use --force to update") _obj, created = GlobalConfig.objects.update_or_create(name=options["name"], defaults=defaults) action = "Created" if created else "Updated" - self.stdout.write(self.style.SUCCESS(f"{action} GlobalConfig {options['name']!r}.")) + self.stdout.write(self.style.SUCCESS(f"{action} global config {options['name']!r}.")) diff --git a/src/pobsync_backend/management/commands/configure_pobsync_host.py b/src/pobsync_backend/management/commands/configure_pobsync_host.py index 6b79c04..a22961c 100644 --- a/src/pobsync_backend/management/commands/configure_pobsync_host.py +++ b/src/pobsync_backend/management/commands/configure_pobsync_host.py @@ -10,7 +10,7 @@ from pobsync_backend.models import GlobalConfig, HostConfig class Command(BaseCommand): - help = "Create or update a SQL-backed host pobsync configuration." + help = "Create or update a host backup configuration." def add_arguments(self, parser) -> None: parser.add_argument("host") @@ -29,7 +29,7 @@ class Command(BaseCommand): def handle(self, *args: Any, **options: Any) -> None: host = sanitize_host(options["host"]) if HostConfig.objects.filter(host=host).exists() and not options["force"]: - raise CommandError(f"HostConfig {host!r} already exists; use --force to update") + raise CommandError(f"Host {host!r} already exists; use --force to update") retention = self._retention(options["retention"]) defaults = { @@ -49,7 +49,7 @@ class Command(BaseCommand): } _obj, created = HostConfig.objects.update_or_create(host=host, defaults=defaults) action = "Created" if created else "Updated" - self.stdout.write(self.style.SUCCESS(f"{action} HostConfig {host!r}.")) + self.stdout.write(self.style.SUCCESS(f"{action} host {host!r}.")) def _retention(self, value: str | None) -> dict[str, int]: if value: diff --git a/src/pobsync_backend/management/commands/configure_pobsync_schedule.py b/src/pobsync_backend/management/commands/configure_pobsync_schedule.py index b646389..fbef47e 100644 --- a/src/pobsync_backend/management/commands/configure_pobsync_schedule.py +++ b/src/pobsync_backend/management/commands/configure_pobsync_schedule.py @@ -9,11 +9,16 @@ from pobsync_backend.scheduler import parse_cron_expr class Command(BaseCommand): - help = "Create, update, disable, or remove a SQL-backed pobsync schedule." + help = "Create, update, disable, or remove a scheduler-managed host schedule." def add_arguments(self, parser) -> None: parser.add_argument("host") - parser.add_argument("--cron", help='Cron expression, e.g. "15 2 * * *"') + parser.add_argument( + "--schedule-expression", + "--cron", + dest="schedule_expression", + help='Five-field schedule expression, e.g. "15 2 * * *"', + ) parser.add_argument("--prune", action="store_true") parser.add_argument("--prune-max-delete", type=int, default=10) parser.add_argument("--prune-protect-bases", action="store_true") @@ -24,24 +29,25 @@ class Command(BaseCommand): try: host = HostConfig.objects.get(host=options["host"]) except HostConfig.DoesNotExist as exc: - raise CommandError(f"Missing HostConfig {options['host']!r}") from exc + raise CommandError(f"Missing host {options['host']!r}") from exc if options["delete"]: deleted, _details = ScheduleConfig.objects.filter(host=host).delete() self.stdout.write(self.style.SUCCESS(f"Deleted {deleted} schedule row(s) for {host.host!r}.")) return - if not options["cron"]: - raise CommandError("--cron is required unless --delete is used") + schedule_expression = options["schedule_expression"] + if not schedule_expression: + raise CommandError("--schedule-expression is required unless --delete is used") try: - parse_cron_expr(options["cron"]) + parse_cron_expr(schedule_expression) except ValueError as exc: raise CommandError(str(exc)) from exc schedule, created = ScheduleConfig.objects.update_or_create( host=host, defaults={ - "cron_expr": options["cron"], + "cron_expr": schedule_expression, "enabled": not options["disabled"], "prune": bool(options["prune"]), "prune_max_delete": int(options["prune_max_delete"]), diff --git a/src/pobsync_backend/management/commands/discover_pobsync_snapshots.py b/src/pobsync_backend/management/commands/discover_pobsync_snapshots.py index 1e5ca32..fab9c74 100644 --- a/src/pobsync_backend/management/commands/discover_pobsync_snapshots.py +++ b/src/pobsync_backend/management/commands/discover_pobsync_snapshots.py @@ -20,14 +20,14 @@ class Command(BaseCommand): try: global_config = GlobalConfig.objects.get(name="default") except GlobalConfig.DoesNotExist as exc: - raise CommandError("Missing GlobalConfig 'default'") from exc + raise CommandError("Missing default global config") from exc host = None if options["host"]: try: host = HostConfig.objects.get(host=options["host"], enabled=True) except HostConfig.DoesNotExist as exc: - raise CommandError(f"Missing enabled HostConfig {options['host']!r}") from exc + raise CommandError(f"Missing enabled host {options['host']!r}") from exc kind = normalize_kind(options["kind"]) kinds = ["scheduled", "manual", "incomplete"] if kind == "all" else [kind] diff --git a/src/pobsync_backend/management/commands/run_pobsync_backup.py b/src/pobsync_backend/management/commands/run_pobsync_backup.py index 57e18c9..874f7af 100644 --- a/src/pobsync_backend/management/commands/run_pobsync_backup.py +++ b/src/pobsync_backend/management/commands/run_pobsync_backup.py @@ -30,7 +30,7 @@ class Command(BaseCommand): try: host = HostConfig.objects.get(host=host_name, enabled=True) except HostConfig.DoesNotExist as exc: - raise CommandError(f"Missing enabled HostConfig {host_name!r}") from exc + raise CommandError(f"Missing enabled host {host_name!r}") from exc run = BackupRun.objects.create( host=host, diff --git a/src/pobsync_backend/management/commands/run_pobsync_retention.py b/src/pobsync_backend/management/commands/run_pobsync_retention.py index 5067e40..2100a09 100644 --- a/src/pobsync_backend/management/commands/run_pobsync_retention.py +++ b/src/pobsync_backend/management/commands/run_pobsync_retention.py @@ -12,7 +12,7 @@ from pobsync_backend.retention import run_sql_retention_apply, run_sql_retention class Command(BaseCommand): - help = "Plan or apply retention using SQL-backed pobsync configuration." + help = "Plan or apply retention using the Django backup configuration." def add_arguments(self, parser) -> None: parser.add_argument("host") diff --git a/src/pobsync_backend/tests/test_configure_commands.py b/src/pobsync_backend/tests/test_configure_commands.py index bf5ef99..7656e1e 100644 --- a/src/pobsync_backend/tests/test_configure_commands.py +++ b/src/pobsync_backend/tests/test_configure_commands.py @@ -23,7 +23,7 @@ class ConfigureCommandsTests(TestCase): config = GlobalConfig.objects.get(name="default") self.assertEqual(config.backup_root, "/backups") self.assertEqual(config.retention_daily, 3) - self.assertIn("Created GlobalConfig", out.getvalue()) + self.assertIn("Created global config", out.getvalue()) def test_configure_host_uses_global_retention_defaults(self) -> None: GlobalConfig.objects.create( @@ -61,7 +61,7 @@ class ConfigureCommandsTests(TestCase): call_command( "configure_pobsync_schedule", host.host, - cron="15 2 * * *", + schedule_expression="15 2 * * *", prune=True, stdout=out, )