Notifiers

Notifiers receive every event that passes their when expression — they are not tied to the scm.provider annotation. All support name, enabled, when; message-based ones support template. For most (slack, teams, discord) the template is optional — omit it for the built-in structured message. For email and grafana a template is required (the chart supplies a shipped default when you omit the field). See Templates → Supplying a template.

notifiers:
  slack:
    - name: prod-alerts
      enabled: true
      secretRef:
        name: slack-webhook
      channel: "#prod-alerts"
      when: 'event.Namespace == "production" && stateIn("failure", "error")'
      template: |
        :rotating_light: *{{.PipelineName}}* failed in *{{.Namespace}}*
        Run: {{.RunName}} · Commit: `{{ .CommitSHA | trunc 8 }}`
        {{if .TargetURL}}<{{.TargetURL}}|View logs>{{end}}

Tip: without a when, a notifier fires for every state of every run — including running. Production configs almost always want stateIn("failure", "error") or terminal-states-only.

Slack

Microsoft Teams

Discord

PagerDuty

Datadog

Grafana annotations

Posts a deployment/event marker to the Grafana Annotations API — the vertical line that lets you correlate “the graph changed here” with “we deployed here”.

grafana:
  - name: deploy-markers
    enabled: true
    url: https://grafana.company.example.com
    token:
      secretRef:
        name: grafana-token              # service-account token, key "token"
    tags: ["deploy"]                    # added to: tekton-events-relay, <state>
    # dashboard_uid: abc123             # optional: scope to a dashboard (org-wide when empty)
    # panel_id: 4                       # optional: scope to a panel (requires dashboard_uid)
    when: 'isPipelineRun() && event.PipelineName.startsWith("deploy-") && stateIn("success", "failure")'

The annotation timestamp is the run’s finish time. The marker template is required: in the Helm chart it is supplied inline, via configmapRef, or omitted to use the shipped default (deploy-marker.tmpl, {{.PipelineName}} {{.State}} ({{.RunName}})). See Templates.

Email (SMTP)

Sends pipeline events as email over SMTP (STARTTLS on 587 by default, implicit TLS on 465, or unencrypted in-cluster relays on 25).

email:
  - name: oncall
    enabled: true
    host: smtp.example.com
    from: ci@example.com
    to: ["oncall@example.com"]
    # cc: ["leads@example.com"]          # optional visible carbon-copy
    # bcc: ["audit@example.com"]         # optional blind carbon-copy (envelope only)
    # reply_to: noreply@example.com      # optional Reply-To override
    # subject and template are required; supply inline, via configmapRef,
    # or omit to use the shipped defaults (email-subject.tmpl / email-default.tmpl):
    # subject:
    #   value: "[tekton] {{ .PipelineName }} — {{ .State }}"
    # template:
    #   configmapRef:
    #     name: my-email-templates
    #     key: body.tmpl
    html: false
    when: 'isPipelineRun() && stateIn("failure", "error")'

Sentry releases

Creates a Sentry release (version = CommitSHA, Sentry’s recommended scheme) and marks a deploy to the environment (scm.context annotation, default production) — unlocking “this error first appeared in commit X”. Fires only on success; creating an existing release is an upsert.

sentry:
  - name: sentry
    enabled: true
    org: acme                            # organization slug
    projects: ["api"]
    token:
      secretRef:
        name: sentry-token               # auth token, key "token"
    # base_url: https://sentry.company.example.com   # self-hosted
    when: 'isPipelineRun() && event.PipelineName.startsWith("deploy-")'

Generic webhook

Sends the event as JSON to any HTTP endpoint — the escape hatch for systems without a dedicated notifier.

webhook:
  - name: devlake
    enabled: true
    url:
      secretRef:
        name: devlake-webhook            # key "url"
    headers:
      X-Source: tekton-events-relay
    transform: |
      {pipeline: .pipeline_name, result: .state, sha: .commit_sha,
       startedDate: .started_at, finishedDate: .finished_at}
    when: 'isPipelineRun() && stateIn("success", "failure")'

Jira (issue tracking)

Jira is a top-level jira: integration (sibling of scm: / notifiers:), not a chat notifier — it acts on the work item linked to the run. Each instance has actions of type comment or transition.

jira:
  - name: default
    enabled: true
    base_url: https://yourorg.atlassian.net   # Cloud, or your Data Center URL
    # api_version: "3"                        # "2" (default, plain text) or "3" (Atlassian Document Format)
    auth:
      email: ci@example.com                   # set ⇒ Cloud basic auth; omit ⇒ Data Center bearer (PAT)
      token:
        secretRef:
          name: jira-token                    # API token / PAT, key "token"
    actions:
      - name: result-comment
        type: comment
        enabled: true
        when: 'isPipelineRun() && stateIn("success", "failure", "error")'
        # template:                            # omit for the shipped default (jira-comment.tmpl)
        #   value: |                            # …inline, or
        #     Pipeline {{ .State }}: {{ .PipelineName }}
        #   configmapRef:                       # …from a ConfigMap (name + key)
        #     name: jira-templates
        #     key: comment.tmpl
      - name: mark-done
        type: transition
        enabled: true
        transition: "Done"                    # transition name (case-insensitive) or numeric id
        when: 'isPipelineRun() && event.State == "success"'

Delivery semantics (all notifiers)

Outbound calls go through the shared retry policy (backoff + jitter, Retry-After aware). Failures are visible in /readyz, tekton_events_relay_notifier_retries_total and, for permanent errors with the DLQ enabled, replayable.