Notification templates

Notification templates are a way of generating notifications: by defining a title and a content templates, they will be filled up with the data provided through the API endpoints.

Notify17 notification templates use the well known Go templates syntax, with the request payload being the context of the template.

You can find extensive documentation, which applies to all the basic syntax of the templates, at https://golang.org/pkg/text/template/ .

Basic example

A notification template can be created in the Notification templates  page.

To trigger a notification using a template, you can send a cURL  request containing your payload (JSON/Form):

curl "https://hook.notify17.net/api/template/TEMPLATE_API_KEY?name=Mr.%20Anderson"
curl -X POST \
  "https://hook.notify17.net/api/template/TEMPLATE_API_KEY" \
  -F name="Mr. Anderson"
curl -X POST \
  "https://hook.notify17.net/api/template/TEMPLATE_API_KEY" \
   --header "Content-Type: application/json" \
   --data "{\"name\":\"Mr. Anderson\"}"

The basic usage of a template is:

Template Payload
This is a greeting!

---

Hello {{ .name }}!
{
  "name": "Mr. Anderson"
}
Rendered
This is a greeting!

---

Hello Mr. Anderson!

Access payload variables

Template Payload
Hello {{ .name }}!

---

You live in {{ .address.city }}.
{
  "name": "John",
  "address": {
    "city": "Toronto"
  }
}
Rendered
Hello John!

---

You live in Toronto.

Delete all the whitespaces!

The little dashes (-) you see around are used to delete the whitespaces and newlines between where they’re used and:

  • {{- <- The word closest to the left of the template block
  • -}} <- The word closest to the right of the template block
Template Payload
Hello    {{ .name }}!

Hello    {{- .name }}!
{
    "name": "General Kenobi"
}
Rendered
Hello    General Kenobi!

HelloGeneral Kenobi!

NOTE: By default Notify17 will remove, from generated notifications, groups of 3+ newlines and collapse them into 2 newlines, to improve content readability.

Delete all the whitespaces!

Comments

You can add a comment using the notation {{/* This is a comment! */}}. Comments will not be rendered in the notification.

To remove whitespaces and newlines around comments, use the {{- /* and */ -}} tags.

Template
Line 1

{{/* 
    We're doing lots of stuff here, so we want some comments.
    
    This is a multiline comment.
*/}}

Line 2

{{/* Single line comment with white space clearing*/ -}}
 
Line 3
Rendered
Line 1

Line 2

Line 3

Conditionals

Template Payload
{{ if eq .success true -}}
Success!
{{- else -}}
Failed!
{{- end }}

{{ if gt .value 5 -}}
The value is bigger than 5!
{{- else -}}
What a small value!
{{- end }}
{
  "success": true,
  "value": 10.1
}
Rendered
Success!

The value is bigger than 5!

Available comparison functions:

  • eq .A .B -> A == B (also existsAndEq)
  • ne .A .B -> A != B (also existsAndNE)
  • lt .A .B -> A < B (also existsAndLT)
  • le .A .B -> A <= B (also existsAndLE)
  • gt .A .B -> A > B (also existsAndGT)
  • ge .A .B -> A >= B (also existsAndGE)

existsAnd- variants

A generic exists functions is available to test if a field is present or not.

The other existsAnd- comparison variants are quite useful when dealing with trigger conditions, whenever you want to check if a field exists before comparing it.

Template Payload
{{ if not (exists .hello) }}
Oh, hello does not exist!
{{ end }}

{{ if existsAndEq .value .invalidOne }}
Wow, really?
{{ else }}
Oh, some values did not exist!
{{ end }}

{{ if existsAndEq .value 10.1 }}
Yay!
{{ end }}
{
  "value": 10.1
}
Rendered
Oh, hello does not exist!

Oh, some values did not exist!

Yay!

Why do we need these variants?

These variants were introduced to solve the problem “how do I trigger a template only if this field exists and is not 0?”.

One may think it is possible to check if a field (e.g. .code) exists and is not 0 by using the following template:

{{ if and (.code) (ne .code 0) }}
It exists!
{{ end }}

The problem with the previous template is that the second argument of the conditional ((ne .code 0)) is evaluated BEFORE the actual and, triggering a comparison error (nil vs 0). Therefore, you need a wrapper to the conditional, that returns false whenever any of the arguments are null or do not exist.

Arrays

Template Payload
Second element: {{ index .myArray 1 }}
{
  "myArray": [
     "I'm first!",
     "I'm second :("
  ]
}
Rendered
Second element: I'm second :(

Loops

Template Payload
The number 3 is perfect:

{{ range $entry := .entries -}}
* {{ $entry.name }}
{{ end }}
{
  "entries": [
    {"name": "Doom 3"},
    {"name": "Half-Life 3 😈"},
    {"name": "Far Cry 3"}
  ]
}
Rendered
The number 3 is perfect:

* Doom 3
* Half-Life 3 😈
* Far Cry 3
Template Payload
Ids:

