Dedup with precision=datetime crashed with TypeError: redminelib returns naive created_on/updated_on while the cutoff from _compute_dedup_cutoff is aware UTC. Normalize at a single point: _parse_datetime now always returns an aware datetime (naive treated as UTC), matching its docstring. The dedup cutoff is normalized the same way, and any residual comparison TypeError is wrapped in RedmineAPIError instead of leaking raw. Also fix --commit saving last_used.to as naive local time; it now stores aware UTC (datetime.now(timezone.utc)) so the next run computes a correct aware cutoff. Closes #58
redmine-reporter
CLI-инструмент для генерации отчётов по задачам Redmine на основе записей о затраченном времени.
Проект предназначен для внутреннего использования с https://red.eltex.loc/.
Лицензия: MIT.
Возможности
- Получение time entries текущего или указанного пользователя из Redmine.
- Авторизация через Redmine API token или логин/пароль.
- Группировка задач по проекту и версии.
- Перевод статусов задач на русский язык.
- Разбивка по типам активности (
--by-activity). - Вывод в консоль (таблица / компактный вид).
- Экспорт в ODT, CSV, Markdown, HTML, JSON и Excel (.xlsx).
- Excel-отчёт с merge-ячейками по проекту/версии, итогами, автошириной, автофильтром и закреплённой шапкой.
- Сводка по времени (
--summary). - YAML-конфиг (
~/.config/redmine-reporter/config.yml): шаблон имени файла, путь по умолчанию, период, email, настройки содержимого отчёта (report.no_time). - Умное разрешение
--output: bare-формат (xlsx) → путь по шаблону, без расширения → автодописывание. --commit: автосохранение отчёта в файл + фиксация периода в YAML-конфиге для следующего запуска.--send: отправка отчёта по email через SMTP сразу после генерации.- HTML-версия тела письма при
--send, если включено в YAML-конфиге (email.html: true). - Понятные сообщения об ошибках Redmine API, SMTP и файловой системы.
- Загрузка альтернативного
.envчерез--config.
Установка
git clone https://git.akokos.ru/artem.kokos/redmine-reporter.git
cd redmine-reporter
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install .
Для разработки:
pip install -e ".[dev]"
Настройка
Источники конфигурации (от высшего приоритета к низшему):
CLI-флаги > переменные окружения > .env > YAML-конфиг > кодовые дефолты
YAML-конфиг (основной способ)
# Сгенерировать YAML из текущего .env
redmine-reporter --init-config
# Редактировать под себя
vim ~/.config/redmine-reporter/config.yml
Структура:
redmine:
url: https://red.eltex.loc
api_key: ${REDMINE_API_KEY}
author: "Кокос А.А."
verify_ssl: true
period:
precision: date # date | datetime
default_from: "2026-06-01"
# default_to можно не указывать — конец периода будет сегодня
default_to: "2026-06-30"
dynamic: false
# last_used заполняется --commit (см. docs/CONFIG.md)
output:
dir: ~/reports
filename: "{author}_{from}_{to}.{ext}"
default_format: xlsx
report:
no_time: false
email:
html: false
smtp:
host: smtp.example.com
port: 587
user: bot@example.com
password: ${SMTP_PASSWORD}
tls: true
from: bot@example.com
to:
- boss@example.com
cc: []
bcc: []
subject: "Отчёт {author} за {period}"
body_text: "Во вложении отчёт."
attach: true
Шаблон output.filename поддерживает {author}, {from}, {to}, {date} (DD_MM_YYYY), {ext}.
Шаблоны email.subject и email.body_text поддерживают {author}, {period} (строка диапазона, например 2026-06-01--2026-06-30).
Подробнее: docs/CONFIG.md.
.env (legacy)
REDMINE_URL=https://red.eltex.loc/
REDMINE_API_KEY=ваш_api_token
REDMINE_AUTHOR=Иванов Иван Иванович
DEFAULT_FROM_DATE=2026-01-01
# DEFAULT_TO_DATE можно не задавать — тогда конец периода будет сегодня
DEFAULT_TO_DATE=2026-01-31
Переменные окружения:
| Переменная | Обязательность | Описание |
|---|---|---|
REDMINE_URL |
Да | URL Redmine. |
REDMINE_API_KEY |
Да, если нет логина и пароля | Redmine API token. |
REDMINE_USER |
Да, если нет токена | Логин Redmine. |
REDMINE_PASSWORD |
Да, если нет токена | Пароль Redmine. |
REDMINE_AUTHOR |
Нет | Имя автора для отчёта. |
DEFAULT_FROM_DATE |
Нет | Начальная дата периода по умолчанию (YYYY-MM-DD). |
DEFAULT_TO_DATE |
Нет | Конечная дата периода по умолчанию (YYYY-MM-DD). Если не задана, а DEFAULT_FROM_DATE задана — используется сегодняшняя дата. |
REDMINE_VERIFY |
Нет | TLS-проверка: true / false / путь к CA bundle. |
Использование
source .venv/bin/activate
Основные сценарии
Отчёт за период по умолчанию:
redmine-reporter
Произвольный период:
redmine-reporter --date 2026-02-01--2026-02-28
Другой пользователь:
redmine-reporter --user-id 42
redmine-reporter --user-login ivanov
redmine-reporter --user-name "Иванов И.И."
Переопределить URL / API-ключ:
redmine-reporter --url https://red.example.com --api-key ваш_токен
Альтернативный .env:
redmine-reporter --config /path/to/.env
Компактный / отладочный вывод:
redmine-reporter --compact
redmine-reporter --debug
Экспорт в файл
Явный путь:
redmine-reporter --output report.xlsx
redmine-reporter --output /path/to/report.odt
Только формат (путь и имя берутся из YAML-шаблона):
redmine-reporter --output xlsx # → output.dir/отчёт_01_07_2026.xlsx
redmine-reporter --output odt # → output.dir/отчёт_01_07_2026.odt
Путь без расширения (дописывается default_format из конфига):
redmine-reporter --output /tmp/report # → /tmp/report.xlsx (если default_format: xlsx)
Отправка по email (--send)
Отправить отчёт на email, указанный в YAML-конфиге (секция email):
# Сохранить по шаблону и отправить
redmine-reporter --date 2026-06-01--2026-06-30 --send
# С явным путём
redmine-reporter --date 2026-06-01--2026-06-30 --output ~/report.xlsx --send
# Вместе с фиксацией периода
redmine-reporter --date 2026-06-01--2026-06-30 --send --commit
Если в секции email установить html: true, письмо будет отправлено в двух версиях: plain-text и HTML (таблица отчёта прямо в теле письма). Файл отчёта всё равно прикрепляется, если attach: true.
email:
html: true
Если секция email не настроена — ошибка с пояснением. При ошибке SMTP файл отчёта остаётся на диске, данные не теряются. Поддерживаются to, cc, bcc, TLS, отключение вложения (attach: false).
Фиксация периода (--commit)
# Сгенерировать, сохранить в файл по шаблону, запомнить период
redmine-reporter --commit
# С явным путём
redmine-reporter --commit --output report.xlsx
# Следующий запуск (без --date) возьмёт следующий период автоматически
redmine-reporter
# При precision=datetime запоминает момент времени
# (предотвращает дублирование записей внутри дня)
redmine-reporter --commit
Сводка и опции
Без времени / с разбивкой по активностям:
redmine-reporter --no-time
redmine-reporter --by-activity
redmine-reporter --by-activity --summary
--no-time можно задать в YAML-конфиге (report.no_time: true), чтобы автоматические режимы (--commit, --send) не включали затраченное время без явного флага. При ручном --output YAML-значение не применяется — только CLI-флаг --no-time.
Сводка:
redmine-reporter --summary
Форматы вывода
| Формат | Особенности |
|---|---|
| ODT | Заголовок с автором и месяцем, группировка по проекту/версии. |
| CSV | UTF-8 с BOM, полные значения project/version в каждой строке. |
| Markdown | Компактная таблица, повторяющиеся группы скрыты. |
| HTML | Полноценный HTML-документ с meta charset="utf-8". |
| JSON | Массив объектов: project, version, issue_id, subject, status, time. |
| Excel (.xlsx) | Merge cells, колонки Hours/Spent Time, итоги, автоширина, автофильтр, freeze panes. |
Полный список флагов
--date DATE Диапазон дат: YYYY-MM-DD--YYYY-MM-DD
--compact Компактный текстовый вывод вместо таблицы
--output PATH/FMT Путь к файлу (.odt/.csv/.md/.html/.json/.xlsx)
или bare-формат (xlsx/odt/...) — путь из конфига
--author NAME Переопределить имя автора
--no-time Не включать затраченное время в таблицу
--url URL Переопределить Redmine URL
--api-key KEY Переопределить Redmine API key
--config PATH Путь к альтернативному .env-файлу
--verbose Подробный вывод
--debug Отладочный вывод
--version Показать версию и выйти
--summary Вывести сводку по времени в stderr
--user-id ID Redmine ID пользователя для отчёта
--user-login LOGIN Логин пользователя Redmine
--user-name NAME Полное имя пользователя Redmine
--by-activity Разбить время по типам активности
--init-config Сгенерировать YAML-конфиг и выйти
--force Перезаписать существующий конфиг (с --init-config)
--config-path PATH Путь к YAML-конфигу (по умолчанию ~/.config/redmine-reporter/config.yml)
--commit Сохранить отчёт в файл и зафиксировать период в конфиге
--send Отправить отчёт по email после сохранения
Разработка
Проверки перед коммитом:
pytest
ruff check redmine_reporter tests
ruff format --check redmine_reporter tests
mypy redmine_reporter
Безопасность
- Не коммитьте
.env, API token, пароль или логин. - YAML-конфиг имеет права
0600, директория —0700. - Рекомендуется хранить секреты через
${VAR}, а не plaintext. - Используйте аккаунт с минимальными правами, достаточными для чтения time entries и задач.
- Инструмент работает только в режиме чтения и не изменяет данные в Redmine.