CEL Expressions
Every action and notifier accepts a when expression in CEL. The expression must return a boolean; the handler only runs when it evaluates to true. An empty/absent when means “always”.
when: 'event.Namespace == "production" && stateIn("failure", "error")'
Expressions are compiled at startup (and on hot reload) — an invalid expression fails fast, never at event time.
The event object
All fields of the neutral event are available under event.:
| Field | Type | Notes |
|---|---|---|
event.Resource | string | taskrun, pipelinerun, customrun, eventlistener |
event.State | string | pending, running, success, failure, error, canceled, done |
event.Provider | string | From the scm.provider annotation |
event.RunName / event.RunID | string | Resource name / UID |
event.Namespace | string | Kubernetes namespace |
event.PipelineName / event.TaskName | string | Referenced Pipeline/Task spec names |
event.PipelineTaskName | string | Task name within the pipeline |
event.PipelineDisplayName / event.TaskDisplayName | string | Display names, if set |
event.TriggerName / event.EventListenerName | string | Tekton Triggers metadata |
event.TaskCount | int | Child tasks of a PipelineRun |
event.CommitSHA | string | |
event.Context / event.Description / event.TargetURL | string | Check name / human message / dashboard link |
event.APIBaseURL | string | Per-run API override |
event.Repo.Owner / .Name / .ID / .Workspace / .Project / .Org | string | Repository identifiers |
event.PRNumber / event.IssueNumber / event.DiscussionNumber | int | 0 when absent |
event.IsFinallyTask | bool | Task belongs to a finally block |
event.SCMEventType | string | Originating webhook type (push, pull_request, …) when known |
event.Results | map[string]string | Tekton results by name, e.g. event.Results["IMAGE_DIGEST"] |
event.StartedAt / event.FinishedAt | timestamp | Comparable: event.FinishedAt > event.StartedAt |
Plus the CEL standard library: startsWith(), endsWith(), contains(), matches() (RE2), in, arithmetic, ternaries, etc.
Built-in macros
Shorthand helpers that expand to common checks:
| Macro | Expands to |
|---|---|
isTaskRun() / isPipelineRun() / isCustomRun() / isEventListener() | event.Resource == "…" |
isPR() | event.PRNumber != 0 |
isIssue() | issue number set, PR and discussion unset |
isDiscussion() | event.DiscussionNumber != 0 |
isFinallyTask() | event.IsFinallyTask == true |
isPushEvent() / isPREvent() / isIssueEvent() / isCommentEvent() | event.SCMEventType == "push" / "pull_request" / "issues" / "issue_comment" |
stateIn("a", "b", …) | event.State in ["a", "b", …] |
Recipes
Only production failures:
when: 'event.Namespace == "production" && stateIn("failure", "error")'
Terminal states of pipeline runs (skip per-task noise):
when: 'isPipelineRun() && stateIn("success", "failure", "error", "canceled")'
PRs of one team’s repos:
when: 'isPR() && (event.Repo.Owner == "payments" || event.Repo.Name.startsWith("pay-"))'
Deploy pipelines only:
when: 'isPipelineRun() && event.PipelineName.matches("^deploy-.*")'
Skip finally cleanup tasks:
when: 'isTaskRun() && !isFinallyTask()'
Only when the pipeline produced an image:
when: 'event.Results["IMAGE_DIGEST"] != ""'
Per-team Slack routing (one notifier instance per team):
notifiers:
slack:
- name: payments-alerts
channel: "#payments-alerts"
when: 'event.Repo.Owner == "payments" && stateIn("failure", "error")'
- name: platform-alerts
channel: "#platform-alerts"
when: 'event.Repo.Owner == "platform" && stateIn("failure", "error")'
Pitfalls
- Quote the whole expression in YAML (single quotes) — inner string literals use double quotes.
- States are lowercase strings:
"failure", not"Failed". event.PRNumberis anint— compare with numbers (!= 0), or just useisPR().matches()is RE2: no lookaheads/backreferences.