The trap mocked issue.filter to return only issue 2, so result == [2]
would pass even with a wrong fix that suppresses TypeError but keeps all
entries. Now the API mock returns both issues; only correct filtering
of the pre-cutoff time entry keeps the result at [2].
Refs #67, #58
- tests/test_cli.py: fix 26 fetch_issues_with_spent_time mocks to return
3-element tuples (issue, hours, activities) matching the real signature
- pyproject.toml: add [tool.pytest.ini_options] with testpaths and
pythonpath so bare pytest works
- tests/test_client.py: add pagination test (>100 time entries arriving
in pages, hours aggregated across all pages)
- tests/test_formatters.py: add structural tests — XLSX full header row
and grand total row via openpyxl, HTML thead with all columns and
tbody row count
- add strict xfail trap-tests for known bugs: #58 (naive created_on vs
aware dedup cutoff TypeError) and #59 (parse_date_range rejects
datetime range from dynamic+datetime period)
Closes#67
#43 — Имя файла и пути по умолчанию:
- resolve_output_path() в yaml_config.py: резолвит --output с учётом
output.dir, filename_template, default_format из YAML-конфига
- Bare format (xlsx/odt/...) → путь по шаблону
- Без расширения → автодописывается default_format (.xlsx)
- Config.get_output_dir/filename/default_format()
#47 — datetime precision и дедупликация:
- period.last_used.from/to в YAML-конфиге и AppConfig
- period.precision: date|datetime
- _compute_dedup_cutoff() в cli.py: при precision=datetime вычисляет
cutoff из period.last_used.to
- _parse_datetime() + AND-логика дедупликации в client.py:
запись исключается если created_on И updated_on < cutoff
- Пропуск issues без часов после дедупликации
Closes#43Closes#47
- Load time entry activity names from Redmine enumeration.
- Aggregate hours per issue and per activity in fetch_issues_with_spent_time.
- Add --by-activity CLI flag and propagate it through report builder,
summary, and all formatters (console, CSV, HTML, JSON, ODT).
- Keep backward-compatible 2-tuple input in build_grouped_report.
- Bump version to 1.8.0.
Closes#41
- Add user_id parameter to fetch_issues_with_spent_time().
- Support numeric ID, login, or full name resolution.
- Reject ambiguous names and unknown users with clear messages.
- Add CLI flags: --user-id, --user-login, --user-name.
- Only allow one user flag at a time.
- Add ResourceNotFoundError handling.
- Update README with usage examples.
- Add tests for user resolution and CLI flags.
Closes#40
- Introduce RedmineAPIError with human-friendly messages.
- Distinguish AuthError, ForbiddenError, HTTP status codes, timeouts
and connection errors in client.py.
- Update CLI to print the readable message instead of generic
"Redmine API error: ...".
- Log original exception with traceback when --debug is enabled.
- Add tests for all error paths and CLI output.
Closes#39
python-redmine exposes as a context manager, while the
actual requests.Session lives in . Mounting the
retry adapter on the wrong object caused:
'function' object has no attribute 'mount'
on startup. Update the related test to mock the real session.
- #24: Mount HTTPAdapter with Retry(total=3, backoff_factor=0.5) for
HTTP 429/500/502/503/504 on the Redmine session, set 30s timeout
- #21: Split large issue_id lists into chunks of 100 to avoid exceeding
URL length limits on reverse proxies
Closes#24, #21