Перейти к содержимому

Шаблоны

Побеждает верхнее:

  1. message — дословно. Без подстановки, без экранирования.
  2. template_<status>, совпадающий с сообщаемым статусом.
  3. message_template.
  4. Встроенный шаблон.

Пустая строка считается «не задано», поэтому оставленный пустым вход проваливается на следующий уровень, а не отправляет пустое сообщение.

Встроенный шаблон:

{{.StatusEmoji}} *{{.Workflow}}* on `{{.Repo}}`
Status: {{.Status}}
Branch: {{.Branch}} @ {{.ShortSha}}
Actor: {{.Actor}}
[Open run]({{.RunUrl}})
Placeholder Value
{{.Repo}} owner/name of the repository
{{.Workflow}} Workflow name
{{.Job}} Job id inside the workflow
{{.Status}} The reported status, verbatim
{{.StatusEmoji}} ✅ / ❌ / ⚠️ / ⏭ for the reported status
{{.Actor}} User that triggered the run (git user.name outside Actions)
{{.Ref}} Full ref, e.g. refs/heads/main
{{.RefName}} Short ref name, e.g. main
{{.Branch}} Alias of RefName
{{.Sha}} Full commit SHA
{{.ShortSha}} First 7 characters of the SHA
{{.RunId}} Workflow run id (empty outside Actions)
{{.RunNumber}} Workflow run number (empty outside Actions)
{{.RunUrl}} Direct link to the run (empty outside Actions)
{{.EventName}} Event that triggered the run (empty outside Actions)
{{.ServerUrl}} GitHub server URL

Внутри workflow значения берутся из окружения GITHUB_*. Вне его поля, связанные с репозиторием, восстанавливаются из локального git: Repo из remote origin, Branch и Ref из HEAD, Sha и ShortSha из текущего коммита, Actor из git config user.name. Поля запуска — RunId, RunNumber, RunUrl, EventName — пустые, потому что запуска нет.

Известный плейсхолдер без значения рендерится пустой строкой. Неизвестный выбрасывается с предупреждением UNKNOWN_PLACEHOLDER:<имя> — это твой детектор опечаток.

Всё, что не является корректным {{.Name}}, остаётся как есть: {{.}}, {{.1Bad}}, {{Repo}} и {{.Repo} выводятся дословно.

Экранируются только подставляемые значения. Тело шаблона проходит дословно.

Именно это разделение делает шаблоны одновременно полезными и безопасными: в шаблоне может быть настоящий *жирный* и [ссылки](...), а ветка с именем fix/a.b-c не может подмешать разметку в результат.

Окно терминала
notiflow render --template '*ветка:* {{.Branch}}' --set Branch='fix/a.b-c'
# *ветка:* fix/a\.b\-c

Что именно экранирует каждый режим — в Parse modes.

Telegram допускает 4096 UTF-16 code units. Большинство символов стоят один; эмодзи вне базовой плоскости — два. Более длинное сообщение обрезается и заканчивается на ....

Обрез приходится между токенами разметки, никогда внутри: escape-пара MarkdownV2, HTML-сущность и HTML-тег неделимы. В HTML-режиме теги, оставшиеся открытыми на месте обреза, закрываются, так что обрезанное сообщение остаётся валидной разметкой, а не превращается в 400 от Telegram.

Окно терминала
notiflow render --template '…' --explain

--explain сообщает, какой шаблон победил, какой parse mode активен, пришлось ли обрезать текст и какие плейсхолдеры оказались неизвестны, — до того, как что-то отправлено.