Built-in Functions
Probe evaluates expressions with expr-lang/expr (v1.17). Every function on this page is either a built-in of that language or a function Probe registers on top of it.
Overview
Expressions appear in two shapes:
- Template expressions - a
{{ ... }}placeholder inside a string, replaced by the evaluated value. - Boolean expressions - a bare expression, evaluated as a condition.
Where Expressions Can Be Used
| Level | Field | Template | Boolean | Notes |
|---|---|---|---|---|
| workflow | vars | Yes | - | Global variables. Environment variables are referenced by bare name here |
| job | name | Yes | - | Job name |
| job | skipif | - | Yes | Skip condition for the job |
| step | name | Yes | - | Step name |
| step | with | Yes | - | Action arguments |
| step | test | - | Yes | Assertion |
| step | echo | Yes | - | Report output |
| step | vars | Yes | - | Step variables |
| step | outputs | Yes | - | Values shared with later steps and jobs |
| step | skipif | - | Yes | Skip condition for the step |
Syntax
Functions are called directly, or chained with the pipe operator. The pipe passes the left-hand value as the first argument.
vars:
service: "{{SERVICE_NAME | upper}}"
slug: "{{replace(lower(SERVICE_NAME), ' ', '-')}}"
path: "{{BASE_URL | trimSuffix('/')}}/api"Arithmetic and comparison use operators, not functions: +, -, *, /, %, **, ==, !=, <, >, &&, ||, !, ?? (nil coalescing), in, contains, startsWith, endsWith, matches (regular expression).
test: |
res.code == 200 &&
res.body.status contains "ok" &&
rt.sec < 1Probe Functions
These functions are registered by Probe itself.
match_json
Compares two objects strictly. Every key and value must match on both sides - extra or missing keys make it fail.
Syntax: match_json(src, target)
Returns: Boolean
test: match_json(res.body, {"status": "ok", "count": 3})diff_json
Compares two objects the same way as match_json and describes the differences. Returns the string No diff when they match.
Syntax: diff_json(src, target)
Returns: String
echo: "{{diff_json(res.body, vars.expected)}}"parse_json
Parses a JSON string into an object.
Syntax: parse_json(string)
Returns: Any
outputs:
meta: "{{parse_json(res.body.metadata)}}"
test: parse_json(res.body.metadata).version == "1.0"parse_int
Converts a string or a number to a 64-bit integer. Fails on a string that is not a base-10 integer.
Syntax: parse_int(value)
Returns: Integer
test: parse_int(res.headers["Content-Length"]) > 0parse_float
Converts a string to a floating-point number.
Syntax: parse_float(string)
Returns: Float
test: parse_float(res.body.score) >= 8.5encode_base64
Encodes a string with standard base64.
Syntax: encode_base64(string)
Returns: String
with:
headers:
Authorization: "Basic {{encode_base64(vars.user + ':' + vars.pass)}}"decode_base64
Decodes a standard base64 string.
Syntax: decode_base64(string)
Returns: String
outputs:
payload: "{{decode_base64(res.body.data)}}"unixtime
Returns the current time as a Unix timestamp in seconds.
Syntax: unixtime()
Returns: Integer
with:
headers:
X-Timestamp: "{{unixtime()}}"random_int
Returns a random integer in the range [0, n). n must be positive.
Syntax: random_int(n)
Returns: Integer
with:
url: "{{vars.base_url}}/test?seed={{random_int(1000)}}"random_str
Returns a random alphanumeric string of the given length ([a-zA-Z0-9], at most 1000000 characters).
Syntax: random_str(length)
Returns: String
vars:
email: "user-{{random_str(8)}}@example.com"String Functions
| Function | Description |
|---|---|
upper(s) | Uppercase |
lower(s) | Lowercase |
trim(s) / trim(s, chars) | Strip whitespace, or the given characters, from both ends |
trimPrefix(s, prefix) | Strip a leading prefix |
trimSuffix(s, suffix) | Strip a trailing suffix |
replace(s, old, new) | Replace every occurrence |
split(s, sep) / split(s, sep, n) | Split into an array |
splitAfter(s, sep) | Split, keeping the separator on each element |
join(array, sep) | Join an array into a string |
repeat(s, n) | Repeat a string |
indexOf(s, sub) | Index of the first occurrence, or -1 |
lastIndexOf(s, sub) | Index of the last occurrence, or -1 |
hasPrefix(s, prefix) | Prefix test |
hasSuffix(s, suffix) | Suffix test |
len(s) | Length in bytes |
vars:
host: "{{trimPrefix(API_URL, 'https://')}}"
slug: "{{replace(lower(TITLE), ' ', '-')}}"
test: hasSuffix(res.body.filename, ".json")contains, startsWith, endsWith and matches are operators rather than functions:
test: |
res.headers["Content-Type"] contains "application/json" &&
res.body.id matches "^[0-9a-f]{8}"Number Functions
| Function | Description |
|---|---|
abs(n) | Absolute value |
ceil(n) | Round up |
floor(n) | Round down |
round(n) | Round to the nearest integer |
max(a, b, ...) | Largest value |
min(a, b, ...) | Smallest value |
sum(array) | Sum of an array |
mean(array) | Arithmetic mean |
median(array) | Median |
bitnot(n) | Bitwise NOT |
There is no add / sub / mul / div / mod function - use the operators instead.
outputs:
seconds: "{{round(rt.sec)}}"
test: res.body.id % 2 == 0Type Conversion Functions
| Function | Description |
|---|---|
int(v) | Convert to an integer |
float(v) | Convert to a float |
string(v) | Convert to a string |
type(v) | Name of the value’s type, such as string or int |
Probe’s parse_int and parse_float differ from int and float in that they always parse base-10 text and return a 64-bit value.
Date and Time Functions
| Function | Description |
|---|---|
now() | Current time as a time value |
date(s) / date(s, layout) / date(s, layout, tz) | Parse a string into a time value |
duration(s) | Parse a duration such as "1h30m" |
timezone(name) | Look up a location such as "UTC" or "Asia/Tokyo" |
now() returns a time value, not a number. Format it with Go layouts through Format, or take a Unix timestamp with Unix() - or use Probe’s unixtime().
outputs:
today: "{{now().Format('2006-01-02')}}"
started_at: "{{now().Format('2006-01-02T15:04:05Z07:00')}}"
epoch: "{{unixtime()}}"
test: date(res.body.expires_at) > now()Array and Map Functions
| Function | Description |
|---|---|
len(v) | Number of elements |
first(array) / last(array) | First or last element |
take(array, n) | First n elements |
reverse(array) | Reversed copy |
uniq(array) | Duplicates removed |
concat(a, b, ...) | Concatenate arrays |
flatten(array) | Flatten nested arrays |
sort(array) / sort(array, "desc") | Sort |
sortBy(array, expr) | Sort by a computed key |
groupBy(array, expr) | Group into a map by a computed key |
filter(array, predicate) | Elements matching a predicate |
map(array, expr) | Transform each element |
find(array, predicate) / findLast(array, predicate) | First or last matching element |
findIndex(array, predicate) / findLastIndex(array, predicate) | Index of a matching element |
count(array, predicate) | Number of matching elements |
all / any / one / none | Quantifiers over a predicate |
reduce(array, expr, initial) | Fold an array into a single value |
keys(map) / values(map) | Keys or values of a map |
get(map, key) | Value for a key, or nil |
toPairs(map) / fromPairs(array) | Convert between a map and key/value pairs |
Inside a predicate, # is the current element and #acc is the accumulator of reduce.
test: |
len(res.body.items) > 0 &&
all(res.body.items, #.status == "active")
outputs:
names: "{{join(map(res.body.users, #.name), ', ')}}"
total: "{{reduce(res.body.items, #acc + #.price, 0)}}"JSON and Encoding Functions
| Function | Description |
|---|---|
toJSON(v) | Serialize a value as indented JSON |
fromJSON(s) | Parse a JSON string |
toBase64(s) | Encode with base64 |
fromBase64(s) | Decode base64 |
Note the camel case: there is no tojson or base64. Probe’s parse_json, encode_base64 and decode_base64 cover the same ground with stricter argument checking and Probe’s own error messages.
with:
body: "{{toJSON(outputs.setup.user)}}"
outputs:
version: "{{fromJSON(res.body).version}}"Limits
Expression evaluation is bounded for safety:
- An expression may be at most 1000000 characters long.
- Evaluation times out after 5 seconds.
parse_json,encode_base64anddecode_base64reject an argument longer than 1000000 characters.
See Also
- YAML Configuration - Where each field accepts expressions
- Actions Reference - Action parameters and response objects
- Expressions and Templates - Concepts behind the expression language
- Testing and Assertions - Writing
testexpressions