Кокос Артем Николаевич 598f2d35a1 fix: resolve --user-login by exact match
Redmine user.filter(login=...) performs an inexact substring search, but
_resolve_user_id took users[0].id unconditionally, so a report could
silently be built for the wrong user (e.g. 'ivanov' matching 'ivanov2').

Now only exact (case-sensitive) login matches are considered: exactly one
match resolves to its id, multiple matches raise an ambiguity error,
no match falls through to the name lookup and then to a 'not found'
error — symmetric with the --user-name resolution.

Closes #60
2026-07-17 12:21:47 +07:00
2026-01-21 10:44:53 +07:00

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.
Description
Инструмент для генерации отчётов по задачам в Redmine на основе ваших записей о затраченном времени.
Readme MIT 1.1 MiB
2026-07-17 18:39:53 +07:00
Languages
Python 100%