Tekton’s CEL conditions let you gate whether a Task or PipelineTask runs based on arbitrary expressions.
Let’s see this in action. Imagine a Pipeline that deploys to staging and then, only if a specific Git tag is found, deploys to production.
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: deploy-pipeline
spec:
params:
- name: git-tag
description: The Git tag to deploy.
type: string
default: ""
tasks:
- name: deploy-to-staging
taskRef:
name: deploy-task
params:
- name: environment
value: "staging"
- name: deploy-to-production
taskRef:
name: deploy-task
params:
- name: environment
value: "production"
conditions:
# This is the magic!
- expression: "params.git-tag != ''"
Here, the deploy-to-production task will only execute if the git-tag parameter is not an empty string. We’re using Common Expression Language (CEL) for this. The params.git-tag part accesses the git-tag parameter we defined at the Pipeline level.
This simple != '' condition is super powerful. It means your CI/CD can automatically promote to production only when you explicitly provide a tag, preventing accidental deployments.
The Problem It Solves
Traditionally, you’d achieve this with separate PipelineRuns or complex branching logic within your GitOps tooling. Tekton’s CEL conditions bring this decision-making into the pipeline definition itself. It allows for dynamic control flow based on various inputs:
- Parameters: As seen above, use input parameters to control execution.
- Workspace/Artifacts: Check for the existence or content of files in workspaces.
- Results: Depend on the successful completion and output of previous tasks.
- Custom Resources: Evaluate fields within custom Kubernetes resources.
How It Works Internally
When Tekton evaluates a PipelineRun or TaskRun, it iterates through the tasks. Before starting a task, it checks if any conditions are defined. If conditions exist, it evaluates the expression against the current execution context. This context includes all available params, results, and workspaces.
The CEL engine parses and executes the expression. If the expression evaluates to true, the task proceeds. If it evaluates to false, the task is skipped. Skipped tasks are marked with a Skipped status, and subsequent dependent tasks won’t run.
The Exact Levers You Control
-
expression: This is the core. It’s a CEL string.- Accessing parameters:
params.myParamName - Accessing results:
tasks.previousTaskName.results.myResultName - Accessing workspace files:
workspaces.myWorkspaceName.path(though this is more for checking existence rather than content, direct file content evaluation is complex and less common). - Basic operators:
==,!=,>,<,>=,<=,&&(AND),||(OR),!(NOT). - String functions:
.startsWith(),.endsWith(),.contains(),.matches(). - Type checks:
is(type)(e.g.,is(string)).
- Accessing parameters:
-
separator: (Optional) If you have multiple conditions, this defines how they are combined. The default is&&(all must be true). You can set it to||(any must be true). -
condition: (Deprecated, useexpression) This was the older field name.
Let’s look at a more complex example:
apiVersion: tekton.dev/v1beta1
kind: PipelineTask
metadata:
name: deploy-to-prod-with-approval
spec:
taskRef:
name: deploy-task
params:
- name: environment
value: "production"
conditions:
- expression: "params.git-tag != '' && params.approval-status == 'approved'"
Here, we require both a Git tag to be present and a custom approval-status parameter to be set to approved. This is a common pattern for manual gating in automated pipelines.
The most surprising thing about Tekton’s CEL conditions is how deeply they integrate with Kubernetes’ own API machinery. When you define a PipelineRun or TaskRun, Tekton doesn’t just execute a script; it’s creating and managing Kubernetes resources. The CEL expressions are evaluated by the Kubernetes API server itself (or a component acting on its behalf) as part of the reconciliation loop. This means you’re leveraging robust, battle-tested expression evaluation capabilities directly within your Kubernetes workflow, without needing external webhooks or complex sidecars for simple conditional logic. It’s not just a scripting language; it’s a declarative way to express system state transitions.
The next concept you’ll run into is how to manage multiple, complex conditions and their interactions, often leading to the need for more structured pipeline design patterns.