mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-06-18 05:10:48 +00:00
Introducing runs_on to run pipelines on failure
This commit is contained in:
parent
2253ca66db
commit
a433591afa
|
@ -23,6 +23,7 @@ type (
|
||||||
Volumes Volumes
|
Volumes Volumes
|
||||||
Labels libcompose.SliceorMap
|
Labels libcompose.SliceorMap
|
||||||
DependsOn []string `yaml:"depends_on,omitempty"`
|
DependsOn []string `yaml:"depends_on,omitempty"`
|
||||||
|
RunsOn []string `yaml:"runs_on,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Workspace defines a pipeline workspace.
|
// Workspace defines a pipeline workspace.
|
||||||
|
|
|
@ -40,6 +40,8 @@ func TestParse(t *testing.T) {
|
||||||
g.Assert(out.Labels["com.example.type"]).Equal("build")
|
g.Assert(out.Labels["com.example.type"]).Equal("build")
|
||||||
g.Assert(out.DependsOn[0]).Equal("lint")
|
g.Assert(out.DependsOn[0]).Equal("lint")
|
||||||
g.Assert(out.DependsOn[1]).Equal("test")
|
g.Assert(out.DependsOn[1]).Equal("test")
|
||||||
|
g.Assert(out.RunsOn[0]).Equal("success")
|
||||||
|
g.Assert(out.RunsOn[1]).Equal("failure")
|
||||||
})
|
})
|
||||||
// Check to make sure variable expansion works in yaml.MapSlice
|
// Check to make sure variable expansion works in yaml.MapSlice
|
||||||
// g.It("Should unmarshal variables", func() {
|
// g.It("Should unmarshal variables", func() {
|
||||||
|
@ -99,6 +101,9 @@ labels:
|
||||||
depends_on:
|
depends_on:
|
||||||
- lint
|
- lint
|
||||||
- test
|
- test
|
||||||
|
runs_on:
|
||||||
|
- success
|
||||||
|
- failure
|
||||||
`
|
`
|
||||||
|
|
||||||
var sampleVarYaml = `
|
var sampleVarYaml = `
|
||||||
|
|
|
@ -127,7 +127,7 @@ func TestFifoDependencies(t *testing.T) {
|
||||||
task2 := &Task{
|
task2 := &Task{
|
||||||
ID: "2",
|
ID: "2",
|
||||||
Dependencies: []string{"1"},
|
Dependencies: []string{"1"},
|
||||||
DepStatus: make(map[string]bool),
|
DepStatus: make(map[string]bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
q := New().(*fifo)
|
q := New().(*fifo)
|
||||||
|
@ -157,14 +157,14 @@ func TestFifoErrors(t *testing.T) {
|
||||||
task2 := &Task{
|
task2 := &Task{
|
||||||
ID: "2",
|
ID: "2",
|
||||||
Dependencies: []string{"1"},
|
Dependencies: []string{"1"},
|
||||||
DepStatus: make(map[string]bool),
|
DepStatus: make(map[string]bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
task3 := &Task{
|
task3 := &Task{
|
||||||
ID: "3",
|
ID: "3",
|
||||||
Dependencies: []string{"1"},
|
Dependencies: []string{"1"},
|
||||||
DepStatus: make(map[string]bool),
|
DepStatus: make(map[string]bool),
|
||||||
RunOn: []string{"success", "failure"},
|
RunOn: []string{"success", "failure"},
|
||||||
}
|
}
|
||||||
|
|
||||||
q := New().(*fifo)
|
q := New().(*fifo)
|
||||||
|
@ -202,3 +202,69 @@ func TestFifoErrors(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestShouldRun(t *testing.T) {
|
||||||
|
task := &Task{
|
||||||
|
ID: "2",
|
||||||
|
Dependencies: []string{"1"},
|
||||||
|
DepStatus: map[string]bool{
|
||||||
|
"1": true,
|
||||||
|
},
|
||||||
|
RunOn: []string{"failure"},
|
||||||
|
}
|
||||||
|
if task.ShouldRun() {
|
||||||
|
t.Errorf("expect task to not run, it runs on failure only")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
task = &Task{
|
||||||
|
ID: "2",
|
||||||
|
Dependencies: []string{"1"},
|
||||||
|
DepStatus: map[string]bool{
|
||||||
|
"1": true,
|
||||||
|
},
|
||||||
|
RunOn: []string{"failure", "success"},
|
||||||
|
}
|
||||||
|
if !task.ShouldRun() {
|
||||||
|
t.Errorf("expect task to run")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
task = &Task{
|
||||||
|
ID: "2",
|
||||||
|
Dependencies: []string{"1"},
|
||||||
|
DepStatus: map[string]bool{
|
||||||
|
"1": false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if task.ShouldRun() {
|
||||||
|
t.Errorf("expect task to not run")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
task = &Task{
|
||||||
|
ID: "2",
|
||||||
|
Dependencies: []string{"1"},
|
||||||
|
DepStatus: map[string]bool{
|
||||||
|
"1": true,
|
||||||
|
},
|
||||||
|
RunOn: []string{"success"},
|
||||||
|
}
|
||||||
|
if !task.ShouldRun() {
|
||||||
|
t.Errorf("expect task to run")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
task = &Task{
|
||||||
|
ID: "2",
|
||||||
|
Dependencies: []string{"1"},
|
||||||
|
DepStatus: map[string]bool{
|
||||||
|
"1": false,
|
||||||
|
},
|
||||||
|
RunOn: []string{"failure"},
|
||||||
|
}
|
||||||
|
if !task.ShouldRun() {
|
||||||
|
t.Errorf("expect task to run")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -36,17 +36,29 @@ type Task struct {
|
||||||
|
|
||||||
// ShouldRun tells if a task should be run or skipped, based on dependencies
|
// ShouldRun tells if a task should be run or skipped, based on dependencies
|
||||||
func (t *Task) ShouldRun() bool {
|
func (t *Task) ShouldRun() bool {
|
||||||
if runsOnFailure(t.RunOn) {
|
if runsOnFailure(t.RunOn) && runsOnSuccess(t.RunOn) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, success := range t.DepStatus {
|
if !runsOnFailure(t.RunOn) && runsOnSuccess(t.RunOn) {
|
||||||
if !success {
|
for _, success := range t.DepStatus {
|
||||||
return false
|
if !success {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
if runsOnFailure(t.RunOn) && !runsOnSuccess(t.RunOn) {
|
||||||
|
for _, success := range t.DepStatus {
|
||||||
|
if success {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func runsOnFailure(runsOn []string) bool {
|
func runsOnFailure(runsOn []string) bool {
|
||||||
|
@ -58,6 +70,19 @@ func runsOnFailure(runsOn []string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runsOnSuccess(runsOn []string) bool {
|
||||||
|
if len(runsOn) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, status := range runsOn {
|
||||||
|
if status == "success" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// InfoT provides runtime information.
|
// InfoT provides runtime information.
|
||||||
type InfoT struct {
|
type InfoT struct {
|
||||||
Pending []*Task `json:"pending"`
|
Pending []*Task `json:"pending"`
|
||||||
|
|
|
@ -321,6 +321,7 @@ func queueBuild(build *model.Build, repo *model.Repo, buildItems []*buildItem) {
|
||||||
task.Labels["platform"] = item.Platform
|
task.Labels["platform"] = item.Platform
|
||||||
task.Labels["repo"] = repo.FullName
|
task.Labels["repo"] = repo.FullName
|
||||||
task.Dependencies = taskIds(item.DependsOn, buildItems)
|
task.Dependencies = taskIds(item.DependsOn, buildItems)
|
||||||
|
task.RunOn = item.RunsOn
|
||||||
task.DepStatus = make(map[string]bool)
|
task.DepStatus = make(map[string]bool)
|
||||||
|
|
||||||
task.Data, _ = json.Marshal(rpc.Pipeline{
|
task.Data, _ = json.Marshal(rpc.Pipeline{
|
||||||
|
|
|
@ -50,6 +50,7 @@ type buildItem struct {
|
||||||
Platform string
|
Platform string
|
||||||
Labels map[string]string
|
Labels map[string]string
|
||||||
DependsOn []string
|
DependsOn []string
|
||||||
|
RunsOn []string
|
||||||
Config *backend.Config
|
Config *backend.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +112,7 @@ func (b *procBuilder) Build() ([]*buildItem, error) {
|
||||||
Config: ir,
|
Config: ir,
|
||||||
Labels: parsed.Labels,
|
Labels: parsed.Labels,
|
||||||
DependsOn: parsed.DependsOn,
|
DependsOn: parsed.DependsOn,
|
||||||
|
RunsOn: parsed.RunsOn,
|
||||||
Platform: metadata.Sys.Arch,
|
Platform: metadata.Sys.Arch,
|
||||||
}
|
}
|
||||||
if item.Labels == nil {
|
if item.Labels == nil {
|
||||||
|
|
|
@ -124,3 +124,37 @@ depends_on:
|
||||||
t.Fatal("Should depend on test")
|
t.Fatal("Should depend on test")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRunsOn(t *testing.T) {
|
||||||
|
b := procBuilder{
|
||||||
|
Repo: &model.Repo{},
|
||||||
|
Curr: &model.Build{},
|
||||||
|
Last: &model.Build{},
|
||||||
|
Netrc: &model.Netrc{},
|
||||||
|
Secs: []*model.Secret{},
|
||||||
|
Regs: []*model.Registry{},
|
||||||
|
Link: "",
|
||||||
|
Yamls: []*remote.FileMeta{
|
||||||
|
&remote.FileMeta{Data: []byte(`
|
||||||
|
pipeline:
|
||||||
|
deploy:
|
||||||
|
image: scratch
|
||||||
|
|
||||||
|
runs_on:
|
||||||
|
- success
|
||||||
|
- failure
|
||||||
|
`)},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
buildItems, err := b.Build()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(buildItems[0].RunsOn) != 2 {
|
||||||
|
t.Fatal("Should run on success and failure")
|
||||||
|
}
|
||||||
|
if buildItems[0].RunsOn[1] != "failure" {
|
||||||
|
t.Fatal("Should run on failure")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue