You just followed a guide to start your Tekton pipeline (or task) when a merge request is created or updated on your GitLab project. So you configured GitLab to send merge request events as webhooks. And you deployed some Tekton components:
- EventListener: receives webhooks from GitLab
- Trigger: starts your Pipeline every time the EventListener receives a new webhook from GitLab
- Pipeline: fetches the source code from GitLab and builds it
Then you notice that any event in your merge request (a new comment, a tag change) triggers the pipeline. That's not the behavior you desire. You don't need to build a comment or a tag, after all. You only want the pipeline to run when there is actual new code to build. Here's how I use Tekton's CEL Interceptor to create conditionals for my pipelines.
Have your trigger ready
I expect you have a trigger already defined. It's probably something similar to the snippet below.
The trigger's interceptor rejects anything that's not coming from a merge request. Still, the interceptor is not able to differentiate between code and non-code updates (like new comments).
apiVersion: triggers.tekton.dev/v1beta1
kind: Trigger
metadata:
name: webhook-listener-trigger
spec:
interceptors:
# reject any payload that's not a merge request webhook
- name: "filter-event-types"
ref:
name: "gitlab"
kind: ClusterInterceptor
params:
- name: eventTypes
value:
- "Merge Request Hook"
bindings:
- ref: binding
template:
ref: template
Add a CEL interceptor
Here comes the cel
interceptor. This interceptor filters the webhook payload using the CEL expression language. If the filter expression evaluates to true
, the pipeline starts.
Here I'm checking for the object_attributes.oldrev
field to exist in the JSON body of the webhook payload. If object_attributes.oldrev
exists, then that means this event is about a code change. If there wasn't a code change, there's no previous revision (oldrev
) to refer to.
spec:
interceptors:
- name: "allow-code-changes-only"
ref:
name: cel
kind: ClusterInterceptor
params:
- name: filter
value: >
has(body.object_attributes.oldrev)
Add the new interceptor to your trigger. Now your trigger looks like this:
apiVersion: triggers.tekton.dev/v1beta1
kind: Trigger
metadata:
name: gitlab-listener-trigger
spec:
interceptors:
- name: "verify-gitlab-payload"
ref:
name: "gitlab"
kind: ClusterInterceptor
params:
- name: eventTypes
value:
- "Merge Request Hook"
- name: "allow-code-changes-only"
ref:
name: "cel"
kind: ClusterInterceptor
params:
- name: filter
value: >
has(body.object_attributes.oldrev)
bindings:
- ref: binding
template:
ref: template
Deploy this new version of the trigger and enjoy the powers of automation. From now on, your pipeline only starts if there is some new code to build.
Tips
There are no limits to the conditions you can set in a CEL filter.
You may check that the merge request is currently open:
body.object_attributes.state in ['opened']
You can make sure the contributor finished their work on the code:
body.object_attributes.work_in_progress == false
You just have to concatenate multiple conditions correctly:
- name: filter
value: >
has(body.object_attributes.oldrev) &&
body.object_attributes.state in ['opened'] &&
body.object_attributes.work_in_progress == false
Check out the merge request events documentation to get inspired to write your own conditions.
You may need the CEL language definition to know how to translate your thoughts into code.
To evaluate types other than strings, you want to know the mapping between JSON and CEL types.
Comments are closed.