feat: filter Wishlist from --my-tasks; document the mode (#71)

Tasks in the "Wishlist" bucket version are now excluded from the list
and summary entirely (no due date, noise backlog); exact case match,
tasks without a version are unaffected. Document --my-tasks in README
and the user guide (sorting, summary metrics, OSC 8 links, stream
separation); all examples use synthetic data. Declare ruff
known-first-party in pyproject so the lint result is CWD-independent.
This commit is contained in:
Кокос Артем Николаевич
2026-10-28 15:53:50 +07:00
parent 5d1cf4ab74
commit f00c6705ba
13 changed files with 224 additions and 1 deletions

View File

@@ -16,7 +16,12 @@ from .formatters.factory import get_console_formatter, get_formatter_by_extensio
from .formatters.task_table import TaskTableFormatter
from .mailer import send_report
from .report_builder import build_grouped_report, calculate_summary
from .task_list import build_task_rows, calculate_task_summary, format_summary_line
from .task_list import (
build_task_rows,
calculate_task_summary,
filter_excluded_versions,
format_summary_line,
)
from .yaml_config import ensure_config_dir, resolve_output_path, save_period_to_config
# Маскируем API-ключ Redmine в тексте ошибок (#55):
@@ -287,6 +292,10 @@ def _run_my_tasks(args: argparse.Namespace) -> int:
logging.exception("Unexpected error") # noqa: LOG015
return 1
# Бакет-версии (Wishlist) исключаются до проверки на пустоту: если все
# открытые задачи в них, пользователь видит "Открытых задач нет".
items = filter_excluded_versions(items)
if not items:
print("ℹ️ Открытых задач нет.", file=sys.stderr)
return 0

View File

@@ -22,6 +22,31 @@ def _issue_version_name(issue: Issue) -> str:
return get_version(issue, default="")
# "Wishlist" -- постоянная бакет-версия без срока (личный бакет Wendy, факт
# из трекера): задачи в ней -- отложенные идеи, создающие мусорный фон в
# персональной выборке, поэтому режим --my-tasks исключает их целиком --
# из таблицы и из саммари. Сравнение имени точное, без нормализации регистра.
EXCLUDED_VERSION_NAMES: frozenset[str] = frozenset({"Wishlist"})
def filter_excluded_versions(
items: list[tuple[Issue, date | None]],
) -> list[tuple[Issue, date | None]]:
"""Убирает задачи версий-исключений из выборки --my-tasks.
Доступ к fixed_version.name getattr-безопасный: задача без версии или
с версией без имени остаётся в выборке. Даты в парах сохраняются как есть.
"""
kept: list[tuple[Issue, date | None]] = []
for item in items:
version = getattr(item[0], "fixed_version", None)
name = getattr(version, "name", None) if version is not None else None
if name and str(name) in EXCLUDED_VERSION_NAMES:
continue
kept.append(item)
return kept
def _sort_key(item: tuple[Issue, date | None]) -> tuple[int, bool, date, int]:
"""Ключ сортировки: приоритет, затем срок по возрастанию, затем id.