Skip to content

CEL Expressions

Fábio Luciano edited this page Jun 11, 2026 · 2 revisions

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.PRNumber is an int — compare with numbers (!= 0), or just use isPR().
  • matches() is RE2: no lookaheads/backreferences.

Clone this wiki locally