Skip to content

Commit eb50fac

Browse files
committed
feat: annotation for matching PipelineRun on paths
Introduce easier-to-use annotations for matching PipelineRuns by file path changes: - `on-path-changed`: Matches PipelineRun if specified paths have changes. - `on-path-changed-ignore`: Matches PipelineRun if specified paths **do not** have changes. Examples: 1. `on-path-changed: ["pkg/*", "cli/*"]` matches if files in `pkg` or `cli` changed. 2. `on-path-changed-ignore: ["docs/**"]` matches if no changes occurred in the `docs` directory. Annotations can be combined for more specific use cases: - `on-path-changed: ["docs/**"]` - `on-path-changed-ignore: ["docs/generated/**"]` This setup triggers a PipelineRun when there are changes in the `docs` directory, except for files under `docs/generated`. Enhanced annotation options also support: - Targeting specific events (`on-target-event`: e.g., `pull_request`, `push`). - Matching specific branches (`on-target-branch`: e.g., `main`). This improves usability over existing CEL-based configuration and makes defining file-based triggers more intuitive. **Jira**: https://issues.redhat.com/browse/SRVKP-6464 Signed-off-by: Chmouel Boudjnah <[email protected]>
1 parent b13ca43 commit eb50fac

8 files changed

+575
-37
lines changed

docs/content/docs/guide/authoringprs.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,100 @@ too, it will only be matched when a `Pull Request` is opened or updated or on a
132132
`Push` to a branch
133133
{{< /hint >}}
134134

