List open Redmine issues assigned to the current (or overridden) user,
sorted by priority rank (P1..P5) then version due date with a stable id
tie-break. Renders an OSC 8 hyperlinked console table on stdout and a
counts/hours summary line on stderr; version due dates are fetched once
per unique version, unavailable versions degrade to an empty due date.
Also migrates the codebase to ruff 0.17.3 defaults (PEP 585/604
annotations, targeted noqa for intentional blind excepts and CLI root
logging). Behavior-neutral: 408 tests pass with -W error.
cli.py: drop redundant 'if issue_hours is None' branch before
'if not issue_hours'. The branch is not formally dead (client
returns None when no time entries found, client.py), but it is a
semantic duplicate: both branches print the same message and
return 0, and None is falsy, so a single 'not issue_hours' check
covers None, empty list and keeps behavior identical.
test_cli_returns_zero_on_no_entries stays green unchanged.
xlsx.py: drop unreachable 'if ws is None' fallback. Workbook()
(write_only=False) always creates one worksheet in __init__, so
wb.active is never None; set the title directly.
Closes#63
- #23: add JSONFormatter and XLSXFormatter
- add openpyxl dependency for .xlsx export
- #22: add --summary flag and calculate_summary() in report_builder
- ReportRow now carries raw hours for summary calculations
- update CLI help and README with .json/.xlsx formats and --summary
- add tests for new formatters and summary computation
Closes#22, closes#23