Introducing runs_on to run pipelines on failure

This commit is contained in:
Laszlo Fogas 2019-06-17 09:06:36 +02:00
parent 2253ca66db
commit a433591afa
7 changed files with 143 additions and 9 deletions

View file

@ -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.

View file

@ -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 = `

View file

@ -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
}
}

View file

@ -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"`

View file

@ -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{

View file

@ -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 {

View file

@ -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")
}
}