Yong Wei Lun
Cloud Zone

Cloud Zone

Tekton CI/CD Part 3: Building custom Interceptor for Triggers

Photo by Fleur on Unsplash

Tekton CI/CD Part 3: Building custom Interceptor for Triggers

Trigger pipeline based on path changes from last commit

Yong Wei Lun's photo
Yong Wei Lun
·Mar 31, 2022·

4 min read

Table of contents

On previous post, we have built Triggers that will react to push events.


However, if we were using monorepo, we would like to trigger different Pipeline build based on the path change

For example the repository like this

|-- ui/
|-- backend/
|-- tools/

When changes on ui are detected, it will only trigger the Pipeline for ui

Solution 1: use another CI to trigger tekton

We could use another CI that supports this, for example

Write the path changes on the CI, and trigger Tekton

For example, on GitHub Actions

      - 'main'
      - 'my-project/**'
    runs-on: ubuntu-latest
      - name: Trigger Tekton
        run: curl -X POST --data '{}' https://trigger-tekton.example.com

On Tekton, we need to add an listener

apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
  name: general-listener
  serviceAccountName: tekton-triggers-example-sa
    - name: push-trigger
      - ref: push-binding
        ref: simple-pipeline-template

Add TriggerBinding with hard-coded values

branch can be dynamically set, but that requires to write custom ClusterInterceptor, more on solution 2

apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerBinding
  name: push-binding
  namespace: tekton
    - name: git_branch
      value:  main
    - name: git_url
      value: https://github.com/tektoncd/triggers

this only handles one project inside monorepo, we need to repeat the process (some files can be reuse, eg TriggerBinding) if we have more than one projects to be deployed on a monorepo

Solution 2: implement custom ClusterInterceptor

This solution will not depends on another CI service, but will need to write ClusterInterceptor. A ClusterInterceptor must meet the following requirements

I have written a ClusterInterceptor, which will get the file changes based on last commit, and match with the glob pattern on the config

Check out the examples directory for Tekton complete example

How it works

The ClusterInterceptor will do the following when it is called by Tekton Triggers

1. clone

It will clone the repository with --depth 2 to save time and network bandwidth

2. diff

It will run git diff, to get the file changes from last commit

git --no-pager diff --name-only HEAD^

# example output

3. match

It will match the file changes based on glob pattern on config

example of config.yaml

    # can be http format or ssh format
    url: https://github.com/WLun001/path-change 
      # only match of if files inside examples directory
      - "examples/**"


if match: set the continue field in the response to true.

  "extensions": {
    "paths": "MATCH"
  "continue": true,
  "status": {}

if not match: set the continue field to false

  "extensions": {
    "paths": "NOT_MATCH"
  "continue": false,
  "status": {}

The response will be interpret by Tekton

How to use

Check out the examples directory for Tekton complete example

Deploy path-change

Checkout the example deployment on examples directory.

For git credentials, it works with any git credentials, just need to bind the volume to the deployment. The example is showing ssh credentials

After deploy path-change, we need to add ClusterInterceptor to reference it

apiVersion: triggers.tekton.dev/v1alpha1
kind: ClusterInterceptor
  name: path-change-interceptor
      name: path-change
      namespace: tekton

And we can use it on EventListener, and set the repo that we are interested at at params field

For example, if we specify demo as our repo, based on the config on previous example, it will check against https://github.com/WLun001/path-change and with path that match "examples/**" pattern

apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
    - name: push-trigger
        - ref:
            # here we can use our custom ClusterInterceptor
            name: path-change-interceptor
            kind: ClusterInterceptor
           # on params, put the repo we would like to check with
            - name: repo
              value: demo # this will map the values in config.yaml

After deploy everything, we could do a test

Test it out

Do a port forward

kubectl port-forward -n tekton service/el-simple-listener 8080

Test it locally

Send example payload

The response status code should be 202 Accepted

HMAC tool used to create X-Hub-Signature.

curl -v \
-H 'X-GitHub-Event: push' \
-H 'X-Hub-Signature: sha1=87b1adbb9aca10522739f9f94d372afd1542e498' \
-H 'Content-Type: application/json' \
-d '{"ref": "refs/heads/main", "repository": {"git_url": "https://github.com/WLun001/cncf-demo.git"}}' \

You should see a new PipelineRun is running

Test with GitHub

Create a tunnel using tools like ngrok

ngrok http 8080

Add the generated URL to Payload URL

Make commit that match the path pattern and push, you should see a new PipelineRun is running


Dealing with monorepo

Back to our problem, to solve it, we can create a config.yaml that specify all the paths pattern and git url, and create different EventListener and Webhook for each apps

For example, we would create 3 EventListeners and Webhooks in order to trigger the correct Pipelines for ui, backend and tools.

|-- ui
|-- backend/
|-- tools/


Tekton is very powerful with its extensibility, it might feel complex at the first sight, but in a long run really worth to invest time on it,

We have built a custom ClusterInterceptor that works well with Tekton Triggers, and solve our problems with monorepo.

Next, we will look at advanced use case of Tekton Pipelines, running Docker-Compose on Pipelines

Did you find this article valuable?

Support Yong Wei Lun by becoming a sponsor. Any amount is appreciated!

Learn more about Hashnode Sponsors
Share this