Commit Graph

82 Commits

Author SHA1 Message Date
Кокос Артем Николаевич
17b0e99aa3 chore: bump version to 1.10.1 and update README
- Update README to document optional DEFAULT_TO_DATE / default_to
- Default end date falls back to today when not explicitly set

Closes #50
2026-07-10 16:46:30 +07:00
Кокос Артем Николаевич
8992bb922e docs: explain optional period.default_to and today fallback 2026-07-10 16:40:22 +07:00
Кокос Артем Николаевич
608afe08e3 fix: default missing period.default_to to today 2026-07-10 16:33:28 +07:00
Кокос Артем Николаевич
e1862462af feat: add HTML email body for --send (#48)
Add email.html config flag (default false). When enabled, --send
includes an HTML version of the report body generated via HTMLFormatter
alongside the plain-text part in a multipart/alternative message.

- EmailConfig gains html: bool field
- mailer.build_message/send_report accept rows for HTML generation
- CLI passes rows to send_report
- --init-config generates email.html: false
- README.md and docs/CONFIG.md updated

Bump version to 1.10.0.

Closes #48
v1.10.0
2026-07-10 15:24:27 +07:00
Кокос Артем Николаевич
863ad50cc3 feat: add report.no_time config option for automatic modes
Add YAML section `report.no_time` that controls `--no-time` behavior
in automatic modes (`--commit`, `--send`). CLI flag `--no-time`
always wins. Manual `--output` ignores the YAML setting.

- Config.get_report_no_time() reads the YAML value (defaults to false)
- cli._resolve_no_time() encapsulates CLI > YAML priority
- --init-config now generates the report section
- docs updated in README.md and docs/CONFIG.md

Closes #49
2026-07-10 14:38:07 +07:00
Кокос Артем Николаевич
5e1c366a60 docs: update README, CONFIG and pyproject.toml for --send feature
- README: add --send flag to features, usage examples, full flag list;
  replace black/isort with ruff in dev section; add email config
  template variables docs
- CONFIG: new email section with all fields documented, --send usage
  examples, error handling and flag compatibility table
- pyproject.toml: remove unused black and isort from dev dependencies
  and their tool configs (project uses ruff for both lint and format)
2026-07-10 12:46:46 +07:00
Кокос Артем Николаевич
0968560090 style: apply ruff format to all source files 2026-07-10 12:39:24 +07:00
Кокос Артем Николаевич
25425901b1 fix: handle save_period_to_config errors, remove duplicate _MockIssue
- cli.py: wrap save_period_to_config in try/except to avoid
  unhandled traceback on disk full / permission denial (I2)
- test_cli.py: remove duplicate _MockIssue class definition (I3)
2026-07-10 12:37:46 +07:00
Кокос Артем Николаевич
b0e353c565 feat: auto-email sending via SMTP (--send flag)
Closes #45

- New redmine_reporter/mailer.py: SMTP email sending with
  {author}/{period} template substitution, MIME attachment
  with correct content-type per file extension
- Config.get_email_config(): returns EmailConfig from YAML
  or None when not configured
- CLI --send flag: sends report after generation, works with
  --output, --commit, or standalone (saves to template path)
- 31 new tests (22 mailer + 6 CLI + 3 config)
- 249/249 tests passing, ruff clean, mypy clean
2026-07-10 12:37:02 +07:00
Кокос Артем Николаевич
b926dd0d49 chore: bump version to 1.9.0 v1.9.0 2026-07-07 11:11:58 +07:00
Кокос Артем Николаевич
80faccb1f9 docs: add --commit documentation to README and CONFIG 2026-07-07 10:48:36 +07:00
Кокос Артем Николаевич
9b78d66769 feat: --commit flag (#44)
- --commit: после генерации отчёта сохраняет период в
  period.last_used.from/to YAML-конфига
- При period.dynamic=true следующий запуск вычисляет период от last_used:
  полный месяц → следующий месяц, произвольный диапазон → та же длина
- При period.dynamic=false перезаписывает default_from/default_to
- При period.precision=datetime сохраняет timestamps с точностью до секунд
- --commit без --output сохраняет отчёт по шаблону из конфига
- compute_next_period() в config.py
- save_period_to_config() в yaml_config.py
- 23 новых теста (7 CLI, 6 config, 6 yaml, 4 date_range)

Closes #44
2026-07-07 10:47:08 +07:00
Кокос Артем Николаевич
485be063d2 docs: update README and CONFIG for #43 #47
- README: add YAML config section, --by-activity, bare format --output,
  output without extension, period.precision
- CONFIG: document period.last_used, period.precision (date/datetime),
  output path resolution rules, resolve_output_path() behavior
2026-07-07 10:34:49 +07:00
Кокос Артем Николаевич
47152f8f04 feat: output path defaults (#43) + datetime precision & dedup (#47)
#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 #43
Closes #47
2026-07-07 10:16:46 +07:00
Кокос Артем Николаевич
67350bfcd6 fix: verify_ssl: true in YAML now uses DEFAULT_REDMINE_VERIFY path
Previously boolean True was passed directly to python-redmine
which used system CA bundle instead of the project's default CA file.
Now 'true' in YAML maps to DEFAULT_REDMINE_VERIFY path.
2026-07-03 18:24:11 +07:00
Кокос Артем Николаевич
0fa4e271a7 fix: auto-load YAML config on CLI startup
CLI now reads ~/.config/redmine-reporter/config.yml automatically.
Previously Config.load_yaml() existed but was never called.
2026-07-03 18:19:30 +07:00
Кокос Артем Николаевич
b1a565bc9e feat: filename template expansion with {date} placeholder
- Add expand_filename_template() to yaml_config.py
- Supports {author}, {from}, {to}, {date}, {ext} placeholders
- {date} formats as DD_MM_YYYY (e.g. 31_03_2026)
- Spaces in author replaced with underscores for safe filenames
- Unknown placeholders left as-is
- Add comprehensive CONFIG.md documentation covering YAML setup, migration, and template syntax
2026-07-03 18:13:55 +07:00
Кокос Артем Николаевич
c962a93f30 feat: YAML config support (~/.config/redmine-reporter/config.yml)
- Add AppConfig/SmtpConfig/EmailConfig dataclasses with from_yaml()/from_env()
- Add yaml_config.py: ${VAR} resolver, 0700/0600 permission helpers
- Config.get_*() methods gain YAML fallback in priority chain
- Priority: CLI > env > .env > YAML > code defaults
- CLI --init-config generates YAML from current environment
- --force flag allows overwriting existing config
- Secrets default to ${VAR} references, plaintext allowed
- Full backward compatibility with existing .env setups

Closes #46
2026-07-03 18:00:28 +07:00
Кокос Артем Николаевич
676f7ede30 fix: bump __version__ to 1.8.1 v1.8.1 2026-06-30 09:48:37 +07:00
Кокос Артем Николаевич
5dd234e7b3 fix(odt): remove stray blank paragraph from template (#42)
The template contained an empty <text:p/> that was rendered as
a blank line before the report header.  After loading the template,
strip all text:p children so that ODT output no longer depends on
template editing artifacts.

Closes #42.
2026-06-30 09:43:08 +07:00
Кокос Артем Николаевич
59af7ce464 feat(activity): add --by-activity flag to break down spent time by activity type
- 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
v1.8.0
2026-06-29 16:44:52 +07:00
Кокос Артем Николаевич
f6861382e6 feat(user): report on another user's time entries
- 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
v1.7.0
2026-06-29 15:15:17 +07:00
Кокос Артем Николаевич
67b5d093d9 docs(readme): update README and bump version to 1.6.1
- Remove duplicated --config bullet.
- Update Excel section to reflect production-grade XLSX features.
- Add --no-time note for file formats.
- Add readable API error messaging to feature list.
- Fix development commands: use --check flags and add mypy.
- Replace verbose per-format sections with a summary table.
- Bump pyproject.toml version to 1.6.1.
2026-06-29 15:02:31 +07:00
Кокос Артем Николаевич
f80f3a8b52 feat(errors): provide readable Redmine API error messages
- 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
2026-06-29 14:58:42 +07:00
Кокос Артем Николаевич
222d31730e feat(xlsx): make Excel export production-grade
- Add merge cells for project/version groups.
- Add numeric Hours column and human-readable Spent Time.
- Add version/project/grand totals.
- Apply auto-width, freeze panes, auto-filter and styling.
- Respect --no-time: keep columns empty, skip totals.
- Pass no_time flag through formatter factory to all file formatters.
- Add tests for XLSX features and --no-time behavior.

Closes #38
v1.6.1
2026-06-29 14:41:37 +07:00
Кокос Артем Николаевич
86f083aa79 chore(release): bump version to 1.6.0
Bump version from 1.5.0 to 1.6.0 in __init__.py and pyproject.toml.
Update test_cli_version_flag to assert against the current package
version instead of a hardcoded string.
v1.6.0
2026-06-29 12:38:54 +07:00
Кокос Артем Николаевич
a82be05b83 fix: handle empty time entries and add missing mypy override for openpyxl
- Treat empty list from fetch_issues_with_spent_time as 'no entries' and exit 0
  instead of crashing later in the pipeline.
- Update CLI output-extension tests to use non-empty mock data so they actually
  reach the extension validation code path.
- Add openpyxl to mypy ignore_missing_imports overrides.

Closes #36
2026-06-29 12:21:44 +07:00
Кокос Артем Николаевич
ca89832d74 feat: JSON, Excel export and time summary
- #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
2026-06-29 12:09:58 +07:00
Кокос Артем Николаевич
f6afc4096d feat(cli): dynamic default range, --version, --verbose, --debug, --url, --api-key, --config
- #17: default date range falls back to current month when .env dates are missing
- #18: add --version, --verbose, --debug flags
- #20: add --url, --api-key, --config CLI overrides
- Config supports CLI overrides for URL/API key and explicit config file loading
- Update README with new CLI options
- Add tests for new flags and config overrides

Closes #17, closes #18, closes #20
2026-06-29 12:02:51 +07:00
Кокос Артем Николаевич
738d9d543e fix: mount retry adapter on Redmine engine session
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.
2026-06-29 11:53:09 +07:00
Артём Кокос
58fa5a7ab4 Add retry/backoff, timeout, and issue_id chunking to Redmine client
- #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
2026-06-27 13:06:41 +07:00
Артём Кокос
14219564dd Fix 9 bugs: ODT covered-cells, CSV BOM, HTML charset, stderr, dead code
- #13 (critical): Add CoveredTableCell elements to ODT for valid row spans (ODF 1.2)
- #28: Move "Total issues" info message from stdout to stderr (clean pipe output)
- #27: Wrap HTML export in full document with DOCTYPE and meta charset utf-8
- #26: Save CSV with utf-8-sig encoding (UTF-8 BOM for Excel compatibility)
- #31: Document CSV uses full project/version values (not display_* like console/MD)
- #30: Fix ODT header formatting when author is empty (no leading dot/space)
- #36: Remove test_cli_smoke_empty testing unreachable code path (return [])
- #37: Remove unused mock_path variable in ODT test fixture
- #34: Remove unreachable len(parts) != 2 check in parse_date_range

Closes #13, #28, #27, #26, #31, #30, #36, #37, #34
2026-06-27 13:01:32 +07:00
Артём Кокос
da069993b9 Extract grouping logic into shared function (#19)
Add group_rows_by_project_and_version() to report_builder.py and replace
the duplicated inline grouping in both html.py and odt.py with a single
call to the shared function. This ensures consistent grouping behavior
across formatters and removes a maintenance burden — any change to
grouping logic now happens in one place.

Closes #19
2026-06-26 00:21:58 +07:00
Артём Кокос
dbc4cf960a Fix version display, deterministic sort, remove duplicate sort
get_version() now returns version.name instead of str(version), which
returned the numeric ID from redminelib.resources.Version. Falls back
to str() when .name is absent (#14).

Add issue.id as tertiary sort key in build_grouped_report so tasks
within the same project+version group always appear in the same order
regardless of API response ordering (#33).

Remove redundant sort from client.fetch_issues_with_spent_time — the
sort already runs in report_builder.build_grouped_report, so doing it
twice wastes CPU. Also remove the now-unused get_version import (#32).

Closes #14, closes #32, closes #33
2026-06-25 23:32:14 +07:00
Артём Кокос
3a6d1b7ba7 Fix .env override priority and password whitespace stripping
Change load_dotenv() to load_dotenv(override=False) so real environment
variables always take priority over stale .env files. This prevents a
hardcoded or outdated REDMINE_API_KEY in .env from silently overriding
a fresh token exported in the shell (#15).

Add .strip() to get_redmine_password() for consistency with all other
config getters — trailing whitespace in .env no longer causes silent
auth failures (#35).

Closes #15, closes #35
2026-06-25 21:06:19 +07:00
Артём Кокос
3956decd4e Fix package structure and lazy-import ODT formatter
Add missing __init__.py to formatters/ so setuptools.find_packages
includes the subpackage in wheel/sdist builds (#16).

Move ODTFormatter import from top-level to lazy import inside
get_formatter_by_extension() so missing odfpy no longer crashes module
load before main() runs. Remove dead except ImportError handler in
cli.py save() block; surface a clear 'odfpy is not installed' message
when the formatter factory returns None for .odt (#25).

Closes #16, closes #25
2026-06-25 20:42:13 +07:00
Кокос Артем Николаевич
0e4e0f3ee2 Bump version: v1.5.0 v1.5.0 2026-05-22 17:49:18 +07:00
Кокос Артем Николаевич
2db0ab1f0b Tighten configuration and export handling 2026-05-22 17:41:56 +07:00
Кокос Артем Николаевич
8bc8181ce3 Add Redmine API token authentication 2026-05-22 17:19:00 +07:00
Artem Kokos
7bc6e024c0 Quick fixes & tests 2026-03-28 23:55:46 +07:00
Кокос Артем Николаевич
06cd57e2c4 Blacked 2026-02-05 15:31:31 +07:00
Кокос Артем Николаевич
d7e927e6eb Bump version: v1.4.1 v1.4.1 2026-02-05 15:18:40 +07:00
Кокос Артем Николаевич
000bf37503 Update status map 2026-02-05 15:15:44 +07:00
Артём Кокос
dfb8d474b4 Update README.md 2026-01-26 21:03:24 +07:00
Кокос Артем Николаевич
b7f03666dc Bump version: v1.4.0 v1.4.0 2026-01-26 13:43:54 +07:00
Кокос Артем Николаевич
30310d614d Add HTML formatter
Closes #7
2026-01-26 12:57:33 +07:00
Кокос Артем Николаевич
ad62ef4f6c Fix CSV & MD 2026-01-26 12:56:57 +07:00
Кокос Артем Николаевич
355849e004 Fix issue mock for tests 2026-01-26 12:37:57 +07:00
Артём Кокос
d839be8776 Add unit-tests 2026-01-25 12:40:23 +07:00
Артём Кокос
ea90fe79d0 ODT template into resources 2026-01-25 12:24:32 +07:00