Maintain Pipeline Code
This guide is for regular users to create and maintain pipeline definitions in their Git repositories.
This guide explains how to maintain pipeline definitions in your source code repository using PAC.
TOC
Pipeline File LocationDefault LocationMultiple Pipeline FilesPipeline Definition StructureBasic StructureUsing Existing PipelineEvent AnnotationsMatching a Pull Request Event to a Pipeline RunMatching a Push Event to a Pipeline RunBranch SpecificationBranch and Path FilteringBranch FilteringPath FilteringExcluding Path ChangesCombining Path Change and IgnoreAdvanced Event MatchingCEL Expression FormatAvailable CEL Fields and FunctionsBasic FieldsFile Change FieldsAdvanced FieldsFunctionsCEL Expression ExamplesMatch Pull Request from Specific BranchPath-Based Filtering with.pathChanged()Match Multiple Path PatternsEvent Title MatchingExclude BranchComplex CEL Expression ExampleMatching PipelineRun by Branch with RegexMatching PipelineRun by File Changes with Files PropertyFiltering PipelineRuns to Exclude Non-Code ChangesMatching PipelineRun to Event TitleMatching PipelineRun on Body PayloadMatching PipelineRun to Request HeaderCancellation in ProgressConfigure CancellationExample Use CasesParameterizing Commits and URLsAvailable VariablesVariable Usage ExamplesGit Repository InformationEvent InformationPull Request InformationUsing Git Authentication SecretTask ResolutionUsing PAC Annotations (Recommended)Remote Task AnnotationsUsing Resolver SyntaxLocal TasksTekton Hub TasksRemote URL TasksPipeline ExamplesSimple Build PipelineTest Pipeline for PRsMulti-Stage PipelineConditional PipelineBest Practices1. Version Control2. Organization3. Security4. Reusability5. TestingTroubleshootingPipeline Not TriggeringVariables Not ResolvingTasks Not FoundNext StepsPipeline File Location
PAC looks for pipeline definitions in specific locations within your repository:
Default Location
The default location is .tekton/pipelinerun.yaml in the root of your repository.
Multiple Pipeline Files
You can organize pipelines in multiple files:
PAC will process all .yaml and .yml files in the .tekton/ directory.
When you have multiple PipelineRun definitions in different files:
- Each PipelineRun is evaluated independently
- Multiple PipelineRuns can match the same event (they will run in parallel)
- Each PipelineRun must have unique annotations to control when it triggers
- Use descriptive file names to organize different pipeline types (e.g.,
test-pipeline.yaml,deploy-pipeline.yaml)
Example: If you have both test-pipeline.yaml and deploy-pipeline.yaml that match a push event to main branch, both pipelines will run in parallel.
Pipeline Definition Structure
A PAC pipeline is a standard Tekton PipelineRun resource with PAC-specific annotations.
- PipelineRun: A Tekton resource that executes a pipeline. In PAC, you define PipelineRun resources in your Git repository, and PAC automatically creates and manages them based on Git events.
- Pipeline: A Tekton resource that defines a reusable set of tasks. You can reference an existing Pipeline resource in your PipelineRun using
pipelineRef, or define tasks inline usingpipelineSpec.
Basic Structure
Using Existing Pipeline
You can reference an existing Pipeline resource that is already defined in your Kubernetes cluster:
Pipeline resources can be defined:
- In the same namespace as your Repository CR
- As Cluster-scoped resources (ClusterTasks)
- In your Git repository and referenced using resolver syntax (see Task Resolution section)
Event Annotations
PAC uses annotations to determine when to trigger pipelines. These annotations are added to the PipelineRun metadata. You can match different Git provider events with each pipeline by using special annotations on the pipeline run. If there are multiple pipeline runs matching an event, Pipelines as Code runs them in parallel and posts the results to the Git provider as soon as a pipeline run finishes.
Matching a Pull Request Event to a Pipeline Run
You can use the following example to match a pipeline with a pull_request event that targets the main branch:
Matching a Push Event to a Pipeline Run
You can use the following example to match a pipeline with a push event targeting the refs/heads/main branch:
Branch Specification
You can specify multiple branches by adding comma-separated entries. For example, "[main, release-nightly]". In addition, you can specify the following:
- Full references to branches such as
"refs/heads/main" - Globs with pattern matching such as
"refs/heads/*" - Tags such as
"refs/tags/1.*"
Examples:
Multiple branches:
All branches using glob:
Branch pattern:
Tags:
Note: The on-target-branch and on-event annotations are the standard format as specified in the official documentation. For comment-based triggers, use the pipelinesascode.tekton.dev/on-comment annotation.
Branch and Path Filtering
Branch Filtering
Filter by target branch using the on-target-branch annotation. You can use glob patterns to match multiple branches:
Filter multiple specific branches:
Path Filtering
Matching a PipelineRun to specific path changes via annotation is a Technology Preview feature only. Technology Preview features are not currently supported and might not be functionally complete. We do not recommend using them in production.
To trigger a PipelineRun based on specific path changes in an event, use the annotation pipelinesascode.tekton.dev/on-path-change.
Multiple paths can be specified, separated by commas. The first glob matching the files changed in the PR will trigger the PipelineRun. If you want to match a file or path that has a comma, you can HTML escape it with the , HTML entity.
You still need to specify the event type and target branch using on-target-branch and on-event annotations.
:::important Path Change Annotation Limitation
If you use a CEL expression (on-cel-expression), the on-path-change and on-path-change-ignore annotations will be ignored. Use CEL expressions with files.* properties or .pathChanged() function for path-based filtering when using CEL.
:::
Example:
This configuration will match and trigger the PipelineRun when a pull_request event targets the main branch and includes changes to files with a .md suffix in the docs directory (and its subdirectories) or files with a .rst suffix in the manual directory.
Path patterns:
- Use glob patterns, not regex
src/**- Matches all files in thesrcdirectory and subdirectories*.go- Matches all Go files in the repository root- Use comma-separated values for multiple patterns:
"[src/**,*.go,config/**]"
Test glob patterns:
The tkn pac CLI provides a handy globbing command to test the glob pattern matching:
Excluding Path Changes
You can use the reverse annotation pipelinesascode.tekton.dev/on-path-change-ignore to trigger a PipelineRun when the specified paths have not changed.
You still need to specify the event type and target branch. If you have a CEL expression, the on-path-change-ignore annotation will be ignored.
This PipelineRun will run when there are changes outside the docs folder:
Combining Path Change and Ignore
You can combine on-path-change and on-path-change-ignore annotations:
This configuration triggers the PipelineRun when there are changes in the docs directory but not in the docs/generated directory.
Important: The on-path-change-ignore annotation will always take precedence over the on-path-change annotation. If a file matches both patterns, the PipelineRun will not be triggered.
Advanced Event Matching
Pipelines as Code supports using Common Expression Language (CEL) based filtering for advanced event matching.
:::important CEL vs Annotation Matching
- If you use
on-cel-expression: PAC will use the CEL expression and ignore theon-target-branchandon-eventannotations - If you don't use
on-cel-expression: PAC will use theon-target-branchandon-eventannotations for matching
You cannot use both CEL expressions and simple annotations at the same time. Choose one approach based on your needs:
- Use simple annotations (
on-target-branch,on-event) for basic matching - Use CEL expressions for complex filtering, negation, and advanced conditions
:::
Compared to the simple on-target-branch annotation matching, the CEL expressions allow complex filtering and negation.
CEL Expression Format
Use the pipelinesascode.tekton.dev/on-cel-expression annotation with a CEL expression:
Available CEL Fields and Functions
Basic Fields
event: A push orpull_requesteventtarget_branch: The target branchsource_branch: The branch of origin of apull_requestevent. For push events, it is same as thetarget_branchevent_title: Matches the title of the event, such as the commit title for a push event, and the title of a pull or merge request for apull_requestevent. Currently, only GitHub, GitLab, and Bitbucket Cloud are the supported providerslast_commit_title: The title of the last commit in the event (Platform enhancement - not available in upstream Tekton)
File Change Fields
These fields allow you to filter based on specific file changes in the event:
files.all: All changed files (added, modified, deleted, renamed)files.added: Files that were addedfiles.deleted: Files that were deletedfiles.modified: Files that were modifiedfiles.renamed: Files that were renamed
Note: For pull requests, every file belonging to the pull request will be listed. These properties are available for both push and pull_request events.
Advanced Fields
body: Full payload body from the Git provider (Technology Preview)headers: HTTP headers from the Git provider (available as a map, headers are always in lowercase)
Functions
.matches(pattern): Match a string against a regular expression pattern.pathChanged(): A suffix function to a string. The string can be a glob pattern to check if the path has changed. Currently, only GitHub and GitLab are supported as providers. Note:.pathChanged()supports glob patterns but does not support different types of changes (added, modified, deleted). Usefiles.*properties for more specific filtering.startsWith(prefix): Check if a string starts with the given prefix.contains(substring): Check if a string contains the given substring.exists(iterator, condition): Check if any element in a collection matches the condition (used withfiles.*properties)
CEL Expression Examples
Match Pull Request from Specific Branch
To match a pull_request event targeting the main branch and coming from the wip branch:
Path-Based Filtering with .pathChanged()
Pipelines-as-Code supports two ways to match files changed in a particular event:
- The
.pathChanged()suffix function (in CEL expressions) - supports glob patterns but does not support different types of "changes" (added, modified, deleted) - The
files.*property (in CEL expressions) - can target specific types of changed files and supports using CEL expressions - The
on-path-changeannotation - simpler annotation-based approach (Technology Preview)
To run a pipeline only if a path has changed, you can use the .pathChanged() suffix function with a glob pattern:
This matches every markdown file in the docs directory.
Match Multiple Path Patterns
Note: .pathChanged() supports glob patterns but does not distinguish between file change types (added, modified, deleted, renamed). For more specific filtering, use the files.* properties described below.
Event Title Matching
To match all pull requests starting with the title [DOWNSTREAM]:
Exclude Branch
To run a pipeline on a pull_request event, but skip the experimental branch:
Complex CEL Expression Example
A comprehensive example combining multiple conditions:
This expression:
- Matches push or pull_request events
- Only triggers on main, master, or release-* branches (or tags)
- Excludes commits with "Auto-commit" in the title (unless on protected branches)
Matching PipelineRun by Branch with Regex
Match a branch name using regular expressions. For example, trigger a PipelineRun for pull_request events where the source branch name contains the substring feat/:
Matching PipelineRun by File Changes with Files Property
You can use the files property to match specific types of file changes. This is more powerful than .pathChanged() as it can target specific change types (added, modified, deleted, renamed).
Match any changed file in the tmp directory:
Match any added file in the src or pkg directory:
Match modified files with the name test.go:
Available file properties:
files.all: All changed files (added, modified, deleted, renamed)files.added: Files that were addedfiles.deleted: Files that were deletedfiles.modified: Files that were modifiedfiles.renamed: Files that were renamed
Filtering PipelineRuns to Exclude Non-Code Changes
Exclude PipelineRuns when only documentation or configuration files are changed. This example filters pull_request events to exclude changes that only affect documentation, configuration files, or other non-code files:
This expression will:
- Only match
pull_requestevents targeting themainbranch - Exclude the PipelineRun if all changed files match any of the following patterns:
- Files in the
docs/directory (^docs/) - Markdown files (
\\.md$) - Common repository metadata files (
.gitignore,OWNERS,PROJECT,LICENSE)
- Files in the
Note: When using regex patterns in CEL expressions, remember to properly escape special characters. The backslash (\) needs to be doubled (\\) to escape properly within the CEL string context.
Matching PipelineRun to Event Title
Match pull requests or commits by their title. The event_title will be the pull request title for pull_request events and the commit title for push events:
Match commits that don't contain "Auto-commit" in the title:
Matching PipelineRun on Body Payload
Matching PipelineRun on body payload is a Technology Preview feature only. Technology Preview features are not currently supported and might not be functionally complete. We do not recommend using them in production.
The payload body as passed by the Git provider is available in the CEL variable as body. You can use this to filter based on any data the Git provider sends.
For example, on GitHub, match only if the pull request targets main, the author is superuser, and the action is synchronize (i.e., an update occurred on a pull request):
Important Notes:
- When matching the body payload in a Pull Request, GitOps comments such as
/retestwon't work as expected because the payload body becomes that of the comment, not the original pull request payload - To retest a Pull Request when using CEL on body payload, make a dummy update by amending and force-pushing:
git commit --amend --no-edit && git push --force-with-lease
Matching PipelineRun to Request Header
Filter based on headers sent by the Git provider. Headers are available as a list and are always in lowercase.
Match only GitHub pull_request events by checking the header:
Match only GitLab merge request events:
Cancellation in Progress
The pipelinesascode.tekton.dev/cancel-in-progress annotation allows you to automatically cancel a running pipeline when a new pipeline of the same type is triggered.
Configure Cancellation
Set the annotation to "true" to enable automatic cancellation:
Behavior:
- When a new pipeline is triggered (e.g., a new push to the same branch), any currently running pipeline with the same annotation will be automatically cancelled
- This is useful for preventing multiple pipeline runs from running simultaneously on the same branch
- Cancelled pipelines will show as "Cancelled" status in the Git provider
Example Use Cases
Prevent duplicate runs on main branch:
This ensures that if multiple pushes occur quickly to the main branch, only the latest pipeline runs, preventing resource waste.
Use with Pull Requests:
When a PR is updated with a new commit, any running pipeline for that PR will be cancelled and a new one will start.
Parameterizing Commits and URLs
You can specify the parameters of your commit and URL by using dynamic, expandable variables with the {{<var>}} format. These variables can be used in:
PAC supports two types of variables:
- PAC dynamic variables (
{{ variable_name }}): PAC-specific variables (e.g.,{{ revision }},{{ repo_url }}) that are replaced by PAC before creating the PipelineRun - Tekton parameters (
$(params.param-name)): Tekton Pipeline parameters that can be defined in Repository CRspec.params(see Advanced Repository Configuration for details)
This section covers PAC dynamic variables. For Repository CR parameters, see Advanced Repository Configuration.
- PipelineRun
paramsvalues - Task parameters
- Step scripts and commands
- Any string value in the pipeline definition
Available Variables
Currently, you can use the following variables:
Variable Usage Examples
Git Repository Information
Event Information
Pull Request Information
Note: The {{ pull_request_number }} variable is only available for pull_request event types. For push events, this variable is not populated.
Using Git Authentication Secret
For private repositories, PAC automatically generates a secret for git authentication. You can reference this secret in your pipeline tasks:
Note: The {{ git_auth_secret }} variable is only available for private repositories. PAC automatically creates this secret when you configure authentication for a private repository (see Configure Authentication for Private Repositories). The secret name format is pac-gitauth-<repository-name>-<hash>.
Task Resolution
PAC can automatically resolve tasks from multiple sources. You can use either PAC annotations (recommended) or Tekton resolver syntax.
Using PAC Annotations (Recommended)
PAC provides annotations to automatically fetch and embed remote tasks from Tekton Hub. This is simpler than using resolver syntax.
Remote Task Annotations
Reference tasks from Tekton Hub using annotations:
How it works:
- The annotation
pipelinesascode.tekton.dev/task: "git-clone"tells PAC to fetch the task from Tekton Hub - Use numbered annotations (
task-1,task-2, etc.) to reference additional tasks - PAC automatically embeds all referenced task definitions into your PipelineRun
- You can then reference them using
taskRef.namewith the task name from Tekton Hub
Annotation numbering:
pipelinesascode.tekton.dev/task: First task (equivalent totask-0)pipelinesascode.tekton.dev/task-1: Second taskpipelinesascode.tekton.dev/task-2: Third task- And so on...
For more details, see PAC Resolver.
Using Resolver Syntax
You can also use Tekton's resolver syntax to reference tasks.
Local Tasks
Reference tasks defined in the same repository:
Tekton Hub Tasks
Reference tasks from Tekton Hub:
Remote URL Tasks
Reference tasks from remote URLs using PAC annotations (recommended):
Pipeline Examples
Simple Build Pipeline
Test Pipeline for PRs
Multi-Stage Pipeline
This example demonstrates a complete CI pipeline with clone, test, and build stages using a real repository:
Conditional Pipeline
Use different pipelines based on branch:
Best Practices
1. Version Control
- Keep all pipeline definitions in Git
- Review pipeline changes through Merge Requests
- Tag pipeline versions for reproducibility
2. Organization
- Use descriptive pipeline names
- Group related tasks together
- Use separate files for different pipeline types
3. Security
- Don't hardcode secrets in pipeline files
- Use Kubernetes Secrets for sensitive data
- Limit pipeline permissions using RBAC
4. Reusability
- Create reusable task definitions
- Use Tekton Hub tasks when possible
- Share common tasks across repositories
5. Testing
- Test pipeline changes in feature branches
- Use Merge Request pipelines to validate changes
- Keep pipelines simple and maintainable
Troubleshooting
Pipeline Not Triggering
-
Check annotations are correct:
-
Verify branch names match:
-
Check PAC controller logs:
Variables Not Resolving
- Verify variable syntax: Use
{{ variable_name }}format, for example{{ revision }}or{{ repo_url }} - Check variable name spelling: Ensure variable names match exactly (e.g.,
{{ repo_owner }},{{ source_branch }}) - Verify variable availability: Some variables like
{{ pull_request_number }}are only available forpull_requestevents - Review PAC controller logs for variable resolution errors
Tasks Not Found
- Verify task references are correct
- Check task files exist in repository
- Verify Tekton Hub task names
- Check network connectivity for remote tasks
Next Steps
- PAC Resolver - Learn about remote task and pipeline annotations
- Trigger Pipelines - Learn about different trigger methods
- Configure Repository - Repository setup guide
- Common Issues - Troubleshooting guide