diff --git a/server/hook.go b/server/hook.go index ee50c3991..5c145455f 100644 --- a/server/hook.go +++ b/server/hook.go @@ -177,6 +177,11 @@ func PostHook(c *gin.Context) { return } + if zeroSteps(*build, remoteYamlConfigs) { + c.String(200, "Step conditions yield zero runnable steps") + return + } + // update some build fields build.RepoID = repo.ID build.Verified = true @@ -293,6 +298,30 @@ func branchFiltered(build *model.Build, remoteYamlConfigs []*remote.FileMeta) bo return true } +// uses pass by value as procBuilder has side effects on build. Something to be fixed +func zeroSteps(build model.Build, remoteYamlConfigs []*remote.FileMeta) bool { + b := procBuilder{ + Repo: &model.Repo{}, + Curr: &build, + Last: &model.Build{}, + Netrc: &model.Netrc{}, + Secs: []*model.Secret{}, + Regs: []*model.Registry{}, + Link: "", + Yamls: remoteYamlConfigs, + } + + buildItems, err := b.Build() + if err != nil { + return false + } + if len(buildItems) == 0 { + return true + } + + return false +} + func findOrPersistPipelineConfig(build *model.Build, remoteYamlConfig *remote.FileMeta) (*model.Config, error) { sha := shasum(remoteYamlConfig.Data) conf, err := Config.Storage.Config.ConfigFindIdentical(build.RepoID, sha) diff --git a/server/procBuilder.go b/server/procBuilder.go index 5eaadeefa..a78318d90 100644 --- a/server/procBuilder.go +++ b/server/procBuilder.go @@ -59,7 +59,9 @@ func (b *procBuilder) Build() ([]*buildItem, error) { sort.Sort(remote.ByName(b.Yamls)) - for j, y := range b.Yamls { + pidSequence := 1 + + for _, y := range b.Yamls { // matrix axes axes, err := matrix.ParseString(string(y.Data)) if err != nil { @@ -69,16 +71,15 @@ func (b *procBuilder) Build() ([]*buildItem, error) { axes = append(axes, matrix.Axis{}) } - for i, axis := range axes { + for _, axis := range axes { proc := &model.Proc{ BuildID: b.Curr.ID, - PID: j + i + 1, - PGID: j + i + 1, + PID: pidSequence, + PGID: pidSequence, State: model.StatusPending, Environ: axis, Name: sanitizePath(y.Name), } - b.Curr.Procs = append(b.Curr.Procs, proc) metadata := metadataFromStruct(b.Repo, b.Curr, b.Last, proc, b.Link) environ := b.environmentVariables(metadata, axis) @@ -111,6 +112,10 @@ func (b *procBuilder) Build() ([]*buildItem, error) { ir := b.toInternalRepresentation(parsed, environ, metadata, proc.ID) + if len(ir.Stages) == 0 { + continue + } + item := &buildItem{ Proc: proc, Config: ir, @@ -122,7 +127,10 @@ func (b *procBuilder) Build() ([]*buildItem, error) { if item.Labels == nil { item.Labels = map[string]string{} } + + b.Curr.Procs = append(b.Curr.Procs, proc) items = append(items, item) + pidSequence++ } } diff --git a/server/procBuilder_test.go b/server/procBuilder_test.go index 4452dfaf4..1c456cc29 100644 --- a/server/procBuilder_test.go +++ b/server/procBuilder_test.go @@ -201,6 +201,78 @@ pipeline: } } if buildItems[1].Proc.State != model.StatusPending { - t.Fatal("Should not run on dev branch") + t.Fatal("Should run on dev branch") + } +} + +func TestZeroSteps(t *testing.T) { + build := &model.Build{Branch: "dev"} + + b := procBuilder{ + Repo: &model.Repo{}, + Curr: build, + Last: &model.Build{}, + Netrc: &model.Netrc{}, + Secs: []*model.Secret{}, + Regs: []*model.Registry{}, + Link: "", + Yamls: []*remote.FileMeta{ + &remote.FileMeta{Data: []byte(` +skip_clone: true +pipeline: + build: + when: + branch: notdev + image: scratch + yyy: ${DRONE_COMMIT_MESSAGE} +`)}, + }, + } + + buildItems, err := b.Build() + if err != nil { + t.Fatal(err) + } + if len(buildItems) != 0 { + t.Fatal("Should not generate a build item if there are no steps") + } + if len(build.Procs) != 0 { + t.Fatal("Should not generate a build item if there are no steps") + } +} + +func TestTree(t *testing.T) { + build := &model.Build{} + + b := procBuilder{ + Repo: &model.Repo{}, + Curr: build, + Last: &model.Build{}, + Netrc: &model.Netrc{}, + Secs: []*model.Secret{}, + Regs: []*model.Registry{}, + Link: "", + Yamls: []*remote.FileMeta{ + &remote.FileMeta{Data: []byte(` +pipeline: + build: + image: scratch + yyy: ${DRONE_COMMIT_MESSAGE} +`)}, + }, + } + + _, err := b.Build() + if err != nil { + t.Fatal(err) + } + if len(build.Procs) != 3 { + t.Fatal("Should generate three in total") + } + if build.Procs[1].PPID != 1 { + t.Fatal("Clone step should be a children of the stage") + } + if build.Procs[2].PPID != 1 { + t.Fatal("Build step should be a children of the stage") } }