grim/convey

3351eae5b1d5
Parents b412c2b5fc64
Children 178aec6c4f86
Move stages.Stage to the runtime package
--- a/plans/plans.go Thu Dec 23 09:08:12 2021 -0600
+++ b/plans/plans.go Thu Dec 23 09:18:29 2021 -0600
@@ -27,7 +27,6 @@
"keep.imfreedom.org/grim/convey/environment"
"keep.imfreedom.org/grim/convey/logging"
"keep.imfreedom.org/grim/convey/runtime"
- "keep.imfreedom.org/grim/convey/stages"
"keep.imfreedom.org/grim/convey/yaml"
)
@@ -39,7 +38,7 @@
// Plan is the representation of a Plan.
type Plan struct {
Environment yaml.StringOrSlice `yaml:"environment"`
- Stages []stages.Stage `yaml:"stages"`
+ Stages []runtime.Stage `yaml:"stages"`
logger *log.Entry
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/stages.go Thu Dec 23 09:18:29 2021 -0600
@@ -0,0 +1,167 @@
+// Convey
+// Copyright 2016-2018 Gary Kramlich <grim@reaperworld.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+// Package stages contains the stages api.
+package runtime
+
+import (
+ "fmt"
+ "sync"
+
+ log "github.com/sirupsen/logrus"
+
+ "keep.imfreedom.org/grim/convey/environment"
+ "keep.imfreedom.org/grim/convey/logging"
+ "keep.imfreedom.org/grim/convey/yaml"
+)
+
+const (
+ RunAlways = "always"
+ RunOnFailure = "on-failure"
+ RunOnSuccess = "on-success"
+)
+
+// Stage is a representation of a stage.
+type Stage struct {
+ Name string `yaml:"name"`
+ Run string `yaml:"run"`
+ Environment yaml.StringOrSlice `yaml:"environment"`
+ Tasks yaml.StringOrSlice `yaml:"tasks"`
+ Enabled bool `yaml:"enabled"`
+ Concurrent bool `yaml:"concurrent"`
+}
+
+// UnmarshalYAML is a custom yaml unmarshaller for stages.
+func (s *Stage) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ type rawStage Stage
+ raw := rawStage{Enabled: true}
+
+ if err := unmarshal(&raw); err != nil {
+ return err
+ }
+
+ *s = Stage(raw)
+
+ // validate the run attribute
+ switch s.Run {
+ case RunOnSuccess:
+ case RunOnFailure:
+ case RunAlways:
+ case "":
+ s.Run = RunOnSuccess
+ default:
+ return fmt.Errorf("Invalid value '%s' for run attribute", s.Run)
+ }
+
+ return nil
+}
+
+// Execute runs the stage.
+func (s *Stage) Execute(path string, logger *log.Entry, env environment.Environment, rt *Runtime) error {
+ stageEnv := env.Copy().Merge(env).MergeSlice(s.Environment)
+
+ if s.Concurrent && !rt.ForceSequential {
+ taskRes := make(chan error)
+ stageRes := make(chan error)
+
+ wg := sync.WaitGroup{}
+
+ // process all of the task results
+ go func(taskRes, stageRes chan error) {
+ var stageErr error
+
+ for err := range taskRes {
+ if err != nil && stageErr == nil {
+ stageErr = err
+ }
+ }
+
+ stageRes <- stageErr
+
+ // now close the stageRes channel
+ close(stageRes)
+ }(taskRes, stageRes)
+
+ // run all of the tasks in go routines
+ for _, taskName := range s.Tasks {
+ wg.Add(1)
+ go func(path, name string, res chan error) {
+ defer wg.Done()
+ res <- s.runTask(path, name, stageEnv, rt)
+ }(path, taskName, taskRes)
+ }
+
+ // block until the task wait group is done, then close the taskRes channel
+ wg.Wait()
+ close(taskRes)
+
+ // now return the result from the stageRes channel
+ return <-stageRes
+ }
+
+ // serial execution
+ for _, taskName := range s.Tasks {
+ err := s.runTask(path, taskName, stageEnv, rt)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (s *Stage) runTask(path, name string, stageEnv environment.Environment, rt *Runtime) error {
+ absTaskName := fmt.Sprintf("%s/%s", path, name)
+ taskLogger := logging.NewAdapter(fmt.Sprintf("%s/%s", path, name))
+
+ taskLogger.Info("starting")
+
+ task, found := rt.Tasks[name]
+ if !found {
+ taskLogger.Error("failed, task not found")
+
+ return fmt.Errorf("task %s not found", absTaskName)
+ }
+
+ err := task.Execute(absTaskName, taskLogger, stageEnv, rt)
+ if err != nil {
+ taskLogger.Errorf("failed, %s", err)
+
+ return err
+ }
+
+ taskLogger.Info("finished")
+
+ return nil
+}
+
+// ShouldRun will return True if a stage should be run based on the passed in
+// error (from the plan) and whether or not the stage is enabled.
+func (s *Stage) ShouldRun(err error) bool {
+ if !s.Enabled {
+ return false
+ }
+
+ if s.Run == RunAlways {
+ return true
+ }
+
+ if err != nil {
+ return s.Run == RunOnFailure
+ }
+
+ return s.Run == RunOnSuccess
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/stages_test.go Thu Dec 23 09:18:29 2021 -0600
@@ -0,0 +1,78 @@
+// Convey
+// Copyright 2016-2018 Gary Kramlich <grim@reaperworld.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package runtime
+
+import (
+ "errors"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestStageShouldRunOnFailEnabled(t *testing.T) {
+ stage := Stage{Enabled: true}
+ err := errors.New("testing")
+
+ stage.Run = "on-failure"
+ assert.True(t, stage.ShouldRun(err))
+
+ stage.Run = "always"
+ assert.True(t, stage.ShouldRun(err))
+
+ stage.Run = "on-success"
+ assert.False(t, stage.ShouldRun(err))
+}
+
+func TestStageShouldRunOnFailDisabled(t *testing.T) {
+ stage := Stage{Enabled: false}
+ err := errors.New("testing")
+
+ stage.Run = "on-failure"
+ assert.False(t, stage.ShouldRun(err))
+
+ stage.Run = "always"
+ assert.False(t, stage.ShouldRun(err))
+
+ stage.Run = "on-success"
+ assert.False(t, stage.ShouldRun(err))
+}
+
+func TestStageShouldRunOnSuccessEnabled(t *testing.T) {
+ stage := Stage{Enabled: true}
+
+ stage.Run = "on-success"
+ assert.True(t, stage.ShouldRun(nil))
+
+ stage.Run = "always"
+ assert.True(t, stage.ShouldRun(nil))
+
+ stage.Run = "on-failure"
+ assert.False(t, stage.ShouldRun(nil))
+}
+
+func TestStageShouldRunOnSuccessDisabled(t *testing.T) {
+ stage := Stage{Enabled: false}
+
+ stage.Run = "on-success"
+ assert.False(t, stage.ShouldRun(nil))
+
+ stage.Run = "always"
+ assert.False(t, stage.ShouldRun(nil))
+
+ stage.Run = "on-failure"
+ assert.False(t, stage.ShouldRun(nil))
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/stages_unmarshal_test.go Thu Dec 23 09:18:29 2021 -0600
@@ -0,0 +1,74 @@
+// Convey
+// Copyright 2016-2018 Gary Kramlich <grim@reaperworld.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package runtime
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "gopkg.in/yaml.v2"
+)
+
+func TestUnmarshalDefaults(t *testing.T) {
+ // we need a non empty string to get go-yaml to call our UnmarshalYAML
+ // function
+ data := `name: foo`
+ var stage Stage
+ err := yaml.Unmarshal([]byte(data), &stage)
+
+ assert.Nil(t, err)
+ assert.Equal(t, stage.Run, "on-success")
+}
+
+func TestUnmarshalInvalidRun(t *testing.T) {
+ data := `run: invalid`
+
+ var stage Stage
+ err := yaml.Unmarshal([]byte(data), &stage)
+
+ assert.NotNil(t, err)
+}
+
+func TestUnmarshalRunOnSuccess(t *testing.T) {
+ data := `run: on-success`
+
+ var stage Stage
+ err := yaml.Unmarshal([]byte(data), &stage)
+
+ assert.Nil(t, err)
+ assert.Equal(t, stage.Run, "on-success")
+}
+
+func TestUnmarshalRunOnFailure(t *testing.T) {
+ data := `run: on-failure`
+
+ var stage Stage
+ err := yaml.Unmarshal([]byte(data), &stage)
+
+ assert.Nil(t, err)
+ assert.Equal(t, stage.Run, "on-failure")
+}
+
+func TestUnmarshalRunAlways(t *testing.T) {
+ data := `run: always`
+
+ var stage Stage
+ err := yaml.Unmarshal([]byte(data), &stage)
+
+ assert.Nil(t, err)
+ assert.Equal(t, stage.Run, "always")
+}
--- a/stages/stages.go Thu Dec 23 09:08:12 2021 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,168 +0,0 @@
-// Convey
-// Copyright 2016-2018 Gary Kramlich <grim@reaperworld.com>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-// Package stages contains the stages api.
-package stages
-
-import (
- "fmt"
- "sync"
-
- log "github.com/sirupsen/logrus"
-
- "keep.imfreedom.org/grim/convey/environment"
- "keep.imfreedom.org/grim/convey/logging"
- "keep.imfreedom.org/grim/convey/runtime"
- "keep.imfreedom.org/grim/convey/yaml"
-)
-
-const (
- RunAlways = "always"
- RunOnFailure = "on-failure"
- RunOnSuccess = "on-success"
-)
-
-// Stage is a representation of a stage.
-type Stage struct {
- Name string `yaml:"name"`
- Run string `yaml:"run"`
- Environment yaml.StringOrSlice `yaml:"environment"`
- Tasks yaml.StringOrSlice `yaml:"tasks"`
- Enabled bool `yaml:"enabled"`
- Concurrent bool `yaml:"concurrent"`
-}
-
-// UnmarshalYAML is a custom yaml unmarshaller for stages.
-func (s *Stage) UnmarshalYAML(unmarshal func(interface{}) error) error {
- type rawStage Stage
- raw := rawStage{Enabled: true}
-
- if err := unmarshal(&raw); err != nil {
- return err
- }
-
- *s = Stage(raw)
-
- // validate the run attribute
- switch s.Run {
- case RunOnSuccess:
- case RunOnFailure:
- case RunAlways:
- case "":
- s.Run = RunOnSuccess
- default:
- return fmt.Errorf("Invalid value '%s' for run attribute", s.Run)
- }
-
- return nil
-}
-
-// Execute runs the stage.
-func (s *Stage) Execute(path string, logger *log.Entry, env environment.Environment, rt *runtime.Runtime) error {
- stageEnv := env.Copy().Merge(env).MergeSlice(s.Environment)
-
- if s.Concurrent && !rt.ForceSequential {
- taskRes := make(chan error)
- stageRes := make(chan error)
-
- wg := sync.WaitGroup{}
-
- // process all of the task results
- go func(taskRes, stageRes chan error) {
- var stageErr error
-
- for err := range taskRes {
- if err != nil && stageErr == nil {
- stageErr = err
- }
- }
-
- stageRes <- stageErr
-
- // now close the stageRes channel
- close(stageRes)
- }(taskRes, stageRes)
-
- // run all of the tasks in go routines
- for _, taskName := range s.Tasks {
- wg.Add(1)
- go func(path, name string, res chan error) {
- defer wg.Done()
- res <- s.runTask(path, name, stageEnv, rt)
- }(path, taskName, taskRes)
- }
-
- // block until the task wait group is done, then close the taskRes channel
- wg.Wait()
- close(taskRes)
-
- // now return the result from the stageRes channel
- return <-stageRes
- }
-
- // serial execution
- for _, taskName := range s.Tasks {
- err := s.runTask(path, taskName, stageEnv, rt)
- if err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func (s *Stage) runTask(path, name string, stageEnv environment.Environment, rt *runtime.Runtime) error {
- absTaskName := fmt.Sprintf("%s/%s", path, name)
- taskLogger := logging.NewAdapter(fmt.Sprintf("%s/%s", path, name))
-
- taskLogger.Info("starting")
-
- task, found := rt.Tasks[name]
- if !found {
- taskLogger.Error("failed, task not found")
-
- return fmt.Errorf("task %s not found", absTaskName)
- }
-
- err := task.Execute(absTaskName, taskLogger, stageEnv, rt)
- if err != nil {
- taskLogger.Errorf("failed, %s", err)
-
- return err
- }
-
- taskLogger.Info("finished")
-
- return nil
-}
-
-// ShouldRun will return True if a stage should be run based on the passed in
-// error (from the plan) and whether or not the stage is enabled.
-func (s *Stage) ShouldRun(err error) bool {
- if !s.Enabled {
- return false
- }
-
- if s.Run == RunAlways {
- return true
- }
-
- if err != nil {
- return s.Run == RunOnFailure
- }
-
- return s.Run == RunOnSuccess
-}
--- a/stages/stages_test.go Thu Dec 23 09:08:12 2021 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-// Convey
-// Copyright 2016-2018 Gary Kramlich <grim@reaperworld.com>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package stages
-
-import (
- "errors"
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestStageShouldRunOnFailEnabled(t *testing.T) {
- stage := Stage{Enabled: true}
- err := errors.New("testing")
-
- stage.Run = "on-failure"
- assert.True(t, stage.ShouldRun(err))
-
- stage.Run = "always"
- assert.True(t, stage.ShouldRun(err))
-
- stage.Run = "on-success"
- assert.False(t, stage.ShouldRun(err))
-}
-
-func TestStageShouldRunOnFailDisabled(t *testing.T) {
- stage := Stage{Enabled: false}
- err := errors.New("testing")
-
- stage.Run = "on-failure"
- assert.False(t, stage.ShouldRun(err))
-
- stage.Run = "always"
- assert.False(t, stage.ShouldRun(err))
-
- stage.Run = "on-success"
- assert.False(t, stage.ShouldRun(err))
-}
-
-func TestStageShouldRunOnSuccessEnabled(t *testing.T) {
- stage := Stage{Enabled: true}
-
- stage.Run = "on-success"
- assert.True(t, stage.ShouldRun(nil))
-
- stage.Run = "always"
- assert.True(t, stage.ShouldRun(nil))
-
- stage.Run = "on-failure"
- assert.False(t, stage.ShouldRun(nil))
-}
-
-func TestStageShouldRunOnSuccessDisabled(t *testing.T) {
- stage := Stage{Enabled: false}
-
- stage.Run = "on-success"
- assert.False(t, stage.ShouldRun(nil))
-
- stage.Run = "always"
- assert.False(t, stage.ShouldRun(nil))
-
- stage.Run = "on-failure"
- assert.False(t, stage.ShouldRun(nil))
-}
--- a/stages/unmarshal_test.go Thu Dec 23 09:08:12 2021 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-// Convey
-// Copyright 2016-2018 Gary Kramlich <grim@reaperworld.com>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package stages
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
- "gopkg.in/yaml.v2"
-)
-
-func TestUnmarshalDefaults(t *testing.T) {
- // we need a non empty string to get go-yaml to call our UnmarshalYAML
- // function
- data := `name: foo`
- var stage Stage
- err := yaml.Unmarshal([]byte(data), &stage)
-
- assert.Nil(t, err)
- assert.Equal(t, stage.Run, "on-success")
-}
-
-func TestUnmarshalInvalidRun(t *testing.T) {
- data := `run: invalid`
-
- var stage Stage
- err := yaml.Unmarshal([]byte(data), &stage)
-
- assert.NotNil(t, err)
-}
-
-func TestUnmarshalRunOnSuccess(t *testing.T) {
- data := `run: on-success`
-
- var stage Stage
- err := yaml.Unmarshal([]byte(data), &stage)
-
- assert.Nil(t, err)
- assert.Equal(t, stage.Run, "on-success")
-}
-
-func TestUnmarshalRunOnFailure(t *testing.T) {
- data := `run: on-failure`
-
- var stage Stage
- err := yaml.Unmarshal([]byte(data), &stage)
-
- assert.Nil(t, err)
- assert.Equal(t, stage.Run, "on-failure")
-}
-
-func TestUnmarshalRunAlways(t *testing.T) {
- data := `run: always`
-
- var stage Stage
- err := yaml.Unmarshal([]byte(data), &stage)
-
- assert.Nil(t, err)
- assert.Equal(t, stage.Run, "always")
-}