Files
redmine-reporter/docs/CONFIG.md
Кокос Артем Николаевич 27d21ef639 refactor: период через period.from вместо last_used; дедуп удалён
Удалены last_used, precision, dynamic и дедупликация по created_on/updated_on. Период задаётся одним полем period.from (env FROM_DATE), окно -- от этой даты до сегодня. После успешного --commit/--send начало окна сдвигается на конец отчёта; datetime-границы --date приводятся к полным дням. Схема конфига ломающая: старые ключи игнорируются, миграция описана в документации.
2026-09-30 12:37:00 +07:00

547 lines
27 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Настройка redmine-reporter
## Оглавление
- [Источники конфигурации](#источники-конфигурации)
- [YAML-конфиг](#yaml-конфиг)
- [Структура](#структура)
- [`redmine.verify_ssl` — проверка TLS-сертификата](#redmineverify_ssl--проверка-tls-сертификата)
- [`period.from` — начало окна отчёта](#periodfrom--начало-окна-отчёта)
- [`--date` — формат диапазона](#--date--формат-диапазона)
- [Авто-сдвиг начала периода](#авто-сдвиг-начала-периода)
- [Миграция старых ключей периода](#миграция-старых-ключей-периода)
- [`email` — настройка отправки по почте](#email--настройка-отправки-по-почте)
- [`--send` — отправка отчёта по email](#--send--отправка-отчёта-по-email)
- [`output` — путь и имя файла по умолчанию](#output--путь-и-имя-файла-по-умолчанию)
- [Подстановка переменных окружения](#подстановка-переменных-окружения)
- [`report` — настройки содержимого отчёта](#report--настройки-содержимого-отчёта)
- [`report.status_translation` — перевод статусов](#reportstatus_translation--перевод-статусов)
- [Разрешение выходного пути](#разрешение-выходного-пути)
- [Миграция с `.env` на YAML](#миграция-с-env-на-yaml)
- [Быстрый старт](#быстрый-старт)
- [Что делает `--init-config`](#что-делает---init-config)
- [Флаги миграции](#флаги-миграции)
- [Проверка после миграции](#проверка-после-миграции)
- [Сосуществование `.env` и YAML](#сосуществование-env-и-yaml)
- [Откат](#откат)
- [`.env` (legacy)](#env-legacy)
- [Безопасность](#безопасность)
## Источники конфигурации
Приоритет, от высшего к низшему:
```
CLI-флаги > переменные окружения > .env > YAML > кодовые дефолты
```
Нюанс с `override` при автозагрузке `.env` и `--config` — см.
[Сосуществование `.env` и YAML](#сосуществование-env-и-yaml).
Если значение не задано на верхнем уровне, берётся уровень ниже. `.env` и YAML
работают одновременно — можно оставить оба, можно удалить `.env` после миграции.
## YAML-конфиг
Основной файл: `~/.config/redmine-reporter/config.yml`.
Создаётся с правами `0600` (владелец: чтение/запись, остальные: доступ запрещён).
Директория `~/.config/redmine-reporter/` — с правами `0700`.
Если права файла шире `0600`, при запуске выводится предупреждение.
### Структура
```yaml
redmine:
url: https://red.eltex.loc
api_key: ${REDMINE_API_KEY}
author: "Кокос А.А."
verify_ssl: true
period:
from: "2026-06-01"
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
```
### `redmine.verify_ssl` — проверка TLS-сертификата
Управляет проверкой TLS-сертификата Redmine. Семантика едина с переменной
окружения `REDMINE_VERIFY`:
| Значение | Поведение |
|---|---|
| `true` (по умолчанию) | Проверка по системному хранилищу CA операционной системы (через truststore) — корпоративные CA, добавленные в ОС, работают без настройки |
| `false` | Проверка отключена — при запуске выводится предупреждение о риске MITM |
| строка с путём, например `/etc/ssl/my-ca.pem` | Путь к собственному CA-bundle, передаётся в requests как есть |
До версии с унификацией `verify_ssl: true` подставлял захардкоженный путь
`/etc/ssl/certs/ca-certificates.crt`, который существует только в
Debian/Ubuntu. Теперь `true` в YAML и `REDMINE_VERIFY=true` в env работают
одинаково — оба включают проверку по системному хранилищу CA на любой ОС
(через truststore), без привязки к конкретному пути.
### `period.from` — начало окна отчёта
Единственный ключ периода в YAML. Дата в формате `YYYY-MM-DD`:
```yaml
period:
from: "2026-06-01"
```
Окно отчёта — `from..сегодня`: конец окна всегда сегодняшняя дата и отдельно
не настраивается. Переменная окружения `FROM_DATE` задаёт то же начало и имеет
приоритет над YAML:
```
--date > FROM_DATE (env) > period.from (YAML) > 1-е число текущего месяца
```
Разрешение начала окна:
| Условие | Начало окна |
|---|---|
| `from` не задан (`FROM_DATE` и `period.from` пусты) | 1-е число текущего месяца |
| `from` — корректная дата | `from` |
| `from` позже сегодняшней даты | сегодня (окно «сегодня--сегодня») |
| `from` некорректна (не `YYYY-MM-DD`) | warning в stderr + 1-е число текущего месяца |
Граничный день (день коммита) становится началом следующего окна и потому
перечитывается: уже отправленные записи этого дня повторятся в следующем
отчёте. Это осознанное следствие отсутствия дедупликации; зато поздние
записи, добавленные в Redmine в день коммита после отправки, не теряются.
Повторный запуск `--commit`/`--send` в тот же день даёт окно
«сегодня--сегодня».
`period.from` записывается автоматически при `--commit`/`--send`; вручную
редактировать не требуется.
### `--date` — формат диапазона
Флаг `--date` задаёт диапазон явно и переопределяет все остальные источники.
Каждая граница — дата `YYYY-MM-DD` или datetime `YYYY-MM-DDTHH:MM:SS`:
- `2026-06-01--2026-06-30`;
- `2026-06-30T09:00:00--2026-06-30T12:00:00`.
Время в границах отбрасывается — окно всегда состоит из полных дней, так как
гранулярность Redmine — день. Границы можно смешивать (дата + datetime).
Начало позже конца (`start > end`) — ошибка.
### Авто-сдвиг начала периода
`--commit` и `--send` генерируют отчёт, сохраняют его в файл (по `--output`
или по шаблону `output.dir`/`output.filename`) и сдвигают начало окна.
`--send` дополнительно отправляет отчёт по email (см.
[ниже](#--send--отправка-отчёта-по-email)).
После успешного `--commit` (файл сохранён) или реальной отправки `--send`
(подтверждение «y» + успешная отправка) в конфиг пишется
`period.from = <конец окна отчёта>`. Следующий запуск без `--date` начинает
окно с граничного дня последнего отчёта.
Сдвиг НЕ происходит:
- если за период нет time entries (отчёт пуст — выход до сохранения);
- при отказе от подтверждения отправки в `--send` (ответ не «y»/«yes»);
- при ошибке SMTP в `--send` (соединение, аутентификация, таймаут);
- при ошибке сохранения файла отчёта.
Исключение: при явном `--commit` (сочетание `--send --commit`) отказ от
подтверждения отправки сдвиг не отменяет: окно всё равно сдвигается по
`--commit`.
При сочетании `--send --commit` ошибка SMTP подавляет и сдвиг по `--commit`:
файл остаётся сохранён, но начало периода не двигается.
Примеры:
```bash
# Окно 1--30 июня → следующий запуск (без --date) начнётся с 30 июня
redmine-reporter --date 2026-06-01--2026-06-30 --commit
# Произвольный диапазон 15--20 июня → следующее окно с 20 июня
redmine-reporter --date 2026-06-15--2026-06-20 --commit
# Отправить и сдвинуть окно (только при подтверждении «y» и успехе)
redmine-reporter --date 2026-06-01--2026-06-30 --send --commit
```
`--commit`/`--send` перезаписывают только `period.from`; остальные секции и
ключи YAML сохраняются. Файл перезаписывается через `yaml.dump` —
пользовательские комментарии и ручное форматирование теряются.
### Миграция старых ключей периода
Старые ключи периода больше не читаются и тихо игнорируются при загрузке —
их можно удалить из YAML:
- `period.last_used` (включая `from`/`to`);
- `period.precision`;
- `period.dynamic`;
- `period.default_from` / `period.default_to`.
Env `DEFAULT_FROM_DATE` / `DEFAULT_TO_DATE` заменены на `FROM_DATE`; конец
периода больше не настраивается (всегда сегодня). Дедупликация time entries
по `created_on`/`updated_on` удалена.
### `email` — настройка отправки по почте
Секция `email` используется флагом `--send`. Если секция не настроена или `smtp.host`
пуст, `--send` завершится с ошибкой «Email не настроен».
**Все поля:**
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
| `smtp.host` | строка | `""` | Адрес SMTP-сервера |
| `smtp.port` | число | `587` | Порт SMTP |
| `smtp.user` | строка | `""` | Логин для аутентификации |
| `smtp.password` | строка | `""` | Пароль (рекомендуется `${SMTP_PASSWORD}`) |
| `smtp.tls` | bool | `true` | Использовать STARTTLS |
| `from` | строка | `""` | Адрес отправителя |
| `to` | список | `[]` | Основные получатели |
| `cc` | список | `[]` | Копия |
| `bcc` | список | `[]` | Скрытая копия (не отображается в заголовках письма) |
| `subject` | строка | `"Отчёт {author} за {period}"` | Тема письма |
| `body_text` | строка | `"Во вложении отчёт."` | Текст письма (plain text) |
| `attach` | bool | `true` | Прикреплять файл отчёта. Если `false` — только текст |
| `html` | bool | `false` | Добавить HTML-версию тела письма (`multipart/alternative`) |
**Подстановки в `subject` и `body_text`:**
| Плейсхолдер | Описание | Пример |
|---|---|---|
| `{author}` | Имя автора из конфига или `--author` | `Кокос А.А.` |
| `{period}` | Строка диапазона дат | `2026-06-01--2026-06-30` |
**MIME-тип вложения** определяется по расширению файла:
| Расширение | MIME-тип |
|---|---|
| `.xlsx` | `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` |
| `.odt` | `application/vnd.oasis.opendocument.text` |
| `.csv` | `text/csv` |
| `.html` | `text/html` |
| `.json` | `application/json` |
| `.md` | `text/markdown` |
Неизвестное расширение → `application/octet-stream`.
**Пример конфигурации:**
```yaml
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
- team-lead@example.com
cc:
- manager@example.com
bcc: []
subject: "Отчёт {author} за {period}"
body_text: "Во вложении отчёт за период {period}."
attach: true
```
### `--send` — отправка отчёта по email
Флаг `--send` сохраняет отчёт в файл, отправляет его через SMTP и сдвигает
начало периода при подтверждении и успешной отправке (см.
[Авто-сдвиг](#авто-сдвиг-начала-периода)). Требует настроенную
секцию `email` в YAML-конфиге.
**Что делает:**
1. Генерирует отчёт как обычно.
2. Сохраняет отчёт в файл:
- Если указан `--output` — по явному пути.
- Если `--output` не указан — по шаблону из `output.dir` / `output.filename`.
3. Запрашивает подтверждение: «Отправить? [y/N]». Ответ «y»/«yes» продолжает,
иначе отправка отменяется (без сдвига периода).
4. Формирует MIME-письмо:
- Тема, plain-text тело и вложение (если `attach: true`).
- При `email.html: true` — дополнительно HTML-версия тела (`multipart/alternative`), сгенерированная из таблицы отчёта.
5. Отправляет через SMTP (таймаут 30 секунд). STARTTLS включается только при
`email.smtp.tls: true`; аутентификация — только если задан `email.smtp.user`.
6. При успешной отправке сдвигает начало периода.
**Файл отчёта сохраняется до попытки отправки** — при ошибке SMTP файл остаётся
на диске, данные не теряются.
**Ошибки SMTP:**
- Нет соединения → `"Не удалось подключиться к SMTP-серверу host:port"`
- Неверный логин/пароль → `"Ошибка аутентификации SMTP. Проверьте логин и пароль."`
- Таймаут → `"Таймаут соединения с SMTP-сервером."`
- Другая ошибка → `"Ошибка отправки письма: <детали>"`
Все ошибки выводятся в stderr, код возврата 1.
**Примеры:**
```bash
# Отправить отчёт за июнь (сохранится по шаблону output.filename)
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
```
**Совместимость с другими флагами:**
| Комбинация | Поведение |
|---|---|
| `--send` | Сохранить по шаблону → отправить |
| `--send --output X` | Сохранить в X → отправить |
| `--send --commit` | Сохранить → подтвердить → отправить → сдвинуть начало периода |
| `--send` с `email.html: true` | Письмо с plain-text + HTML-таблицей |
| `--send` без `email` в конфиге | Ошибка, exit 1 |
| `--send` при ошибке SMTP | Файл сохранён, ошибка в stderr, exit 1 |
### `output` — путь и имя файла по умолчанию
Секция управляет тем, куда и с каким именем сохраняется отчёт, когда `--output` не содержит полного пути.
**Правила разрешения `--output`:**
| Аргумент `--output` | Поведение |
|---|---|
| `/полный/путь/report.xlsx` | Используется как есть, конфиг игнорируется |
| `xlsx` (bare format: `xlsx`, `odt`, `csv`, `md`, `html`, `json`) | Путь = `output.dir` + `output.filename`, расширение = bare format |
| `/tmp/report` (путь без расширения) | Дописывается `.default_format` → `/tmp/report.xlsx` |
**Шаблон имени файла:**
`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` |
Неизвестные плейсхолдеры остаются в имени как есть.
Примеры:
```yaml
# По умолчанию
filename: "{author}_{from}_{to}.{ext}" # → Кокос_А.А._2026-06-01_2026-06-30.xlsx
# Русский формат даты
filename: "отчёт_{date}.{ext}" # → отчёт_30_06_2026.xlsx
# Без автора, только диапазон
filename: "report_{from}--{to}.{ext}" # → report_2026-06-01--2026-06-30.xlsx
```
### Подстановка переменных окружения
В любом строковом значении YAML можно использовать `${VAR}` — при загрузке
оно заменяется на значение переменной окружения:
```yaml
redmine:
api_key: ${REDMINE_API_KEY}
email:
smtp:
password: ${SMTP_PASSWORD}
```
Это безопаснее, чем хранить секреты plaintext в YAML. Однако plaintext-секреты
**не запрещены** — если вписать `api_key: "abc123"` напрямую, система примет.
Права `0600` — основная защита.
### `report` — настройки содержимого отчёта
Секция управляет тем, что попадает в сгенерированный отчёт.
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
| `no_time` | bool | `false` | Не включать затраченное время в файл отчёта |
| `status_translation` | map[str,str] | `{}` | Переопределение/дополнение перевода статусов |
`report.no_time` применяется только в автоматических режимах (`--commit`, `--send`).
При ручном `--output` YAML-настройка игнорируется — там работает только CLI-флаг `--no-time`.
CLI-флаг `--no-time` всегда имеет приоритет над YAML.
**Примеры:**
```yaml
report:
no_time: true
```
```bash
# Автоматический режим: время не выводится
redmine-reporter --commit
# Ручной режим: report.no_time игнорируется, время выводится
redmine-reporter --output report.odt
# Ручной режим с явным флагом: время не выводится
redmine-reporter --output report.odt --no-time
```
### `report.status_translation` — перевод статусов
По умолчанию статусы Redmine переводятся встроенным словарём
(`New` → `В работе`, `Closed` → `Закрыто` и т.д.). Секция
`report.status_translation` переопределяет отдельные переводы и/или
добавляет новые статусы; не указанные здесь статусы переводятся
встроенным словарём, а совсем неизвестные выводятся как есть.
```yaml
report:
status_translation:
"New": "Новая"
"Wait Release": "Ожидает релиза"
"Custom Status": "Кастомный статус"
```
## Разрешение выходного пути
Функция `resolve_output_path()` определяет итоговый путь к файлу:
1. `--output` не указан → консольный вывод.
2. `--output xlsx` (bare format) → путь формируется как `output.dir / output.filename` с подстановкой `{ext}` = bare format и дат из периода.
3. `--output /path/report` (без расширения) → дописывается `.output.default_format`.
4. `--output /path/report.csv` (с расширением) → используется как есть.
5. `--output /path/report.xyz` (неизвестное расширение) → ошибка «Неизвестный формат файла», exit 1.
## Миграция с `.env` на YAML
### Быстрый старт
```bash
# 1. Генерируем YAML из текущего .env
redmine-reporter --init-config
# 2. Проверяем, что создалось
cat ~/.config/redmine-reporter/config.yml
# 3. Редактируем под себя (шаблон имени, период, etc.)
vim ~/.config/redmine-reporter/config.yml
```
### Что делает `--init-config`
- Читает текущие значения из `.env` и переменных окружения.
- Формирует YAML со всеми секциями (`redmine`, `period`, `output`, `report`, `email`).
- В конец файла дописывает закомментированный пример `report.status_translation`.
- Секреты (`REDMINE_API_KEY`, `SMTP_PASSWORD`) записывает как `${VAR}`, если
переменная существует, иначе — пустая строка.
- Создаёт файл с правами `0600`, директорию — с `0700`.
### Флаги миграции
| Флаг | Назначение |
|---|---|
| `--init-config` | Создать YAML и выйти |
| `--init-config --force` | Перезаписать существующий YAML |
| `--config-path PATH` | Путь к YAML-конфигу: загрузка при запуске, запись при `--init-config` и `--commit` (по умолчанию `~/.config/redmine-reporter/config.yml`) |
Если задана `FROM_DATE`, сгенерированный YAML будет содержать `period.from` с
этим значением.
### Проверка после миграции
```bash
# Запустить без .env в текущей директории
cd /tmp
redmine-reporter --date 2026-06-01--2026-06-30
```
Если отработал — YAML-конфиг читается корректно. Если `REDMINE_URL is required` —
проверь права:
```bash
ls -la ~/.config/redmine-reporter/
# config.yml должно быть -rw------- (600)
# директория должна быть drwx------ (700)
```
### Сосуществование `.env` и YAML
Можно оставить оба источника. `.env` имеет **более высокий приоритет**, чем YAML:
```
.env значения переопределяют YAML, если заданы
YAML работает как базовый слой для всего, что не в .env
```
Автозагрузка `.env` (без `--config`) не перебивает реальные переменные
окружения (`override=False`). Исключение — `--config FILE`: указанный `.env`
загружается с `override=True` и перебивает переменные окружения (но не CLI-флаги).
Это safe — если с YAML что-то пойдёт не так, просто положи `.env` обратно.
### Откат
```bash
rm ~/.config/redmine-reporter/config.yml
```
## `.env` (legacy)
Для обратной совместимости `.env` продолжает работать как раньше, кроме ключей
периода: `DEFAULT_FROM_DATE` заменён на `FROM_DATE`, `DEFAULT_TO_DATE` удалён
(см. [Миграция старых ключей периода](#миграция-старых-ключей-периода)).
```ini
REDMINE_URL=https://red.eltex.loc
REDMINE_API_KEY=your-api-key
REDMINE_AUTHOR=Кокос А.А.
FROM_DATE=2026-06-01
```
Если ни `.env`, ни YAML не заданы — используются кодовые дефолты (текущий месяц
как период, стандартная проверка TLS, пустой автор).
## Безопасность
- YAML-конфиг: права `0600`, директория `0700`.
- Права шире `0600` → warning в stderr при каждом запуске.
- Секреты рекомендуется хранить через `${VAR}`, а не plaintext.
- `.env` **не рекомендуется** для постоянных настроек — оставьте его только
для CI/CD или временных переопределений.