Templates

Comment bodies, chat messages and check-run output are rendered with Go text/template, executed against the event. Label entries (labels.add/remove) use the same engine.

template: |
  ## Pipeline {{.State}}{{if eq .State "success"}} βœ…{{else}} ❌{{end}}
  **Pipeline:** {{.PipelineName}} Β· **Run:** {{.RunName}}
  **Commit:** `{{ .CommitSHA | trunc 8 }}`
  {{- if .TargetURL }}
  [View logs]({{.TargetURL}})
  {{- end }}

The relay ships 15 pre-built templates in the tekton-events-relay-templates ConfigMap. Each is tuned for a specific surface (GitHub PR comments, Slack messages, email bodies, etc.) with the right Markdown dialect, emoji, and layout for that destination.

Further reading

PageWhat you’ll find
Template-Field-ReferenceEvery available field, its type, and when it’s populated
Template-Function-ReferenceSprig functions plus the domain helpers (Truncate, PRRef, IssueRef, UserMention)
Template-Markdown-CapabilitiesWhat Markdown features each surface supports (tables, <details>, emoji, etc.)
Template-Customization-GuideStep-by-step guide to writing and shipping your own templates
Notifier-Format-RequirementsPer-notifier format rules (Slack mrkdwn, Teams Adaptive Cards, Discord embeds, etc.)

Available fields

The template context is the same event the CEL layer sees β€” identical names, accessed with a leading dot:

{{.State}}, {{.Resource}}, {{.Provider}}, {{.RunName}}, {{.RunID}}, {{.Namespace}}, {{.PipelineName}}, {{.TaskName}}, {{.PipelineTaskName}}, {{.PipelineDisplayName}}, {{.TaskDisplayName}}, {{.TriggerName}}, {{.EventListenerName}}, {{.TaskCount}}, {{.CommitSHA}}, {{.Context}}, {{.Description}}, {{.TargetURL}}, {{.APIBaseURL}}, {{.Repo.Owner}}, {{.Repo.Name}}, {{.Repo.ID}}, {{.Repo.Workspace}}, {{.Repo.Project}}, {{.Repo.Org}}, {{.IsFinallyTask}}, {{.SCMEventType}}, {{.StartedAt}}, {{.FinishedAt}}.

Pointer fields β€” guard before dereferencing:

{{ if .PRNumber }}PR #{{ .PRNumber }}{{ end }}

Tekton results (slice of {Name, Value}):

{{ range .Results }}{{ if eq .Name "IMAGE_DIGEST" }}Image: `{{ .Value }}`{{ end }}{{ end }}

Functions

Sprig

The full Sprig function library is available in SCM comment, check-run, Grafana, email, Jira, and accumulator templates: upper, lower, title, trim, trunc, replace, default, now, date, add, printf, join, ternary, regexReplaceAll, …

{{ .CommitSHA | trunc 8 }}
{{ .Description | default "no description" }}
{{ ternary "βœ…" "❌" (eq .State "success") }}
{{ regexReplaceAll "[.][0-9]+s" (toString (.FinishedAt.Sub .StartedAt)) "s" }}

Slack, Teams, and Discord use plain Go text/template only, no Sprig. Use printf for truncation (printf "%.200s" .Description) instead of trunc.

Domain helpers

Provider-aware helpers that override any Sprig equivalent:

FunctionExampleRenders
IssueRef provider n{{ IssueRef .Provider .IssueNumber }}#42 in the provider’s linking syntax
PRRef provider n{{ PRRef .Provider .PRNumber }}PR/MR reference (#42, !42 on GitLab)
UserMention provider user{{ UserMention .Provider "alice" }}@alice in the provider’s syntax
Truncate s n{{ Truncate .Description 200 }}Rune-aware truncation with ellipsis

Shipped templates

The chart ships 15 templates in configmap-templates.yaml, mounted at /etc/templates. Each is tuned for its destination’s Markdown dialect.

GitHub PR comment (github-pr-comment.tmpl)

Full GFM with <details> for results. Designed for mode: upsert so a single comment is updated as the run progresses.

## βœ… Pipeline `build-and-test` β€” **success**

| | |
|---|---|
| **Run** | `build-and-test-abc123` |
| **Namespace** | `ci` |
| **Commit** | `a1b2c3d4` |
| **Context** | `tekton/build` |
| **Tasks** | 6 |
| **Duration** | 42s |

> Build passed all checks

<details><summary>πŸ“¦ Results (3)</summary>

| Name | Value |
|---|---|
| `IMAGE_DIGEST` | `sha256:abc123...` |
| `COVERAGE` | `87.3%` |
| `ARTIFACT_URL` | `https://...` |

</details>

πŸ”— [View logs in Tekton Dashboard](https://tekton.example.com/#/namespaces/ci/pipelineruns/build-and-test-abc123)

GitHub check run (github-checkrun.tmpl)

Shown in the Checks tab. Results stay expanded instead of collapsed.

## βœ… Build result: **success**

| | |
|---|---|
| **Run** | `build-and-test-abc123` |
| **Pipeline** | `build-and-test` |
| **Namespace** | `ci` |
| **Tasks executed** | 6 |
| **Duration** | 42s |

### Summary

Build passed all checks

### Results

| Name | Value |
|---|---|
| `IMAGE_DIGEST` | `sha256:abc123...` |
| `COVERAGE` | `87.3%` |

πŸ”— [View logs in Tekton Dashboard](https://tekton.example.com/#/namespaces/ci/pipelineruns/build-and-test-abc123)

GitLab MR note (gitlab-note.tmpl)

GitLab Flavored Markdown with tables and <details>.

## βœ… Pipeline `deploy-staging` β€” **success**

| | |
|---|---|
| **Run** | `deploy-staging-xyz789` |
| **Namespace** | `staging` |
| **Commit** | `f0e1d2c3` |
| **Context** | `tekton/build` |
| **Duration** | 1m23s |

<details><summary>πŸ“¦ Results (2)</summary>

| Name | Value |
|---|---|
| `DEPLOY_URL` | `https://staging.example.com` |
| `IMAGE_TAG` | `v1.2.3-abc123` |

</details>

πŸ”— [View logs in Tekton Dashboard](https://tekton.example.com/#/namespaces/staging/pipelineruns/deploy-staging-xyz789)

Slack default (slack-default.tmpl)

Slack mrkdwn syntax. No Sprig, uses printf for truncation.

:white_check_mark: *deploy-staging* β€” *success*
> *Run:* `deploy-staging-xyz789`  *Namespace:* `staging`
> *Commit:* `f0e1d2c3`
> *Duration:* 83s
> Deployed to staging environment
<https://tekton.example.com/#/namespaces/staging/pipelineruns/deploy-staging-xyz789|:mag: View logs>

Slack failure alert (slack-failure-rich.tmpl)

Rotating light for failures only. Designed for when: 'stateIn("failure", "error")'.

:rotating_light: *deploy-production* failed in *production*
> *Run:* `deploy-production-abc123`  *Commit:* `a1b2c3d4`
> *Duration:* 45s
> Error: image pull backoff for gcr.io/my-project/app:v1.2.3
<https://tekton.example.com/#/namespaces/production/pipelineruns/deploy-production-abc123|:mag: View logs>

Discord default (discord-default.tmpl)

Discord Markdown with code block for structured data.

βœ… **Pipeline success** in `ci`

Run: deploy-staging-xyz789 Pipeline: deploy-staging Commit: f0e1d2c3 Duration: 83s

> Deployed to staging environment
πŸ”— [View in Dashboard](https://tekton.example.com/#/namespaces/ci/pipelineruns/deploy-staging-xyz789)

Teams default (teams-default.tmpl)

Adaptive Card TextBlock subset: bold, italic, lists, links only. No tables, no code blocks.

βœ… **deploy-staging** β€” **success**

- **Run:** deploy-staging-xyz789
- **Namespace:** staging
- **Commit:** f0e1d2c3
- **Duration:** 83s

Deployed to staging environment

[View logs](https://tekton.example.com/#/namespaces/ci/pipelineruns/deploy-staging-xyz789)

Email default (email-default.tmpl)

Plain text. Used for both subject and body.

Pipeline success: deploy-staging

Run:       deploy-staging-xyz789
Namespace: staging
Commit:    f0e1d2c3

Deployed to staging environment

View logs: https://tekton.example.com/#/namespaces/ci/pipelineruns/deploy-staging-xyz789

Grafana deploy marker (deploy-marker.tmpl)

Short one-line annotation correlatable with dashboards.

deploy-staging success (deploy-staging-xyz789) β€” f0e1d2c3

Provider-agnostic rich PR summary (pr-summary-rich.tmpl)

Works across GitHub, GitLab, Gitea, Bitbucket, Azure DevOps. Designed for mode: upsert.

## βœ… Pipeline `deploy-staging` β€” **success**

| | |
|---|---|
| **Run** | `deploy-staging-xyz789` |
| **Commit** | `f0e1d2c3` |
| **Namespace** | `staging` |
| **Started** | 2026-06-19 14:30:00 UTC |

<details><summary>πŸ“¦ Pipeline results</summary>

| Name | Value |
|---|---|
| `DEPLOY_URL` | `https://staging.example.com` |

</details>

πŸ”— [View logs in Tekton Dashboard](https://tekton.example.com/#/namespaces/staging/pipelineruns/deploy-staging-xyz789)

Gitea issue comment (gitea-issue-comment.tmpl)

GFM with tables. Used for issue-level notifications.

## ⚠️ Pipeline `deploy-staging` β€” **failure**

| | |
|---|---|
| **Run** | `deploy-staging-xyz789` |
| **Namespace** | `staging` |
| **Context** | `tekton/build` |
| **Duration** | 45s |

> Error: image pull backoff

πŸ”— [View logs in Tekton Dashboard](https://tekton.example.com/#/namespaces/staging/pipelineruns/deploy-staging-xyz789)

Jira comment (jira-comment.tmpl)

Minimal plain text for Jira’s wiki-markup renderer.

Pipeline success: deploy-staging
Run: deploy-staging-xyz789
Commit: f0e1d2c3
Logs: https://tekton.example.com/#/namespaces/staging/pipelineruns/deploy-staging-xyz789

Bitbucket PR comment (bitbucket-comment.tmpl)

Limited Markdown (no <details>, unreliable tables). Uses bold lists instead.

## βœ… Pipeline `deploy-staging` β€” **success**

- **Run:** `deploy-staging-xyz789`
- **Namespace:** `staging`
- **Commit:** `f0e1d2c3`
- **Duration:** 83s

> Deployed to staging environment

πŸ”— [View logs in Tekton Dashboard](https://tekton.example.com/#/namespaces/staging/pipelineruns/deploy-staging-xyz789)

Azure DevOps PR comment (azuredevops-comment.tmpl)

GFM tables, no <details>.

## βœ… Pipeline `deploy-staging` β€” **success**

| | |
|---|---|
| **Run** | `deploy-staging-xyz789` |
| **Namespace** | `staging` |
| **Commit** | `f0e1d2c3` |
| **Tasks** | 6 |
| **Duration** | 83s |

> Deployed to staging environment

**Results**

| Name | Value |
|---|---|
| `DEPLOY_URL` | `https://staging.example.com` |

πŸ”— [View logs in Tekton Dashboard](https://tekton.example.com/#/namespaces/staging/pipelineruns/deploy-staging-xyz789)

Accumulator default (accumulator-default.tmpl)

Summary context with task-level breakdown. Sprig available.

βœ… Pipeline success β€” deploy-staging

Run: deploy-staging-xyz789
Namespace: staging
Commit: f0e1d2c3
Tasks: 6
Duration: 42s
Results:
- IMAGE_DIGEST: sha256:abc123...
- COVERAGE: 87.3%
URL: https://tekton.example.com/#/namespaces/staging/pipelineruns/deploy-staging-xyz789

Per-surface notes

See Template-Markdown-Capabilities for a detailed comparison of what each surface supports.

Accumulator summary template

The accumulator renders a different context, SummaryData:

{{.PipelineName}} {{.RunName}} {{.State}}
{{ range .Tasks }}{{ .Emoji }} {{ .Name }} β€” {{ .State }} ({{ .Duration }})
{{ end }}

Fields: .PipelineName, .RunName, .State, and .Tasks[] with .Name, .State, .Emoji, .Duration. Without a custom template you get the shipped accumulator-default.tmpl.

Supplying a template

Every templatable field (template, and email’s subject) accepts up to three forms in the Helm chart. There are no hardcoded template defaults in the application code. For the required-template notifiers (email, grafana, and the jira comment action), omitting the field makes the chart wire in a shipped default from its tekton-events-relay-templates ConfigMap (configmap-templates.yaml). For optional-template handlers (slack, teams, discord, webhook, and all SCM comment actions), omitting the field is valid and uses the handler’s built-in fallback β€” no shipped default is wired. See the category breakdown below.

1. Inline β€” short templates, written directly in values.yaml:

template: |
  Pipeline {{.State}}: {{.RunName}}
  Commit: {{.CommitSHA}}

2. ConfigMap reference β€” long templates, kept in a ConfigMap and mounted at /etc/templates:

template:
  configmapRef:
    name: my-custom-templates   # optional; defaults to tekton-events-relay-templates
    key: slack.tpl

3. Omitted β€” leave the field out and the chart points at the shipped default:

NotifierFieldDefault key
emailsubjectemail-subject.tmpl
emailtemplateemail-default.tmpl
grafanatemplatedeploy-marker.tmpl
jira (comment)templatejira-comment.tmpl
slacktemplateslack-default.tmpl
teamstemplateteams-default.tmpl
discordtemplatediscord-default.tmpl
accumulatortemplateaccumulator-default.tmpl
GitHub PR commenttemplategithub-pr-comment.tmpl
GitHub check runtemplategithub-checkrun.tmpl
GitHub issue commenttemplategithub-issue-comment.tmpl
GitHub discussion commenttemplategithub-discussion-comment.tmpl
GitLab MR/issue notetemplategitlab-note.tmpl
Gitea PR commenttemplategitea-pr-comment.tmpl
Gitea issue commenttemplategitea-issue-comment.tmpl
Bitbucket PR commenttemplatebitbucket-comment.tmpl
Azure DevOps PR commenttemplateazuredevops-comment.tmpl

For the rich PR summary that works across providers, use pr-summary-rich.tmpl with any SCM comment action.

Raw app config (non-Helm): if you run the binary with a hand-written config (see examples/config.yaml), a template field is either an inline string or an absolute file path beginning with / (e.g. /etc/templates/slack.tmpl). The chart’s configmapRef form is sugar that resolves to such a path. There are no in-code defaults, so the field is required β€” mount the templates ConfigMap and point at it.

Custom templates

To write your own templates, see Template-Customization-Guide for a step-by-step walkthrough. The Template-Function-Reference covers every available function, and Template-Field-Reference lists every field you can use.

Common patterns:

Conditional sections:

{{- if .CommitSHA }}
| **Commit** | `{{ .CommitSHA | trunc 8 }}` |
{{- end }}

Duration calculation:

{{- if and (not .StartedAt.IsZero) (not .FinishedAt.IsZero) }}
| **Duration** | {{ regexReplaceAll "[.][0-9]+s" (toString (.FinishedAt.Sub .StartedAt)) "s" }} |
{{- end }}

Collapsible results:

<details><summary>πŸ“¦ Results ({{ len .Results }})</summary>

| Name | Value |
|---|---|
{{ range .Results }}
| `{{ .Name }}` | `{{ Truncate .Value 120 }}` |
{{ end }}

</details>

State-dependent emoji:

{{- if eq .State "success" }}βœ…
{{- else if eq .State "failure" }}❌
{{- else if eq .State "error" }}⚠️
{{- else if eq .State "canceled" }}🚫
{{- else }}⏳
{{- end }}