-
Notifications
You must be signed in to change notification settings - Fork 0
Template Function Reference
Templates use Go text/template with two layers of functions: a sprig subset for general-purpose string/date/math operations, and domain-specific helpers for provider-aware cross-references. This page documents every available function, its signature, and examples.
Not all notifiers get the same functions. Before using a function, check whether your target notifier supports it.
| Function category | SCM comments | Grafana | Jira | Accumulator | Slack | Teams | Discord | |
|---|---|---|---|---|---|---|---|---|
| Sprig subset | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Domain helpers | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
Slack, Teams, Discord, and Email use plain Go templates. Use printf for formatting, if/range/eq for logic, and manual string construction for everything else.
These functions are defined by the relay and take precedence over any sprig equivalents. They produce provider-aware output.
IssueRef(provider string, issueNum int, owner string, repo string) string
Returns the provider-specific markdown syntax for referencing an issue.
| Provider | Same-repo output | Cross-repo output |
|---|---|---|
| github | #42 |
owner/repo#42 |
| gitlab | #42 |
owner/repo#42 |
| gitea | #42 |
owner/repo#42 |
| bitbucket_cloud | #42 |
owner/repo#42 |
| bitbucket_server | #42 |
owner/repo#42 |
| azure_devops | #42 |
#42 (no cross-repo) |
| sourcehut |
"" (not supported) |
"" |
Examples:
{{ IssueRef .Provider 42 "" "" }}
Renders #42 on most providers, empty string on SourceHut.
{{ IssueRef .Provider 42 "acme" "backend" }}
Renders acme/backend#42 on GitHub/GitLab/Gitea/Bitbucket, #42 on Azure DevOps.
Guard usage (safe to call even when IssueNumber is nil):
{{ if .IssueNumber }}Related: {{ IssueRef .Provider .IssueNumber .Repo.Owner .Repo.Name }}{{ end }}
PRRef(provider string, prNum int, owner string, repo string) string
Returns the provider-specific syntax for referencing a pull request or merge request.
| Provider | Same-repo output | Cross-repo output |
|---|---|---|
| github | #42 |
owner/repo#42 |
| gitlab | !42 |
owner/repo!42 |
| gitea | #42 |
owner/repo#42 |
| bitbucket_cloud | #42 |
owner/repo#42 |
| bitbucket_server | #42 |
owner/repo#42 |
| azure_devops | #42 |
#42 (no cross-repo) |
| sourcehut |
"" (not supported) |
"" |
Note the GitLab difference: merge requests use ! instead of #.
Examples:
{{ PRRef .Provider 123 "" "" }}
Renders #123 on most providers, !123 on GitLab.
{{ PRRef .Provider 123 "acme" "frontend" }}
Renders acme/frontend!123 on GitLab, acme/frontend#123 on GitHub/Gitea/Bitbucket.
UserMention(provider string, username string) string
Returns the provider-specific syntax for mentioning a user. All supported providers use @username.
| Provider | Output |
|---|---|
| github | @alice |
| gitlab | @alice |
| gitea | @alice |
| bitbucket_cloud | @alice |
| bitbucket_server | @alice |
| azure_devops | @alice |
| sourcehut |
alice (no mention syntax) |
Example:
Assigned to {{ UserMention .Provider "alice" }}
Truncate(s string, limit int) string
Rune-aware truncation with ... suffix. Counts runes (Unicode characters), not bytes, so multi-byte characters like emoji don't cause issues.
- If
limitis 0, returns the original string (no limit). - If the string is shorter than the limit, returns it unchanged.
- If truncated, appends
...(consuming 3 characters of the limit). - If
limitis less than 3, truncates without the ellipsis.
Examples:
{{ Truncate .Description 200 }}
If Description is 250 characters, returns the first 197 characters followed by ....
{{ Truncate .Description 300 }}
If Description is 250 characters, returns the full string unchanged.
{{ Truncate "short" 200 }}
Returns short (already under the limit).
The relay starts with sprig's full TxtFuncMap and removes dangerous functions. Here are the most commonly used categories.
These functions are stripped from the template environment:
| Function | Why removed |
|---|---|
env, expandenv, expand
|
Prevents environment variable exfiltration |
base64Encode, base64Decode
|
Prevents cryptographic misuse |
genPrivateKey, genCA, genSelfSignedCert
|
Prevents key generation in templates |
| Function | Signature | Example | Output |
|---|---|---|---|
upper |
upper(string) |
{{ .State | upper }} |
SUCCESS |
lower |
lower(string) |
{{ .State | lower }} |
success |
title |
title(string) |
{{ .State | title }} |
Success |
trim |
trim(string) |
{{ .Description | trim }} |
trimmed |
trimAll |
trimAll(string) |
{{ " hello " | trimAll }} |
hello |
trimPrefix |
trimPrefix(prefix, string) |
{{ "build-123" | trimPrefix "build-" }} |
123 |
trimSuffix |
trimSuffix(suffix, string) |
{{ "123-test" | trimSuffix "-test" }} |
123 |
replace |
replace(old, new, string) |
{{ "hello world" | replace "world" "relay" }} |
hello relay |
trunc |
trunc(n, string) |
{{ .CommitSHA | trunc 8 }} |
first 8 characters |
contains |
contains(substr, string) |
{{ contains "fail" .Description }} |
bool |
hasPrefix |
hasPrefix(prefix, string) |
{{ hasPrefix "tekton-" .RunName }} |
bool |
hasSuffix |
hasSuffix(suffix, string) |
{{ hasSuffix "-run" .RunName }} |
bool |
repeat |
repeat(count, string) |
{{ repeat 3 "-" }} |
--- |
quote |
quote(string) |
{{ .RunName | quote }} |
"my-run" |
squote |
squote(string) |
{{ .RunName | squote }} |
'my-run' |
cat |
cat(args...) |
{{ cat "hello" "world" }} |
hello world |
split |
split(sep, string) |
{{ index (split ":" "a:b:c") "_1" }} |
b |
splitList |
splitList(sep, string) |
{{ splitList "/" "a/b/c" }} |
[a b c] |
join |
join(sep, list) |
{{ join "," (list "a" "b") }} |
a,b |
regexReplaceAll |
regexReplaceAll(pattern, string, repl) |
See below | matched pattern replaced |
Truncation in non-sprig notifiers: For Slack, Teams, Discord, and Email, use printf "%.200s" .Description instead of Truncate. The printf function is always available.
| Function | Signature | Example | Output |
|---|---|---|---|
add |
add(a, b) |
{{ add 1 2 }} |
3 |
sub |
sub(a, b) |
{{ sub 10 3 }} |
7 |
mul |
mul(a, b) |
{{ mul 3 4 }} |
12 |
div |
div(a, b) |
{{ div 10 3 }} |
3 |
mod |
mod(a, b) |
{{ mod 10 3 }} |
1 |
max |
max(a, b) |
{{ max 5 3 }} |
5 |
min |
min(a, b) |
{{ min 5 3 }} |
3 |
| Function | Signature | Example | Output |
|---|---|---|---|
now |
now() |
{{ now }} |
current time |
date |
date(fmt, time) |
{{ date "2006-01-02" .StartedAt }} |
2024-01-15 |
dateModify |
dateModify(mod, time) |
{{ dateModify "-24h" now }} |
24h ago |
ago |
ago(time) |
{{ ago .StartedAt }} |
5m30s |
duration |
duration(seconds) |
{{ duration 90 }} |
1h30m0s |
unixEpoch |
unixEpoch(time) |
{{ unixEpoch .StartedAt }} |
unix timestamp |
Duration calculation (common pattern):
{{- if and (not .StartedAt.IsZero) (not .FinishedAt.IsZero) -}}
Duration: {{ regexReplaceAll "[.][0-9]+s" (toString (.FinishedAt.Sub .StartedAt)) "s" }}
{{- end }}
| Function | Signature | Example | Output |
|---|---|---|---|
list |
list(items...) |
{{ list "a" "b" }} |
[a b] |
first |
first(n, list) |
{{ first 2 (list 1 2 3) }} |
[1 2] |
last |
last(n, list) |
{{ last 2 (list 1 2 3) }} |
[2 3] |
reverse |
reverse(list) |
{{ reverse (list 1 2 3) }} |
[3 2 1] |
sortAlpha |
sortAlpha(list) |
{{ sortAlpha (list "c" "a" "b") }} |
[a b c] |
uniq |
uniq(list) |
{{ uniq (list 1 1 2 3) }} |
[1 2 3] |
has |
has(item, list) |
{{ has "a" (list "a" "b") }} |
true |
append |
append(list, items...) |
{{ append (list 1 2) 3 }} |
[1 2 3] |
concat |
concat(lists...) |
{{ concat (list 1) (list 2 3) }} |
[1 2 3] |
| Function | Signature | Example | Output |
|---|---|---|---|
ternary |
ternary(trueVal, falseVal, condition) |
{{ ternary "✅" "❌" (eq .State "success") }} |
✅ or ❌
|
default |
default(defaultVal, val) |
{{ .PipelineName | default .RunName }} |
falls back to RunName |
empty |
empty(val) |
{{ if empty .Description }}no desc{{ end }} |
checks emptiness |
coalesce |
coalesce(vals...) |
{{ coalesce .Description "N/A" }} |
first non-empty |
toJson |
toJson(val) |
{{ . | toJson }} |
JSON string |
| Function | Signature | Example | Output |
|---|---|---|---|
toString |
toString(val) |
{{ toString 42 }} |
"42" |
toInt |
toInt(val) |
{{ "42" | toInt }} |
42 |
toBool |
toBool(val) |
{{ toBool "true" }} |
true |
| Function | Signature | Example | Output |
|---|---|---|---|
printf |
printf(fmt, args...) |
{{ printf "%.8s" .CommitSHA }} |
first 8 chars |
println |
println(args...) |
{{ println "hello" "world" }} |
hello world\n |
indent |
indent(spaces, string) |
{{ indent 2 "line1\nline2" }} |
indented |
nindent |
nindent(spaces, string) |
{{ nindent 2 "line1" }} |
newline + indented |
{{ .PipelineName | default .RunName }}
{{- if eq .State "success" }}✅
{{- else if eq .State "failure" }}❌
{{- else if eq .State "error" }}⚠️
{{- else if eq .State "canceled" }}🚫
{{- else }}⏳
{{- end }}
{{ Truncate (.Description | default "No description available") 300 }}
{{- if and (not .StartedAt.IsZero) (not .FinishedAt.IsZero) }}
Duration: {{ regexReplaceAll "[.][0-9]+s" (toString (.FinishedAt.Sub .StartedAt)) "s" }}
{{- end }}
{{- if .Results }}
<details><summary>Results ({{ len .Results }})</summary>
| Name | Value |
|---|---|
{{- range .Results }}
| {{ .Name }} | {{ Truncate .Value 120 }} |
{{- end }}
</details>
{{- end }}
{{- if .Results }}
Results:
{{- range .Results }}
- {{ .Name }}: {{ printf "%.120s" .Value }}
{{- end }}
{{- end }}
Getting started
Reference
SCM providers
Notifiers
Running in production
More