{{ range $idx, $field := .array -}}
- {{ $field }} at idx {{ $idx }}
{{ end }}
{
  "array": [
    "id-1",
    "id-2",
    "id-3"
  ]
}
Rendered
Ids:

- id-1 at idx 0
- id-2 at idx 1
- id-3 at idx 2
Template Payload
Ids:

{{ range $key, $value := .map -}}
- {{ printf "%s: %s" $key $value }}
{{ end }}
{
  "map": {
    "a": 1,
    "b": 25,
    "c": 10
  }
}
Rendered
Ids:

- a: %!s(float64=1)
- b: %!s(float64=25)
- c: %!s(float64=10)

Trigger conditions

If you want your notification templates to generate notifications ONLY if certain conditions are met (e.g. the payload variable status is alerting), you can use the Trigger condition field.

This field can contain one Go-template expression (an expression that you would place inside a if block), which gets checked whenever the notification template is used through the templated notifications API.

Examples:

  • Trigger only if status is alerting:

    eq .status "alerting"

  • Trigger only if the decoded base64 value of signature is report/1234:

    eq (b64dec .signature) "report/1234"

  • Trigger only if timestamp (unix time) is not older than 1 hour (e.g. to prevent old useless/delayed notifications from popping up):

    (parseUnixTime .timestamp).After (now.Add (parseDuration "-1h"))

    Let’s break this one down:

    • parseUnixTime .timestamp converts the payload field timestamp to a time.Time  element.
    • parseDuration "-1h" converts the literal -1h to a time.Duration  element.
    • now.Add (ParseDuration "-1h") subtracts 1 hour from the current time.
    • .After is the actual check for (now.Add (parseDuration "-1h")) to be after (parseUnixTime .timestamp).

You can find more examples in the Conditionals section.

Functions

Notify17 has a set of embedded functions that you can use to process the notification payloads, mainly based on the open-source library Sprig  (you may be familiar with these functions if you use Helm  to deploy resources in Kubernetes).

Note: all functions starting with must prefix will cause a failure of the template execution if an error is found. Unless another behavior is specified, in presence of both a must and a non-must variant, the non-must variant will return an empty value of the relevant type:

{{ $date := mustToDate "January 02, 2006" "November 16, 2004" }}
Invalid duration here: {{ dateModify "25bla" $date }}
Result: Invalid duration here: 2004-11-16 00:00:00 +0200 EET

The same template, if executed with mustDateModify function, would fail completely the execution.

Dump

Function nameArgsOutputExample
toStringobjHuman friendly representation of obj
{{ toString (split " " "a b c") }}
Result: map[_0:a _1:b _2:c]
dumpobjHuman friendly YAML representation of obj
{{ dump (split " " "a b c") }}
Result:
_0: a
_1: b
_2: c

Dates

Note: $dateVar variable refers to November 16, 2004 - 00:12:34.567 UTC .

Function nameArgsOutputExample
agodateHow many seconds have elapsed since the provided date
{{ ago $dateVar }}
Result: 131631h49m27s
dateformat, dateFormat date to string using format (UTC)
{{ date "2006/01/02 15:04:05" $dateVar }}
Result: 2004/11/16 00:12:34
dateInZoneformat, date, timeZoneFormat date to string using format, interpreting date within timeZone
{{ dateInZone "2006/01/02 15:04:05" $dateVar "America/New_York" }}
Result: 2004/11/15 19:12:34
dateISOdateFormat date to string using ISO 8601 format  (UTC timezone)
{{ dateISO $dateVar }}
Result: 2004-11-16T00:12:34.567Z
dateModifyduration, datedate + duration. If duration is a non valid string, returns the date
{{ dateISO (dateModify "-2h" $dateVar) }}
Result: 2004-11-15T22:12:34.567Z
mustDateModifyduration, datedate + duration. If duration is a non valid string, fails to generate the notification
{{ dateISO (mustDateModify "-2h" $dateVar) }}
Result: 2004-11-15T22:12:34.567Z
durationRounddurationRounds duration down to the closest biggest time interval
{{ durationRound "32h15m28s" }}, {{ durationRound "15m28s" }}
Result: 1d, 15m
htmlDatedatedate formatted as YYYY-MM-DD
{{ htmlDate $dateVar }}
Result: 2004-11-16
htmlDateInZonedate, timeZonedate formatted as YYYY-MM-DD, interpreting date within timeZone
{{ htmlDateInZone $dateVar "America/New_York" }}
Result: 2004-11-15
nowThe current date as object, to be used in conjunction with other date functions
{{ dateISO now }}
Result: 2019-11-22T16:02:01.824Z
toDateformat, valueParses value using format  into a date object. On bad parsing, returns a void date
{{ toDate "January 02, 2006" "November 16, 2004" }}
Result: 2004-11-16 00:00:00 +0200 EET
mustToDateformat, valueParses value using format  into a date object. On bad parsing, fails to generate the notification
{{ htmlDate (mustToDate "January 02, 2006" "November 16, 2004") }}
Result: 2004-11-16
unixEpochdatedate in unix-time seconds
{{ unixEpoch $dateVar }}
Result: 1100563954
parseUnixTimesecondsReturns a date from unix-time seconds
{{ parseUnixTime 1574402832 }}
Result: 2019-11-22 08:07:12 +0200 EET
parseUnixTimeMsmillisecondsReturns a date from unix-time milliseconds
{{ parseUnixTimeMs 1574402832123 }}
Result: 2019-11-22 08:07:12.123 +0200 EET

Strings

Function nameArgsOutputExample
abbrevmaxWidth, textLimits text + to maxWidth
{{ abbrev 5 "Do not go gentle into that good night" }}
Result: Do...
abbrevbothoffset, maxWidth, textLimits text + to maxWidth, also ellipsizing () the left side by offset
{{ abbrevboth 6 25 "Do not go gentle into that good night" }}
Result: ... go gentle into tha...
trunclength, textTruncates text at the provided length
{{ trunc 5 "Do not go gentle into that good night" }}
Result: Do no
trimtextRemoved any whitespace/newline from beginning and end of text
{{ trim " ohoh   " }}!
Result: ohoh!
uppertextUpper-cases text
{{ upper "Yes sir, Mister Johnson" }}
Result: YES SIR, MISTER JOHNSON
lowertextLower-cases text
{{ lower "Yes sir, Mister Johnson" }}
Result: yes sir, mister johnson
titletextTitle-cases text
{{ title "Yes sir, mister johnson" }}
Result: Yes Sir, Mister Johnson
untitletextUn-title-cases text
{{ untitle "Yes sir, MISTER Johnson" }}
Result: yes sir, mISTER johnson
substrstart, end, textSubstring of text
{{ substr 4 10 "Yes sir, Mister Johnson" }}
Result: sir, M
repeatcount, textRepeats text count times
{{ repeat 3 "Oh " }}!
Result: Oh Oh Oh !
trimAllset, textRemoves all occurrences of each set character from both ends of text
{{ trimAll "-_" "--Some text__" }}
Result: Some text
trimSuffixsuffix, textRemoves suffix from ending of text
{{ trimSuffix "__" "--Some text__" }}
Result: --Some text
trimPrefixprefix, textRemoves prefix from beginning of text
{{ trimPrefix "--" "--Some text__" }}
Result: Some text__
nospacetextRemoves all whitespaces from text
{{ nospace "Yes sir, Mister Johnson" }}
Result: Yessir,MisterJohnson
initialstextExtracts the initial letters from each word in text
{{ initials "Carl Johnson" }}
Result: CJ
randAlphaNumlengthRandom alpha-numeric string with length characters
{{ randAlphaNum 15 }}
Result: z5LCuxkiAXDySuJ
randAlphalengthRandom alpha string with length characters
{{ randAlpha 14 }}
Result: FHVcbBzlhbvNtm
randAsciilengthRandom ASCII string with length characters
{{ randAscii 13 }}
Result: r\9L7Qq$jgy*#
randNumericlengthRandom numeric string with length characters
{{ randNumeric 12 }}
Result: 251752917141
swapcasetextSwaps upper-case with lower-case in text
{{ swapcase "Yes sir, Mister Johnson" }}
Result: yES SIR, mISTER jOHNSON
shuffletextShuffles all characters of text
{{ shuffle "Yes sir, Mister Johnson" }}
Result: ro JsiYssMih soternn e,
snakecasetextSnake-cases text
{{ snakecase "BeginTheAwakening" }}
Result: begin_the_awakening
camelcasetextCamel-cases text
{{ camelcase "_begin_the_awakening" }}
Result: _BeginTheAwakening
kebabcasetextKebab-cases text
{{ kebabcase "beginTheAwakening" }}
Result: begin-the-awakening
wraplength, textWrap text with newlines to desired length
{{ wrap 10 "Do not go gentle into that good night" }}
Result:
Do not go
gentle
into that
good night
wrapWithlength, sep, textWrap text with sep to desired length
{{ wrapWith 10 "#" "Do not go gentle into that good night" }}
Result: Do not go#gentle#into that#good night
containsstr, textTrue if text contains str
{{ if contains "oh" "Helloh!" }}Yes!{{ end }}
Result: Yes!
hasPrefixstr, textTrue if text starts with str
{{ if hasPrefix "He" "Helloh!" }}Yes!{{ end }}
Result: Yes!
hasSuffixstr, textTrue if text ends with str
{{ if hasSuffix "h!" "Helloh!" }}Yes!{{ end }}
Result: Yes!
quotestr1, str2, ...Wraps all args with "
{{ quote "Ohoh! \" some characters ' here" }}
Result: "Ohoh! \" some characters ' here"
squotestr1, str2, ...Wrap all args with '
{{ squote "Ohoh! \" some characters ' here" }}
Result: 'Ohoh! " some characters ' here'
catstr1, str2, ...Concatenates all args
{{ cat "hello" "world" "!" }}
Result: hello world !
indentspaces, textIndent text with desired number of spaces
{{ indent 4 "hello" }}
Result: hello
nindentspaces, textIndent text with desired number of spaces and prepend a newline
{{ nindent 4 "hello" }}
Result: hello
replaceold, new, textReplaces all occurrences of old with new in text
{{ replace "ap" "pr" "Apple, say \"Apple\"!"  }}
Result: Apple, say "Apple"!
pluralone, many, countIf count > 1, returns many, otherwise returns one
{{ plural "Apple" "Apples" 3 }}
Result: Apples
sha1sumtextSHA1 hash of text
{{ sha1sum "hello" }}
Result: aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
sha256sumtextSHA256 hash of text
{{ sha256sum "hello" }}
Result: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
adler32sumtextAdler-32 hash of text
{{ adler32sum "hello" }}
Result: 103547413
b64enctextBase64-encoded text
{{ b64enc "Hello 🐄" }}
Result: SGVsbG8g8J+QhA==
b64decb64Decodes b64 with Base64-encoding
{{ b64dec "SEwzIQ==" }}
Result: HL3!
b64encUrltextBase64-encoded text (URL-friendly)
{{ b64encUrl "Hello 🐄" }}
Result: SGVsbG8g8J-QhA==
b64decUrlb64Decodes b64 with Base64-encoding (URL-friendly)
{{ b64decUrl "T2ghIFNwZWNpYWwgY2hhcnMg8J-YgQ=" }}
Result: Oh! Special chars 😁
b32enctextBase64-encoded text
{{ b32enc "hello in 32!" }}
Result: NBSWY3DPEBUW4IBTGIQQ====
b64decb64Decodes b64 with Base64-encoding
{{ b32dec "JBGDIPY=" }}
Result: HL4?
urlParsetextParses text into a dictionary with URL parts
{{ dump (urlParse "http://admin:secret@server.com:8080/api?list=false#anchor") }}
Result:
fragment: anchor
host: server.com:8080
hostname: server.com
opaque: ""
path: /api
query: list=false
scheme: http
userinfo: admin:secret
urlJoinmapJoins map (dictionary) into a URL string
{{ urlJoin (dict "host" "host:80" "path" "/path" "query" "query" "scheme" "http") }}
Result: http://host:80/path?query
stripHTMLtextStrips HTML-specific chars from text and formats the result
{{ stripHTML "Hello!<br/>Wussup?" }}
Result:
Hello!
Wussup?

String lists

Function nameArgsOutputExample
splitseparator, textSplits text into a map using separator
{{ dump (split "," "abc,def,ghi") }}
Result:
_0: abc
_1: def
_2: ghi
splitListseparator, textSplits text into a list using separator
{{ dump (splitList "," "abc,def,ghi") }}
Result:
- abc
- def
- ghi
splitnseparator, n, textSplits text into a map using separator, and limiting the split count by n
{{ dump (splitn "," 3 "abc,def,ghi,jkl,mno,pqr") }}
Result:
_0: abc
_1: def
_2: ghi,jkl,mno,pqr
toStringsvalueConverts value to a string list
{{ dump (toStrings (until 3)) }}
Result:
- "0"
- "1"
- "2"
joinseparator, listJoins list items using separator
{{ join "-" (splitList "," "a,b,c,d") }}
Result: a-b-c-d
sortAlphalistSorts list ascendingly
{{ sortAlpha (splitList "," "d,a,c,g,e,e6,e0") }}
Result: [a c d e e0 e6 g]

Conversions

Function nameArgsOutputExample
atoitextConverts test to an integer
{{ add (atoi "25") 3 }}
Result: 28
int64valueConverts value to int64
{{ int64 "42" }}
Result: 42
intvalueConverts values to int
{{ int 45.34 }}
Result: 45
float64valueConverts value to float64
{{ float64 "1.234" }}
Result: 1.234
toDecimaltextConverts text from octal to decimal
{{ toDecimal "764" }}
Result: 500
parseJsontextParses text using JSON, fails on error
{{ parseJson "{\"a\": 4}" }}
Result: map[a:4]
parseYamltextParses text using YAML, fails on error
{{ parseYaml "a: 5" }}
Result: map[a:5]

Arithmetic (int)

Note: all the following functions convert all their parameters to int64 before performing any operation. This means any decimal numbers precision will be lost. For decimal/floating arithmetic, please use the Arithmetic (float) functions.

