Skip to content

Notifier Format Requirements

Fábio Luciano edited this page Jun 22, 2026 · 1 revision

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.

Sprig availability

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
Email 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.

Per-notifier details

Slack

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>

Microsoft Teams

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)

Discord

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)

Email

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

Grafana

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

Jira

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

PagerDuty

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.

Datadog

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.

Sentry

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.

Webhook

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

Accumulator

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 }}

Choosing the right template format

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

Clone this wiki locally