fix: reject invalid --ads selector values instead of silent fallback (#834)

## Summary

- When an invalid `--ads` value is explicitly provided (e.g.
`--ads=my-directory-name`), the bot now exits with code 2 and a clear
error message listing valid options, instead of silently falling back to
the command default
- Fixes the numeric ID regex from unanchored `\d+[,\d+]*` (which could
match partial strings like `abc123`) to anchored `^\d+(,\d+)*$`
- Adds `_is_valid_ads_selector()` helper to deduplicate validation logic
across publish/update/download/extend commands

## Motivation

When calling `kleinanzeigen-bot publish --ads=led-grow-light-set`
(passing a directory name instead of a numeric ad ID), the bot silently
fell back to `--ads=due` and republished all due ads — causing
unintended republication of multiple ads and loss of conversations on
those ads.

The silent fallback with only a WARNING log message makes it too easy to
accidentally trigger unwanted operations. An explicit error with exit
code 2 (consistent with other argument validation like
`--workspace-mode`) is the expected behavior for invalid arguments.

## Changes

| File | Change |
|------|--------|
| `src/kleinanzeigen_bot/__init__.py` | Added `_ads_selector_explicit`
flag (set when `--ads` or `--force` is used), `_is_valid_ads_selector()`
helper method, and updated all 4 command blocks
(publish/update/download/extend) to error on explicitly invalid
selectors |
| `resources/translations.de.yaml` | Replaced 3 old fallback messages
with 4 new error messages |
| `tests/unit/test_init.py` | Updated 2 existing tests to expect
`SystemExit(2)` instead of silent fallback, added 2 new tests for
update/extend invalid selectors |

## Test plan

- [x] All 754 unit tests pass (`pdm run utest`)
- [x] Lint clean (`pdm run lint`)
- [x] Translation completeness verified
(`test_all_log_messages_have_translations`,
`test_no_obsolete_translations`)
- [x] `--ads=invalid` on publish/update/download/extend all exit with
code 2
- [x] Default behavior (no `--ads` flag) unchanged for all commands
- [x] Valid selectors (`--ads=all`, `--ads=due`, `--ads=12345,67890`,
`--ads=changed,due`) still work

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Stricter validation of ad selectors; invalid selectors now terminate
with exit code 2 and preserve safe defaults when no selector is
provided.

* **New Features**
* Support for comma-separated numeric ID lists as a valid selector
format.

* **Tests**
* Unit tests updated to assert non-zero exit on invalid selectors and
verify default-fallback behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Liermann Torsten - Hays <liermann.hays@partner.akdb.de>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Torsten Liermann
2026-02-21 20:30:06 +01:00
committed by GitHub
parent 304e6b48ec
commit 3308d31b8e
3 changed files with 102 additions and 40 deletions

View File

@@ -253,14 +253,15 @@ kleinanzeigen_bot/__init__.py:
run:
"DONE: No configuration errors found.": "FERTIG: Keine Konfigurationsfehler gefunden."
"DONE: No active ads found.": "FERTIG: Keine aktiven Anzeigen gefunden."
"You provided no ads selector. Defaulting to \"due\".": "Es wurden keine Anzeigen-Selektor angegeben. Es wird \"due\" verwendet."
"Invalid --ads selector: \"%s\". Valid values: all, new, due, changed, or comma-separated numeric IDs.": "Ungültiger --ads-Selektor: \"%s\". Gültige Werte: all, new, due, changed oder kommagetrennte numerische IDs."
"Invalid --ads selector: \"%s\". Valid values: all, changed, or comma-separated numeric IDs.": "Ungültiger --ads-Selektor: \"%s\". Gültige Werte: all, changed oder kommagetrennte numerische IDs."
"Invalid --ads selector: \"%s\". Valid values: all, new, or comma-separated numeric IDs.": "Ungültiger --ads-Selektor: \"%s\". Gültige Werte: all, new oder kommagetrennte numerische IDs."
"Invalid --ads selector: \"%s\". Valid values: all or comma-separated numeric IDs.": "Ungültiger --ads-Selektor: \"%s\". Gültige Werte: all oder kommagetrennte numerische IDs."
"DONE: No new/outdated ads found.": "FERTIG: Keine neuen/veralteten Anzeigen gefunden."
"DONE: No ads to delete found.": "FERTIG: Keine zu löschenden Anzeigen gefunden."
"DONE: No changed ads found.": "FERTIG: Keine geänderten Anzeigen gefunden."
"Extending all ads within 8-day window...": "Verlängere alle Anzeigen innerhalb des 8-Tage-Zeitfensters..."
"DONE: No ads found to extend.": "FERTIG: Keine Anzeigen zum Verlängern gefunden."
"You provided no ads selector. Defaulting to \"new\".": "Es wurden keine Anzeigen-Selektor angegeben. Es wird \"new\" verwendet."
"You provided no ads selector. Defaulting to \"changed\".": "Es wurden keine Anzeigen-Selektor angegeben. Es wird \"changed\" verwendet."
"Unknown command: %s": "Unbekannter Befehl: %s"
"Timing collector flush failed: %s": "Zeitmessdaten konnten nicht gespeichert werden: %s"