Function nameArgsOutputExample
add1numberAdds 1 to number
{{ add1 13 }}
Result: 14
addn1, n2, …Sum of all n*
{{ add 2 4 7.2 }}
Result: 13
subn1, n2n1 - n2
{{ sub 10 7 }}
Result: 3
divn1, n2n1 / n2
{{ div 25 4 }}
Result: 6
modn1, n2Remainder of n1 / n2
{{ mod 25 4 }}
Result: 1
muln1, n2, …Multiplication of all n*
{{ mul 2 3 4 }}
Result: 24
biggest/maxn1, n2, …Returns the biggest of n*
{{ max 13 34 25 }}
Result: 34
minn1, n2, …Returns the smallest of n*
{{ min 13 34 25 }}
Result: 13
untillimitint list, from 0 to limit (excluded)
{{ until 5 }}
Result: [0 1 2 3 4]
untilStepstart, end, stepint list, from start to end (excluded), with step
{{ untilStep 3 9 2 }}
Result: [3 5 7]

Arithmetic (float)

Function nameArgsOutputExample
addf1numberAdds 1 to number
{{ addf1 13 }}
Result: 14
addfn1, n2, …Sum of all n*
{{ addf 2 4 7.2 }}
Result: 13.2
subfn1, n2n1 - n2
{{ subf 10 7 }}
Result: 3
divfn1, n2n1 / n2
{{ divf 25 4 }}
Result: 6.25
mulfn1, n2, …Multiplication of all n*
{{ mulf 2 3 4 }}
Result: 24
biggestf/maxfn1, n2, …Returns the biggest of n*
{{ maxf 13 34 25 }}
Result: 34
minfn1, n2, …Returns the smallest of n*
{{ minf 13 34 25 }}
Result: 13
ceilnLeast integer value greater than or equal to n
{{ ceil 7.2 }}
Result: 8
floornGreatest integer value less than or equal to n
{{ floor 7.2 }}
Result: 7
roundn, p, [rp]Rounds n to have p decimal places, using rp (default 0.5) as roundness threshold.
{{ round 7.256 2 }}, {{ round 7.34 1 0.4 }}
Result: 7.26, 7.4

Utilities

Function nameArgsOutputExample
defaultdef, valueReturns value, or def if value is empty (see empty function below)
{{ default "hello!" "" }}, {{ default 5 0 }}
Result: hello!, 5
emptyvalueTrue if value has the zero value for its type
{{ empty nil }}, {{ empty 0 }}
Result: true, true
coalescev1, v2, …Returns the first non-empty v*
{{ coalesce "" "" "hi!" }}, {{ coalesce nil nil 4 }}
Result: hi!, 4
compactlistReturns a copy of list without any empty value
{{ compact (splitList "," "a,,c,,e,f") }}
Result: [a c e f]
toJsonvalueEncodes value into a JSON string
{{ toJson (split "," "a,b,c,<script>") }}
Result: {"_0":"a","_1":"b","_2":"c","_3":"\u003cscript\u003e"}
toPrettyJsonvalueEncodes value into a pretty (indented) JSON string
{{ toPrettyJson (split "," "a,b,c,<script>") }}
Result:
{
  "_0": "a",
  "_1": "b",
  "_2": "c",
  "_3": "\u003cscript\u003e"
}
toRawJsonvalueEncodes value into a JSON string with no escaping of HTML characters
{{ toRawJson (split "," "a,b,c,<script>") }}
Result: {"_0":"a","_1":"b","_2":"c","_3":"<script>"}
ternaryvtrue, vfalse, testReturns vtrue if test is true, otherwise returns vfalse
{{ ternary "I'm true!" "So false!" (gt 1 0) }}
Result: I'm true!
deepCopyvalueCreates a deep-clone of value
{{$a := dict "a" 12 "b" 34}}{{$v := deepCopy $a}}{{$_ := unset $v "b"}}{{printf "%v -> %v" $a $v}}
Result: map[a:12 b:34] -> map[a:12]

Reflection

If you define a struct named Foo, the kind is struct and the type is Foo. [source ]

Function nameArgsOutputExample
typeOfvalueGo-type of value
{{ typeOf "hi!" }}, {{ typeOf 1.123 }}, {{ typeOf (dict "a" 34 ) }}, {{ typeOf (list 1 2) }}
Result: string, float64, map[string]interface {}, []interface {}
typeIstarget, srcTrue if type of src is target
{{ typeIs "float64" 1.234 }}
Result: true
kindOfvalueGo-kind of value
{{ kindOf "hi!" }}, {{ kindOf 1.123 }}, {{ kindOf (dict "a" 34 ) }}, {{ kindOf (list 1 2) }}
Result: string, float64, map, slice
kindIstarget, srcTrue if kind of src is target
{{ kindIs "mmm" 1.234 }}
Result: false
deepEqualx, yTrue if x and y are equal in value
{{ deepEqual (dict "a" "b") (dict "a" "b") }}
Result: true

Lists, dictionaries

