diff --git a/docs/content/docs/guide/authoringprs.md b/docs/content/docs/guide/authoringprs.md index 3cfc6d23e..c9ce222c9 100644 --- a/docs/content/docs/guide/authoringprs.md +++ b/docs/content/docs/guide/authoringprs.md @@ -132,6 +132,100 @@ too, it will only be matched when a `Pull Request` is opened or updated or on a `Push` to a branch {{< /hint >}} +### Matching a PipelineRun to Specific Path Changes + +{{< tech_preview "Matching a PipelineRun to specific path changes via annotation" >}} + +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 changes in the PR will trigger the `PipelineRun`. + +You still need to specify the event type and target branch. If you have a [CEL +expression](#matching-pipelinerun-by-path-change) the `on-path-change` +annotation will be ignored + +Example: + +```yaml +metadata: + name: pipeline-docs-and-manual + annotations: + pipelinesascode.tekton.dev/on-target-branch: "[main]" + pipelinesascode.tekton.dev/on-event: "[pull_request]" + pipelinesascode.tekton.dev/on-path-change: "[docs/***.md, manual/***.rst]" +``` + +This configuration will match and trigger the `PipelineRun` named +`pipeline-docs-and-manual` 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. + +{{< hint info >}} +The patterns used are [glob](https://en.wikipedia.org/wiki/Glob_(programming)) +patterns, not regexp. Here are some +[examples](https://github.com/gobwas/glob?tab=readme-ov-file#example) from the +library used for matching. +{{< /hint >}} + +### Matching a PipelineRun by Ignoring Specific Path Changes + +{{< tech_preview "Matching a PipelineRun to ignore specific path changes via annotation" >}} + +Following the same principle as the `on-path-change` annotation, 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](#matching-pipelinerun-by-path-change) the `on-path-change-ignore` +annotation will be ignored + +This example triggers a `PipelineRun` when there are no changes in the `docs` +directory: + +```yaml +metadata: + name: pipeline-not-on-docs-change + annotations: + pipelinesascode.tekton.dev/on-target-branch: "[main]" + pipelinesascode.tekton.dev/on-event: "[pull_request]" + pipelinesascode.tekton.dev/on-path-change-ignore: "[docs/***]" +``` + +Furthermore, you can combine `on-path-change` and `on-path-change-ignore` +annotations: + +```yaml +metadata: + name: pipeline-docs-not-generated + annotations: + pipelinesascode.tekton.dev/on-target-branch: "[main]" + pipelinesascode.tekton.dev/on-event: "[pull_request]" + pipelinesascode.tekton.dev/on-path-change: "[docs/***]" + pipelinesascode.tekton.dev/on-path-change-ignore: "[docs/generated/***]" +``` + +This configuration triggers the `PipelineRun` when there are changes in the +`docs` directory but not in the `docs/generated` directory. + +The `on-path-change-ignore` annotation will always take precedence over the +`on-path-change` annotation, It means if you have these annotations: + +```yaml +metadata: + name: pipelinerun-go-only-no-markdown-or-yaml + pipelinesascode.tekton.dev/on-target-branch: "[main]" + pipelinesascode.tekton.dev/on-event: "[pull_request]" + pipelinesascode.tekton.dev/on-path-change: "[***.go]" + pipelinesascode.tekton.dev/on-path-change-ignore: "[***.md, ***.yaml]" +``` + +and you have a `Pull Request` changing the files `.tekton/pipelinerun.yaml`, +`README.md`, and `main.go` the `PipelineRun` will not be triggered since the +`on-path-change-ignore` annotation will ignore the `***.md` and `***.yaml` +files. + ## Advanced event matching If you need to do some advanced matching, `Pipelines-as-Code` supports CEL diff --git a/pkg/apis/pipelinesascode/keys/keys.go b/pkg/apis/pipelinesascode/keys/keys.go index 684d980ca..e528d6860 100644 --- a/pkg/apis/pipelinesascode/keys/keys.go +++ b/pkg/apis/pipelinesascode/keys/keys.go @@ -23,40 +23,42 @@ import ( ) const ( - ControllerInfo = pipelinesascode.GroupName + "/controller-info" - Task = pipelinesascode.GroupName + "/task" - Pipeline = pipelinesascode.GroupName + "/pipeline" - URLOrg = pipelinesascode.GroupName + "/url-org" - URLRepository = pipelinesascode.GroupName + "/url-repository" - SHA = pipelinesascode.GroupName + "/sha" - Sender = pipelinesascode.GroupName + "/sender" - EventType = pipelinesascode.GroupName + "/event-type" - Branch = pipelinesascode.GroupName + "/branch" - SourceBranch = pipelinesascode.GroupName + "/source-branch" - Repository = pipelinesascode.GroupName + "/repository" - GitProvider = pipelinesascode.GroupName + "/git-provider" - State = pipelinesascode.GroupName + "/state" - ShaTitle = pipelinesascode.GroupName + "/sha-title" - ShaURL = pipelinesascode.GroupName + "/sha-url" - RepoURL = pipelinesascode.GroupName + "/repo-url" - SourceRepoURL = pipelinesascode.GroupName + "/source-repo-url" - PullRequest = pipelinesascode.GroupName + "/pull-request" - InstallationID = pipelinesascode.GroupName + "/installation-id" - GHEURL = pipelinesascode.GroupName + "/ghe-url" - SourceProjectID = pipelinesascode.GroupName + "/source-project-id" - TargetProjectID = pipelinesascode.GroupName + "/target-project-id" - OriginalPRName = pipelinesascode.GroupName + "/original-prname" - GitAuthSecret = pipelinesascode.GroupName + "/git-auth-secret" - CheckRunID = pipelinesascode.GroupName + "/check-run-id" - OnEvent = pipelinesascode.GroupName + "/on-event" - OnComment = pipelinesascode.GroupName + "/on-comment" - OnTargetBranch = pipelinesascode.GroupName + "/on-target-branch" - OnCelExpression = pipelinesascode.GroupName + "/on-cel-expression" - TargetNamespace = pipelinesascode.GroupName + "/target-namespace" - MaxKeepRuns = pipelinesascode.GroupName + "/max-keep-runs" - CancelInProgress = pipelinesascode.GroupName + "/cancel-in-progress" - LogURL = pipelinesascode.GroupName + "/log-url" - ExecutionOrder = pipelinesascode.GroupName + "/execution-order" + ControllerInfo = pipelinesascode.GroupName + "/controller-info" + Task = pipelinesascode.GroupName + "/task" + Pipeline = pipelinesascode.GroupName + "/pipeline" + URLOrg = pipelinesascode.GroupName + "/url-org" + URLRepository = pipelinesascode.GroupName + "/url-repository" + SHA = pipelinesascode.GroupName + "/sha" + Sender = pipelinesascode.GroupName + "/sender" + EventType = pipelinesascode.GroupName + "/event-type" + Branch = pipelinesascode.GroupName + "/branch" + SourceBranch = pipelinesascode.GroupName + "/source-branch" + Repository = pipelinesascode.GroupName + "/repository" + GitProvider = pipelinesascode.GroupName + "/git-provider" + State = pipelinesascode.GroupName + "/state" + ShaTitle = pipelinesascode.GroupName + "/sha-title" + ShaURL = pipelinesascode.GroupName + "/sha-url" + RepoURL = pipelinesascode.GroupName + "/repo-url" + SourceRepoURL = pipelinesascode.GroupName + "/source-repo-url" + PullRequest = pipelinesascode.GroupName + "/pull-request" + InstallationID = pipelinesascode.GroupName + "/installation-id" + GHEURL = pipelinesascode.GroupName + "/ghe-url" + SourceProjectID = pipelinesascode.GroupName + "/source-project-id" + TargetProjectID = pipelinesascode.GroupName + "/target-project-id" + OriginalPRName = pipelinesascode.GroupName + "/original-prname" + GitAuthSecret = pipelinesascode.GroupName + "/git-auth-secret" + CheckRunID = pipelinesascode.GroupName + "/check-run-id" + OnEvent = pipelinesascode.GroupName + "/on-event" + OnComment = pipelinesascode.GroupName + "/on-comment" + OnTargetBranch = pipelinesascode.GroupName + "/on-target-branch" + OnPathChange = pipelinesascode.GroupName + "/on-path-change" + OnPathChangeIgnore = pipelinesascode.GroupName + "/on-path-change-ignore" + OnCelExpression = pipelinesascode.GroupName + "/on-cel-expression" + TargetNamespace = pipelinesascode.GroupName + "/target-namespace" + MaxKeepRuns = pipelinesascode.GroupName + "/max-keep-runs" + CancelInProgress = pipelinesascode.GroupName + "/cancel-in-progress" + LogURL = pipelinesascode.GroupName + "/log-url" + ExecutionOrder = pipelinesascode.GroupName + "/execution-order" // PublicGithubAPIURL default is "https://api.github.com" but it can be overridden by X-GitHub-Enterprise-Host header. PublicGithubAPIURL = "https://api.github.com" GithubApplicationID = "github-application-id" diff --git a/pkg/matcher/annotation_matcher.go b/pkg/matcher/annotation_matcher.go index 8847d477f..028ff079c 100644 --- a/pkg/matcher/annotation_matcher.go +++ b/pkg/matcher/annotation_matcher.go @@ -223,6 +223,46 @@ func MatchPipelinerunByAnnotation(ctx context.Context, logger *zap.SugaredLogger } prMatch.Config["target-branch"] = targetBranch prMatch.Config["target-event"] = targetEvent + + if key, ok := prun.GetObjectMeta().GetAnnotations()[keys.OnPathChange]; ok { + changedFiles, err := vcx.GetFiles(ctx, event) + if err != nil { + logger.Errorf("error getting changed files: %v", err) + continue + } + // // TODO(chmou): we use the matchOnAnnotation function, it's + // really made to match git branches but we can still use it for + // our own path changes. we may split up if needed to refine. + matched, err := matchOnAnnotation(key, changedFiles.All, true) + if err != nil { + return matchedPRs, err + } + if !matched { + continue + } + logger.Infof("Matched pipelinerun with name: %s, annotation PathChange: %q", prName, key) + prMatch.Config["path-change"] = key + } + + if key, ok := prun.GetObjectMeta().GetAnnotations()[keys.OnPathChangeIgnore]; ok { + changedFiles, err := vcx.GetFiles(ctx, event) + if err != nil { + logger.Errorf("error getting changed files: %v", err) + continue + } + // // TODO(chmou): we use the matchOnAnnotation function, it's + // really made to match git branches but we can still use it for + // our own path changes. we may split up if needed to refine. + matched, err := matchOnAnnotation(key, changedFiles.All, true) + if err != nil { + return matchedPRs, err + } + if matched { + logger.Infof("Skipping pipelinerun with name: %s, annotation PathChangeIgnore: %q", prName, key) + continue + } + prMatch.Config["path-change-ignore"] = key + } } logger.Infof("matched pipelinerun with name: %s, annotation Config: %q", prName, prMatch.Config) diff --git a/pkg/matcher/annotation_matcher_test.go b/pkg/matcher/annotation_matcher_test.go index 4b160e965..7eff749c0 100644 --- a/pkg/matcher/annotation_matcher_test.go +++ b/pkg/matcher/annotation_matcher_test.go @@ -140,6 +140,7 @@ func TestMatchPipelinerunAnnotationAndRepositories(t *testing.T) { }, }, }, + { name: "cel/match source/target", wantPRName: pipelineTargetNSName, @@ -526,6 +527,279 @@ func TestMatchPipelinerunAnnotationAndRepositories(t *testing.T) { }, }, }, + { + name: "ignored/on-path-change-ignore/include and ignore path", + wantLog: "Skipping pipelinerun with name: pipeline-target-ns", + wantErr: true, + args: annotationTestArgs{ + fileChanged: []struct { + FileName string + Status string + NewFile bool + RenamedFile bool + DeletedFile bool + }{ + { + FileName: "doc/generated/gen.md", + Status: "added", + NewFile: true, + RenamedFile: false, + DeletedFile: false, + }, + }, + pruns: []*tektonv1.PipelineRun{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: pipelineTargetNSName, + Annotations: map[string]string{ + keys.OnTargetBranch: mainBranch, + keys.OnEvent: "[pull_request]", + keys.OnPathChange: "[doc/***]", + keys.OnPathChangeIgnore: "[doc/generated/*]", + }, + }, + }, + }, + runevent: info.Event{ + URL: targetURL, + TriggerTarget: "pull_request", + EventType: "pull_request", + BaseBranch: mainBranch, + HeadBranch: "unittests", + PullRequestNumber: 1000, + Organization: "mylittle", + Repository: "pony", + }, + data: testclient.Data{ + Repositories: []*v1alpha1.Repository{ + testnewrepo.NewRepo( + testnewrepo.RepoTestcreationOpts{ + Name: "test-good", + URL: targetURL, + InstallNamespace: targetNamespace, + }, + ), + }, + }, + }, + }, + { + name: "match/on-path-change-ignore/include and ignore path", + wantPRName: pipelineTargetNSName, + args: annotationTestArgs{ + fileChanged: []struct { + FileName string + Status string + NewFile bool + RenamedFile bool + DeletedFile bool + }{ + { + FileName: "doc/added.md", + Status: "added", + NewFile: true, + RenamedFile: false, + DeletedFile: false, + }, + }, + pruns: []*tektonv1.PipelineRun{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: pipelineTargetNSName, + Annotations: map[string]string{ + keys.OnTargetBranch: mainBranch, + keys.OnEvent: "[pull_request]", + keys.OnPathChange: "[doc/***]", + keys.OnPathChangeIgnore: "[doc/generated/*]", + }, + }, + }, + }, + runevent: info.Event{ + URL: targetURL, + TriggerTarget: "pull_request", + EventType: "pull_request", + BaseBranch: mainBranch, + HeadBranch: "unittests", + PullRequestNumber: 1000, + Organization: "mylittle", + Repository: "pony", + }, + data: testclient.Data{ + Repositories: []*v1alpha1.Repository{ + testnewrepo.NewRepo( + testnewrepo.RepoTestcreationOpts{ + Name: "test-good", + URL: targetURL, + InstallNamespace: targetNamespace, + }, + ), + }, + }, + }, + }, + { + name: "match/on-path-change-ignore/ignore path", + wantPRName: pipelineTargetNSName, + args: annotationTestArgs{ + fileChanged: []struct { + FileName string + Status string + NewFile bool + RenamedFile bool + DeletedFile bool + }{ + { + FileName: ".tekton/pull_request.yaml", + Status: "added", + NewFile: true, + RenamedFile: false, + DeletedFile: false, + }, + }, + pruns: []*tektonv1.PipelineRun{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: pipelineTargetNSName, + Annotations: map[string]string{ + keys.OnTargetBranch: mainBranch, + keys.OnEvent: "[pull_request]", + keys.OnPathChangeIgnore: "[doc/*md]", + }, + }, + }, + }, + runevent: info.Event{ + URL: targetURL, + TriggerTarget: "pull_request", + EventType: "pull_request", + BaseBranch: mainBranch, + HeadBranch: "unittests", + PullRequestNumber: 1000, + Organization: "mylittle", + Repository: "pony", + }, + data: testclient.Data{ + Repositories: []*v1alpha1.Repository{ + testnewrepo.NewRepo( + testnewrepo.RepoTestcreationOpts{ + Name: "test-good", + URL: targetURL, + InstallNamespace: targetNamespace, + }, + ), + }, + }, + }, + }, + { + name: "match/on-path-change/match path by glob", + wantPRName: pipelineTargetNSName, + args: annotationTestArgs{ + fileChanged: []struct { + FileName string + Status string + NewFile bool + RenamedFile bool + DeletedFile bool + }{ + { + FileName: ".tekton/pull_request.yaml", + Status: "added", + NewFile: true, + RenamedFile: false, + DeletedFile: false, + }, + }, + pruns: []*tektonv1.PipelineRun{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: pipelineTargetNSName, + Annotations: map[string]string{ + keys.OnTargetBranch: mainBranch, + keys.OnEvent: "[pull_request]", + keys.OnPathChange: "[.tekton/*yaml]", + }, + }, + }, + }, + runevent: info.Event{ + URL: targetURL, + TriggerTarget: "pull_request", + EventType: "pull_request", + BaseBranch: mainBranch, + HeadBranch: "unittests", + PullRequestNumber: 1000, + Organization: "mylittle", + Repository: "pony", + }, + data: testclient.Data{ + Repositories: []*v1alpha1.Repository{ + testnewrepo.NewRepo( + testnewrepo.RepoTestcreationOpts{ + Name: "test-good", + URL: targetURL, + InstallNamespace: targetNamespace, + }, + ), + }, + }, + }, + }, + { + name: "error/match/on-path-change/match path no match event", + wantErr: true, + args: annotationTestArgs{ + fileChanged: []struct { + FileName string + Status string + NewFile bool + RenamedFile bool + DeletedFile bool + }{ + { + FileName: ".tekton/pull_request.yaml", + Status: "added", + NewFile: true, + RenamedFile: false, + DeletedFile: false, + }, + }, + pruns: []*tektonv1.PipelineRun{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: pipelineTargetNSName, + Annotations: map[string]string{ + keys.OnTargetBranch: mainBranch, + keys.OnEvent: "[push]", + keys.OnPathChange: "[.tekton/*yaml]", + }, + }, + }, + }, + runevent: info.Event{ + URL: targetURL, + TriggerTarget: "pull_request", + EventType: "pull_request", + BaseBranch: mainBranch, + HeadBranch: "unittests", + PullRequestNumber: 1000, + Organization: "mylittle", + Repository: "pony", + }, + data: testclient.Data{ + Repositories: []*v1alpha1.Repository{ + testnewrepo.NewRepo( + testnewrepo.RepoTestcreationOpts{ + Name: "test-good", + URL: targetURL, + InstallNamespace: targetNamespace, + }, + ), + }, + }, + }, + }, { name: "match TargetPipelineRun", @@ -1080,6 +1354,10 @@ func runTest(ctx context.Context, t *testing.T, tt annotationTest, vcx provider. client, &tt.args.runevent, vcx, ) + if tt.wantLog != "" { + assert.Assert(t, log.FilterMessage(tt.wantLog) != nil, "We didn't get the expected log message") + } + if tt.wantErr { assert.Assert(t, err != nil, "We should have get an error") } @@ -1096,9 +1374,6 @@ func runTest(ctx context.Context, t *testing.T, tt annotationTest, vcx provider. if tt.wantPRName != "" { assert.Assert(t, tt.wantPRName == matches[0].PipelineRun.GetName()) } - if tt.wantLog != "" { - assert.Assert(t, log.FilterMessage(tt.wantLog) != nil, "We didn't get the expected log message") - } } func TestMatchPipelinerunByAnnotation(t *testing.T) { diff --git a/test/gitea_test.go b/test/gitea_test.go index 7196c3a31..5d4dd2ecc 100644 --- a/test/gitea_test.go +++ b/test/gitea_test.go @@ -612,6 +612,69 @@ func TestGiteaConcurrencyOrderedExecution(t *testing.T) { time.Sleep(time.Second * 10) } +func TestGiteaOnPathChange(t *testing.T) { + topts := &tgitea.TestOpts{ + TargetEvent: triggertype.PullRequest.String(), + YAMLFiles: map[string]string{ + ".tekton/pr.yaml": "testdata/pipelinerun-on-path-change.yaml", + "doc/foo/bar/README.md": "README.md", + }, + CheckForStatus: "success", + } + _, f := tgitea.TestPR(t, topts) + defer f() +} + +// TestGiteaOnPathChangeIgnore will test that pipelinerun is not triggered when +// a path is ignored but all other will do. +func TestGiteaOnPathChangeIgnore(t *testing.T) { + // This should trigger a pipelinerun since we ignore the path + // on-path-change-ignore: "[doc/foo/***.md]" + // and we create a file doc/bar/README.md + topts := &tgitea.TestOpts{ + TargetEvent: triggertype.PullRequest.String(), + YAMLFiles: map[string]string{ + ".tekton/pr2.yaml": "testdata/pipelinerun-on-path-change-ignore.yaml", + "doc/bar/README.md": "README.md", + }, + CheckForStatus: "success", + CheckForNumberStatus: 1, + } + _, f := tgitea.TestPR(t, topts) + defer f() + + // This should not trigger a pipelinerun since we have + // on-path-change-ignore: "[doc/foo/***.md]" + // and the file doc/foo/README.md is created + topts2 := &tgitea.TestOpts{ + TargetEvent: triggertype.PullRequest.String(), + YAMLFiles: map[string]string{ + ".tekton/pr2.yaml": "testdata/pipelinerun-on-path-change-ignore.yaml", + "doc/foo/README.md": "README.md", + }, + CheckForNumberStatus: 0, + } + _, f2 := tgitea.TestPR(t, topts2) + defer f2() +} + +// TestGiteaOnPathChangeAndOnPathChangeIgnore will test that +// on-path-change and on-path-change-ignore both work together. +func TestGiteaOnPathChangeAndOnPathChangeIgnore(t *testing.T) { + topts := &tgitea.TestOpts{ + TargetEvent: triggertype.PullRequest.String(), + YAMLFiles: map[string]string{ + ".tekton/pr.yaml": "testdata/pipelinerun-on-path-change.yaml", + ".tekton/pr2.yaml": "testdata/pipelinerun-on-path-change-and-ignore.yaml", + "doc/foo/bar/README.md": "README.md", + }, + CheckForStatus: "success", + CheckForNumberStatus: 1, + } + _, f := tgitea.TestPR(t, topts) + defer f() +} + func TestGiteaErrorSnippet(t *testing.T) { topts := &tgitea.TestOpts{ TargetEvent: triggertype.PullRequest.String(), diff --git a/test/testdata/pipelinerun-on-path-change-and-ignore.yaml b/test/testdata/pipelinerun-on-path-change-and-ignore.yaml new file mode 100644 index 000000000..8a5a35195 --- /dev/null +++ b/test/testdata/pipelinerun-on-path-change-and-ignore.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +metadata: + name: "\\ .PipelineName //" + annotations: + pipelinesascode.tekton.dev/target-namespace: "\\ .TargetNamespace //" + pipelinesascode.tekton.dev/on-target-branch: "[\\ .TargetBranch //]" + pipelinesascode.tekton.dev/on-event: "[\\ .TargetEvent //]" + pipelinesascode.tekton.dev/on-path-change: "[doc/***.md]" + pipelinesascode.tekton.dev/on-path-change-ignore: "[doc/foo/***.md]" +spec: + pipelineSpec: + tasks: + - name: task + taskSpec: + steps: + - name: success + image: registry.access.redhat.com/ubi9/ubi-micro + script: | + echo "I have matched" + exit 0 diff --git a/test/testdata/pipelinerun-on-path-change-ignore.yaml b/test/testdata/pipelinerun-on-path-change-ignore.yaml new file mode 100644 index 000000000..869789285 --- /dev/null +++ b/test/testdata/pipelinerun-on-path-change-ignore.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +metadata: + name: "\\ .PipelineName //" + annotations: + pipelinesascode.tekton.dev/target-namespace: "\\ .TargetNamespace //" + pipelinesascode.tekton.dev/on-target-branch: "[\\ .TargetBranch //]" + pipelinesascode.tekton.dev/on-event: "[\\ .TargetEvent //]" + pipelinesascode.tekton.dev/on-path-change-ignore: "[doc/foo/***.md]" +spec: + pipelineSpec: + tasks: + - name: task + taskSpec: + steps: + - name: success + image: registry.access.redhat.com/ubi9/ubi-micro + script: | + echo "I have matched" + exit 0 diff --git a/test/testdata/pipelinerun-on-path-change.yaml b/test/testdata/pipelinerun-on-path-change.yaml new file mode 100644 index 000000000..e3b195938 --- /dev/null +++ b/test/testdata/pipelinerun-on-path-change.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +metadata: + name: "\\ .PipelineName //" + annotations: + pipelinesascode.tekton.dev/target-namespace: "\\ .TargetNamespace //" + pipelinesascode.tekton.dev/on-target-branch: "[\\ .TargetBranch //]" + pipelinesascode.tekton.dev/on-event: "[\\ .TargetEvent //]" + pipelinesascode.tekton.dev/on-path-change: "[doc/***.md]" +spec: + pipelineSpec: + tasks: + - name: task + taskSpec: + steps: + - name: success + image: registry.access.redhat.com/ubi9/ubi-micro + script: | + echo "I am a such a good booooy" + exit 0