135+
### Matching a PipelineRun to Specific Path Changes
136+
137+
{{< tech_preview "Matching a PipelineRun to specific path changes via annotation" >}}
138+
139+
To trigger a `PipelineRun` based on specific path changes in an event, use the
140+
annotation `pipelinesascode.tekton.dev/on-path-change`.
141+
142+
Multiple paths can be specified, separated by commas. The first glob matching
143+
the files changes in the PR will trigger the `PipelineRun`.
144+
145+
You still need to specify the event type and target branch. If you have a [CEL
146+
expression](#matching-pipelinerun-by-path-change) the `on-path-change`
147+
annotation will be ignored
148+
149+
Example:
150+
151+
```yaml
152+
metadata:
153+
name: pipeline-docs-and-manual
154+
annotations:
155+
pipelinesascode.tekton.dev/on-target-branch: "[main]"
156+
pipelinesascode.tekton.dev/on-event: "[pull_request]"
157+
pipelinesascode.tekton.dev/on-path-change: "[docs/***.md, manual/***.rst]"
158+
```
159+
160+
This configuration will match and trigger the `PipelineRun` named
161+
`pipeline-docs-and-manual` when a `pull_request` event targets the `main` branch
162+
and includes changes to files with a `.md` suffix in the `docs` directory (and
163+
its subdirectories) or files with a `.rst` suffix in the `manual` directory.
164+
165+
{{< hint info >}}
166+
The patterns used are [glob](https://en.wikipedia.org/wiki/Glob_(programming))
167+
patterns, not regexp. Here are some
168+
[examples](https://github.com/gobwas/glob?tab=readme-ov-file#example) from the
169+
library used for matching.
170+
{{< /hint >}}
171+
172+
### Matching a PipelineRun by Ignoring Specific Path Changes
173+
174+
{{< tech_preview "Matching a PipelineRun to ignore specific path changes via annotation" >}}
175+
176+
Following the same principle as the `on-path-change` annotation, you can use the
177+
reverse annotation `pipelinesascode.tekton.dev/on-path-change-ignore` to trigger
178+
a `PipelineRun` when the specified paths have not changed.
179+
180+
You still need to specify the event type and target branch. If you have a [CEL
181+
expression](#matching-pipelinerun-by-path-change) the `on-path-change-ignore`
182+
annotation will be ignored
183+
184+
This example triggers a `PipelineRun` when there are no changes in the `docs`
185+
directory:
186+
187+
```yaml
188+
metadata:
189+
name: pipeline-not-on-docs-change
190+
annotations:
191+
pipelinesascode.tekton.dev/on-target-branch: "[main]"
192+
pipelinesascode.tekton.dev/on-event: "[pull_request]"
193+
pipelinesascode.tekton.dev/on-path-change-ignore: "[docs/***]"
194+
```
195+
196+
Furthermore, you can combine `on-path-change` and `on-path-change-ignore`
197+
annotations:
198+
199+
```yaml
200+
metadata:
201+
name: pipeline-docs-not-generated
202+
annotations:
203+
pipelinesascode.tekton.dev/on-target-branch: "[main]"
204+
pipelinesascode.tekton.dev/on-event: "[pull_request]"
205+
pipelinesascode.tekton.dev/on-path-change: "[docs/***]"
206+
pipelinesascode.tekton.dev/on-path-change-ignore: "[docs/generated/***]"
207+
```
208+
209+
This configuration triggers the `PipelineRun` when there are changes in the
210+
`docs` directory but not in the `docs/generated` directory.
211+
212+
The `on-path-change-ignore` annotation will always take precedence over the
213+
`on-path-change` annotation, It means if you have these annotations:
214+
215+
```yaml
216+
metadata:
217+
name: pipelinerun-go-only-no-markdown-or-yaml
218+
pipelinesascode.tekton.dev/on-target-branch: "[main]"
219+
pipelinesascode.tekton.dev/on-event: "[pull_request]"
220+
pipelinesascode.tekton.dev/on-path-change: "[***.go]"
221+
pipelinesascode.tekton.dev/on-path-change-ignore: "[***.md, ***.yaml]"
222+
```
223+
224+
and you have a `Pull Request` changing the files `.tekton/pipelinerun.yaml`,
225+
`README.md`, and `main.go` the `PipelineRun` will not be triggered since the
226+
`on-path-change-ignore` annotation will ignore the `***.md` and `***.yaml`
227+
files.
228+
135229
## Advanced event matching
136230

137231
If you need to do some advanced matching, `Pipelines-as-Code` supports CEL

pkg/apis/pipelinesascode/keys/keys.go

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -23,40 +23,42 @@ import (
2323
)
2424

2525
const (
26-
ControllerInfo = pipelinesascode.GroupName + "/controller-info"
27-
Task = pipelinesascode.GroupName + "/task"
28-
Pipeline = pipelinesascode.GroupName + "/pipeline"
29-
URLOrg = pipelinesascode.GroupName + "/url-org"
30-
URLRepository = pipelinesascode.GroupName + "/url-repository"
31-
SHA = pipelinesascode.GroupName + "/sha"
32-
Sender = pipelinesascode.GroupName + "/sender"
33-
EventType = pipelinesascode.GroupName + "/event-type"
34-
Branch = pipelinesascode.GroupName + "/branch"
35-
SourceBranch = pipelinesascode.GroupName + "/source-branch"
36-
Repository = pipelinesascode.GroupName + "/repository"
37-
GitProvider = pipelinesascode.GroupName + "/git-provider"
38-
State = pipelinesascode.GroupName + "/state"
39-
ShaTitle = pipelinesascode.GroupName + "/sha-title"
40-
ShaURL = pipelinesascode.GroupName + "/sha-url"
41-
RepoURL = pipelinesascode.GroupName + "/repo-url"
42-
SourceRepoURL = pipelinesascode.GroupName + "/source-repo-url"
43-
PullRequest = pipelinesascode.GroupName + "/pull-request"
44-
InstallationID = pipelinesascode.GroupName + "/installation-id"
45-
GHEURL = pipelinesascode.GroupName + "/ghe-url"
46-
SourceProjectID = pipelinesascode.GroupName + "/source-project-id"
47-
TargetProjectID = pipelinesascode.GroupName + "/target-project-id"
48-
OriginalPRName = pipelinesascode.GroupName + "/original-prname"
49-
GitAuthSecret = pipelinesascode.GroupName + "/git-auth-secret"
50-
CheckRunID = pipelinesascode.GroupName + "/check-run-id"
51-
OnEvent = pipelinesascode.GroupName + "/on-event"
52-
OnComment = pipelinesascode.GroupName + "/on-comment"
53-
OnTargetBranch = pipelinesascode.GroupName + "/on-target-branch"
54-
OnCelExpression = pipelinesascode.GroupName + "/on-cel-expression"
55-
TargetNamespace = pipelinesascode.GroupName + "/target-namespace"
56-
MaxKeepRuns = pipelinesascode.GroupName + "/max-keep-runs"
57-
CancelInProgress = pipelinesascode.GroupName + "/cancel-in-progress"
58-
LogURL = pipelinesascode.GroupName + "/log-url"
59-
ExecutionOrder = pipelinesascode.GroupName + "/execution-order"
26+
ControllerInfo = pipelinesascode.GroupName + "/controller-info"
27+
Task = pipelinesascode.GroupName + "/task"
28+
Pipeline = pipelinesascode.GroupName + "/pipeline"
29+
URLOrg = pipelinesascode.GroupName + "/url-org"
30+
URLRepository = pipelinesascode.GroupName + "/url-repository"
31+
SHA = pipelinesascode.GroupName + "/sha"
32+
Sender = pipelinesascode.GroupName + "/sender"
33+
EventType = pipelinesascode.GroupName + "/event-type"
34+
Branch = pipelinesascode.GroupName + "/branch"
35+
SourceBranch = pipelinesascode.GroupName + "/source-branch"
36+
Repository = pipelinesascode.GroupName + "/repository"
37+
GitProvider = pipelinesascode.GroupName + "/git-provider"
38+
State = pipelinesascode.GroupName + "/state"
39+
ShaTitle = pipelinesascode.GroupName + "/sha-title"
40+
ShaURL = pipelinesascode.GroupName + "/sha-url"
41+
RepoURL = pipelinesascode.GroupName + "/repo-url"
42+
SourceRepoURL = pipelinesascode.GroupName + "/source-repo-url"
43+
PullRequest = pipelinesascode.GroupName + "/pull-request"
44+
InstallationID = pipelinesascode.GroupName + "/installation-id"
45+
GHEURL = pipelinesascode.GroupName + "/ghe-url"
46+
SourceProjectID = pipelinesascode.GroupName + "/source-project-id"
47+
TargetProjectID = pipelinesascode.GroupName + "/target-project-id"
48+
OriginalPRName = pipelinesascode.GroupName + "/original-prname"
49+
GitAuthSecret = pipelinesascode.GroupName + "/git-auth-secret"
50+
CheckRunID = pipelinesascode.GroupName + "/check-run-id"
51+
OnEvent = pipelinesascode.GroupName + "/on-event"
52+
OnComment = pipelinesascode.GroupName + "/on-comment"
53+
OnTargetBranch = pipelinesascode.GroupName + "/on-target-branch"
54+
OnPathChange = pipelinesascode.GroupName + "/on-path-change"
55+
OnPathChangeIgnore = pipelinesascode.GroupName + "/on-path-change-ignore"
56+
OnCelExpression = pipelinesascode.GroupName + "/on-cel-expression"
57+
TargetNamespace = pipelinesascode.GroupName + "/target-namespace"
58+
MaxKeepRuns = pipelinesascode.GroupName + "/max-keep-runs"
59+
CancelInProgress = pipelinesascode.GroupName + "/cancel-in-progress"
60+
LogURL = pipelinesascode.GroupName + "/log-url"
61+
ExecutionOrder = pipelinesascode.GroupName + "/execution-order"
6062
// PublicGithubAPIURL default is "https://api.github.com" but it can be overridden by X-GitHub-Enterprise-Host header.
6163
PublicGithubAPIURL = "https://api.github.com"
6264
GithubApplicationID = "github-application-id"

pkg/matcher/annotation_matcher.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,46 @@ func MatchPipelinerunByAnnotation(ctx context.Context, logger *zap.SugaredLogger
223223
}
224224
prMatch.Config["target-branch"] = targetBranch
225225
prMatch.Config["target-event"] = targetEvent
226+
227+
if key, ok := prun.GetObjectMeta().GetAnnotations()[keys.OnPathChange]; ok {
228+
changedFiles, err := vcx.GetFiles(ctx, event)
229+
if err != nil {
230+
logger.Errorf("error getting changed files: %v", err)
231+
continue
232+
}
233+
// // TODO(chmou): we use the matchOnAnnotation function, it's
234+
// really made to match git branches but we can still use it for
235+
// our own path changes. we may split up if needed to refine.
236+
matched, err := matchOnAnnotation(key, changedFiles.All, true)
237+
if err != nil {
238+
return matchedPRs, err
239+
}
240+
if !matched {
241+
continue
242+
}
243+
logger.Infof("Matched pipelinerun with name: %s, annotation PathChange: %q", prName, key)
244+
prMatch.Config["path-change"] = key
245+
}
246+
247+
if key, ok := prun.GetObjectMeta().GetAnnotations()[keys.OnPathChangeIgnore]; ok {
248+
changedFiles, err := vcx.GetFiles(ctx, event)
249+
if err != nil {
250+
logger.Errorf("error getting changed files: %v", err)
251+
continue
252+
}
253+
// // TODO(chmou): we use the matchOnAnnotation function, it's
254+
// really made to match git branches but we can still use it for
255+
// our own path changes. we may split up if needed to refine.
256+
matched, err := matchOnAnnotation(key, changedFiles.All, true)
257+
if err != nil {
258+
return matchedPRs, err
259+
}
260+
if matched {
261+
logger.Infof("Skipping pipelinerun with name: %s, annotation PathChangeIgnore: %q", prName, key)
262+
continue
263+
}
264+
prMatch.Config["path-change-ignore"] = key
265+
}
226266
}
227267

228268
logger.Infof("matched pipelinerun with name: %s, annotation Config: %q", prName, prMatch.Config)

0 commit comments

Comments
 (0)