mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-30 12:20:33 +00:00
Add when evaluate filter (#1213)
closes #312 closes #224 closes #963 Have a look for https://github.com/antonmedv/expr/blob/master/docs/Language-Definition.md
This commit is contained in:
parent
f1339412eb
commit
287800ac62
12 changed files with 159 additions and 39 deletions
|
@ -157,7 +157,7 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
|||
}
|
||||
|
||||
// compiles the yaml file
|
||||
compiled := compiler.New(
|
||||
compiled, err := compiler.New(
|
||||
compiler.WithEscalated(
|
||||
c.StringSlice("privileged")...,
|
||||
),
|
||||
|
@ -185,6 +185,9 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
|||
compiler.WithSecret(secrets...),
|
||||
compiler.WithEnviron(droneEnv),
|
||||
).Compile(conf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
backend.Init(context.WithValue(c.Context, types.CliContext, c))
|
||||
|
||||
|
|
|
@ -435,6 +435,33 @@ when:
|
|||
|
||||
**Hint:** Passing a defined ignore-message like `[ALL]` inside the commit message will ignore all path conditions.
|
||||
|
||||
#### `evaluate`
|
||||
|
||||
Execute a step only if the provided evaluate expression is equal to true. Each [`CI_` variable](./50-environment.md#built-in-environment-variables) can be used inside the expression.
|
||||
|
||||
The expression syntax can be found in [the docs](https://github.com/antonmedv/expr/blob/master/docs/Language-Definition.md) of the underlying library.
|
||||
|
||||
Run on pushes to the default branch for the repository `owner/repo`:
|
||||
|
||||
```yaml
|
||||
when:
|
||||
- evaluate: 'CI_BUILD_EVENT == "push" && CI_REPO == "owner/repo" && CI_COMMIT_BRANCH == CI_REPO_DEFAULT_BRANCH'
|
||||
```
|
||||
|
||||
Run on commits created by user `woodpecker-ci`:
|
||||
|
||||
```yaml
|
||||
when:
|
||||
- evaluate: 'CI_COMMIT_AUTHOR == "woodpecker-ci"'
|
||||
```
|
||||
|
||||
Skip all commits containing `please ignore me` in the commit message:
|
||||
|
||||
```yaml
|
||||
when:
|
||||
- evaluate: 'not (CI_COMMIT_MESSAGE contains "please ignore me")'
|
||||
```
|
||||
|
||||
### `group` - Parallel execution
|
||||
|
||||
Woodpecker supports parallel step execution for same-machine fan-in and fan-out. Parallel steps are configured using the `group` attribute. This instructs the pipeline runner to execute the named group in parallel.
|
||||
|
|
1
go.mod
1
go.mod
|
@ -5,6 +5,7 @@ go 1.18
|
|||
require (
|
||||
code.gitea.io/sdk/gitea v0.15.1-0.20220831004139-a0127ed0e7fe
|
||||
codeberg.org/6543/go-yaml2json v0.2.1
|
||||
github.com/antonmedv/expr v1.9.0
|
||||
github.com/bmatcuk/doublestar/v4 v4.2.0
|
||||
github.com/caddyserver/certmagic v0.17.1-0.20220901172127-2e22c6fa8c47
|
||||
github.com/docker/cli v20.10.17+incompatible
|
||||
|
|
16
go.sum
16
go.sum
|
@ -66,6 +66,7 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl
|
|||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
|
||||
|
@ -85,6 +86,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
|
|||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/antonmedv/expr v1.9.0 h1:j4HI3NHEdgDnN9p6oI6Ndr0G5QryMY0FNxT4ONrFDGU=
|
||||
github.com/antonmedv/expr v1.9.0/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmHhwGEk8=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
|
@ -143,6 +146,7 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
|||
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg=
|
||||
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
@ -195,6 +199,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
|||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
|
@ -506,6 +512,8 @@ github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
|
|||
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
|
@ -532,6 +540,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
|
|||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
|
@ -624,6 +634,7 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||
github.com/pkg/sftp v1.13.4 h1:Lb0RYJCmgUcBgZosfoi9Y9sbl6+LJgOIgk/2Y4YjMFg=
|
||||
github.com/pkg/sftp v1.13.4/go.mod h1:LzqnAvaD5TWeNBsZpfKxSYn1MbjWwOsCIAFFJbpIsK8=
|
||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
|
@ -663,6 +674,8 @@ github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0ua
|
|||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/tview v0.0.0-20200219210816-cd38d7432498/go.mod h1:6lkG1x+13OShEf0EaOCaTQYyB7d5nSbb181KtjlS+84=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
|
||||
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
|
@ -683,6 +696,7 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf
|
|||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/sanity-io/litter v1.2.0/go.mod h1:JF6pZUFgu2Q0sBZ+HSV35P8TVPI1TTzEwyu9FXAw2W4=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
|
@ -716,6 +730,7 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
|
@ -962,6 +977,7 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
|
@ -93,13 +93,15 @@ func New(opts ...Option) *Compiler {
|
|||
|
||||
// Compile compiles the YAML configuration to the pipeline intermediate
|
||||
// representation configuration format.
|
||||
func (c *Compiler) Compile(conf *yaml.Config) *backend.Config {
|
||||
func (c *Compiler) Compile(conf *yaml.Config) (*backend.Config, error) {
|
||||
config := new(backend.Config)
|
||||
|
||||
if !conf.When.Match(c.metadata, true) {
|
||||
if match, err := conf.When.Match(c.metadata, true); !match && err == nil {
|
||||
// This pipeline does not match the configured filter so return an empty config and stop further compilation.
|
||||
// An empty pipeline will just be skipped completely.
|
||||
return config
|
||||
return config, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create a default volume
|
||||
|
@ -166,9 +168,12 @@ func (c *Compiler) Compile(conf *yaml.Config) *backend.Config {
|
|||
config.Stages = append(config.Stages, stage)
|
||||
} else if !c.local && !conf.SkipClone {
|
||||
for i, container := range conf.Clone.Containers {
|
||||
if !container.When.Match(c.metadata, false) {
|
||||
if match, err := container.When.Match(c.metadata, false); !match && err == nil {
|
||||
continue
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stage := new(backend.Stage)
|
||||
stage.Name = fmt.Sprintf("%s_clone_%v", c.prefix, i)
|
||||
stage.Alias = container.Name
|
||||
|
@ -193,8 +198,10 @@ func (c *Compiler) Compile(conf *yaml.Config) *backend.Config {
|
|||
stage.Alias = nameServices
|
||||
|
||||
for i, container := range conf.Services.Containers {
|
||||
if !container.When.Match(c.metadata, false) {
|
||||
if match, err := container.When.Match(c.metadata, false); !match && err == nil {
|
||||
continue
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("%s_%s_%d", c.prefix, nameServices, i)
|
||||
|
@ -213,8 +220,10 @@ func (c *Compiler) Compile(conf *yaml.Config) *backend.Config {
|
|||
continue
|
||||
}
|
||||
|
||||
if !container.When.Match(c.metadata, false) {
|
||||
if match, err := container.When.Match(c.metadata, false); !match && err == nil {
|
||||
continue
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stage == nil || group != container.Group || container.Group == "" {
|
||||
|
@ -233,7 +242,7 @@ func (c *Compiler) Compile(conf *yaml.Config) *backend.Config {
|
|||
|
||||
c.setupCacheRebuild(conf, config)
|
||||
|
||||
return config
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (c *Compiler) setupCache(conf *yaml.Config, ir *backend.Config) {
|
||||
|
|
|
@ -79,37 +79,45 @@ func TestParse(t *testing.T) {
|
|||
}
|
||||
|
||||
g.It("Should match event tester", func() {
|
||||
g.Assert(matchConfig.When.Match(frontend.Metadata{
|
||||
match, err := matchConfig.When.Match(frontend.Metadata{
|
||||
Curr: frontend.Build{
|
||||
Event: "tester",
|
||||
},
|
||||
}, false)).Equal(true)
|
||||
}, false)
|
||||
g.Assert(match).Equal(true)
|
||||
g.Assert(err).IsNil()
|
||||
})
|
||||
|
||||
g.It("Should match event tester2", func() {
|
||||
g.Assert(matchConfig.When.Match(frontend.Metadata{
|
||||
match, err := matchConfig.When.Match(frontend.Metadata{
|
||||
Curr: frontend.Build{
|
||||
Event: "tester2",
|
||||
},
|
||||
}, false)).Equal(true)
|
||||
}, false)
|
||||
g.Assert(match).Equal(true)
|
||||
g.Assert(err).IsNil()
|
||||
})
|
||||
|
||||
g.It("Should match branch tester", func() {
|
||||
g.Assert(matchConfig.When.Match(frontend.Metadata{
|
||||
match, err := matchConfig.When.Match(frontend.Metadata{
|
||||
Curr: frontend.Build{
|
||||
Commit: frontend.Commit{
|
||||
Branch: "tester",
|
||||
},
|
||||
},
|
||||
}, true)).Equal(true)
|
||||
}, true)
|
||||
g.Assert(match).Equal(true)
|
||||
g.Assert(err).IsNil()
|
||||
})
|
||||
|
||||
g.It("Should not match event push", func() {
|
||||
g.Assert(matchConfig.When.Match(frontend.Metadata{
|
||||
match, err := matchConfig.When.Match(frontend.Metadata{
|
||||
Curr: frontend.Build{
|
||||
Event: "push",
|
||||
},
|
||||
}, false)).Equal(false)
|
||||
}, false)
|
||||
g.Assert(match).Equal(false)
|
||||
g.Assert(err).IsNil()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/antonmedv/expr"
|
||||
"github.com/bmatcuk/doublestar/v4"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
|
@ -31,6 +32,7 @@ type (
|
|||
Matrix Map
|
||||
Local types.BoolTrue
|
||||
Path Path
|
||||
Evaluate string `yaml:"evaluate,omitempty"`
|
||||
}
|
||||
|
||||
// List defines a runtime constraint for exclude & include string slices.
|
||||
|
@ -58,10 +60,14 @@ func (when *When) IsEmpty() bool {
|
|||
}
|
||||
|
||||
// Returns true if at least one of the internal constraints is true.
|
||||
func (when *When) Match(metadata frontend.Metadata, global bool) bool {
|
||||
func (when *When) Match(metadata frontend.Metadata, global bool) (bool, error) {
|
||||
for _, c := range when.Constraints {
|
||||
if c.Match(metadata, global) {
|
||||
return true
|
||||
match, err := c.Match(metadata, global)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if match {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +76,7 @@ func (when *When) Match(metadata frontend.Metadata, global bool) bool {
|
|||
empty := &Constraint{}
|
||||
return empty.Match(metadata, global)
|
||||
}
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (when *When) IncludesStatus(status string) bool {
|
||||
|
@ -126,7 +132,7 @@ 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, global bool) bool {
|
||||
func (c *Constraint) Match(metadata frontend.Metadata, global bool) (bool, error) {
|
||||
match := true
|
||||
if !global {
|
||||
c.SetDefaultEventFilter()
|
||||
|
@ -155,7 +161,20 @@ func (c *Constraint) Match(metadata frontend.Metadata, global bool) bool {
|
|||
match = match && c.Cron.Match(metadata.Curr.Cron)
|
||||
}
|
||||
|
||||
return match
|
||||
if c.Evaluate != "" {
|
||||
env := metadata.Environ()
|
||||
out, err := expr.Compile(c.Evaluate, expr.Env(env), expr.AsBool())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, err := expr.Run(out, env)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
match = match && result.(bool)
|
||||
}
|
||||
|
||||
return match, nil
|
||||
}
|
||||
|
||||
// SetDefaultEventFilter set default e event filter if not event filter is already set
|
||||
|
|
|
@ -484,14 +484,29 @@ func TestConstraints(t *testing.T) {
|
|||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
desc: "filter by eval based on event",
|
||||
conf: `{ evaluate: 'CI_BUILD_EVENT == "push"' }`,
|
||||
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
desc: "filter by eval based on event and repo",
|
||||
conf: `{ evaluate: 'CI_BUILD_EVENT == "push" && CI_REPO == "owner/repo"' }`,
|
||||
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}},
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testdata {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
c := parseConstraints(t, test.conf)
|
||||
got, want := c.Match(test.with, false), test.want
|
||||
if got != want {
|
||||
t.Errorf("Expect %+v matches %q is %v", test.with, test.conf, want)
|
||||
got, err := c.Match(test.with, false)
|
||||
if err != nil {
|
||||
t.Errorf("Match returned error: %v", err)
|
||||
}
|
||||
if got != test.want {
|
||||
t.Errorf("Expect %+v matches %q is %v", test.with, test.conf, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -134,9 +134,16 @@ pipeline:
|
|||
image: alpine
|
||||
commands: echo "test"
|
||||
when:
|
||||
event: cron
|
||||
- event: cron
|
||||
cron:
|
||||
include:
|
||||
- test
|
||||
- hello
|
||||
exclude: hi
|
||||
|
||||
when-evaluate:
|
||||
image: alpine
|
||||
commands: echo "test"
|
||||
when:
|
||||
- event: push
|
||||
evaluate: 'CI_BUILD_EVENT == "push" && CI_REPO == "owner/repo"'
|
||||
|
|
|
@ -189,6 +189,10 @@
|
|||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"evaluate": {
|
||||
"description": "Execute a step only if the expression evaluates to true. Read more: https://woodpecker-ci.org/docs/usage/pipeline-syntax#evaluate",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -344,6 +348,10 @@
|
|||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"evaluate": {
|
||||
"description": "Execute a step only if the expression evaluates to true. Read more: https://woodpecker-ci.org/docs/usage/pipeline-syntax#evaluate",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -499,10 +507,7 @@
|
|||
"description": "expose ports to which other steps can connect to",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{ "type": "number" },
|
||||
{ "type": "string" }
|
||||
]
|
||||
"oneOf": [{ "type": "number" }, { "type": "string" }]
|
||||
},
|
||||
"minLength": 1
|
||||
}
|
||||
|
|
|
@ -72,8 +72,10 @@ func checkIfFiltered(build *model.Build, remoteYamlConfigs []*remote.FileMeta) (
|
|||
log.Trace().Msgf("config '%s': %#v", remoteYamlConfig.Name, parsedPipelineConfig)
|
||||
|
||||
// ignore if the pipeline was filtered by matched constraints
|
||||
if !parsedPipelineConfig.When.Match(matchMetadata, true) {
|
||||
if match, err := parsedPipelineConfig.When.Match(matchMetadata, true); !match && err == nil {
|
||||
continue
|
||||
} else if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// ignore if the pipeline was filtered by the branch (legacy)
|
||||
|
|
|
@ -119,11 +119,16 @@ func (b *ProcBuilder) Build() ([]*BuildItem, error) {
|
|||
}
|
||||
|
||||
// checking if filtered.
|
||||
if !parsed.When.Match(metadata, true) {
|
||||
if match, err := parsed.When.Match(metadata, true); !match && err == nil {
|
||||
log.Debug().Str("pipeline", proc.Name).Msg(
|
||||
"Marked as skipped, dose not match metadata",
|
||||
)
|
||||
proc.State = model.StatusSkipped
|
||||
} else if err != nil {
|
||||
log.Debug().Str("pipeline", proc.Name).Msg(
|
||||
"Pipeline config could not be parsed",
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: deprecated branches filter => remove after some time
|
||||
|
@ -134,7 +139,10 @@ func (b *ProcBuilder) Build() ([]*BuildItem, error) {
|
|||
proc.State = model.StatusSkipped
|
||||
}
|
||||
|
||||
ir := b.toInternalRepresentation(parsed, environ, metadata, proc.ID)
|
||||
ir, err := b.toInternalRepresentation(parsed, environ, metadata, proc.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(ir.Stages) == 0 {
|
||||
continue
|
||||
|
@ -229,7 +237,7 @@ func (b *ProcBuilder) environmentVariables(metadata frontend.Metadata, axis matr
|
|||
return environ
|
||||
}
|
||||
|
||||
func (b *ProcBuilder) toInternalRepresentation(parsed *yaml.Config, environ map[string]string, metadata frontend.Metadata, procID int64) *backend.Config {
|
||||
func (b *ProcBuilder) toInternalRepresentation(parsed *yaml.Config, environ map[string]string, metadata frontend.Metadata, procID int64) (*backend.Config, error) {
|
||||
var secrets []compiler.Secret
|
||||
for _, sec := range b.Secs {
|
||||
if !sec.Match(b.Curr.Event) {
|
||||
|
|
Loading…
Reference in a new issue