From ca84f703e32f4e08c67215cce5be646f6b96012c Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 30 Aug 2022 00:36:37 +0200 Subject: [PATCH] Add default event filter (#1140) breakout from #934 when new events are added you don't have to worry that pipeline will behave different as it does now with this Co-authored-by: Anbraten --- Makefile | 1 + docs/docs/20-usage/20-pipeline-syntax.md | 51 ++++++------- .../frontend/yaml/constraint/constraint.go | 23 +++++- .../yaml/constraint/constraint_test.go | 75 +++++++++++-------- pipeline/schema/schema.json | 12 +-- server/shared/procBuilder_test.go | 4 +- 6 files changed, 101 insertions(+), 65 deletions(-) diff --git a/Makefile b/Makefile index 0f02cfaa8..142530104 100644 --- a/Makefile +++ b/Makefile @@ -52,6 +52,7 @@ else all: build +.PHONY: vendor vendor: go mod tidy go mod vendor diff --git a/docs/docs/20-usage/20-pipeline-syntax.md b/docs/docs/20-usage/20-pipeline-syntax.md index f224c9314..23773c5c8 100644 --- a/docs/docs/20-usage/20-pipeline-syntax.md +++ b/docs/docs/20-usage/20-pipeline-syntax.md @@ -100,7 +100,7 @@ pipeline: Woodpecker gives the ability to skip individual commits by adding `[CI SKIP]` to the commit message. Note this is case-insensitive. -```diff +```sh git commit -m "updated README [CI SKIP]" ``` @@ -234,7 +234,7 @@ Commands of every pipeline step are executed serially as if you would enter them There is no magic here. The above commands are converted to a simple shell script. The commands in the above example are roughly converted to the below script: -```diff +```sh #!/bin/sh set -e @@ -244,7 +244,7 @@ go test The above shell script is then executed as the container entrypoint. The below docker command is an (incomplete) example of how the script is executed: -```bash +```sh docker run --entrypoint=build.sh golang ``` @@ -315,21 +315,21 @@ pipeline: Execute a step if the branch is `master` or `develop`: -```diff +```yaml when: - branch: [master, develop] ``` Execute a step if the branch starts with `prefix/*`: -```diff +```yaml when: - branch: prefix/* ``` Execute a step using custom include and exclude logic: -```diff +```yaml when: - branch: include: [ master, release/* ] @@ -338,9 +338,17 @@ when: #### `event` +:::info +**By default steps are filtered by following event types:** + +`push`, `pull_request, `tag`, `deployment`. +::: + +Available events: `push`, `pull_request`, `tag`, `deployment` + Execute a step if the build event is a `tag`: -```diff +```yaml when: - event: tag ``` @@ -353,26 +361,19 @@ when: + branch: main ``` -Execute a step for all non-pull request events: +Execute a step for multiple events: -```diff +```yaml when: - event: [push, tag, deployment] ``` -Execute a step for all build events: - -```diff -when: - - event: [push, pull_request, tag, deployment] -``` - #### `tag` This filter only applies to tag events. Use glob expression to execute a step if the tag name starts with `v`: -```diff +```yaml when: - event: tag tag: v* @@ -400,14 +401,14 @@ This condition should be used in conjunction with a [matrix](/docs/usage/matrix- Execute a step for a specific platform: -```diff +```yaml when: - platform: linux/amd64 ``` Execute a step for a specific platform using wildcards: -```diff +```yaml when: - platform: [ linux/*, windows/amd64 ] ``` @@ -416,7 +417,7 @@ when: Execute a step for deployment events matching the target deployment environment: -```diff +```yaml when: - environment: production - event: deployment @@ -426,7 +427,7 @@ when: Execute a step for a single matrix permutation: -```diff +```yaml when: - matrix: GO_VERSION: 1.5 @@ -437,7 +438,7 @@ when: Execute a step only on a certain Woodpecker instance matching the specified hostname: -```diff +```yaml when: - instance: stage.woodpecker.company.com ``` @@ -452,14 +453,14 @@ Gitea only support **push** at the moment ([go-gitea/gitea#18228](https://github Execute a step only on a pipeline with certain files being changed: -```diff +```yaml when: - path: "src/*" ``` You can use [glob patterns](https://github.com/bmatcuk/doublestar#patterns) to match the changed files and specify if the step should run if a file matching that pattern has been changed `include` or if some files have **not** been changed `exclude`. -```diff +```yaml when: - path: include: [ '.woodpecker/*.yml', '*.ini' ] @@ -559,7 +560,7 @@ The base attribute defines a shared base volume available to all pipeline steps. This would be equivalent to the following docker commands: -```bash +```sh docker volume create my-named-volume docker run --volume=my-named-volume:/go golang:latest diff --git a/pipeline/frontend/yaml/constraint/constraint.go b/pipeline/frontend/yaml/constraint/constraint.go index b6e763ed5..45948c6ff 100644 --- a/pipeline/frontend/yaml/constraint/constraint.go +++ b/pipeline/frontend/yaml/constraint/constraint.go @@ -63,7 +63,13 @@ func (when *When) Match(metadata frontend.Metadata) bool { return true } } - return when.IsEmpty() + + if when.IsEmpty() { + // test against default Constraints + empty := &Constraint{} + return empty.Match(metadata) + } + return false } func (when *When) IncludesStatus(status string) bool { @@ -120,6 +126,16 @@ func (when *When) UnmarshalYAML(value *yaml.Node) error { // Match returns true if all constraints match the given input. If a single // constraint fails a false value is returned. func (c *Constraint) Match(metadata frontend.Metadata) bool { + // if event filter is not set, set default + if c.Event.IsEmpty() { + c.Event.Include = []string{ + frontend.EventPush, + frontend.EventPull, + frontend.EventTag, + frontend.EventDeploy, + } + } + match := c.Platform.Match(metadata.Sys.Platform) && c.Environment.Match(metadata.Curr.Target) && c.Event.Match(metadata.Curr.Event) && @@ -140,6 +156,11 @@ func (c *Constraint) Match(metadata frontend.Metadata) bool { return match } +// IsEmpty return true if a constraint has no conditions +func (c List) IsEmpty() bool { + return len(c.Include) == 0 && len(c.Exclude) == 0 +} + // Match returns true if the string matches the include patterns and does not // match any of the exclude patterns. func (c *List) Match(v string) bool { diff --git a/pipeline/frontend/yaml/constraint/constraint_test.go b/pipeline/frontend/yaml/constraint/constraint_test.go index 94c364b18..1a48f37a4 100644 --- a/pipeline/frontend/yaml/constraint/constraint_test.go +++ b/pipeline/frontend/yaml/constraint/constraint_test.go @@ -383,89 +383,98 @@ func TestConstraintMap(t *testing.T) { func TestConstraints(t *testing.T) { testdata := []struct { + desc string conf string with frontend.Metadata want bool }{ - // no constraints, must match { + desc: "no constraints, must match on default events", conf: "", - with: frontend.Metadata{}, + with: frontend.Metadata{ + Curr: frontend.Build{ + Event: frontend.EventPush, + }, + }, want: true, }, - // branch constraint { + desc: "global branch filter", conf: "{ branch: develop }", - with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Branch: "master"}}}, + with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush, Commit: frontend.Commit{Branch: "master"}}}, want: false, }, { + desc: "global branch filter", conf: "{ branch: master }", - with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Branch: "master"}}}, + with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush, Commit: frontend.Commit{Branch: "master"}}}, want: true, }, - // environment constraint - { - conf: "{ branch: develop }", - with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Branch: "master"}}}, - want: false, - }, - { - conf: "{ branch: master }", - with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Branch: "master"}}}, - want: true, - }, - // repo constraint { + desc: "repo constraint", conf: "{ repo: owner/* }", - with: frontend.Metadata{Repo: frontend.Repo{Name: "owner/repo"}}, + with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}}, want: true, }, { + desc: "repo constraint", conf: "{ repo: octocat/* }", - with: frontend.Metadata{Repo: frontend.Repo{Name: "owner/repo"}}, + with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}}, want: false, }, - // ref constraint { + desc: "ref constraint", conf: "{ ref: refs/tags/* }", - with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Ref: "refs/tags/v1.0.0"}}}, + with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Ref: "refs/tags/v1.0.0"}, Event: frontend.EventPush}}, want: true, }, { + desc: "ref constraint", conf: "{ ref: refs/tags/* }", - with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Ref: "refs/heads/master"}}}, + with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Ref: "refs/heads/master"}, Event: frontend.EventPush}}, want: false, }, - // platform constraint { + desc: "platform constraint", conf: "{ platform: linux/amd64 }", - with: frontend.Metadata{Sys: frontend.System{Platform: "linux/amd64"}}, + with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Sys: frontend.System{Platform: "linux/amd64"}}, want: true, }, { + desc: "platform constraint", conf: "{ repo: linux/amd64 }", - with: frontend.Metadata{Sys: frontend.System{Platform: "windows/amd64"}}, + with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Sys: frontend.System{Platform: "windows/amd64"}}, want: false, }, - // instance constraint { + desc: "instance constraint", conf: "{ instance: agent.tld }", - with: frontend.Metadata{Sys: frontend.System{Host: "agent.tld"}}, + with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Sys: frontend.System{Host: "agent.tld"}}, want: true, }, { + desc: "instance constraint", conf: "{ instance: agent.tld }", - with: frontend.Metadata{Sys: frontend.System{Host: "beta.agent.tld"}}, + with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Sys: frontend.System{Host: "beta.agent.tld"}}, + want: false, + }, + { + desc: "no constraints, and event get filtered by default default event filter", + conf: "", + with: frontend.Metadata{ + Curr: frontend.Build{Event: "non-default"}, + }, want: false, }, } for _, test := range testdata { - c := parseConstraints(t, test.conf) - got, want := c.Match(test.with), test.want - if got != want { - t.Errorf("Expect %+v matches %q is %v", test.with, test.conf, want) - } + t.Run(test.desc, func(t *testing.T) { + c := parseConstraints(t, test.conf) + got, want := c.Match(test.with), test.want + if got != want { + t.Errorf("Expect %+v matches %q is %v", test.with, test.conf, want) + } + }) } } diff --git a/pipeline/schema/schema.json b/pipeline/schema/schema.json index 506864769..259e68189 100644 --- a/pipeline/schema/schema.json +++ b/pipeline/schema/schema.json @@ -186,13 +186,11 @@ "oneOf": [ { "type": "array", - "items": { - "enum": ["push", "pull_request", "tag", "deployment"] - }, - "minLength": 1 + "minLength": 1, + "items": { "$ref": "#/definitions/event_enum" } }, { - "enum": ["push", "pull_request", "tag", "deployment"] + "$ref": "#/definitions/event_enum" } ] }, @@ -270,6 +268,10 @@ } } }, + "event_enum": { + "default": ["push", "pull_request", "tag", "deployment"], + "enum": ["push", "pull_request", "tag", "deployment"] + }, "step_image": { "description": "Read more: https://woodpecker-ci.org/docs/usage/pipeline-syntax#image", "type": "string" diff --git a/server/shared/procBuilder_test.go b/server/shared/procBuilder_test.go index 77bb891c5..2b92281ca 100644 --- a/server/shared/procBuilder_test.go +++ b/server/shared/procBuilder_test.go @@ -465,7 +465,9 @@ depends_on: [ shouldbefiltered ] func TestTree(t *testing.T) { t.Parallel() - build := &model.Build{} + build := &model.Build{ + Event: model.EventPush, + } b := ProcBuilder{ Repo: &model.Repo{},