mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-26 11:51:02 +00:00
Allow multiple when conditions (#1087)
Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: LamaAni <zshotan@bloomberg.net>
This commit is contained in:
parent
98e6396e3e
commit
e269890643
10 changed files with 215 additions and 58 deletions
|
@ -264,7 +264,20 @@ For more details check the [secrets docs](/docs/usage/secrets/).
|
||||||
|
|
||||||
### `when` - Conditional Execution
|
### `when` - Conditional Execution
|
||||||
|
|
||||||
Woodpecker supports defining conditions for pipeline step by a `when` block. If all conditions in the `when` block evaluate to true the step is executed, otherwise it is skipped.
|
Woodpecker supports defining a list of conditions for a pipeline step by using a `when` block. If at least one of the conditions in the `when` block evaluate to true the step is executed, otherwise it is skipped. A condition can be a check like:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
pipeline:
|
||||||
|
slack:
|
||||||
|
image: plugins/slack
|
||||||
|
settings:
|
||||||
|
channel: dev
|
||||||
|
+ when:
|
||||||
|
+ - event: pull_request
|
||||||
|
+ repo: test/test
|
||||||
|
+ - event: push
|
||||||
|
+ branch: main
|
||||||
|
```
|
||||||
|
|
||||||
#### `repo`
|
#### `repo`
|
||||||
|
|
||||||
|
@ -277,7 +290,7 @@ Example conditional execution by repository:
|
||||||
settings:
|
settings:
|
||||||
channel: dev
|
channel: dev
|
||||||
+ when:
|
+ when:
|
||||||
+ repo: test/test
|
+ - repo: test/test
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `branch`
|
#### `branch`
|
||||||
|
@ -295,7 +308,7 @@ pipeline:
|
||||||
settings:
|
settings:
|
||||||
channel: dev
|
channel: dev
|
||||||
+ when:
|
+ when:
|
||||||
+ branch: master
|
+ - branch: master
|
||||||
```
|
```
|
||||||
|
|
||||||
> The step now triggers on master, but also if the target branch of a pull request is `master`. Add an event condition to limit it further to pushes on master only.
|
> The step now triggers on master, but also if the target branch of a pull request is `master`. Add an event condition to limit it further to pushes on master only.
|
||||||
|
@ -304,23 +317,23 @@ Execute a step if the branch is `master` or `develop`:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
when:
|
when:
|
||||||
branch: [master, develop]
|
- branch: [master, develop]
|
||||||
```
|
```
|
||||||
|
|
||||||
Execute a step if the branch starts with `prefix/*`:
|
Execute a step if the branch starts with `prefix/*`:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
when:
|
when:
|
||||||
branch: prefix/*
|
- branch: prefix/*
|
||||||
```
|
```
|
||||||
|
|
||||||
Execute a step using custom include and exclude logic:
|
Execute a step using custom include and exclude logic:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
when:
|
when:
|
||||||
branch:
|
- branch:
|
||||||
include: [ master, release/* ]
|
include: [ master, release/* ]
|
||||||
exclude: [ release/1.0.0, release/1.1.* ]
|
exclude: [ release/1.0.0, release/1.1.* ]
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `event`
|
#### `event`
|
||||||
|
@ -329,29 +342,29 @@ Execute a step if the build event is a `tag`:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
when:
|
when:
|
||||||
event: tag
|
- event: tag
|
||||||
```
|
```
|
||||||
|
|
||||||
Execute a step if the pipeline event is a `push` to a specified branch:
|
Execute a step if the pipeline event is a `push` to a specified branch:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
when:
|
when:
|
||||||
event: push
|
- event: push
|
||||||
+ branch: main
|
+ branch: main
|
||||||
```
|
```
|
||||||
|
|
||||||
Execute a step for all non-pull request events:
|
Execute a step for all non-pull request events:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
when:
|
when:
|
||||||
event: [push, tag, deployment]
|
- event: [push, tag, deployment]
|
||||||
```
|
```
|
||||||
|
|
||||||
Execute a step for all build events:
|
Execute a step for all build events:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
when:
|
when:
|
||||||
event: [push, pull_request, tag, deployment]
|
- event: [push, pull_request, tag, deployment]
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `tag`
|
#### `tag`
|
||||||
|
@ -361,8 +374,8 @@ Use glob expression to execute a step if the tag name starts with `v`:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
when:
|
when:
|
||||||
event: tag
|
- event: tag
|
||||||
tag: v*
|
tag: v*
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `status`
|
#### `status`
|
||||||
|
@ -376,7 +389,7 @@ pipeline:
|
||||||
settings:
|
settings:
|
||||||
channel: dev
|
channel: dev
|
||||||
+ when:
|
+ when:
|
||||||
+ status: [ success, failure ]
|
+ - status: [ success, failure ]
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `platform`
|
#### `platform`
|
||||||
|
@ -389,14 +402,14 @@ Execute a step for a specific platform:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
when:
|
when:
|
||||||
platform: linux/amd64
|
- platform: linux/amd64
|
||||||
```
|
```
|
||||||
|
|
||||||
Execute a step for a specific platform using wildcards:
|
Execute a step for a specific platform using wildcards:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
when:
|
when:
|
||||||
platform: [ linux/*, windows/amd64 ]
|
- platform: [ linux/*, windows/amd64 ]
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `environment`
|
#### `environment`
|
||||||
|
@ -405,8 +418,8 @@ Execute a step for deployment events matching the target deployment environment:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
when:
|
when:
|
||||||
environment: production
|
- environment: production
|
||||||
event: deployment
|
- event: deployment
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `matrix`
|
#### `matrix`
|
||||||
|
@ -415,9 +428,9 @@ Execute a step for a single matrix permutation:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
when:
|
when:
|
||||||
matrix:
|
- matrix:
|
||||||
GO_VERSION: 1.5
|
GO_VERSION: 1.5
|
||||||
REDIS_VERSION: 2.8
|
REDIS_VERSION: 2.8
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `instance`
|
#### `instance`
|
||||||
|
@ -426,7 +439,7 @@ Execute a step only on a certain Woodpecker instance matching the specified host
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
when:
|
when:
|
||||||
instance: stage.woodpecker.company.com
|
- instance: stage.woodpecker.company.com
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `path`
|
#### `path`
|
||||||
|
@ -441,17 +454,17 @@ Execute a step only on a pipeline with certain files being changed:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
when:
|
when:
|
||||||
path: "src/*"
|
- 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`.
|
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
|
```diff
|
||||||
when:
|
when:
|
||||||
path:
|
- path:
|
||||||
include: [ '.woodpecker/*.yml', '*.ini' ]
|
include: [ '.woodpecker/*.yml', '*.ini' ]
|
||||||
exclude: [ '*.md', 'docs/**' ]
|
exclude: [ '*.md', 'docs/**' ]
|
||||||
ignore_message: "[ALL]"
|
ignore_message: "[ALL]"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Hint:** Passing a defined ignore-message like `[ALL]` inside the commit message will ignore all path conditions.
|
**Hint:** Passing a defined ignore-message like `[ALL]` inside the commit message will ignore all path conditions.
|
||||||
|
|
|
@ -145,7 +145,7 @@ func (c *Compiler) Compile(conf *yaml.Config) *backend.Config {
|
||||||
config.Stages = append(config.Stages, stage)
|
config.Stages = append(config.Stages, stage)
|
||||||
} else if !c.local && !conf.SkipClone {
|
} else if !c.local && !conf.SkipClone {
|
||||||
for i, container := range conf.Clone.Containers {
|
for i, container := range conf.Clone.Containers {
|
||||||
if !container.Constraints.Match(c.metadata) {
|
if !container.When.Match(c.metadata) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
stage := new(backend.Stage)
|
stage := new(backend.Stage)
|
||||||
|
@ -172,7 +172,7 @@ func (c *Compiler) Compile(conf *yaml.Config) *backend.Config {
|
||||||
stage.Alias = nameServices
|
stage.Alias = nameServices
|
||||||
|
|
||||||
for i, container := range conf.Services.Containers {
|
for i, container := range conf.Services.Containers {
|
||||||
if !container.Constraints.Match(c.metadata) {
|
if !container.When.Match(c.metadata) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,11 +188,11 @@ func (c *Compiler) Compile(conf *yaml.Config) *backend.Config {
|
||||||
var group string
|
var group string
|
||||||
for i, container := range conf.Pipeline.Containers {
|
for i, container := range conf.Pipeline.Containers {
|
||||||
// Skip if local and should not run local
|
// Skip if local and should not run local
|
||||||
if c.local && !container.Constraints.Local.Bool() {
|
if c.local && !container.When.IsLocal() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !container.Constraints.Match(c.metadata) {
|
if !container.When.Match(c.metadata) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -145,6 +145,12 @@ func (c *Compiler) createProcess(name string, container *yaml.Container, section
|
||||||
cpuSet = c.reslimit.CPUSet
|
cpuSet = c.reslimit.CPUSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// all constraints must exclude success.
|
||||||
|
onSuccess := container.When.IsEmpty() ||
|
||||||
|
!container.When.ExcludesStatus("success")
|
||||||
|
// at least one constraint must include the status failure.
|
||||||
|
onFailure := container.When.IncludesStatus("failure")
|
||||||
|
|
||||||
return &backend.Step{
|
return &backend.Step{
|
||||||
Name: name,
|
Name: name,
|
||||||
Alias: container.Name,
|
Alias: container.Name,
|
||||||
|
@ -172,11 +178,9 @@ func (c *Compiler) createProcess(name string, container *yaml.Container, section
|
||||||
CPUShares: cpuShares,
|
CPUShares: cpuShares,
|
||||||
CPUSet: cpuSet,
|
CPUSet: cpuSet,
|
||||||
AuthConfig: authConfig,
|
AuthConfig: authConfig,
|
||||||
OnSuccess: container.Constraints.Status.Match("success"),
|
OnSuccess: onSuccess,
|
||||||
OnFailure: (len(container.Constraints.Status.Include)+
|
OnFailure: onFailure,
|
||||||
len(container.Constraints.Status.Exclude) != 0) &&
|
NetworkMode: networkMode,
|
||||||
container.Constraints.Status.Match("failure"),
|
IpcMode: ipcMode,
|
||||||
NetworkMode: networkMode,
|
|
||||||
IpcMode: ipcMode,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,10 +61,10 @@ func TestParse(t *testing.T) {
|
||||||
}
|
}
|
||||||
g.Assert(out.Pipeline.Containers[0].Name).Equal("notify_fail")
|
g.Assert(out.Pipeline.Containers[0].Name).Equal("notify_fail")
|
||||||
g.Assert(out.Pipeline.Containers[0].Image).Equal("plugins/slack")
|
g.Assert(out.Pipeline.Containers[0].Image).Equal("plugins/slack")
|
||||||
g.Assert(len(out.Pipeline.Containers[0].Constraints.Event.Include)).Equal(0)
|
g.Assert(len(out.Pipeline.Containers[0].When.Constraints)).Equal(0)
|
||||||
g.Assert(out.Pipeline.Containers[1].Name).Equal("notify_success")
|
g.Assert(out.Pipeline.Containers[1].Name).Equal("notify_success")
|
||||||
g.Assert(out.Pipeline.Containers[1].Image).Equal("plugins/slack")
|
g.Assert(out.Pipeline.Containers[1].Image).Equal("plugins/slack")
|
||||||
g.Assert(out.Pipeline.Containers[1].Constraints.Event.Include).Equal([]string{"success"})
|
g.Assert(out.Pipeline.Containers[1].When.Constraints[0].Event.Include).Equal([]string{"success"})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -12,8 +12,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// Constraints defines a set of runtime constraints.
|
// When defines a set of runtime constraints.
|
||||||
Constraints struct {
|
When struct {
|
||||||
|
// If true then read from a list of constraint
|
||||||
|
Constraints []Constraint
|
||||||
|
}
|
||||||
|
|
||||||
|
Constraint struct {
|
||||||
Ref List
|
Ref List
|
||||||
Repo List
|
Repo List
|
||||||
Instance List
|
Instance List
|
||||||
|
@ -47,9 +52,82 @@ type (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (when *When) IsEmpty() bool {
|
||||||
|
return len(when.Constraints) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if at least one of the internal constraints is true.
|
||||||
|
func (when *When) Match(metadata frontend.Metadata) bool {
|
||||||
|
for _, c := range when.Constraints {
|
||||||
|
if c.Match(metadata) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return when.IsEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (when *When) IncludesStatus(status string) bool {
|
||||||
|
for _, c := range when.Constraints {
|
||||||
|
if c.Status.Includes(status) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (when *When) ExcludesStatus(status string) bool {
|
||||||
|
for _, c := range when.Constraints {
|
||||||
|
if !c.Status.Excludes(status) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(when.Constraints) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// False if (any) non local
|
||||||
|
func (when *When) IsLocal() bool {
|
||||||
|
for _, c := range when.Constraints {
|
||||||
|
if !c.Local.Bool() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (when *When) UnmarshalYAML(value *yaml.Node) error {
|
||||||
|
unmarshelAsList := func() error {
|
||||||
|
lst := []Constraint{}
|
||||||
|
err := value.Decode(&lst)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
when.Constraints = lst
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
unmarshelAsDict := func() error {
|
||||||
|
c := Constraint{}
|
||||||
|
err := value.Decode(&c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
when.Constraints = append(when.Constraints, c)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := unmarshelAsList()
|
||||||
|
if err != nil {
|
||||||
|
err = unmarshelAsDict()
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Match returns true if all constraints match the given input. If a single
|
// Match returns true if all constraints match the given input. If a single
|
||||||
// constraint fails a false value is returned.
|
// constraint fails a false value is returned.
|
||||||
func (c *Constraints) Match(metadata frontend.Metadata) bool {
|
func (c *Constraint) Match(metadata frontend.Metadata) bool {
|
||||||
match := c.Platform.Match(metadata.Sys.Platform) &&
|
match := c.Platform.Match(metadata.Sys.Platform) &&
|
||||||
c.Environment.Match(metadata.Curr.Target) &&
|
c.Environment.Match(metadata.Curr.Target) &&
|
||||||
c.Event.Match(metadata.Curr.Event) &&
|
c.Event.Match(metadata.Curr.Event) &&
|
||||||
|
@ -58,10 +136,11 @@ func (c *Constraints) Match(metadata frontend.Metadata) bool {
|
||||||
c.Instance.Match(metadata.Sys.Host) &&
|
c.Instance.Match(metadata.Sys.Host) &&
|
||||||
c.Matrix.Match(metadata.Job.Matrix)
|
c.Matrix.Match(metadata.Job.Matrix)
|
||||||
|
|
||||||
// changed files filter do only apply for pull-request and push events
|
// changed files filter apply only for pull-request and push events
|
||||||
if metadata.Curr.Event == frontend.EventPull || metadata.Curr.Event == frontend.EventPush {
|
if metadata.Curr.Event == frontend.EventPull || metadata.Curr.Event == frontend.EventPush {
|
||||||
match = match && c.Path.Match(metadata.Curr.Commit.ChangedFiles, metadata.Curr.Commit.Message)
|
match = match && c.Path.Match(metadata.Curr.Commit.ChangedFiles, metadata.Curr.Commit.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
if metadata.Curr.Event != frontend.EventTag {
|
if metadata.Curr.Event != frontend.EventTag {
|
||||||
match = match && c.Branch.Match(metadata.Curr.Commit.Branch)
|
match = match && c.Branch.Match(metadata.Curr.Commit.Branch)
|
||||||
}
|
}
|
||||||
|
@ -137,6 +216,7 @@ func (c *Map) Match(params map[string]string) bool {
|
||||||
if len(c.Include) == 0 && len(c.Exclude) == 0 {
|
if len(c.Include) == 0 && len(c.Exclude) == 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// exclusions are processed first. So we can include everything and then
|
// exclusions are processed first. So we can include everything and then
|
||||||
// selectively include others.
|
// selectively include others.
|
||||||
if len(c.Exclude) != 0 {
|
if len(c.Exclude) != 0 {
|
||||||
|
@ -211,12 +291,13 @@ func (c *Path) UnmarshalYAML(value *yaml.Node) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match returns true if file paths in string slice matches the include and not exclude patterns
|
// Match returns true if file paths in string slice matches the include and not exclude patterns
|
||||||
// or if commit message contains ignore message.
|
// or if commit message contains ignore message.
|
||||||
func (c *Path) Match(v []string, message string) bool {
|
func (c *Path) Match(v []string, message string) bool {
|
||||||
// ignore file pattern matches if the commit message contains a pattern
|
// ignore file pattern matches if the commit message contains a pattern
|
||||||
if len(c.IgnoreMessage) > 0 && strings.Contains(strings.ToLower(message), strings.ToLower(c.IgnoreMessage)) {
|
if len(c.IgnoreMessage) > 0 && strings.Contains(strings.ToLower(message), strings.ToLower(c.IgnoreMessage)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// always match if there are no commit files (empty commit)
|
// always match if there are no commit files (empty commit)
|
||||||
if len(v) == 0 {
|
if len(v) == 0 {
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -469,8 +469,8 @@ func TestConstraints(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseConstraints(t *testing.T, s string) *Constraints {
|
func parseConstraints(t *testing.T, s string) *When {
|
||||||
c := &Constraints{}
|
c := &When{}
|
||||||
assert.NoError(t, yaml.Unmarshal([]byte(s), c))
|
assert.NoError(t, yaml.Unmarshal([]byte(s), c))
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ type (
|
||||||
Volumes types.Volumes `yaml:"volumes,omitempty"`
|
Volumes types.Volumes `yaml:"volumes,omitempty"`
|
||||||
Secrets Secrets `yaml:"secrets,omitempty"`
|
Secrets Secrets `yaml:"secrets,omitempty"`
|
||||||
Sysctls types.SliceorMap `yaml:"sysctls,omitempty"`
|
Sysctls types.SliceorMap `yaml:"sysctls,omitempty"`
|
||||||
Constraints constraint.Constraints `yaml:"when,omitempty"`
|
When constraint.When `yaml:"when,omitempty"`
|
||||||
Settings map[string]interface{} `yaml:"settings"`
|
Settings map[string]interface{} `yaml:"settings"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -109,9 +109,13 @@ func TestUnmarshalContainer(t *testing.T) {
|
||||||
{Source: "/etc/configs", Destination: "/etc/configs/", AccessMode: "ro"},
|
{Source: "/etc/configs", Destination: "/etc/configs/", AccessMode: "ro"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Constraints: constraint.Constraints{
|
When: constraint.When{
|
||||||
Branch: constraint.List{
|
Constraints: []constraint.Constraint{
|
||||||
Include: []string{"master"},
|
{
|
||||||
|
Branch: constraint.List{
|
||||||
|
Include: []string{"master"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Settings: map[string]interface{}{
|
Settings: map[string]interface{}{
|
||||||
|
@ -185,9 +189,13 @@ func TestUnmarshalContainers(t *testing.T) {
|
||||||
"tag": stringsToInterface("next", "latest"),
|
"tag": stringsToInterface("next", "latest"),
|
||||||
"dry_run": true,
|
"dry_run": true,
|
||||||
},
|
},
|
||||||
Constraints: constraint.Constraints{
|
When: constraint.When{
|
||||||
Event: constraint.List{Include: []string{"push"}},
|
Constraints: []constraint.Constraint{
|
||||||
Branch: constraint.List{Include: []string{"${CI_REPO_DEFAULT_BRANCH}"}},
|
{
|
||||||
|
Event: constraint.List{Include: []string{"push"}},
|
||||||
|
Branch: constraint.List{Include: []string{"${CI_REPO_DEFAULT_BRANCH}"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -213,9 +221,38 @@ func TestUnmarshalContainers(t *testing.T) {
|
||||||
"dockerfile": "docker/Dockerfile.cli",
|
"dockerfile": "docker/Dockerfile.cli",
|
||||||
"tag": stringsToInterface("next"),
|
"tag": stringsToInterface("next"),
|
||||||
},
|
},
|
||||||
Constraints: constraint.Constraints{
|
When: constraint.When{
|
||||||
Event: constraint.List{Include: []string{"push"}},
|
Constraints: []constraint.Constraint{
|
||||||
Branch: constraint.List{Include: []string{"${CI_REPO_DEFAULT_BRANCH}"}},
|
{
|
||||||
|
Event: constraint.List{Include: []string{"push"}},
|
||||||
|
Branch: constraint.List{Include: []string{"${CI_REPO_DEFAULT_BRANCH}"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: `publish-cli:
|
||||||
|
image: print/env
|
||||||
|
when:
|
||||||
|
- branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||||
|
event: push
|
||||||
|
- event: pull_request`,
|
||||||
|
want: []*Container{
|
||||||
|
{
|
||||||
|
Name: "publish-cli",
|
||||||
|
Image: "print/env",
|
||||||
|
When: constraint.When{
|
||||||
|
Constraints: []constraint.Constraint{
|
||||||
|
{
|
||||||
|
Event: constraint.List{Include: []string{"push"}},
|
||||||
|
Branch: constraint.List{Include: []string{"${CI_REPO_DEFAULT_BRANCH}"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Event: constraint.List{Include: []string{"pull_request"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -111,3 +111,13 @@ pipeline:
|
||||||
- echo "test"
|
- echo "test"
|
||||||
when:
|
when:
|
||||||
repo: test/test
|
repo: test/test
|
||||||
|
|
||||||
|
when-multi:
|
||||||
|
image: alpine
|
||||||
|
commands:
|
||||||
|
- echo "test"
|
||||||
|
when:
|
||||||
|
- event: pull_request
|
||||||
|
repo: test/test
|
||||||
|
- event: push
|
||||||
|
branch: main
|
||||||
|
|
|
@ -140,6 +140,18 @@
|
||||||
},
|
},
|
||||||
"step_when": {
|
"step_when": {
|
||||||
"description": "Steps can be skipped based on conditions. Read more: https://woodpecker-ci.org/docs/usage/pipeline-syntax#when---conditional-execution",
|
"description": "Steps can be skipped based on conditions. Read more: https://woodpecker-ci.org/docs/usage/pipeline-syntax#when---conditional-execution",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"minLength": 1,
|
||||||
|
"items": { "$ref": "#/definitions/step_when_condition" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/step_when_condition"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"step_when_condition": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
Loading…
Reference in a new issue