Tasks in the "Wishlist" bucket version are now excluded from the list and summary entirely (no due date, noise backlog); exact case match, tasks without a version are unaffected. Document --my-tasks in README and the user guide (sorting, summary metrics, OSC 8 links, stream separation); all examples use synthetic data. Declare ruff known-first-party in pyproject so the lint result is CWD-independent.
382 lines
26 KiB
Markdown
382 lines
26 KiB
Markdown
# Руководство пользователя redmine-reporter
|
||
|
||
## Оглавление
|
||
|
||
- [Установка](#установка)
|
||
- [Первоначальная настройка](#первоначальная-настройка)
|
||
- [Выбор периода](#выбор-периода)
|
||
- [Отчёт за другого пользователя](#отчёт-за-другого-пользователя)
|
||
- [Список открытых задач](#список-открытых-задач)
|
||
- [Экспорт в файл](#экспорт-в-файл)
|
||
- [Содержимое отчёта](#содержимое-отчёта)
|
||
- [Отправка по email](#отправка-по-email)
|
||
- [Скользящее окно периода](#скользящее-окно-периода)
|
||
- [Справочник флагов](#справочник-флагов)
|
||
- [Устранение неполадок](#устранение-неполадок)
|
||
- [См. также](#см-также)
|
||
|
||
## Установка
|
||
|
||
Требуется Python >= 3.10.
|
||
|
||
```bash
|
||
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 .
|
||
```
|
||
|
||
Проверка:
|
||
|
||
```bash
|
||
redmine-reporter --version
|
||
```
|
||
|
||
Перед каждым запуском активируйте окружение: `source .venv/bin/activate`.
|
||
|
||
## Первоначальная настройка
|
||
|
||
1. Убедитесь, что в текущей директории есть `.env` с `REDMINE_URL` и `REDMINE_API_KEY` (или задайте эти переменные в окружении).
|
||
2. Сгенерируйте YAML-конфиг:
|
||
|
||
```bash
|
||
redmine-reporter --init-config
|
||
```
|
||
|
||
Результат: файл `~/.config/redmine-reporter/config.yml` (права `0600`, директория `0700`) со всеми секциями и закомментированным примером `report.status_translation`. Секреты, заданные в окружении, записываются как `${VAR}`.
|
||
|
||
3. Если файл уже существует — ошибка; для перезаписи добавьте `--force`:
|
||
|
||
```bash
|
||
redmine-reporter --init-config --force
|
||
```
|
||
|
||
4. Нестандартное расположение конфига:
|
||
|
||
```bash
|
||
redmine-reporter --init-config --config-path /etc/redmine-reporter/config.yml
|
||
```
|
||
|
||
`--config-path` задаёт путь и для загрузки YAML, и для записи при `--init-config` и `--commit`.
|
||
|
||
5. Откройте файл и заполните минимум: `redmine.url`, `redmine.api_key`, `redmine.author`.
|
||
|
||
`--init-config` несовместим с флагами отчёта (`--date`, `--output`, `--compact`, `--summary`, `--user-id`/`--user-login`/`--user-name`, `--no-time`, `--by-activity`, `--send`) — указывайте его отдельно.
|
||
|
||
Полный референс всех секций и переменных: [CONFIG.md](CONFIG.md).
|
||
|
||
## Выбор периода
|
||
|
||
Окно отчёта — диапазон дат `from..to`. Конец (`to`) всегда сегодняшняя дата,
|
||
если диапазон не задан явно через `--date`.
|
||
|
||
Приоритет начала окна (от высшего к низшему):
|
||
|
||
1. `--date` — явный диапазон (полностью переопределяет окно).
|
||
2. `FROM_DATE` (env) — начало; конец — сегодня.
|
||
3. `period.from` (YAML) — начало; конец — сегодня.
|
||
4. Ничего не задано — текущий месяц: с 1-го числа по сегодня.
|
||
|
||
Форматы `--date`:
|
||
|
||
```bash
|
||
# Даты
|
||
redmine-reporter --date 2026-06-01--2026-06-30
|
||
|
||
# Дата-время (границы флорятся до полных дней)
|
||
redmine-reporter --date 2026-06-01T09:00:00--2026-06-01T18:00:00
|
||
```
|
||
|
||
Границы с временем округляются до дат — отчёт строится за полные дни диапазона.
|
||
Границы можно смешивать (дата + дата-время). Начало позже конца
|
||
(`start > end`) — ошибка.
|
||
|
||
Краевые случаи:
|
||
|
||
- `from` позже сегодняшней даты — окно «сегодня--сегодня».
|
||
- `from` некорректна (не `YYYY-MM-DD`) — warning + текущий месяц.
|
||
|
||
## Отчёт за другого пользователя
|
||
|
||
Без флагов отчёт строится за текущего пользователя.
|
||
|
||
```bash
|
||
redmine-reporter --user-id 42
|
||
redmine-reporter --user-login ivanov
|
||
redmine-reporter --user-name "Иванов Иван Иванович"
|
||
```
|
||
|
||
Правила:
|
||
|
||
- Флаги `--user-id`, `--user-login`, `--user-name` взаимоисключающие: укажите только один, иначе ошибка.
|
||
- Все три принимают одно значение. Число или строка из цифр → поиск по ID. Иначе — точное регистрозависимое совпадение логина.
|
||
- Если по логину совпадений нет — поиск по имени. Одно совпадение → пользователь найден.
|
||
- Несколько совпадений по имени → ошибка «Multiple users match...» со списком логинов (при дублях логина — ID).
|
||
- Ноль совпадений → ошибка «User '...' not found...».
|
||
|
||
## Список открытых задач
|
||
|
||
`--my-tasks` -- отдельный режим: вместо отчёта по затраченному времени выводит
|
||
открытые задачи, назначенные на вас, по всем проектам. Отчётное окно периода
|
||
к режиму не применяется.
|
||
|
||
```bash
|
||
redmine-reporter --my-tasks # задачи владельца API-ключа
|
||
redmine-reporter --my-tasks --user-id 42 # чужой список по ID
|
||
redmine-reporter --my-tasks --user-login ivanov # по логину
|
||
```
|
||
|
||
Правила:
|
||
|
||
- `--user-id` / `--user-login` / `--user-name` выбирают, чей список показать; по умолчанию -- владелец API-ключа. Разрешение пользователей то же, что для отчёта (см. [Отчёт за другого пользователя](#отчёт-за-другого-пользователя)).
|
||
- `--url`, `--api-key`, `--config`, `--config-path`, `--verbose`, `--debug` работают как обычно.
|
||
- Совмещение с отчётными флагами (`--date`, `--output`, `--compact`, `--summary`, `--no-time`, `--by-activity`, `--commit`, `--send`) -- ошибка «--my-tasks cannot be used with report-generating flags.», exit 1.
|
||
- Задачи в версии `Wishlist` исключаются из режима целиком: не попадают ни в таблицу, ни в сводку.
|
||
|
||
Сортировка -- от срочного к менее срочному:
|
||
|
||
1. Приоритет `P1..P5`: меньший номер срочнее; неизвестное имя приоритета получает низший ранг.
|
||
2. Внутри приоритетной группы -- срок версии (due date) по возрастанию.
|
||
3. Задачи без версии или без срока -- в конец своей приоритетной группы.
|
||
4. При прочих равных -- по возрастанию ID.
|
||
|
||
Таблица печатается в stdout, сводка -- в stderr перед таблицей. При
|
||
перенаправлении (`redmine-reporter --my-tasks > tasks.txt`) в файл попадает
|
||
только таблица.
|
||
|
||
Колонки таблицы: ID | Тема | Статус | Приор. | Версия | Срок. Пример
|
||
(синтетические данные, ID в терминале кликабелен):
|
||
|
||
```
|
||
ID Тема Статус Приор. Версия Срок
|
||
---- -------------------------------- -------------- -------- -------- --------------
|
||
101 Критический дефект сборки образа В работе P1 v2.4.0 2026-10-15 (!)
|
||
102 Обновить документацию API Новая P2 v2.5.0 2026-12-01
|
||
103 Ревью pull request Обратная связь P3 - -
|
||
```
|
||
|
||
- ID -- гиперссылка (OSC 8) на страницу задачи `<url>/issues/<id>`: в терминалах с поддержкой кликабельна, без поддержки остаётся обычным номером.
|
||
- Срок -- дата релиза целевой версии; просроченный (раньше сегодняшней даты) помечается `(!)`.
|
||
- Пустые «Версия» и «Срок» -- прочерк `-`.
|
||
- Статусы переводятся на русский тем же словарём, что и в отчётах: встроенный словарь + `report.status_translation` (см. [Перевод статусов](#перевод-статусов)).
|
||
|
||
Сводка (пример с синтетическими данными):
|
||
|
||
```
|
||
Открытых: 3 | просроченных: 1 | без версии: 1 | без срока: 0 | потрачено: 12.5h | оценка: 8h (по 2 из 3)
|
||
```
|
||
|
||
- «просроченных» -- задачи со сроком версии раньше сегодняшней даты.
|
||
- «без версии» -- задачи без целевой версии; «без срока» -- задачи с версией, но без известной даты релиза.
|
||
- «потрачено» -- сумма полей `spent_hours` задач списка.
|
||
- «оценка» -- сумма полей `estimated_hours`; «(по N из M)» -- у скольких задач из списка есть оценка. Если оценок нет ни у одной задачи, блок «оценка» не выводится.
|
||
|
||
Сроки версий дозагружаются отдельным запросом на каждую уникальную версию
|
||
списка. Недоступная версия -- предупреждение в stderr и пустой срок у её
|
||
задач, вывод не прерывается.
|
||
|
||
Пустой список (в том числе когда все открытые задачи попали в исключаемую
|
||
версию `Wishlist`): «ℹ️ Открытых задач нет.» (stderr), exit 0.
|
||
|
||
## Экспорт в файл
|
||
|
||
Флаг `--output` определяется по четырём правилам:
|
||
|
||
| Аргумент | Результат |
|
||
| --- | --- |
|
||
| `--output xlsx` (bare-формат: `xlsx`, `odt`, `csv`, `md`, `html`, `json`, регистронезависимо) | Путь = `output.dir` + шаблон `output.filename` из YAML, расширение = указанный формат |
|
||
| `--output /tmp/report` (путь без расширения) | Дописывается `.` + `output.default_format` → `/tmp/report.xlsx` |
|
||
| `--output /tmp/report.csv` (путь с любым расширением) | Используется как есть |
|
||
| `--output /tmp/report.xyz` (неизвестное расширение) | Ошибка «Неизвестный формат файла: '.xyz'. Поддерживаются: .odt, .csv, .md, .html, .json, .xlsx», exit 1 |
|
||
|
||
Формат `.odt` требует установленного пакета `odfpy` (устанавливается по умолчанию) — иначе отдельная ошибка.
|
||
|
||
Примеры:
|
||
|
||
```bash
|
||
redmine-reporter --output xlsx # по шаблону в output.dir
|
||
redmine-reporter --output 2026-06-report # → 2026-06-report.xlsx (если default_format: xlsx)
|
||
redmine-reporter --output reports/june.csv # как есть
|
||
```
|
||
|
||
Плейсхолдеры `output.filename`:
|
||
|
||
| Плейсхолдер | Описание | Пример |
|
||
| --- | --- | --- |
|
||
| `{author}` | Имя автора, пробелы → `_` | `Кокос_А.А.` |
|
||
| `{from}` | Начало периода, `YYYY-MM-DD` | `2026-06-01` |
|
||
| `{to}` | Конец периода, `YYYY-MM-DD` | `2026-06-30` |
|
||
| `{date}` | Конец периода, `DD_MM_YYYY` | `30_06_2026` |
|
||
| `{ext}` | Расширение без точки | `xlsx` |
|
||
|
||
Неизвестные плейсхолдеры остаются в имени как есть.
|
||
|
||
Нюансы с путями:
|
||
|
||
- `~` в явном `--output` раскрывает шелл, а не программа: `redmine-reporter --output ~/report.xlsx` работает, а в кавычках (`"~/report.xlsx"`) — нет.
|
||
- `expanduser` применяется только к `output.dir` из YAML.
|
||
|
||
## Содержимое отчёта
|
||
|
||
### `--no-time`
|
||
|
||
Убирает затраченное время из отчёта. Физически удаляет колонку времени только CSV. XLSX, HTML, ODT, Markdown, JSON и консольный вывод оставляют пустые колонки/поля; в XLSX дополнительно пропадают строки итогов по версиям/проектам/всего.
|
||
|
||
```bash
|
||
redmine-reporter --output report.xlsx --no-time
|
||
```
|
||
|
||
YAML-настройка `report.no_time` действует только в автоматических режимах (`--commit`, `--send`). При ручном `--output` работает только CLI-флаг.
|
||
|
||
### `--by-activity`
|
||
|
||
Разбивка затраченного времени по типам активности. В JSON-отчёте добавляется поле `activities`.
|
||
|
||
```bash
|
||
redmine-reporter --by-activity
|
||
```
|
||
|
||
### `--summary`
|
||
|
||
Печатает сводку в stderr (после отчёта):
|
||
|
||
- `total` — суммарное время;
|
||
- `project:*` — время по каждому проекту;
|
||
- `activity:*` — время по каждой активности (только при одновременном `--by-activity`).
|
||
|
||
Версии в сводку не входят.
|
||
|
||
```bash
|
||
redmine-reporter --by-activity --summary
|
||
```
|
||
|
||
### `--compact`
|
||
|
||
Компактный текстовый вывод в консоль вместо таблицы:
|
||
|
||
```bash
|
||
redmine-reporter --compact
|
||
```
|
||
|
||
### Перевод статусов
|
||
|
||
Статусы задач переводятся встроенным словарём; секция `report.status_translation` переопределяет или дополняет переводы. Подробно: [CONFIG.md](CONFIG.md).
|
||
|
||
## Отправка по email
|
||
|
||
Требуется секция `email` в YAML-конфиге (см. [CONFIG.md](CONFIG.md)).
|
||
|
||
```bash
|
||
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 --send --commit
|
||
```
|
||
|
||
Факты:
|
||
|
||
- Файл отчёта сохраняется на диск ДО отправки: при ошибке SMTP файл остаётся на месте.
|
||
- Перед отправкой запрашивается подтверждение «Отправить? [y/N]»; ответ «y»/«yes» продолжает, иначе отправка отменяется (без сдвига периода, если не задан явный `--commit`).
|
||
- При успешной отправке начало периода сдвигается (см. [Скользящее окно периода](#скользящее-окно-периода)); при отмене (если не задан явный `--commit`) или ошибке SMTP — без сдвига.
|
||
- Секция `email` отсутствует или `smtp.host` пуст → ошибка «Email не настроен. Добавьте секцию 'email' в конфиг...», exit 1.
|
||
- `email.html: true` → письмо `multipart/alternative`: plain-text + HTML-таблица отчёта в теле.
|
||
- Файл прикрепляется при `attach: true`; MIME-тип определяется по расширению, неизвестное → `application/octet-stream`.
|
||
- Получатели `bcc` указываются только в envelope (не видны в заголовках письма).
|
||
- STARTTLS применяется только при `smtp.tls: true`; аутентификация на SMTP-сервере — только если задан `smtp.user`.
|
||
- Таймаут соединения с SMTP — 30 секунд.
|
||
|
||
Точные тексты ошибок:
|
||
|
||
- «Ошибка аутентификации SMTP. Проверьте логин и пароль.»
|
||
- «Таймаут соединения с SMTP-сервером.»
|
||
- «Ошибка отправки письма: ...»
|
||
- «Не удалось подключиться к SMTP-серверу host:port»
|
||
|
||
## Скользящее окно периода
|
||
|
||
После успешного `--commit` (файл сохранён) или реальной отправки `--send`
|
||
(подтверждение «y» + успех) окно отчёта сдвигается вперёд: в конфиг пишется
|
||
`period.from = <конец окна>`. Следующий запуск без `--date`
|
||
начинается с граничного дня последнего отчёта.
|
||
|
||
Типичный цикл:
|
||
|
||
```bash
|
||
# 1. Отчёт за июнь 2026: сохранить, отправить, сдвинуть начало на 30 июня
|
||
redmine-reporter --date 2026-06-01--2026-06-30 --send --commit
|
||
|
||
# 2. Следующий запуск без --date берёт окно с 30 июня по сегодня
|
||
redmine-reporter --send --commit
|
||
```
|
||
|
||
Граничный день: начало следующего окна совпадает с днём коммита, поэтому этот
|
||
день перечитывается. Записи дня коммита, уже попавшие в прошлый отчёт,
|
||
повторятся (дедупликации по `created_on`/`updated_on` нет — это осознанное
|
||
следствие), зато поздние записи, добавленные в Redmine в этот день после
|
||
отправки, не теряются.
|
||
|
||
Повторный запуск `--commit`/`--send` в тот же день даёт окно
|
||
«сегодня--сегодня», которое повторно включает уже отправленные записи этого
|
||
дня.
|
||
|
||
Важно: `--commit`/`--send` перезаписывают только `period.from`; остальные
|
||
ключи YAML сохраняются, но пользовательские комментарии теряются
|
||
(перезапись через `yaml.dump`).
|
||
|
||
## Справочник флагов
|
||
|
||
| Флаг | Описание |
|
||
| --- | --- |
|
||
| `--date` | Явный диапазон: границы — дата `YYYY-MM-DD` или datetime `YYYY-MM-DDTHH:MM:SS`. Время отбрасывается (полные дни), границы можно смешивать; `start > end` — ошибка. |
|
||
| `--compact` | Компактный текстовый вывод в консоль вместо таблицы. |
|
||
| `--output` | Путь к файлу (`.odt`/`.csv`/`.md`/`.html`/`.json`/`.xlsx`) или bare-формат — тогда путь берётся из YAML-шаблона; без флага — вывод в консоль (stdout). |
|
||
| `--author` | Переопределить имя автора отчёта. |
|
||
| `--no-time` | Не включать затраченное время в отчёт. |
|
||
| `--url` | Переопределить URL Redmine. |
|
||
| `--api-key` | Переопределить API-ключ Redmine. |
|
||
| `--config` | Путь к альтернативному `.env`-файлу. |
|
||
| `--verbose` | Подробный вывод; показывает traceback при ошибках. |
|
||
| `--debug` | Отладочный вывод; показывает traceback при ошибках. |
|
||
| `--version` | Показать версию и выйти. |
|
||
| `--summary` | Сводка по времени в stderr: `total`, `project:*`, `activity:*` (версии не печатаются). |
|
||
| `--user-id` | Отчёт за пользователя по ID. |
|
||
| `--user-login` | Отчёт за пользователя по логину (точное регистрозависимое совпадение). |
|
||
| `--user-name` | Отчёт за пользователя по имени. |
|
||
| `--by-activity` | Разбивка времени по типам активности (в JSON — поле `activities`). |
|
||
| `--init-config` | Сгенерировать YAML-конфиг из текущего `.env`/окружения и выйти. |
|
||
| `--force` | Перезаписать существующий YAML-конфиг (только с `--init-config`). |
|
||
| `--config-path` | Путь к YAML-конфигу: загрузка, запись `--init-config` и `--commit`. По умолчанию `~/.config/redmine-reporter/config.yml`. |
|
||
| `--commit` | Сохранить отчёт в файл и сдвинуть начало периода (`period.from` = конец окна) в YAML. |
|
||
| `--send` | Отправить отчёт по email после сохранения файла; при подтверждении и успехе сдвинуть начало периода. |
|
||
| `--my-tasks` | Вместо отчёта вывести открытые задачи, назначенные на вас (или на пользователя из `--user-id`/`--user-login`/`--user-name`): таблица с сортировкой по срочности + сводка в stderr. Несовместим с `--date`, `--output`, `--compact`, `--summary`, `--no-time`, `--by-activity`, `--commit`, `--send`. Подробнее: [Список открытых задач](#список-открытых-задач). |
|
||
|
||
## Устранение неполадок
|
||
|
||
| Ошибка | Причина | Решение |
|
||
| --- | --- | --- |
|
||
| «REDMINE_URL must use HTTPS...» (exit 1) | URL Redmine не по HTTPS | Укажите `https://` в `redmine.url` / `REDMINE_URL` / `--url`. |
|
||
| «Authentication failed: invalid API key, login or password. Check REDMINE_API_KEY / REDMINE_USER / REDMINE_PASSWORD.» | Неверный или отсутствующий API-ключ, логин или пароль | Проверьте `redmine.api_key` / `--api-key` (или `REDMINE_USER` / `REDMINE_PASSWORD`). |
|
||
| «User '...' not found...» | Пользователь не найден ни по ID, ни по логину, ни по имени | Проверьте написание; логин сравнивается точно с учётом регистра. |
|
||
| «Multiple users match...» | По имени найдено несколько пользователей (или несколько дублей логина) | Используйте `--user-login` с логином из списка или уточните числовой ID для `--user-id`. |
|
||
| Указано несколько `--user-*` | Флаги взаимоисключающие | Оставьте только один из `--user-id` / `--user-login` / `--user-name`. |
|
||
| «--my-tasks cannot be used with report-generating flags.» (exit 1) | `--my-tasks` совмещён с отчётными флагами (`--date`, `--output`, `--compact`, `--summary`, `--no-time`, `--by-activity`, `--commit`, `--send`) | Запускайте режим отдельно: список задач и отчёт -- разные команды (см. [Список открытых задач](#список-открытых-задач)). |
|
||
| «Неизвестный формат файла: '.xyz'. Поддерживаются: .odt, .csv, .md, .html, .json, .xlsx» (exit 1) | `--output` с неизвестным расширением | Используйте одно из поддерживаемых расширений. |
|
||
| Ошибка про `odfpy` при `.odt` | Пакет `odfpy` не установлен | `pip install odfpy` или выберите другой формат. |
|
||
| «Email не настроен. Добавьте секцию 'email' в конфиг...» (exit 1) | `--send` без секции `email` в YAML или с пустым `smtp.host` | Добавьте секцию `email` (см. [CONFIG.md](CONFIG.md)). |
|
||
| «Ошибка аутентификации SMTP. Проверьте логин и пароль.» | Неверные `smtp.user`/`smtp.password` | Проверьте логин и пароль в конфиге. |
|
||
| «Таймаут соединения с SMTP-сервером.» | Сервер не ответил за 30 секунд | Проверьте сеть, `smtp.host` и `smtp.port`. |
|
||
| «Не удалось подключиться к SMTP-серверу host:port» | Нет соединения с SMTP | Проверьте `smtp.host`, `smtp.port` и доступность сервера. |
|
||
| «Ошибка отправки письма: ...» | Прочая ошибка SMTP | Смотрите детали после двоеточия; файл отчёта уже сохранён на диске. |
|
||
| Предупреждение о правах конфига при старте | Права `config.yml` шире `0600` | `chmod 600 ~/.config/redmine-reporter/config.yml`. |
|
||
| Предупреждение о MITM при старте | `verify_ssl: false` / `REDMINE_VERIFY=false` — проверка TLS отключена | Включите проверку или используйте только в доверенной сети. |
|
||
| «⚠️ Could not load version ...: Due date will be empty for its issues.» в режиме `--my-tasks` | Версия из списка задач недоступна (нет прав, удалена, сбой сети) | Некритично: срок этой версии останется пустым; проверьте права доступа к проекту версии. |
|
||
| Не виден traceback при ошибке | Traceback показывается только с `--verbose`/`--debug` | Повторите запуск с `--debug`. |
|
||
|
||
API-ключ в текстах ошибок маскируется (`***`).
|
||
|
||
## См. также
|
||
|
||
- [README.md](../README.md) — обзор, быстрый старт, форматы вывода.
|
||
- [CONFIG.md](CONFIG.md) — полный референс конфигурации (YAML, env, приоритеты, безопасность).
|