Authoring PipelineRuns in .tekton/
directory
#
Pipelines-as-Code will always try to be as close to the tekton template as possible. Usually you will write your template and save them with a
.yaml
extension and Pipelines-as-Code will run them.The
.tekton
directory must be at the top level of the repo. You can reference YAML files in other repos using remote URLs (see Remote HTTP URLs for more information), but PipelineRuns will only be triggered by events in the repository containing the.tekton
directory.Using its resolver Pipelines-as-Code will try to bundle the PipelineRun with all its Task as a single PipelineRun with no external dependencies.
Inside your pipeline you need to be able to check out the commit as received from the webhook by checking it out the repository from that ref. Most of the time you want to reuse the git-clone task from the tektoncd/catalog.
To be able to specify the parameters of your commit and URL, Pipelines-as-Code allows you to have those “dynamic” variables expanded. Those variables look like this
{{ var }}
and those are the one you can use:
Variable | Description | Example | Example Output |
---|---|---|---|
body | The full payload body (see below) | {{body.pull_request.user.email }} | email@domain.com |
event_type | The event type (eg: pull_request or push ) | {{event_type}} | pull_request |
git_auth_secret | The secret name auto generated with provider token to check out private repos. | {{git_auth_secret}} | pac-gitauth-xkxkx |
headers | The request headers (see below) | {{headers['x-github-event']}} | push |
pull_request_number | The pull or merge request number, only defined when we are in a pull_request event type. | {{pull_request_number}} | 1 |
repo_name | The repository name. | {{repo_name}} | pipelines-as-code |
repo_owner | The repository owner. | {{repo_owner}} | openshift-pipelines |
repo_url | The repository full URL. | {{repo_url}} | https:/github.com/repo/owner |
revision | The commit full sha revision. | {{revision}} | 1234567890abcdef |
sender | The sender username (or accountid on some providers) of the commit. | {{sender}} | johndoe |
source_branch | The branch name where the event come from. | {{source_branch}} | main |
source_url | The source repository URL from which the event come from (same as repo_url for push events). | {{source_url}} | https:/github.com/repo/owner |
target_branch | The branch name on which the event targets (same as source_branch for push events). | {{target_branch}} | main |
target_namespace | The target namespace where the Repository has matched and the PipelineRun will be created. | {{target_namespace}} | my-namespace |
- For Pipelines-as-Code to process your
PipelineRun
, you must have either an embeddedPipelineSpec
or a separatePipeline
object that references a YAML file in the.tekton
directory. The Pipeline object can includeTaskSpecs
, which may be defined separately as Tasks in another YAML file in the same directory. It’s important to give eachPipelineRun
a unique name to avoid conflicts. PipelineRuns with duplicate names will never be matched.
Matching an event to a PipelineRun #
Each PipelineRun
can match different Git provider events through some special
annotations on the PipelineRun
. For example when you have these metadatas in
your PipelineRun
:
metadata:
name: pipeline-pr-main
annotations:
pipelinesascode.tekton.dev/on-target-branch: "[main]"
pipelinesascode.tekton.dev/on-event: "[pull_request]"
Pipelines-as-Code
will match the pipelinerun pipeline-pr-main
if the Git
provider events target the branch main
and it’s coming from a [pull_request]
Multiple target branch can be specified separated by comma, i.e:
[main, release-nightly]
You can match on pull_request
events as above, and you can as well match
pipelineRuns on push
events to a repository
For example this will match the pipeline when there is a push to a commit in the
main
branch :
metadata:
name: pipeline-push-on-main
annotations:
pipelinesascode.tekton.dev/on-target-branch: "[refs/heads/main]"
pipelinesascode.tekton.dev/on-event: "[push]"
You can specify the full refs like refs/heads/main
or the shortref like
main
. You can as well specify globs, for example refs/heads/*
will match any
target branch or refs/tags/1.*
will match all the tags starting from 1.
.
A full example for a push of a tag :
metadata:
name: pipeline-push-on-1.0-tags
annotations:
pipelinesascode.tekton.dev/on-target-branch: "[refs/tags/1.0]"
pipelinesascode.tekton.dev/on-event: "[push]"
This will match the pipeline pipeline-push-on-1.0-tags
when you push the 1.0
tags into your repository.
Matching annotations are currently mandated or Pipelines-as-Code
will not
match your PipelineRun
.
If there are multiple pipelinerun matching an event, it will run all of them in parallel and posting the results to the provider as soon the PipelineRun finishes.
The matching on payload can only occur on the events Pipelines-as-Code responds too, it will only be matched when aPull Request
is opened or updated or on aPush
to a branch
Advanced event matching #
If you need to do some advanced matching, Pipelines-as-Code
supports CEL
filtering.
If you have the pipelinesascode.tekton.dev/on-cel-expression
annotation in
your PipelineRun, the CEL expression will be used and the on-target-branch
or
on-target-branch
annotations will be skipped.
This example will match a pull_request
event targeting the branch main
coming from a branch called wip
:
pipelinesascode.tekton.dev/on-cel-expression: |
event == "pull_request" && target_branch == "main" && source_branch == "wip"
The fields available are :
event
:push
orpull_request
target_branch
: The branch we are targeting.source_branch
: The branch where this pull_request come from. (onpush
this is the same astarget_branch
).target_url
: The URL of the repository we are targeting.source_url
: The URL of the repository where this pull_request come from. (onpush
this is the same astarget_url
).event_title
: Match the title of the event. When doing a push this will match the commit title and when matching on PR it will match the Pull or Merge Request title. (onlyGitHub
,Gitlab
andBitbucketCloud
providers are supported)body
: The full body as passed by the Git provider. (example:body.pull_request.number
will get the pull request number on GitHub)headers
: The full set of headers as passed by the Git provider. (example:headers['x-github-event']
will get the event type on GitHub).pathChanged
: a suffix function to a string which can be a glob of a path to check if changed (onlyGitHub
andGitlab
provider is supported)
Compared to the simple “on-target” annotation matching, the CEL expression allows you to complex filtering and most importantly express negation.
For example if I want to have a PipelineRun
targeting a pull_request
but
not the experimental
branch I would have :
pipelinesascode.tekton.dev/on-cel-expression: |
event == "pull_request" && target_branch != experimental"
You can find more information about the CEL language spec here :
https://github.com/google/cel-spec/blob/master/doc/langdef.md
Matching PipelineRun by path change #
If you want to have a PipelineRun running only if a path has
changed you can use the .pathChanged
suffix function with a glob
pattern. Here
is a concrete example matching every markdown files (as files who has the .md
suffix) in the docs
directory :
pipelinesascode.tekton.dev/on-cel-expression: |
event == "pull_request" && "docs/*.md".pathChanged()
Matching PipelineRun on event title #
This example will match all pull request starting with the title [DOWNSTREAM]
:
pipelinesascode.tekton.dev/on-cel-expression: |
event == "pull_request && event_title.startsWith("[DOWNSTREAM]")
The event title will be the pull request title on pull_request
and the
commit title on push
Matching PipelineRun on body payload #
The payload body as passed by the Git provider is available in the CEL
variable as body
and you can use this expression to do any filtering on
anything the Git provider is sending over:
For example this expression when run on GitHub:
pipelinesascode.tekton.dev/on-cel-expression: |
body.pull_request.base.ref == "main" &&
body.pull_request.user.login == "superuser" &&
body.action == "synchronize"
will only match if the pull request is targeting the main
branch, the author
of the pull request is called superuser
and the action is synchronize
(ie:
an update occurred on a pull request)
Matching PipelineRun on request header #
You can do some further filtering on the headers as passed by the Git provider
with the CEL variable headers
.
The headers are available as a list and are always in lower case.
For example this is how to make sure the event is a pull_request on GitHub:
pipelinesascode.tekton.dev/on-cel-expression: |
headers['x-github-event'] == "pull_request"
Using the body and headers in a Pipelines-as-Code parameter #
Pipelines-as-Code let you access the full body and headers of the request as a CEL expression.
This allows you to go beyond the standard variables and even play with multiple conditions and variable to output values.
For example if you want to get the title of the Pull Request in your PipelineRun you can simply access it like this:
{{ body.pull_request.title }}
You can then get creative and for example mix the variable inside a python script to evaluate the json.
This task for example is using python and will check the labels on the PR,
exit 0
if it has the label called ‘bug’ on the pull request or exit 1
if it
doesn’t:
taskSpec:
steps:
- name: check-label
image: registry.access.redhat.com/ubi9/ubi
script: |
#!/usr/bin/env python3
import json
labels=json.loads("""{{ body.pull_request.labels }}""")
for label in labels:
if label['name'] == 'bug':
print('This is a PR targeting a BUG')
exit(0)
print('This is not a PR targeting a BUG :(')
exit(1)
The expression are CEL expressions so you can as well make some conditional:
- name: bash
image: registry.access.redhat.com/ubi9/ubi
script: |
if {{ body.pull_request.state == "open" }}; then
echo "PR is Open"
fi
if the PR is open the condition then return true
and the shell script see this
as a valid boolean.
Headers from the payload body can be accessed from the headers
keyword, for
example
{{ headers['x-github-event'] }}
and then you can do the same conditional or access as described above for the body
keyword.
Using the temporary GitHub APP Token for GitHub API operations #
You can use the temporary installation token that is generated by Pipelines as Code from the GitHub App to access the GitHub API.
The token value is stored into the temporary git-auth secret as generated for private
repositories in the key git-provider-token
.
As an example if you want to add a comment to your pull request, you can use the github-add-comment task from the Tekton Hub using a pipelines as code annotation:
pipelinesascode.tekton.dev/task: "github-add-comment"
you can then add the task to your tasks section (or finally tasks) of your PipelineRun :
[...]
tasks:
- name:
taskRef:
name: github-add-comment
params:
- name: REQUEST_URL
value: "{{ repo_url }}/pull/{{ pull_request_number }}"
- name: COMMENT_OR_FILE
value: "Pipelines-as-Code IS GREAT!"
- name: GITHUB_TOKEN_SECRET_NAME
value: "{{ git_auth_secret }}"
- name: GITHUB_TOKEN_SECRET_KEY
value: "git-provider-token"
Since we are using the dynamic variables we are able to reuse this on any PullRequest from any repositories.
and for completeness, here is another example how to set the GITHUB_TOKEN environment variable on a task step:
env:
- name: GITHUB_TOKEN
valueFrom:
secretKeyRef:
name: "{{ git_auth_secret }}"
key: "git-provider-token"
- On GitHub apps the generated installation token will be available for 8 hours
- On GitHub apps the token is scoped to the repository the event (payload) come from unless configured it differently on cluster.
Example #
Pipelines as code
test itself, you can see the examples in its
.tekton repository.