mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-26 03:41:01 +00:00
Introducing runs_on to run pipelines on failure
This commit is contained in:
parent
2253ca66db
commit
a433591afa
7 changed files with 143 additions and 9 deletions
|
@ -23,6 +23,7 @@ type (
|
|||
Volumes Volumes
|
||||
Labels libcompose.SliceorMap
|
||||
DependsOn []string `yaml:"depends_on,omitempty"`
|
||||
RunsOn []string `yaml:"runs_on,omitempty"`
|
||||
}
|
||||
|
||||
// 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.DependsOn[0]).Equal("lint")
|
||||
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
|
||||
// g.It("Should unmarshal variables", func() {
|
||||
|
@ -99,6 +101,9 @@ labels:
|
|||
depends_on:
|
||||
- lint
|
||||
- test
|
||||
runs_on:
|
||||
- success
|
||||
- failure
|
||||
`
|
||||
|
||||
var sampleVarYaml = `
|
||||
|
|
|
@ -127,7 +127,7 @@ func TestFifoDependencies(t *testing.T) {
|
|||
task2 := &Task{
|
||||
ID: "2",
|
||||
Dependencies: []string{"1"},
|
||||
DepStatus: make(map[string]bool),
|
||||
DepStatus: make(map[string]bool),
|
||||
}
|
||||
|
||||
q := New().(*fifo)
|
||||
|
@ -157,14 +157,14 @@ func TestFifoErrors(t *testing.T) {
|
|||
task2 := &Task{
|
||||
ID: "2",
|
||||
Dependencies: []string{"1"},
|
||||
DepStatus: make(map[string]bool),
|
||||
DepStatus: make(map[string]bool),
|
||||
}
|
||||
|
||||
task3 := &Task{
|
||||
ID: "3",
|
||||
Dependencies: []string{"1"},
|
||||
DepStatus: make(map[string]bool),
|
||||
RunOn: []string{"success", "failure"},
|
||||
DepStatus: make(map[string]bool),
|
||||
RunOn: []string{"success", "failure"},
|
||||
}
|
||||
|
||||
q := New().(*fifo)
|
||||
|
@ -202,3 +202,69 @@ func TestFifoErrors(t *testing.T) {
|
|||
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
|
||||
func (t *Task) ShouldRun() bool {
|
||||
if runsOnFailure(t.RunOn) {
|
||||
if runsOnFailure(t.RunOn) && runsOnSuccess(t.RunOn) {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, success := range t.DepStatus {
|
||||
if !success {
|
||||
return false
|
||||
if !runsOnFailure(t.RunOn) && runsOnSuccess(t.RunOn) {
|
||||
for _, success := range t.DepStatus {
|
||||
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 {
|
||||
|
@ -58,6 +70,19 @@ func runsOnFailure(runsOn []string) bool {
|
|||
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.
|
||||
type InfoT struct {
|
||||
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["repo"] = repo.FullName
|
||||
task.Dependencies = taskIds(item.DependsOn, buildItems)
|
||||
task.RunOn = item.RunsOn
|
||||
task.DepStatus = make(map[string]bool)
|
||||
|
||||
task.Data, _ = json.Marshal(rpc.Pipeline{
|
||||
|
|
|
@ -50,6 +50,7 @@ type buildItem struct {
|
|||
Platform string
|
||||
Labels map[string]string
|
||||
DependsOn []string
|
||||
RunsOn []string
|
||||
Config *backend.Config
|
||||
}
|
||||
|
||||
|
@ -111,6 +112,7 @@ func (b *procBuilder) Build() ([]*buildItem, error) {
|
|||
Config: ir,
|
||||
Labels: parsed.Labels,
|
||||
DependsOn: parsed.DependsOn,
|
||||
RunsOn: parsed.RunsOn,
|
||||
Platform: metadata.Sys.Arch,
|
||||
}
|
||||
if item.Labels == nil {
|
||||
|
|
|
@ -124,3 +124,37 @@ depends_on:
|
|||
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