diff --git a/CHANGELOG.md b/CHANGELOG.md index b09500b..f9600ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,17 @@ need no changes. ([#25](https://github.com/tokibito/django-database-task/issues/25)) +### Fixed + +- `purge_completed_database_tasks` treated a negative `--days` like + `--days 0` and deleted every completed task, while + `purge_completed_tasks()` and the purge endpoint refuse a negative value. + The command now refuses it with a `CommandError` before it counts or + deletes anything. `--days 0`, positive values and the default are + unchanged, so existing projects need no changes; only an invocation with a + negative `--days` now fails instead of deleting the whole history. + ([#69](https://github.com/tokibito/django-database-task/issues/69)) + ## 0.6.0 ### Added diff --git a/README.md b/README.md index c353f2c..8fd6f1c 100644 --- a/README.md +++ b/README.md @@ -328,7 +328,7 @@ python manage.py purge_completed_database_tasks [options] | Option | Description | |--------|-------------| -| `--days` | Delete tasks completed more than N days ago (0=all) | +| `--days` | Delete tasks completed more than N days ago (0=all). A negative value is refused | | `--status` | Target statuses, comma-separated (default: "SUCCESSFUL,FAILED") | | `--task-path` | Only delete tasks with this task path, matched exactly (default: all tasks) | | `--batch-size` | Number of tasks to delete at once (default: 1000) | @@ -337,8 +337,8 @@ python manage.py purge_completed_database_tasks [options] The same purge is available as `purge_completed_tasks()` (see [Programmatic API](#programmatic-api)), for a project that purges from its own code. Its defaults differ from the command's: it purges the `default` -backend's tasks only and keeps the last 7 days, and it raises `ValueError` for -a negative `days`. +backend's tasks only and keeps the last 7 days. Like the command, it refuses a +negative `days`, raising `ValueError`. ### requeue_stale_database_tasks diff --git a/django_database_task/management/commands/purge_completed_database_tasks.py b/django_database_task/management/commands/purge_completed_database_tasks.py index bb92cd5..9502852 100644 --- a/django_database_task/management/commands/purge_completed_database_tasks.py +++ b/django_database_task/management/commands/purge_completed_database_tasks.py @@ -1,4 +1,4 @@ -from django.core.management.base import BaseCommand +from django.core.management.base import BaseCommand, CommandError from django.utils.translation import gettext as _ from django_database_task.executor import ( @@ -53,6 +53,9 @@ def handle(self, *args, **options): batch_size = options["batch_size"] dry_run = options["dry_run"] + if days < 0: + raise CommandError(f"--days must not be negative, got {days}") + statuses = _parse_purge_statuses(status_str) if not statuses: diff --git a/tests/test_commands.py b/tests/test_commands.py index 5a4bd93..bfc4510 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -535,6 +535,18 @@ def test_purge_respects_days_option(self): assert DatabaseTask.objects.count() == 0 + def test_purge_refuses_negative_days(self): + """A negative --days is refused before anything is counted or deleted.""" + simple_task.enqueue(1, 1) + call_command("run_database_tasks", stdout=StringIO()) + + out = StringIO() + with pytest.raises(CommandError, match="--days must not be negative, got -1"): + call_command("purge_completed_database_tasks", days=-1, stdout=out) + + assert DatabaseTask.objects.count() == 1 + assert out.getvalue() == "" + def test_purge_keeps_recent_tasks(self): """Recent tasks are not deleted.""" simple_task.enqueue(1, 1)