Function nameArgsOutputExample
tuple,listv1, v2, …List made of all v* elements
{{ list 1 2 3 }}
Result: [1 2 3]
dictk1, v1, k2, v2, …Dictionary made of all k*=v* pairs
{{ dict "a" 1 "b" 2 }}
Result: map[a:1 b:2]
getmap, keyReturns key element of map
{{$a := dict "myKey" 4}}{{get $a "myKey"}}
Result: 4
setmap, key, valueSets key=value in map. Returns map
{{$a := dict "myKey" 4}}{{set $a "key2" "Hello!"}}
Result: map[key2:Hello! myKey:4]
unsetmap, keyRemoves key from map. Returns `map
{{$a := dict "a" 4 "b" 5}}{{unset $a "b"}}
Result: map[a:4]
hasKeymap, keyTrue if map contains key
{{$a := dict "a" 4 "b" 5}}{{hasKey $a "b"}}
Result: true
pluckkey, map1, map2, …Returns a list containing all values of key in all map* dictionaries
{{ pluck "a" (dict "a" 1) (dict "a" 4) }}
Result: [1 4]
keysmap1, map2, …Returns a list of all keys of all map* dictionaries
{{ keys (dict "a" 1) (dict "b" 4) }}
Result: [a b]
valuesmap1, map2, …Returns a list of all values of all map* dictionaries
{{ values (dict "a" 1) (dict "b" 4) }}
Result: [1 4]
pickmap, key1, key2, …Extract all key* keys of map into a new dictionary
{{ pick (split "," "a,b,c,d,e") "_0" "_3" "_10" }}
Result: map[_0:a _3:d]
omitmap, key1, key2, …Returns a clone of map without any key* key
{{ omit (split "," "a,b,c,d,e") "_0" "_3" "_10" }}
Result: map[_1:b _2:c _4:e]
mergedst, srcCopies all src elements into dst, if dst corresponding elements are empty. Returns dst
{{$a := dict "a" 1 "b" 2}}{{merge $a (dict "a" 88 "c" 5)}}
Result: map[a:1 b:2 c:5]
mustMergedst, srcCopies all src elements into dst, if dst corresponding elements are empty. Returns dst, fails on error
{{$a := dict "a" 1 "b" 2}}{{mustMerge $a (dict "a" 88 "c" 5)}}
Result: map[a:1 b:2 c:5]
mergeOverwritedst, srcCopies all src elements into dst, overwriting corresponding existing dst elements. Returns dst
{{$a := dict "a" 1 "b" 2}}{{mergeOverwrite $a (dict "a" 88 "c" 5)}}
Result: map[a:88 b:2 c:5]
mustMergeOverwritedst, srcCopies all src elements into dst, overwriting corresponding existing dst elements. Returns dst, fails on error
{{$a := dict "a" 1 "b" 2}}{{mustMergeOverwrite $a (dict "a" 88 "c" 5)}}
Result: map[a:88 b:2 c:5]
append,pushlist, valueAppends value to list. Returns list
{{$l := until 5}}{{append $l "hello!"}}
Result: [0 1 2 3 4 hello!]
prependlist, valuePrepends value to list. Returns list
{{$l := until 5}}{{prepend $l "hello!"}}
Result: [hello! 0 1 2 3 4]
firstlistFirst value of list
{{ first (until 5) }}
Result: 0
lastlistLast value of list
{{ last (until 5) }}
Result: 4
restlistTail of list (everything but first item)
{{ rest (until 5) }}
Result: [1 2 3 4]
initiallist“Head” of list (everything but last item)
{{ initial (until 5) }}
Result: [0 1 2 3]
reverselistReversed copy of list
{{ reverse (until 5) }}
Result: [4 3 2 1 0]
uniqlistUnique values of list
{{ uniq (splitList "," "a,b,c,a,a,d,b") }}
Result: [a b c d]
withoutlist, el1, el2, …Copy of list, without any el* element
{{ without (until 7) 3 4 }}
Result: [0 1 2 5 6]
hasitem, listTrue if list contains item
{{ has 2 (until 7) }}
Result: true
slicelist, start, [end]Returns a subset of list, starting from start index (inclusive) up to end index (exclusive)
{{ slice (splitList "," "a,b,c,d,e,f") 1 4 }}
Result: [b c d]
concatlist1, list2, …Returns a list made of all elements of all list* lists
{{ concat (until 5) (until 3) (until 2) }}
Result: [0 1 2 3 4 0 1 2 0 1]

Regular expressions

Function nameArgsOutputExample
regexMatchregex, textTrue if regex matches text, false on error
{{ regexMatch "[Hh]ello!" "hello!" }}
Result: true
mustRegexMatchregex, textTrue if regex matches text, fails on error
{{ regexMatch "[Hh]ello!" "hello!" }}
Result: true
regexFindregex, textReturns the first match of regex in text
{{ regexFind "se\\w+" "Unforseen consequences" }}
Result: seen
regexFindAllregex, text, nReturns all matches of regex in text, with max n matches
{{ regexFindAll "se\\w+" "Unforseen consequences see?" 2 }}
Result: [seen sequences]
regexReplaceAllregex, text, replReplaces all matches of regex in text with repl
{{ regexReplaceAll "se(\\w+)" "Unforseen consequences" "be$1" }}
Result: Unforbeen conbequences
regexReplaceAllLiteralregex, text, replReplaces all matches of regex in text with repl without using values expansion
{{ regexReplaceAllLiteral "se(\\w+)" "Unforseen consequences" "be$1" }}
Result: Unforbe$1 conbe$1
regexSplitregex, text, nSplits text using regex as delimiter, with max n substrings
{{ dump (regexSplit "a*" "abaabaccadaaae" 5) }}
Result:
- ""
- b
- b
- c
- cadaaae

Semantic version

Note: this chapter was originally written by Sprig library’s authors .

Some version schemes are easily parseable and comparable. Sprig provides functions for working with SemVer 2  versions.

semver

The semver function parses a string into a Semantic Version:

$version := semver "1.2.3-alpha.1+123"

If the parser fails, it will cause template execution to halt with an error.

At this point, $version is a pointer to a Version object with the following properties:

  • $version.Major: The major number (1 above)
  • $version.Minor: The minor number (2 above)
  • $version.Patch: The patch number (3 above)
  • $version.Prerelease: The prerelease (alpha.1 above)
  • $version.Metadata: The build metadata (123 above)
  • $version.Original: The original version as a string

Additionally, you can compare a Version to another version using the Compare function:

semver "1.4.3" | (semver "1.2.3").Compare

The above will return -1.

The return values are:

  • -1 if the given semver is greater than the semver whose Compare method was called
  • 1 if the version who’s Compare function was called is greater.
  • 0 if they are the same version

(Note that in SemVer, the Metadata field is not compared during version comparison operations.)

semverCompare

A more robust comparison function is provided as semverCompare. This version supports version ranges:

  • semverCompare "1.2.3" "1.2.3" checks for an exact match
  • semverCompare "^1.2.0" "1.2.3" checks that the major and minor versions match, and that the patch number of the second version is greater than or equal to the first parameter.

The SemVer functions use the Masterminds semver library , from the creators of Sprig.

Basic Comparisons

There are two elements to the comparisons. First, a comparison string is a list of space or comma separated AND comparisons. These are then separated by || (OR) comparisons. For example, ">= 1.2 < 3.0.0 || >= 4.2.3" is looking for a comparison that’s greater than or equal to 1.2 and less than 3.0.0 or is greater than or equal to 4.2.3.

The basic comparisons are:

  • =: equal (aliased to no operator)
  • !=: not equal
  • >: greater than
  • <: less than
  • >=: greater than or equal to
  • <=: less than or equal to

Note, according to the Semantic Version specification pre-releases may not be API compliant with their release counterpart. It says,

Working With Prerelease Versions

Pre-releases, for those not familiar with them, are used for software releases prior to stable or generally available releases. Examples of prereleases include development, alpha, beta, and release candidate releases. A prerelease may be a version such as 1.2.3-beta.1 while the stable release would be 1.2.3. In the order of precedence, prereleases come before their associated releases. In this example 1.2.3-beta.1 < 1.2.3.

According to the Semantic Version specification prereleases may not be API compliant with their release counterpart. It says,

A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version.

SemVer comparisons using constraints without a prerelease comparator will skip prerelease versions. For example, >=1.2.3 will skip prereleases when looking at a list of releases while >=1.2.3-0 will evaluate and find prereleases.

The reason for the 0 as a pre-release version in the example comparison is because pre-releases can only contain ASCII alphanumerics and hyphens (along with . separators), per the spec. Sorting happens in ASCII sort order, again per the spec. The lowest character is a 0 in ASCII sort order (see an ASCII Table )

Understanding ASCII sort ordering is important because A-Z comes before a-z. That means >=1.2.3-BETA will return 1.2.3-alpha. What you might expect from case sensitivity doesn’t apply here. This is due to ASCII sort ordering which is what the spec specifies.

Hyphen Range Comparisons

There are multiple methods to handle ranges and the first is hyphens ranges. These look like:

  • 1.2 - 1.4.5 which is equivalent to >= 1.2 <= 1.4.5
  • 2.3.4 - 4.5 which is equivalent to >= 2.3.4 <= 4.5

Wildcards In Comparisons

The x, X, and * characters can be used as a wildcard character. This works for all comparison operators. When used on the = operator it falls back to the patch level comparison (see tilde below). For example,

  • 1.2.x is equivalent to >= 1.2.0, < 1.3.0
  • >= 1.2.x is equivalent to >= 1.2.0
  • <= 2.x is equivalent to < 3
  • * is equivalent to >= 0.0.0

Tilde Range Comparisons (Patch)

The tilde (~) comparison operator is for patch level ranges when a minor version is specified and major level changes when the minor number is missing. For example,

  • ~1.2.3 is equivalent to >= 1.2.3, < 1.3.0
  • ~1 is equivalent to >= 1, < 2
  • ~2.3 is equivalent to >= 2.3, < 2.4
  • ~1.2.x is equivalent to >= 1.2.0, < 1.3.0
  • ~1.x is equivalent to >= 1, < 2

Caret Range Comparisons (Major)

The caret (^) comparison operator is for major level changes once a stable (1.0.0) release has occurred. Prior to a 1.0.0 release the minor versions acts as the API stability level. This is useful when comparisons of API versions as a major change is API breaking. For example,

  • ^1.2.3 is equivalent to >= 1.2.3, < 2.0.0
  • ^1.2.x is equivalent to >= 1.2.0, < 2.0.0
  • ^2.3 is equivalent to >= 2.3, < 3
  • ^2.x is equivalent to >= 2.0.0, < 3
  • ^0.2.3 is equivalent to >=0.2.3 <0.3.0
  • ^0.2 is equivalent to >=0.2.0 <0.3.0
  • ^0.0.3 is equivalent to >=0.0.3 <0.0.4
  • ^0.0 is equivalent to >=0.0.0 <0.1.0
  • ^0 is equivalent to >=0.0.0 <1.0.0

Sprig - unavailable functions

If you use the Sprig  library in other projects, you may want to know that the following functions have been disabled for security/performance/non-usefulness reasons:

  • fail: if you want a template to not render, please use a trigger condition
  • env
  • expandenv
  • getHostByName
  • base
  • dir
  • clean
  • ext
  • isAbs
  • genPrivateKey
  • derivePassword
  • buildCustomCert
  • genCA
  • genSelfSignedCert
  • genSignedCert
  • encryptAES
  • decryptAES
  • uuidv4

Legacy functions

These functions are available for reference, for historical reasons:

ParseJSON

Parses a JSON string to a map.

Template Payload
{{ $content := .value | ParseJSON }}
Hello {{ $content.name }}!
{
  "value": "{\"name\": \"Mr. Anderson\"}"
}
Rendered
Hello Mr. Anderson!

ParseYAML

Parses a YAML string to a map.

Template Payload
{{ $content := .value | ParseYAML }}
Hello {{ $content.name }}!
{
  "value": "name: Mr. Anderson"
}
Rendered
Hello Mr. Anderson!

GetTimeNow

Returns the current time (UTC) as a time.Time  element, which can be formatted as desired, following Go language time formatting  convention (more examples ).

Template
{{ $time := GetTimeNow -}}

ISO 8601: {{ $time.Format "2006-01-02T15:04:05" }} / yyyy-MM-dd'T'HH:mm:ss
ISO 8601: {{ $time.Format "2006-01-02T15:04:05-0700" }} / yyyy-MM-dd'T'HH:mm:ssZ	
{{ $time.Format "2 Jan 2006 15:04:05" }} / d MMM yyyy HH:mm:ss				
RFC 822: {{ $time.Format "Mon, 2 Jan 2006 15:04:05 MST" }} / EEE, d MMM yyyy HH:mm:ss z
Rendered
ISO 8601: 2019-11-22T16:02:06 / yyyy-MM-dd'T'HH:mm:ss
ISO 8601: 2019-11-22T16:02:06+0000 / yyyy-MM-dd'T'HH:mm:ssZ	
22 Nov 2019 16:02:06 / d MMM yyyy HH:mm:ss				
RFC 822: Fri, 22 Nov 2019 16:02:06 UTC / EEE, d MMM yyyy HH:mm:ss z

Parse unix time

Parses the input value to a time.Time  element.

Template Payload
Result: {{ .result }}!
 
{{ $parsedTimeMs := .timeMs | ParseUnixTimeMs -}}
Time (milliseconds): {{ $parsedTimeMs.String }}

{{ $parsedTimeSeconds := .time | ParseUnixTime -}}
Time (seconds): {{ $parsedTimeSeconds.String }}

We can parse also a string: {{ .timeStr | ParseUnixTime }}
{
  "result": "success",
  
  "timeMs": 1549049482225,
  "time": 1549049482,
  
  "timeStr": "1549049482"
}
Rendered
Result: success!
 
Time (milliseconds): 2019-02-01 21:31:22.225 +0200 EET

Time (seconds): 2019-02-01 21:31:22 +0200 EET

We can parse also a string: 2019-02-01 21:31:22 +0200 EET

Base64 encode/decode

Template
The message says "{{ .valueBase64Std | Base64Decode }}".

I'd like to answer back with "{{ "Hello to you too!" | Base64Encode }}"! 
    
What do we have here? {{ .valueBase64URL | Base64DecodeURL }}
Rendered
The message says "Hello 🐄".

I'd like to answer back with "SGVsbG8gdG8geW91IHRvbyE="! 
    
What do we have here? Oh! Special chars 😁
Payload
{
  "valueBase64Std": "SGVsbG8g8J+QhA=",
  "valueBase64URL": "T2ghIFNwZWNpYWwgY2hhcnMg8J-YgQ="
}

Notify17 also supports encoding/decoding URL-safe base64  with Base64EncodeURL and Base64DecodeURL.