-
Notifications
You must be signed in to change notification settings - Fork 0
Notifier Format Requirements
Every notifier has its own rendering engine, template syntax, and data context. A template that works in Slack will fail in Teams. This page documents what each notifier expects, what functions are available, and what data your template receives.
Not all notifiers use the same template engine. Some get the full sprig function library, others get plain Go text/template with no extensions, and some don't support templates at all.
| Notifier | Template support | Sprig functions | Data type | Template field |
|---|---|---|---|---|
| Slack | Go template | ❌ | domain.Event |
template |
| Microsoft Teams | Go template | ❌ | domain.Event |
template |
| Discord | Go template | ❌ | domain.Event |
template |
| Go template | ❌ | domain.Event |
subject + template
|
|
| Grafana | Go template | ✅ | domain.Event |
template |
| Jira | Go template | ✅ | domain.Event |
template |
| PagerDuty | ❌ Native | ❌ | N/A | N/A |
| Datadog | ❌ Native | ❌ | N/A | N/A |
| Sentry | ❌ Native | ❌ | N/A | N/A |
| Webhook | gojq transform | ❌ | JSON payload | transform |
| Accumulator | Go template | ✅ | SummaryData |
template |
Key difference: Slack, Teams, Discord, and Email use plain Go templates without sprig. You can't call trim, default, or ternary in those templates. Use printf and standard Go template logic instead. Grafana, Jira, and the Accumulator have the full sprig + domain helpers.
Format: Slack mrkdwn (not standard markdown)
Syntax rules:
- Bold:
*text*(not**text**) - Italic:
_text_ - Strikethrough:
~text~ - Code:
`code` - Code blocks:
```lang\ncode\n``` - Links:
<url|label>(not[label](url)) - Emoji:
:emoji_name:(e.g.,:white_check_mark:,:rotating_light:) - Channel mention:
<!channel>or<#channel-id>
Data type: domain.Event
Available functions: None beyond built-in Go template functions (printf, if, range, eq, etc.)
Truncation: Use printf "%.200s" .Description instead of Truncate.
Default template (slack-default.tmpl):
:white_check_mark: *Pipeline Name* — *success*
> *Run:* `my-run` *Namespace:* `default`
> *Commit:* `abc12345`
> *Duration:* 45s
<https://dashboard.example.com|:mag: View logs>
Format: Adaptive Card TextBlock markdown
Syntax rules:
- Bold:
**text** - Italic:
*text* - Lists:
- item(unordered),1. item(ordered) - Links:
[label](url) - No tables, no code blocks, no emoji shortcodes
Data type: domain.Event
Available functions: None beyond built-in Go template functions
Truncation: Use printf "%.200s" .Description
Default template (teams-default.tmpl):
✅ **Pipeline Name** — **success**
- **Run:** my-run
- **Namespace:** default
- **Commit:** abc12345
- **Duration:** 45s
[View logs](https://dashboard.example.com)
Format: Discord markdown (similar to standard markdown with some differences)
Syntax rules:
- Bold:
**text** - Italic:
*text* - Underline:
__text__ - Strikethrough:
~~text~~ - Code:
`code` - Code blocks:
```lang\ncode\n``` - Links:
[label](url) - Spoiler:
||text||
Data type: domain.Event
Available functions: None beyond built-in Go template functions
Truncation: Use printf "%.200s" .Description
Default template (discord-default.tmpl):
✅ **Pipeline success** in `default`
Run: my-run Pipeline: my-pipeline Commit: abc12345 Duration: 45s
> Build completed successfully
🔗 [View in Dashboard](https://dashboard.example.com)
Format: Plain text (default) or HTML (when html: true)
Syntax rules:
- Plain text mode: no formatting, just raw text
- HTML mode: full HTML tags (
<b>,<table>,<pre>, etc.)
Data type: domain.Event
Available functions: None beyond built-in Go template functions
Template fields: Two separate templates:
-
subject: Email subject line (required) -
template: Email body (required)
Default subject (email-subject.tmpl):
[tekton] my-pipeline — success
Default body (email-default.tmpl):
Pipeline success: my-pipeline
Run: my-run
Namespace: default
Commit: abc12345
Build completed successfully.
View logs: https://dashboard.example.com
Format: Plain text annotation
Syntax rules: No markdown. Plain text only. Keep it short and correlatable with dashboards.
Data type: domain.Event
Available functions: Full sprig + domain helpers (Truncate, IssueRef, PRRef, UserMention)
Default template (deploy-marker.tmpl):
my-pipeline success (my-run) — abc12345
Format: Plain text comment
Syntax rules: No markdown. Plain text only. Jira has its own wiki markup for rich formatting, but the template renders plain text.
Data type: domain.Event
Available functions: Full sprig + domain helpers
Default template (jira-comment.tmpl):
Pipeline success: my-pipeline
Run: my-run
Commit: abc12345
Logs: https://dashboard.example.com
No template support. PagerDuty uses the Events API v2 with a fixed payload format. The notifier maps domain states to PagerDuty severity levels and sends trigger/resolve events. You configure which states trigger incidents via the when CEL expression, but the payload structure is not customizable.
No template support. Datadog uses the Events API v2 with auto-generated tags. Tags include state, context, namespace, run_id, and resource automatically. You can add custom tags via the tags config field, but the event body is not template-driven.
No template support. Sentry creates releases and deploy markers using the commit SHA and state. The release version is derived from the commit SHA. Only acts on successful runs with a commit SHA present.
Template: Uses gojq transform expressions, not Go templates.
Syntax: jq/gojq expressions. The input is the full JSON payload (domain.Event serialized as JSON). The output is the transformed payload sent to the webhook URL.
Examples:
# Remove results field and rename state
transform: 'del(.results) | .status = .state'
# Extract just the essential fields
transform: '{state: .state, run: .run_name, namespace: .namespace}'
# Add a computed field
transform: '. + {summary: "\(.pipeline_name) \(.state)"}'Data type: JSON-serialized domain.Event
Available functions: Full jq/gojq function set
Format: Markdown (posted via the registered SCM provider's PR comment handler)
Syntax rules: Same as the SCM provider's markdown capabilities. Since the accumulator dispatches through a PR comment handler, the rendered markdown goes through GitHub/GitLab/Gitea/etc.
Data type: SummaryData (NOT domain.Event)
Available functions: Full sprig + domain helpers
SummaryData fields:
type SummaryData struct {
PipelineName string // Name of the pipeline
RunName string // Name of the PipelineRun
State string // Terminal state: success, failure, error, canceled
Tasks []TaskSummary // Sorted list of task summaries
}
type TaskSummary struct {
Name string // Task name
State string // Task state (success, failure, etc.)
Emoji string // State emoji (✅, ❌, ⚠️, 🚫, 🔄, ⏳)
Duration string // Formatted duration (e.g., "45s", "N/A")
}Default output (when no custom template is set):
## Pipeline Summary
| Task | Status | Duration |
|------|--------|----------|
| build | ✅ success | 45s |
| test | ❌ failure | 1m20s |
| deploy | ⏳ pending | N/A |Example custom template:
{{ if eq .State "success" }}✅{{ else }}❌{{ end }} Pipeline {{ .State }} — {{ .PipelineName | default .RunName }}
Run: {{ .RunName }}
{{ range .Tasks }}{{ .Emoji }} {{ .Name }} — {{ .State }} ({{ .Duration }})
{{ end }}
| Your goal | Use this | Why |
|---|---|---|
| Rich PR comments on GitHub | GFM with <details>, tables, emoji |
Full markdown support |
| Brief status updates in Slack | Slack mrkdwn with *bold*, :emoji:
|
Native Slack formatting |
| Teams notifications | Adaptive Card markdown | Teams-specific subset |
| Debug logs in Discord | Discord markdown with code blocks | Discord-native formatting |
| Deploy markers in Grafana | Plain text, short and correlatable | Grafana annotations are text-only |
| Jira issue comments | Plain text, concise | Jira wiki markup not supported via API |
| Generic HTTP integration | gojq transform on JSON payload | Full control over payload shape |
| Pipeline run summary | Accumulator with SummaryData | Different data type than other notifiers |
Getting started
Reference
SCM providers
Notifiers
Running in production
More