Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for matching PipelineRuns to Pull Request labels #1854

Merged
merged 2 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions docs/content/docs/guide/authoringprs.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,23 +47,24 @@ getting tested. You usually use this with the
[git-clone](https://hub.tekton.dev/tekton/task/git-clone) task to be able to
checkout the code that is being tested.

| Variable | Description | Example | Example Output |
|---------------------|---------------------------------------------------------------------------------------------------|-------------------------------------|------------------------------|
| body | The full payload body (see [below](#using-the-body-and-headers-in-a-pipelines-as-code-parameter)) | `{{body.pull_request.user.email }}` | <[email protected]> |
| event_type | The event type (eg: `pull_request` or `push`) | `{{event_type}}` | pull_request (see the note for Gitops Comments [here]({{< relref "/docs/guide/gitops_commands.md#event-type-annotation-and-dynamic-variables" >}}) ) |
| 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](#using-the-body-and-headers-in-a-pipelines-as-code-parameter)) | `{{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 |
| trigger_comment | The comment triggering the pipelinerun when using a [GitOps command]({{< relref "/docs/guide/running.md#gitops-command-on-pull-or-merge-request" >}}) (like `/test`, `/retest`) | `{{trigger_comment}}` | /merge-pr branch |
| Variable | Description | Example | Example Output |
|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
| body | The full payload body (see [below](#using-the-body-and-headers-in-a-pipelines-as-code-parameter)) | `{{body.pull_request.user.email }}` | <[email protected]> |
| event_type | The event type (eg: `pull_request` or `push`) | `{{event_type}}` | pull_request (see the note for Gitops Comments [here]({{< relref "/docs/guide/gitops_commands.md#event-type-annotation-and-dynamic-variables" >}}) ) |
| 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](#using-the-body-and-headers-in-a-pipelines-as-code-parameter)) | `{{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 |
| trigger_comment | The comment triggering the pipelinerun when using a [GitOps command]({{< relref "/docs/guide/running.md#gitops-command-on-pull-or-merge-request" >}}) (like `/test`, `/retest`) | `{{trigger_comment}}` | /merge-pr branch |
| pull_request_labels | The labels of the pull request separated by a newline | `{{pull_request_labels}}` | bugs\nenhancement |

## Matching an event to a PipelineRun

Expand Down
42 changes: 40 additions & 2 deletions docs/content/docs/guide/matchingevents.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ and you have a `Pull Request` changing the files `.tekton/pipelinerun.yaml`,
`on-path-change-ignore` annotation will ignore the `***.md` and `***.yaml`
files.

## Matching a PipelineRun on a regexp in a comment
## Matching a PipelineRun on a Regexp in a comment

{{< tech_preview "Matching PipelineRun on regexp in comments" >}}

Expand Down Expand Up @@ -211,6 +211,44 @@ PipelineRun.

> *NOTE*: The `on-comment` annotation is only supported on GitHub, Gitea and GitLab providers

## Matching PipelineRun to a Pull Request labels

{{< tech_preview "Matching PipelineRun to a Pull-Request label" >}}

Using the annotation `pipelinesascode.tekton.dev/on-label`, you can match a
PipelineRun to a Pull Request label. For example, if you want to match the
PipelineRun `bugs` whenever a Pull Request has the label `bug` or `defect`, you
can use this annotation:

```yaml
metadata:
name: match-bugs-or-defect
annotations:
pipelinesascode.tekton.dev/on-label: [bug, defect]
```

- The `on-label` annotation respects the `pull_request` [Policy]({{< relref
"/docs/guide/policy" >}}) rules.
- This annotation is currently supported only on GitHub, Gitea, and GitLab
providers. Bitbucket Cloud and Bitbucket Server do not support adding labels
to Pull Requests.
- When you add a label to a Pull Request, the corresponding PipelineRun is
triggered immediately, and no other PipelineRun matching the same Pull Request
will be activated.
- If you update the Pull Request by sending a new commit, the PipelineRun
with a matching `on-label` annotation will be triggered again if the label is
still present.
- You can access the `Pull Request` labels with the [dynamic variable]({{<
relref "/docs/guide/authoringprs#dynamic-variables" >}}) `{{ pull_request_labels }}`.
The labels are separated by a Unix newline `\n`.
For example with a shell script you can do this to print them:

```bash
for i in $(echo -e "{{ pull_request_labels }}");do
echo $i
done
```

## Advanced event matching using CEL

If you need to do some advanced matching, `Pipelines-as-Code` supports CEL
Expand Down Expand Up @@ -366,7 +404,7 @@ or close/open the pull request.

{{< /hint >}}

### Matching PipelineRun on request header
### Matching a PipelineRun to a request header

You can do some further filtering on the headers as passed by the Git provider
with the CEL variable `headers`.
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/pipelinesascode/keys/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const (
OnComment = pipelinesascode.GroupName + "/on-comment"
OnTargetBranch = pipelinesascode.GroupName + "/on-target-branch"
OnPathChange = pipelinesascode.GroupName + "/on-path-change"
OnLabel = pipelinesascode.GroupName + "/on-label"
OnPathChangeIgnore = pipelinesascode.GroupName + "/on-path-change-ignore"
OnCelExpression = pipelinesascode.GroupName + "/on-cel-expression"
TargetNamespace = pipelinesascode.GroupName + "/target-namespace"
Expand Down
1 change: 1 addition & 0 deletions pkg/customparams/customparams_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ func TestProcessTemplates(t *testing.T) {
"target_branch": "",
"target_namespace": "",
"trigger_comment": "",
"pull_request_labels": "",
},
repository: &v1alpha1.Repository{
Spec: v1alpha1.RepositorySpec{},
Expand Down
24 changes: 13 additions & 11 deletions pkg/customparams/standard.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,21 @@ func (p *CustomParams) makeStandardParamsFromEvent(ctx context.Context) (map[str
}
changedFiles := p.getChangedFiles(ctx)
triggerCommentAsSingleLine := strings.ReplaceAll(p.event.TriggerComment, "\n", "\\n")
pullRequestLabels := strings.Join(p.event.PullRequestLabel, "\\n")

return map[string]string{
"revision": p.event.SHA,
"repo_url": repoURL,
"repo_owner": strings.ToLower(p.event.Organization),
"repo_name": strings.ToLower(p.event.Repository),
"target_branch": formatting.SanitizeBranch(p.event.BaseBranch),
"source_branch": formatting.SanitizeBranch(p.event.HeadBranch),
"source_url": p.event.HeadURL,
"sender": strings.ToLower(p.event.Sender),
"target_namespace": p.repo.GetNamespace(),
"event_type": opscomments.EventTypeBackwardCompat(p.eventEmitter, p.repo, p.event.EventType),
"trigger_comment": triggerCommentAsSingleLine,
"revision": p.event.SHA,
"repo_url": repoURL,
"repo_owner": strings.ToLower(p.event.Organization),
"repo_name": strings.ToLower(p.event.Repository),
"target_branch": formatting.SanitizeBranch(p.event.BaseBranch),
"source_branch": formatting.SanitizeBranch(p.event.HeadBranch),
"source_url": p.event.HeadURL,
"sender": strings.ToLower(p.event.Sender),
"target_namespace": p.repo.GetNamespace(),
"event_type": opscomments.EventTypeBackwardCompat(p.eventEmitter, p.repo, p.event.EventType),
"trigger_comment": triggerCommentAsSingleLine,
"pull_request_labels": pullRequestLabels,
}, map[string]interface{}{
"all": changedFiles.All,
"added": changedFiles.Added,
Expand Down
44 changes: 23 additions & 21 deletions pkg/customparams/standard_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,32 @@ import (

func TestMakeStandardParamsFromEvent(t *testing.T) {
event := &info.Event{
SHA: "1234567890",
Organization: "Org",
Repository: "Repo",
BaseBranch: "main",
HeadBranch: "foo",
EventType: "pull_request",
Sender: "SENDER",
URL: "https://paris.com",
HeadURL: "https://india.com",
TriggerComment: "/test me\nHelp me obiwan kenobi",
SHA: "1234567890",
Organization: "Org",
Repository: "Repo",
BaseBranch: "main",
HeadBranch: "foo",
EventType: "pull_request",
Sender: "SENDER",
URL: "https://paris.com",
HeadURL: "https://india.com",
TriggerComment: "/test me\nHelp me obiwan kenobi",
PullRequestLabel: []string{"bugs", "enhancements"},
}

result := map[string]string{
"event_type": "pull_request",
"repo_name": "repo",
"repo_owner": "org",
"repo_url": "https://paris.com",
"source_url": "https://india.com",
"revision": "1234567890",
"sender": "sender",
"source_branch": "foo",
"target_branch": "main",
"target_namespace": "myns",
"trigger_comment": "/test me\\nHelp me obiwan kenobi",
"event_type": "pull_request",
"repo_name": "repo",
"repo_owner": "org",
"repo_url": "https://paris.com",
"source_url": "https://india.com",
"revision": "1234567890",
"sender": "sender",
"source_branch": "foo",
"target_branch": "main",
"target_namespace": "myns",
"trigger_comment": "/test me\\nHelp me obiwan kenobi",
"pull_request_labels": "bugs\\nenhancements",
}

repo := &v1alpha1.Repository{
Expand Down
25 changes: 23 additions & 2 deletions pkg/matcher/annotation_matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,12 @@ func MatchPipelinerunByAnnotation(ctx context.Context, logger *zap.SugaredLogger
event.URL,
event.BaseBranch,
event.HeadBranch,
event.TriggerTarget)
event.TriggerTarget,
)

if len(event.PullRequestLabel) > 0 {
infomsg += fmt.Sprintf(", labels=%s", strings.Join(event.PullRequestLabel, "|"))
}

if event.EventType == triggertype.Incoming.String() {
infomsg = fmt.Sprintf("%s, target-pipelinerun=%s", infomsg, event.TargetPipelineRun)
Expand Down Expand Up @@ -248,10 +253,25 @@ func MatchPipelinerunByAnnotation(ctx context.Context, logger *zap.SugaredLogger
if !matched {
continue
}
logger.Infof("Matched pipelinerun with name: %s, annotation PathChange: %q", prName, key)
logger.Infof("matched PipelineRun with name: %s, annotation PathChange: %q", prName, key)
prMatch.Config["path-change"] = key
}

if key, ok := prun.GetObjectMeta().GetAnnotations()[keys.OnLabel]; ok {
matched, err := matchOnAnnotation(key, event.PullRequestLabel, false)
if err != nil {
return matchedPRs, err
}
if !matched {
continue
}
logger.Infof("matched PipelineRun with name: %s, annotation Label: %q", prName, key)
prMatch.Config["label"] = key
} else if event.EventType == string(triggertype.LabelUpdate) {
logger.Infof("label update event, PipelineRun %s does not have a on-label for any of those labels: %s", prName, strings.Join(event.PullRequestLabel, "|"))
continue
}

if key, ok := prun.GetObjectMeta().GetAnnotations()[keys.OnPathChangeIgnore]; ok {
changedFiles, err := vcx.GetFiles(ctx, event)
if err != nil {
Expand Down Expand Up @@ -326,6 +346,7 @@ func matchOnAnnotation(annotations string, eventType []string, branchMatching bo
if v == e {
gotit = v
}

if branchMatching && branchMatch(v, e) {
gotit = v
}
Expand Down
Loading
Loading